Skip to content

Commit

Permalink
Пlog*: +- -> 2x; Refactor tests; Add q as security parameter
Browse files Browse the repository at this point in the history
  • Loading branch information
maurges committed Jan 25, 2023
1 parent b072b87 commit 294f575
Showing 1 changed file with 94 additions and 79 deletions.
173 changes: 94 additions & 79 deletions src/group_element_vs_paillier_encryption_in_range.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
//! ## Description
//!
//! A party P has a number `X = g ^ x`, with g being a generator of
//! multiplicative group G. P wants to prove to party V that the logarithm of X,
//! i.e. x, is at most L bits.
//! multiplicative group G. P has encrypted x as C. P shares X and C with V and
//! wants to prove that the logarithm of X is the plaintext of C, and that the
//! plaintext (i.e. x) is at most L+1 bits.
//!
//! Given:
//! - `key0`, `pkey0` - pair of public and private keys in paillier cryptosystem
Expand Down Expand Up @@ -56,12 +57,14 @@
//!
//! // 3. Prover computes a non-interactive proof that plaintext is at most 1024 bits:
//!
//! let mut rng = rand_core::OsRng::default();
//!
//! let security = p::SecurityParams {
//! l: 1024,
//! epsilon: 128,
//! q: BigNumber::prime_from_rng(128, &mut rng),
//! };
//!
//! let rng = rand_core::OsRng::default();
//! let data = p::Data { key0, c: ciphertext, x: power, g };
//! let pdata = p::PrivateData { x: plaintext, nonce };
//! let (commitment, proof) =
Expand Down Expand Up @@ -93,25 +96,32 @@ use crate::unknown_order::BigNumber;
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct SecurityParams {
/// l in paper, bit size of plaintext
/// l in paper, bit size of +-plaintext
pub l: usize,
/// Epsilon in paper, range extension and security parameter for x
/// Epsilon in paper, slackness parameter
pub epsilon: usize,
/// q in paper. Security parameter for challenge
pub q: BigNumber,
}

#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(bound = ""))]
pub struct Data<C: Curve> {
/// N0 in paper, public key that C was encrypted on
pub key0: EncryptionKey,
/// C in paper, logarithm of X encrypted on N0
pub c: Ciphertext,
/// X in paper, exponent of plaintext of C
pub x: Point<C>,
/// A generator in group
pub g: Point<C>,
}

#[derive(Clone)]
pub struct PrivateData {
/// x in paper, logarithm of X and plaintext of C
pub x: BigNumber,
/// rho in paper, nonce in encryption x -> C
pub nonce: Nonce,
}

Expand Down Expand Up @@ -145,7 +155,7 @@ pub struct Proof {
pub use crate::common::Aux;

pub mod interactive {
use generic_ec::{Curve, Scalar};
use generic_ec::Curve;
use libpaillier::unknown_order::BigNumber;
use rand_core::RngCore;

Expand All @@ -163,8 +173,8 @@ pub mod interactive {
security: &SecurityParams,
mut rng: R,
) -> Result<(Commitment<C>, PrivateCommitment), ProtocolError> {
let two_to_l = BigNumber::one() << security.l;
let two_to_l_e = BigNumber::one() << (security.l + security.epsilon);
let two_to_l = BigNumber::one() << (security.l + 1);
let two_to_l_e = BigNumber::one() << (security.l + security.epsilon + 1);
let modulo_l = two_to_l * &aux.rsa_modulo;
let modulo_l_e = &two_to_l_e * &aux.rsa_modulo;

Expand Down Expand Up @@ -256,21 +266,24 @@ pub mod interactive {
fail_if(lhs == rhs, InvalidProof::EqualityCheckFailed(3))?;
}
fail_if(
proof.z1 <= one << (security.l + security.epsilon),
proof.z1 <= one << (security.l + security.epsilon + 1),
InvalidProof::RangeCheckFailed(4),
)?;

Ok(())
}

/// Generate random challenge
pub fn challenge<C, R>(rng: &mut R) -> BigNumber
///
/// `data` parameter is used to generate challenge in correct range
pub fn challenge<C, R>(rng: &mut R, security: &SecurityParams) -> BigNumber
where
C: Curve,
R: RngCore,
{
let x = Scalar::<C>::random(rng);
BigNumber::from_slice(x.to_be_bytes().as_bytes())
// double the range to account for +-
let m = BigNumber::from(2) * &security.q;
BigNumber::from_rng(&m, rng)
}
}

Expand Down Expand Up @@ -353,8 +366,8 @@ pub mod non_interactive {
.finalize();

let mut rng = rand_chacha::ChaCha20Rng::from_seed(seed.into());
let scalar = Scalar::<C>::random(&mut rng);
BigNumber::from_slice(scalar.to_be_bytes().as_bytes())
let m = BigNumber::from(2) * &security.q;
BigNumber::from_rng(&m, &mut rng)
}
}

