Skip to content
Closed
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
bf9acac
Synthetic benchmark for exponentiation with known totient
dvdplm Jan 8, 2025
a6e4168
Initial benchmark for Fac proof
dvdplm Jan 8, 2025
936fceb
Init tracing for FacProof benches
dvdplm Jan 16, 2025
3d8ebf0
Add test that exercise the ser-/deserialization of FacProof
dvdplm Jan 16, 2025
72355d1
Add benchmark for AffG
dvdplm Jan 17, 2025
e225fb2
mod.rs is not allowed and other clippy fixes
dvdplm Jan 17, 2025
0c78a5c
Allow formatting args in string literals
dvdplm Jan 17, 2025
0d748b7
Benchmark for DecProof construction and verification
dvdplm Jan 17, 2025
0e9b77c
Add Enc proof
dvdplm Jan 17, 2025
c310e31
Add Paillier Mul proof benchmark
dvdplm Jan 17, 2025
b6c79c9
Clippy fixes
dvdplm Jan 17, 2025
6f88bef
moar clippy crap
dvdplm Jan 17, 2025
7cf86ec
Add benches for Prm and Sch proofs
dvdplm Jan 17, 2025
30cc953
Remove workaround for broken/quirky clippy on nightly (https://github…
dvdplm Jan 20, 2025
5eedb88
Prm proofs are broken for now
dvdplm Jan 20, 2025
d45d19c
Appease clippy
dvdplm Jan 20, 2025
05d714b
Don't use a PublicSigned for PrmProof
dvdplm Jan 20, 2025
6ad3132
Merge branch 'master' into dp-zk-proof-benches
dvdplm Jan 21, 2025
58d9fb4
Re-enable Prm benchmark
dvdplm Jan 21, 2025
df1f717
Merge branch 'master' into dp-zk-proof-benches
dvdplm Jan 30, 2025
c3d0d4f
Use multi-exponentiation in ZK proofs
dvdplm Jan 30, 2025
5ab592a
CHANGELOG
dvdplm Jan 30, 2025
d58011e
Extract common code
dvdplm Jan 30, 2025
17c2aa6
Justify inversions
dvdplm Jan 30, 2025
7019228
Docs for PublicModulus
dvdplm Jan 30, 2025
80c49a3
Remove clippy too many args left-over since refactor
dvdplm Jan 30, 2025
2f97af2
Merge branch 'master' into dp-faster-commit-with-multi-exp-bis
dvdplm Mar 7, 2025
e812282
Merge branch 'master' into dp-faster-commit-with-multi-exp-bis
dvdplm Mar 10, 2025
9091fdf
Remove old ZK proofs
dvdplm Mar 10, 2025
d1c3014
Remove unneeded ser/deser test
dvdplm Mar 10, 2025
93dd378
No need for `pub`, `pub(crate)` is enough.
dvdplm Mar 10, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions synedrion/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,13 @@ private_benches = ["criterion"]
bench = true
name = "bench"
harness = false
path = "benches/bench.rs"

[[bench]]
bench = true
name = "pow"
harness = false
path = "benches/pow.rs"
Comment on lines +67 to +71

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@fjarri I left these in, but they are not particularly useful long-term I think. I wrote them to check on progress as I was changing code, but I think we should remove them now.


[[bench]]
bench = true
Expand Down
125 changes: 125 additions & 0 deletions synedrion/benches/pow.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
use criterion::{black_box, criterion_group, criterion_main, BatchSize, Criterion};
use crypto_bigint::{
modular::{MontyForm, MontyParams},
NonZero, Odd, Random, Uint, U1024, U2048, U256, U4096, U512,
};
use crypto_primes::RandomPrimeWithRng;
use rand::SeedableRng;

fn bench_pow_known_totient_512(c: &mut Criterion) {
let mut group = c.benchmark_group("modpow, 512^1024");

let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(1234567890);
let p: U512 = (U256::generate_prime_with_rng(&mut rng, U256::BITS), U256::ZERO).into();
let q: U512 = (U256::generate_prime_with_rng(&mut rng, U256::BITS), U256::ZERO).into();
let m: U512 = p * q;
let totient = (p - U512::ONE) * (q - U512::ONE);
let prms = MontyParams::new_vartime(Odd::new(m).unwrap());

group.bench_function("vanilla", |b| {
let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(1234567890);
b.iter_batched(
|| {
let x = U512::random(&mut rng);
let x = MontyForm::new(&x, prms);
let exponent = U1024::random(&mut rng);
(x, exponent)
},
|(x, exponent)| black_box(x.pow(&exponent)),
BatchSize::SmallInput,
);
});

group.bench_function("known totient", |b| {
let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(1234567890);
b.iter_batched(
|| {
let x = U512::random(&mut rng);
let x = MontyForm::new(&x, prms);
let exponent = U1024::random(&mut rng);
let exponent = Uint::rem_wide_vartime(exponent.split(), &NonZero::new(totient).unwrap());
(x, exponent)
},
|(x, exponent)| black_box(x.pow(&exponent)),
BatchSize::SmallInput,
);
});

group.bench_function("known totient (not ammortized)", |b| {
let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(1234567890);
b.iter_batched(
|| {
let x = U512::random(&mut rng);
let x = MontyForm::new(&x, prms);
let exponent = U1024::random(&mut rng);
(x, exponent)
},
|(x, exponent)| {
let exponent = Uint::rem_wide_vartime(exponent.split(), &NonZero::new(totient).unwrap());
black_box(x.pow(&exponent))
},
BatchSize::SmallInput,
);
});
}

// Our production parameters use 1024-bit primes resulting in 2048-bit moduli
fn bench_pow_known_totient_2048(c: &mut Criterion) {
let mut group = c.benchmark_group("modpow, 2048^4096");

let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(1234567890);
let p: U2048 = (U1024::generate_prime_with_rng(&mut rng, U1024::BITS), U1024::ZERO).into();
let q: U2048 = (U1024::generate_prime_with_rng(&mut rng, U1024::BITS), U1024::ZERO).into();
let m: U2048 = p * q;
let totient = (p - U2048::ONE) * (q - U2048::ONE);
let prms = MontyParams::new_vartime(Odd::new(m).unwrap());

group.bench_function("vanilla", |b| {
let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(1234567890);
b.iter_batched(
|| {
let x = U2048::random(&mut rng);
let x = MontyForm::new(&x, prms);
let exponent = U4096::random(&mut rng);
(x, exponent)
},
|(x, exponent)| black_box(x.pow(&exponent)),
BatchSize::SmallInput,
);
});

group.bench_function("known totient", |b| {
let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(1234567890);
b.iter_batched(
|| {
let x = U2048::random(&mut rng);
let x = MontyForm::new(&x, prms);
let exponent = U4096::random(&mut rng);
let exponent = Uint::rem_wide_vartime(exponent.split(), &NonZero::new(totient).unwrap());
(x, exponent)
},
|(x, exponent)| black_box(x.pow(&exponent)),
BatchSize::SmallInput,
);
});

group.bench_function("known totient (not ammortized)", |b| {
let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(1234567890);
b.iter_batched(
|| {
let x = U2048::random(&mut rng);
let x = MontyForm::new(&x, prms);
let exponent = U4096::random(&mut rng);
(x, exponent)
},
|(x, exponent)| {
let exponent = Uint::rem_wide_vartime(exponent.split(), &NonZero::new(totient).unwrap());
black_box(x.pow(&exponent))
},
BatchSize::SmallInput,
);
});
}
criterion_group!(benches, bench_pow_known_totient_512, bench_pow_known_totient_2048);

criterion_main!(benches);
17 changes: 8 additions & 9 deletions synedrion/src/cggmp21/sigma/aff_g.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,14 +102,14 @@ impl<P: SchemeParams> AffGProof<P> {
let cap_a = (public.cap_c * &alpha + Ciphertext::new_with_randomizer(public.pk0, &beta, &r)).to_wire();
let cap_b_x = secret_scalar_from_signed::<P>(&alpha).mul_by_generator();
let cap_b_y = Ciphertext::new_with_randomizer(public.pk1, &beta, &r_y).to_wire();
let cap_e = setup.commit(&alpha, &gamma).to_wire();
let cap_s = setup.commit(secret.x, &m).to_wire();
let cap_f = setup.commit(&beta, &delta).to_wire();
let cap_e = setup.commit_secret_mixed(&alpha, &gamma).to_wire();
let cap_s = setup.commit_secret_mixed(secret.x, &m).to_wire();
let cap_f = setup.commit_secret_mixed(&beta, &delta).to_wire();

// DEVIATION FROM THE PAPER.
// See the comment in `AffGPublicInputs`.
// Original: $s^y$. Modified: $s^{-y}$
let cap_t = setup.commit(&(-secret.y), &mu).to_wire();
let cap_t = setup.commit_secret_mixed(&(-secret.y), &mu).to_wire();

let mut reader = XofHasher::new_with_dst(HASH_TAG)
// commitments
Expand Down Expand Up @@ -172,7 +172,6 @@ impl<P: SchemeParams> AffGProof<P> {
}
}

#[allow(clippy::too_many_arguments)]
pub fn verify(&self, public: AffGPublicInputs<'_, P>, setup: &RPParams<P::Paillier>, aux: &impl Hashable) -> bool {
assert!(public.cap_c.public_key() == public.pk0);
assert!(public.cap_d.public_key() == public.pk0);
Expand Down Expand Up @@ -243,14 +242,14 @@ impl<P: SchemeParams> AffGProof<P> {
// s^{z_1} t^{z_3} == E S^e \mod \hat{N}
let cap_e = self.cap_e.to_precomputed(setup);
let cap_s = self.cap_s.to_precomputed(setup);
if setup.commit(&self.z1, &self.z3) != &cap_e * &cap_s.pow(&e) {
if setup.commit_pub_mixed(&self.z1, &self.z3) != &cap_e * &cap_s.pow(&e) {
return false;
}

// s^{z_2} t^{z_4} == F T^e \mod \hat{N}
let cap_f = self.cap_f.to_precomputed(setup);
let cap_t = self.cap_t.to_precomputed(setup);
if setup.commit(&self.z2, &self.z4) != &cap_f * &cap_t.pow(&e) {
if setup.commit_pub_mixed(&self.z2, &self.z4) != &cap_f * &cap_t.pow(&e) {
return false;
}

Expand All @@ -270,7 +269,7 @@ mod tests {
uint::SecretSigned,
};

#[test]
#[test_log::test]
fn prove_and_verify() {
type Params = TestParams;
type Paillier = <Params as SchemeParams>::Paillier;
Expand All @@ -295,7 +294,7 @@ mod tests {

let cap_d = &cap_c * &x + Ciphertext::new_with_randomizer(pk0, &-&y, &rho);
let cap_y = Ciphertext::new_with_randomizer(pk1, &y, &rho_y);
let cap_x = secret_scalar_from_signed::<TestParams>(&x).mul_by_generator();
let cap_x = secret_scalar_from_signed::<Params>(&x).mul_by_generator();

let proof = AffGProof::<Params>::new(
&mut OsRng,
Expand Down
7 changes: 3 additions & 4 deletions synedrion/src/cggmp21/sigma/enc_elg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,12 +81,11 @@ impl<P: SchemeParams> EncElgProof<P> {
let r = Randomizer::random(rng, public.pk0);
let beta = Secret::init_with(|| Scalar::random(rng));
let gamma = SecretSigned::random_in_exponent_range_scaled(rng, P::L_BOUND + P::EPS_BOUND, hat_cap_n);

let cap_s = setup.commit(secret.x, &mu).to_wire();
let cap_s = setup.commit_secret_mixed(secret.x, &mu).to_wire();
let cap_d = Ciphertext::new_with_randomizer(public.pk0, &alpha, &r).to_wire();
let cap_y = public.cap_a * &beta + secret_scalar_from_signed::<P>(&alpha).mul_by_generator();
let cap_z = beta.mul_by_generator();
let cap_t = setup.commit(&alpha, &gamma).to_wire();
let cap_t = setup.commit_secret_mixed(&alpha, &gamma).to_wire();

let mut reader = XofHasher::new_with_dst(HASH_TAG)
// commitments
Expand Down Expand Up @@ -188,7 +187,7 @@ impl<P: SchemeParams> EncElgProof<P> {
// s^{z_1} t^{z_3} == T S^e \mod \hat{N}
let cap_t = self.cap_t.to_precomputed(setup);
let cap_s = self.cap_s.to_precomputed(setup);
if setup.commit(&self.z1, &self.z3) != &cap_t * &cap_s.pow(&e_signed) {
if setup.commit_pub_mixed(&self.z1, &self.z3) != &cap_t * &cap_s.pow(&e_signed) {
return false;
}

Expand Down
37 changes: 31 additions & 6 deletions synedrion/src/cggmp21/sigma/fac.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,10 @@ impl<P: SchemeParams> FacProof<P> {
let p = sk0.p_signed();
let q = sk0.q_signed();

let cap_p = setup.commit(&p, &mu).to_wire();
let cap_q = setup.commit(&q, &nu);
let cap_a = setup.commit(&alpha, &x).to_wire();
let cap_b = setup.commit(&beta, &y).to_wire();
let cap_p = setup.commit_secret_mixed(&p, &mu).to_wire();
let cap_q = setup.commit_secret_mixed(&q, &nu);
let cap_a = setup.commit_secret(&alpha, &x).to_wire();
let cap_b = setup.commit_secret(&beta, &y).to_wire();
let cap_t = (&cap_q.pow(&alpha) * &setup.commit_zero_value(&r)).to_wire();
let cap_q = cap_q.to_wire();

Expand Down Expand Up @@ -177,14 +177,14 @@ impl<P: SchemeParams> FacProof<P> {
// s^{z_1} t^{w_1} == A P^e \mod \hat{N}
let cap_a = self.cap_a.to_precomputed(setup);
let cap_p = self.cap_p.to_precomputed(setup);
if setup.commit(&self.z1, &self.w1) != &cap_a * &cap_p.pow(&e) {
if setup.commit_pub(&self.z1, &self.w1) != &cap_a * &cap_p.pow(&e) {
return false;
}

// s^{z_2} t^{w_2} == B Q^e \mod \hat{N}
let cap_b = self.cap_b.to_precomputed(setup);
let cap_q = self.cap_q.to_precomputed(setup);
if setup.commit(&self.z2, &self.w2) != &cap_b * &cap_q.pow(&e) {
if setup.commit_pub(&self.z2, &self.w2) != &cap_b * &cap_q.pow(&e) {
return false;
}

Expand Down Expand Up @@ -233,4 +233,29 @@ mod tests {
let pubkey = pk.clone().into_wire().into_precomputed();
assert!(proof.verify(&pubkey, &rp_params, &aux));
}

#[test_log::test]
fn prove_and_verify_wire_payload() {
type Params = TestParams;
type Paillier = <Params as SchemeParams>::Paillier;

let sk = SecretKeyPaillierWire::<Paillier>::random(&mut OsRng).into_precomputed();
let pk = sk.public_key();

let setup = RPParams::random(&mut OsRng);

let aux: &[u8] = b"abcde";

let proof = FacProof::<Params>::new(&mut OsRng, &sk, &setup, &aux);

// Roundtrip works
let res = BinaryFormat::serialize(proof);
assert!(res.is_ok());
let payload = res.unwrap();

let rp_params = setup.to_wire().to_precomputed();
let pubkey = pk.clone().into_wire().into_precomputed();
let proof: FacProof<Params> = BinaryFormat::deserialize(&payload).unwrap();
assert!(proof.verify(&pubkey, &rp_params, &aux));
}
}
5 changes: 4 additions & 1 deletion synedrion/src/paillier/params.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use crypto_bigint::{
modular::Retrieve,
subtle::{ConditionallyNegatable, ConditionallySelectable, ConstantTimeGreater, CtOption},
Bounded, Encoding, Gcd, Integer, InvMod, Invert, Monty, PowBoundedExp, RandomBits, RandomMod,
Bounded, Encoding, Gcd, Integer, InvMod, Invert, Monty, MultiExponentiateBoundedExp, PowBoundedExp, RandomBits,
RandomMod,
};
use crypto_primes::RandomPrimeWithRng;
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -65,6 +66,8 @@ pub trait PaillierParams: core::fmt::Debug + PartialEq + Eq + Clone + Send + Syn
+ PowBoundedExp<Self::Uint>
+ PowBoundedExp<Self::WideUint>
+ PowBoundedExp<Self::ExtraWideUint>
+ MultiExponentiateBoundedExp<Self::WideUint, [(Self::UintMod, Self::WideUint); 2]>
+ MultiExponentiateBoundedExp<Self::ExtraWideUint, [(Self::UintMod, Self::ExtraWideUint); 2]>
+ Monty<Integer = Self::Uint>
+ Retrieve<Output = Self::Uint>
+ Invert<Output = CtOption<Self::UintMod>>
Expand Down
Loading