Expand All @@ -365,19 +378,29 @@ mod test {

use crate::common::{convert_scalar, InvalidProof};

fn passing_test<C: Curve>()
fn random_key<R: rand_core::RngCore>(rng: &mut R) -> Option<libpaillier::DecryptionKey> {
let p = BigNumber::prime_from_rng(1024, rng);
let q = BigNumber::prime_from_rng(1024, rng);
libpaillier::DecryptionKey::with_primes_unchecked(&p, &q)
}

fn nonce<R: rand_core::RngCore>(rng: &mut R, n: &BigNumber) -> Option<BigNumber> {
Some(BigNumber::from_rng(n, rng))
}

fn run<R: rand_core::RngCore, C: Curve>(
mut rng: R,
security: super::SecurityParams,
plaintext: BigNumber,
) -> Result<(), crate::common::InvalidProof>
where
Scalar<C>: FromHash,
{
let security = super::SecurityParams {
l: 1024,
epsilon: 128,
};
let private_key0 = libpaillier::DecryptionKey::random().unwrap();
let private_key0 = random_key(&mut rng).unwrap();
let key0 = libpaillier::EncryptionKey::from(&private_key0);

let plaintext = BigNumber::from(228);
let (ciphertext, nonce) = key0.encrypt(plaintext.to_bytes(), None).unwrap();
let nonce = nonce(&mut rng, key0.n());
let (ciphertext, nonce) = key0.encrypt(plaintext.to_bytes(), nonce).unwrap();
let g = generic_ec::Point::<C>::generator() * generic_ec::Scalar::<C>::from(1337);
let x = g * convert_scalar(&plaintext);

Expand All @@ -392,8 +415,8 @@ mod test {
nonce,
};

let p = BigNumber::prime(1024);
let q = BigNumber::prime(1024);
let p = BigNumber::prime_from_rng(1024, &mut rng);
let q = BigNumber::prime_from_rng(1024, &mut rng);
let rsa_modulo = p * q;
let s: BigNumber = 123.into();
let t: BigNumber = 321.into();
Expand All @@ -409,18 +432,25 @@ mod test {
&data,
&pdata,
&security,
rand_core::OsRng::default(),
rng,
)
.unwrap();

let r = super::non_interactive::verify(
shared_state,
&aux,
&data,
&commitment,
&security,
&proof,
);
super::non_interactive::verify(shared_state, &aux, &data, &commitment, &security, &proof)
}

fn passing_test<C: Curve>()
where
Scalar<C>: FromHash,
{
let mut rng = rand_core::OsRng::default();
let security = super::SecurityParams {
l: 1024,
epsilon: 256,
q: BigNumber::prime_from_rng(128, &mut rng),
};
let plaintext = BigNumber::from(228);
let r = run(rng, security, plaintext);
match r {
Ok(()) => (),
Err(e) => panic!("{:?}", e),
Expand All @@ -431,57 +461,14 @@ mod test {
where
Scalar<C>: FromHash,
{
let mut rng = rand_core::OsRng::default();
let security = super::SecurityParams {
l: 1024,
epsilon: 128,
q: BigNumber::prime_from_rng(128, &mut rng),
};
let private_key0 = libpaillier::DecryptionKey::random().unwrap();
let key0 = libpaillier::EncryptionKey::from(&private_key0);

let plaintext = BigNumber::from(1) << (security.l + security.epsilon + 1);
let (ciphertext, nonce) = key0.encrypt(plaintext.to_bytes(), None).unwrap();
let g = generic_ec::Point::<C>::generator() * generic_ec::Scalar::<C>::from(1337);
let x = g * convert_scalar(&plaintext);

let data = super::Data {
key0,
c: ciphertext,
x,
g,
};
let pdata = super::PrivateData {
x: plaintext,
nonce,
};

let p = BigNumber::prime(1024);
let q = BigNumber::prime(1024);
let rsa_modulo = p * q;
let s: BigNumber = 123.into();
let t: BigNumber = 321.into();
assert_eq!(s.gcd(&rsa_modulo), 1.into());
assert_eq!(t.gcd(&rsa_modulo), 1.into());
let aux = super::Aux { s, t, rsa_modulo };

let shared_state = sha2::Sha256::default();

let (commitment, proof) = super::non_interactive::prove(
shared_state.clone(),
&aux,
&data,
&pdata,
&security,
rand_core::OsRng::default(),
)
.unwrap();
let r = super::non_interactive::verify(
shared_state,
&aux,
&data,
&commitment,
&security,
&proof,
);
let r = run(rng, security, plaintext);
match r {
Ok(()) => panic!("proof should not pass"),
Err(InvalidProof::RangeCheckFailed(_)) => (),
Expand All @@ -506,4 +493,32 @@ mod test {
fn failing_million() {
failing_test::<crate::curve::C>()
}

// see notes in
// [crate::paillier_encryption_in_range::test::rejected_with_probability_1_over_2]
// for motivation and design of the following test

#[test]
fn mul_rejected_with_probability_1_over_2() {
use rand_core::SeedableRng;
fn maybe_rejected(mut rng: rand_chacha::ChaCha20Rng) -> bool {
let security = super::SecurityParams {
l: 1024,
epsilon: 130,
q: BigNumber::prime_from_rng(128, &mut rng),
};
let plaintext = (BigNumber::from(1) << (security.l + 1)) - 1;
let r = run::<_, generic_ec_curves::rust_crypto::Secp256r1>(rng, security, plaintext);
match r {
Ok(()) => true,
Err(crate::common::InvalidProof::RangeCheckFailed(4)) => false,
Err(e) => panic!("proof should not fail with: {:?}", e),
}
}

let rng = rand_chacha::ChaCha20Rng::seed_from_u64(2);
assert!(!maybe_rejected(rng), "should fail");
let rng = rand_chacha::ChaCha20Rng::seed_from_u64(3);
assert!(maybe_rejected(rng), "should pass");
}
}

0 comments on commit 294f575

Please sign in to comment.