From a3f3f6bc458023b23d1d28ece9fc3a26b8f2dc40 Mon Sep 17 00:00:00 2001 From: David Palm Date: Fri, 22 Nov 2024 10:20:44 +0100 Subject: [PATCH 1/2] Test FacProof with bad Paillier keys --- synedrion/Cargo.toml | 13 ++++-- synedrion/src/cggmp21.rs | 2 + synedrion/src/cggmp21/params.rs | 6 +-- synedrion/src/cggmp21/sigma/fac.rs | 35 +++++++++++++++- synedrion/src/paillier.rs | 3 ++ synedrion/src/paillier/encryption.rs | 60 +++++++++++++++------------- synedrion/src/paillier/keys.rs | 49 ++++++++++++++++++++--- 7 files changed, 126 insertions(+), 42 deletions(-) diff --git a/synedrion/Cargo.toml b/synedrion/Cargo.toml index 62690259..c37e5281 100644 --- a/synedrion/Cargo.toml +++ b/synedrion/Cargo.toml @@ -17,15 +17,21 @@ k256 = { version = "0.13", default-features = false, features = ["ecdsa", "arith rand_core = { version = "0.6.4", default-features = false } sha2 = { version = "0.10", default-features = false } sha3 = { version = "0.10", default-features = false } -digest = { version = "0.10", default-features = false, features = ["alloc"]} +digest = { version = "0.10", default-features = false, features = ["alloc"] } hashing-serializer = { version = "0.1", default-features = false } secrecy = { version = "0.10", default-features = false, features = ["serde"] } zeroize = { version = "1.8", default-features = false, features = ["alloc", "zeroize_derive"] } bip32 = { version = "0.5", default-features = false, features = ["alloc", "secp256k1", "k256"] } +tracing = { version = "0.1", default-features = false } # Note: `alloc` is needed for `crytpto-bigint`'s dependency `serdect` to be able # to serialize Uints in human-readable formats. -crypto-bigint = { version = "0.6.0-rc.6", default-features = false, features = ["serde", "alloc", "rand_core", "zeroize"] } +crypto-bigint = { version = "0.6.0-rc.6", default-features = false, features = [ + "serde", + "alloc", + "rand_core", + "zeroize", +] } crypto-primes = { version = "0.6.0-pre.2", default-features = false } serde = { version = "1", default-features = false, features = ["derive"] } @@ -40,9 +46,10 @@ serde_assert = "0.8" tokio = { version = "1", features = ["rt", "sync", "time", "macros"] } rand = "0.8" criterion = "0.5" -k256 = {version = "0.13", default-features = false, features = ["ecdsa", "arithmetic", "pem", "serde"]} +k256 = { version = "0.13", default-features = false, features = ["ecdsa", "arithmetic", "pem", "serde"] } impls = "1" hex = { version = "0.4", default-features = false, features = ["alloc"] } +test-log = { version = "0.2.16", default-features = false, features = ["trace", "color"] } [[bench]] bench = true diff --git a/synedrion/src/cggmp21.rs b/synedrion/src/cggmp21.rs index cd2537a8..ddc28abd 100644 --- a/synedrion/src/cggmp21.rs +++ b/synedrion/src/cggmp21.rs @@ -23,4 +23,6 @@ pub use entities::{AuxInfo, KeyShare, KeyShareChange}; pub use interactive_signing::{InteractiveSigning, InteractiveSigningProtocol, PrehashedMessage}; pub use key_init::{KeyInit, KeyInitProtocol}; pub use key_refresh::{KeyRefresh, KeyRefreshProtocol}; +#[cfg(test)] +pub use params::{PaillierProduction, PaillierTest2}; pub use params::{ProductionParams, SchemeParams, TestParams}; diff --git a/synedrion/src/cggmp21/params.rs b/synedrion/src/cggmp21/params.rs index 74ac4abd..a16cac53 100644 --- a/synedrion/src/cggmp21/params.rs +++ b/synedrion/src/cggmp21/params.rs @@ -18,7 +18,7 @@ use crate::{ }; #[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)] -pub struct PaillierTest; +pub struct PaillierTest2; const fn upcast_uint(value: K256Uint) -> K256Uint { assert!(N2 >= N1, "Upcast target must be bigger than the upcast candidate"); @@ -35,7 +35,7 @@ const fn convert_uint(value: K256Uint) -> Uint { Uint::from_words(value.to_words()) } -impl PaillierParams for PaillierTest { +impl PaillierParams for PaillierTest2 { /* The prime size is chosen to be minimal for which the `TestSchemeParams` still work. In the presigning, we are effectively constructing a ciphertext of @@ -216,7 +216,7 @@ impl SchemeParams for TestParams { const L_BOUND: usize = 256; const LP_BOUND: usize = 256; const EPS_BOUND: usize = 320; - type Paillier = PaillierTest; + type Paillier = PaillierTest2; const CURVE_ORDER: NonZero<::Uint> = convert_uint(upcast_uint(ORDER)) .to_nz() .expect("Correct by construction"); diff --git a/synedrion/src/cggmp21/sigma/fac.rs b/synedrion/src/cggmp21/sigma/fac.rs index 424f8355..4e0dc760 100644 --- a/synedrion/src/cggmp21/sigma/fac.rs +++ b/synedrion/src/cggmp21/sigma/fac.rs @@ -3,6 +3,7 @@ use rand_core::CryptoRngCore; use secrecy::ExposeSecret; use serde::{Deserialize, Serialize}; +use tracing::trace; use super::super::SchemeParams; use crate::{ @@ -214,8 +215,9 @@ mod tests { use super::FacProof; use crate::{ - cggmp21::{SchemeParams, TestParams}, - paillier::{RPParamsMod, SecretKeyPaillier}, + cggmp21::{params::PaillierTest2, PaillierProduction, SchemeParams, TestParams}, + paillier::{make_broken_paillier_key, RPParamsMod, SecretKeyPaillier}, + ProductionParams, }; #[test] @@ -234,4 +236,33 @@ mod tests { let proof = FacProof::::new(&mut OsRng, &sk, &setup, &aux); assert!(proof.verify(pk, &setup, &aux)); } + + #[test_log::test] + fn malicious_prover_with_production_params() { + type SKP = SecretKeyPaillier; + let sk = make_broken_paillier_key(&mut OsRng, 23); + let sk_precomp = sk.to_precomputed(); + + let aux_sk = SKP::random(&mut OsRng).to_precomputed(); + let setup = RPParamsMod::random(&mut OsRng, &aux_sk); + let aux: &[u8] = b"dontforgetthemilk"; + + let proof = FacProof::::new(&mut OsRng, &sk_precomp, &setup, &aux); + + assert!(!proof.verify(sk_precomp.public_key(), &setup, &aux)); + } + #[test_log::test] + fn malicious_prover_with_test_params() { + type SKP = SecretKeyPaillier; + let sk = make_broken_paillier_key(&mut OsRng, 7); + let sk_precomp = sk.to_precomputed(); + + let aux_sk = SKP::random(&mut OsRng).to_precomputed(); + let setup = RPParamsMod::random(&mut OsRng, &aux_sk); + let aux: &[u8] = b"dontforgetthemilk"; + + let proof = FacProof::::new(&mut OsRng, &sk_precomp, &setup, &aux); + + assert!(!proof.verify(sk_precomp.public_key(), &setup, &aux)); + } } diff --git a/synedrion/src/paillier.rs b/synedrion/src/paillier.rs index 2b5e9778..1decb227 100644 --- a/synedrion/src/paillier.rs +++ b/synedrion/src/paillier.rs @@ -9,3 +9,6 @@ pub(crate) use keys::{ }; pub(crate) use params::PaillierParams; pub(crate) use ring_pedersen::{RPCommitment, RPParams, RPParamsMod, RPSecret}; + +#[cfg(test)] +pub use keys::make_broken_paillier_key; diff --git a/synedrion/src/paillier/encryption.rs b/synedrion/src/paillier/encryption.rs index b86d400f..e7a6678b 100644 --- a/synedrion/src/paillier/encryption.rs +++ b/synedrion/src/paillier/encryption.rs @@ -153,7 +153,8 @@ impl CiphertextMod

{ // where `N` is the Paillier composite modulus, `m` is the plaintext, // and `rho` is the randomizer. - // Simplify `(N + 1)^m mod N^2 == 1 + m * N mod N^2`. + // Simplify `(N + 1)^m mod N^2 == 1 + m * N mod N^2` (using binomial expansion, only the + // first two terms remain given that N^2 ≡ 0 mod N^2). // Since `m` can be negative, we calculate `m * N +- 1` (never overflows since `m < N`), // then conditionally negate modulo N^2 let prod = abs_plaintext.mul_wide(pk.modulus()); @@ -219,6 +220,7 @@ impl CiphertextMod

{ /// Decrypts this ciphertext assuming that the plaintext is in range `[0, N)`. pub fn decrypt(&self, sk: &SecretKeyPaillierPrecomputed

) -> P::Uint { + // TODO(dp): Should be an error? assert_eq!(sk.public_key(), &self.pk); let pk = sk.public_key(); @@ -228,9 +230,10 @@ impl CiphertextMod

{ // where `m` is the plaintext, `C` is the ciphertext, // `N` is the Paillier composite modulus, // `phi` is the Euler totient of `N`, and `mu = phi^(-1) mod N`. + // Note that ϕ(N) is always invertible, because `gcd(ϕ(N), N) = 1` by construction. // `C^phi mod N^2` may be 0 if `C == N`, which is very unlikely for large `N`. - // Note that `C^phi mod N^2 / N < N`, so we can unwrap when converting to `Uint` + // Note that `C^phi mod N^2 / N < N`, so we can unwrap when converting to `Uint` <–– (DP) This assumes that `gcd(C, N) = 1`, but why is this guaranteed? // (because `N` itself fits into `Uint`). let x = P::Uint::try_from_wide( (self @@ -240,7 +243,7 @@ impl CiphertextMod

{ .retrieve() / pk.modulus_wide_nonzero(), ) - .expect("the value is within `Uint` limtis by construction"); + .expect("the value is within `Uint` limits by construction"); let x_mod = x.to_montgomery(pk.precomputed_modulus()); @@ -413,9 +416,10 @@ mod tests { use rand_core::OsRng; use super::{ - super::{params::PaillierTest, PaillierParams, SecretKeyPaillier}, + super::{PaillierParams, SecretKeyPaillier}, CiphertextMod, RandomizerMod, }; + use crate::cggmp21::PaillierTest2; use crate::uint::{ subtle::{ConditionallyNegatable, ConditionallySelectable}, HasWide, NonZero, RandomMod, Signed, @@ -454,10 +458,10 @@ mod tests { #[test] fn roundtrip() { - let sk = SecretKeyPaillier::::random(&mut OsRng).to_precomputed(); + let sk = SecretKeyPaillier::::random(&mut OsRng).to_precomputed(); let pk = sk.public_key(); - let plaintext = ::Uint::random_mod(&mut OsRng, &pk.modulus_nonzero()); - let ciphertext = CiphertextMod::::new(&mut OsRng, pk, &plaintext); + let plaintext = ::Uint::random_mod(&mut OsRng, &pk.modulus_nonzero()); + let ciphertext = CiphertextMod::::new(&mut OsRng, pk, &plaintext); let plaintext_back = ciphertext.decrypt(&sk); assert_eq!(plaintext, plaintext_back); @@ -468,35 +472,35 @@ mod tests { #[test] fn signed_roundtrip() { - let sk = SecretKeyPaillier::::random(&mut OsRng).to_precomputed(); + let sk = SecretKeyPaillier::::random(&mut OsRng).to_precomputed(); let pk = sk.public_key(); let plaintext = - Signed::random_bounded_bits(&mut OsRng, ::Uint::BITS as usize - 2); + Signed::random_bounded_bits(&mut OsRng, ::Uint::BITS as usize - 2); let ciphertext = CiphertextMod::new_signed(&mut OsRng, pk, &plaintext); let plaintext_back = ciphertext.decrypt_signed(&sk); - let plaintext_reduced = reduce::(&plaintext, &pk.modulus_nonzero()); + let plaintext_reduced = reduce::(&plaintext, &pk.modulus_nonzero()); assert_eq!(plaintext_reduced, plaintext_back); } #[test] fn derive_randomizer() { - let sk = SecretKeyPaillier::::random(&mut OsRng).to_precomputed(); + let sk = SecretKeyPaillier::::random(&mut OsRng).to_precomputed(); let pk = sk.public_key(); - let plaintext = ::Uint::random_mod(&mut OsRng, &pk.modulus_nonzero()); + let plaintext = ::Uint::random_mod(&mut OsRng, &pk.modulus_nonzero()); let randomizer = RandomizerMod::random(&mut OsRng, pk); - let ciphertext = CiphertextMod::::new_with_randomizer(pk, &plaintext, &randomizer.retrieve()); + let ciphertext = CiphertextMod::::new_with_randomizer(pk, &plaintext, &randomizer.retrieve()); let randomizer_back = ciphertext.derive_randomizer(&sk); assert_eq!(randomizer, randomizer_back); } #[test] fn homomorphic_mul() { - let sk = SecretKeyPaillier::::random(&mut OsRng).to_precomputed(); + let sk = SecretKeyPaillier::::random(&mut OsRng).to_precomputed(); let pk = sk.public_key(); - let plaintext = ::Uint::random_mod(&mut OsRng, &pk.modulus_nonzero()); - let ciphertext = CiphertextMod::::new(&mut OsRng, pk, &plaintext); + let plaintext = ::Uint::random_mod(&mut OsRng, &pk.modulus_nonzero()); + let ciphertext = CiphertextMod::::new(&mut OsRng, pk, &plaintext); - let coeff = Signed::random_bounded_bits(&mut OsRng, ::Uint::BITS as usize - 2); + let coeff = Signed::random_bounded_bits(&mut OsRng, ::Uint::BITS as usize - 2); let new_ciphertext = ciphertext * coeff; let new_plaintext = new_ciphertext.decrypt(&sk); @@ -505,14 +509,14 @@ mod tests { #[test] fn homomorphic_add() { - let sk = SecretKeyPaillier::::random(&mut OsRng).to_precomputed(); + let sk = SecretKeyPaillier::::random(&mut OsRng).to_precomputed(); let pk = sk.public_key(); - let plaintext1 = ::Uint::random_mod(&mut OsRng, &pk.modulus_nonzero()); - let ciphertext1 = CiphertextMod::::new(&mut OsRng, pk, &plaintext1); + let plaintext1 = ::Uint::random_mod(&mut OsRng, &pk.modulus_nonzero()); + let ciphertext1 = CiphertextMod::::new(&mut OsRng, pk, &plaintext1); - let plaintext2 = ::Uint::random_mod(&mut OsRng, &pk.modulus_nonzero()); - let ciphertext2 = CiphertextMod::::new(&mut OsRng, pk, &plaintext2); + let plaintext2 = ::Uint::random_mod(&mut OsRng, &pk.modulus_nonzero()); + let ciphertext2 = CiphertextMod::::new(&mut OsRng, pk, &plaintext2); let new_ciphertext = ciphertext1 + ciphertext2; let new_plaintext = new_ciphertext.decrypt(&sk); @@ -522,16 +526,16 @@ mod tests { #[test] fn affine_transform() { - let sk = SecretKeyPaillier::::random(&mut OsRng).to_precomputed(); + let sk = SecretKeyPaillier::::random(&mut OsRng).to_precomputed(); let pk = sk.public_key(); - let plaintext1 = ::Uint::random_mod(&mut OsRng, &pk.modulus_nonzero()); + let plaintext1 = ::Uint::random_mod(&mut OsRng, &pk.modulus_nonzero()); let plaintext2 = - Signed::random_bounded_bits(&mut OsRng, ::Uint::BITS as usize - 2); - let plaintext3 = ::Uint::random_mod(&mut OsRng, &pk.modulus_nonzero()); + Signed::random_bounded_bits(&mut OsRng, ::Uint::BITS as usize - 2); + let plaintext3 = ::Uint::random_mod(&mut OsRng, &pk.modulus_nonzero()); - let ciphertext1 = CiphertextMod::::new(&mut OsRng, pk, &plaintext1); - let ciphertext3 = CiphertextMod::::new(&mut OsRng, pk, &plaintext3); + let ciphertext1 = CiphertextMod::::new(&mut OsRng, pk, &plaintext1); + let ciphertext3 = CiphertextMod::::new(&mut OsRng, pk, &plaintext3); let result = ciphertext1 * plaintext2 + ciphertext3; let plaintext_back = result.decrypt(&sk); diff --git a/synedrion/src/paillier/keys.rs b/synedrion/src/paillier/keys.rs index 66c14c7c..c0050957 100644 --- a/synedrion/src/paillier/keys.rs +++ b/synedrion/src/paillier/keys.rs @@ -181,7 +181,7 @@ where SecretBox::new(Box::new( Signed::new_positive(self.sk.p.expose_secret().clone().into_wide(), P::PRIME_BITS as u32).expect( concat![ - "The primes in the `SecretKeyPaillier` are 'safe primes' ", + "The prime p in the `SecretKeyPaillier` are 'safe primes' ", "and positive by construction; the bound is assumed to be configured correctly by the user." ], ), @@ -189,7 +189,7 @@ where SecretBox::new(Box::new( Signed::new_positive(self.sk.q.expose_secret().clone().into_wide(), P::PRIME_BITS as u32).expect( concat![ - "The primes in the `SecretKeyPaillier` are 'safe primes' ", + "The prime q in the `SecretKeyPaillier` are 'safe primes' ", "and positive by construction; the bound is assumed to be configured correctly by the user." ], ), @@ -434,24 +434,41 @@ impl PartialEq for PublicKeyPaillierPrecomputed

{ impl Eq for PublicKeyPaillierPrecomputed

{} +#[cfg(test)] +pub fn make_broken_paillier_key

(rng: &mut impl CryptoRngCore, p: u64) -> SecretKeyPaillier

+where + P: PaillierParams, +{ + use secrecy::SecretBox; + + let p = P::HalfUint::from(p); + let q = P::HalfUint::generate_safe_prime_with_rng(rng, P::PRIME_BITS as u32); + SecretKeyPaillier { + p: SecretBox::new(Box::new(p)), + q: SecretBox::new(Box::new(q)), + } +} #[cfg(test)] mod tests { + use super::SecretKeyPaillier; + use crate::cggmp21::{PaillierProduction, PaillierTest2}; + use crate::paillier::params::PaillierTest; + use crate::paillier::{CiphertextMod, PaillierParams}; + use rand::SeedableRng; use rand_core::OsRng; use serde::Serialize; use serde_assert::Token; - use super::{super::params::PaillierTest, SecretKeyPaillier}; - #[test] fn basics() { - let sk = SecretKeyPaillier::::random(&mut OsRng).to_precomputed(); + let sk = SecretKeyPaillier::::random(&mut OsRng).to_precomputed(); let _pk = sk.public_key(); } #[test] fn debug_redacts_secrets() { - let sk = SecretKeyPaillier::::random(&mut OsRng); + let sk = SecretKeyPaillier::::random(&mut OsRng); let debug_output = format!("Sikrit {:?}", sk); assert_eq!( @@ -495,4 +512,24 @@ mod tests { let clone = sk.clone(); assert_eq!(sk, clone); } + + #[test_log::test] + fn malicious_paillier_key() { + type Uint = ::Uint; + let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(123456); + let sk = super::make_broken_paillier_key::(&mut rng, 23); + let sikrit = { + let s = "attack at dawn!".as_bytes(); + let mut buf = [0u8; Uint::BYTES]; + buf[Uint::BYTES - s.len()..].copy_from_slice(s); + buf + }; + + let sikrit_uint = Uint::from_be_slice(&sikrit); + let sk_precomp = sk.to_precomputed(); + let ciphertext = CiphertextMod::new(&mut rng, sk_precomp.public_key(), &sikrit_uint); + + let decrypted = ciphertext.decrypt(&sk_precomp); + assert_eq!(decrypted, sikrit_uint); + } } From a3c01e383f2fe93cc89501ff380ba850ca17a810 Mon Sep 17 00:00:00 2001 From: David Palm Date: Mon, 2 Dec 2024 09:43:52 +0100 Subject: [PATCH 2/2] Some extra docs --- Cargo.lock | 296 ++++++++++++++++++++++-- synedrion/src/cggmp21/params.rs | 8 +- synedrion/src/cggmp21/sigma/fac.rs | 90 +++++-- synedrion/src/paillier/keys.rs | 5 + synedrion/src/paillier/ring_pedersen.rs | 3 +- 5 files changed, 362 insertions(+), 40 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 016311fe..07dbf037 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -32,11 +32,54 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" +[[package]] +name = "anstream" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + [[package]] name = "anstyle" -version = "1.0.4" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" + +[[package]] +name = "anstyle-parse" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" +dependencies = [ + "anstyle", + "windows-sys 0.59.0", +] [[package]] name = "autocfg" @@ -211,6 +254,12 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67ba02a97a2bd10f4b59b25c7973101c79642302776489e030cd13cdab09ed15" +[[package]] +name = "colorchoice" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" + [[package]] name = "const-oid" version = "0.9.6" @@ -438,6 +487,27 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" +[[package]] +name = "env_filter" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" +dependencies = [ + "log", +] + +[[package]] +name = "env_logger" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "log", +] + [[package]] name = "erased-serde" version = "0.4.5" @@ -455,7 +525,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f258a7194e7f7c2a7837a8913aeab7fd8c383457034fa20ce4dd3dcb813e8eb8" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -558,9 +628,15 @@ checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ "hermit-abi", "rustix", - "windows-sys", + "windows-sys 0.48.0", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + [[package]] name = "itertools" version = "0.10.5" @@ -607,6 +683,12 @@ dependencies = [ "cpufeatures", ] +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + [[package]] name = "libc" version = "0.2.150" @@ -621,9 +703,9 @@ checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829" [[package]] name = "log" -version = "0.4.20" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "manul" @@ -647,6 +729,15 @@ dependencies = [ "tracing", ] +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + [[package]] name = "memchr" version = "2.6.4" @@ -671,6 +762,16 @@ dependencies = [ "adler", ] +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -701,6 +802,12 @@ version = "11.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + [[package]] name = "pem-rfc7468" version = "0.7.0" @@ -848,8 +955,17 @@ checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" dependencies = [ "aho-corasick", "memchr", - "regex-automata", - "regex-syntax", + "regex-automata 0.4.3", + "regex-syntax 0.8.2", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", ] [[package]] @@ -860,9 +976,15 @@ checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" dependencies = [ "aho-corasick", "memchr", - "regex-syntax", + "regex-syntax 0.8.2", ] +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + [[package]] name = "regex-syntax" version = "0.8.2" @@ -904,7 +1026,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -1054,6 +1176,15 @@ dependencies = [ "keccak", ] +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + [[package]] name = "signature" version = "2.2.0" @@ -1117,10 +1248,44 @@ dependencies = [ "sha2", "sha3", "signature", + "test-log", "tokio", + "tracing", "zeroize", ] +[[package]] +name = "test-log" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dffced63c2b5c7be278154d76b479f9f9920ed34e7574201407f0b14e2bbb93" +dependencies = [ + "env_logger", + "test-log-macros", + "tracing-subscriber", +] + +[[package]] +name = "test-log-macros" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5999e24eaa32083191ba4e425deb75cdf25efefabe5aaccb7446dd0d4122a3f5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + [[package]] name = "tinytemplate" version = "1.2.1" @@ -1188,6 +1353,22 @@ dependencies = [ "once_cell", ] +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "thread_local", + "tracing", + "tracing-core", +] + [[package]] name = "typeid" version = "1.0.2" @@ -1206,6 +1387,12 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + [[package]] name = "version_check" version = "0.9.4" @@ -1329,7 +1516,16 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", ] [[package]] @@ -1338,13 +1534,29 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] [[package]] @@ -1353,42 +1565,90 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + [[package]] name = "zeroize" version = "1.8.1" diff --git a/synedrion/src/cggmp21/params.rs b/synedrion/src/cggmp21/params.rs index a16cac53..94403807 100644 --- a/synedrion/src/cggmp21/params.rs +++ b/synedrion/src/cggmp21/params.rs @@ -110,13 +110,13 @@ pub trait SchemeParams: Debug + Clone + Send + PartialEq + Eq + Send + Sync + 's /// The order of the curve as a wide integer. const CURVE_ORDER_WIDE: NonZero<::WideUint>; /// The scheme's statistical security parameter. - const SECURITY_PARAMETER: usize; // $\kappa$ + const SECURITY_PARAMETER: usize; // $\kappa$ (κ) /// The bound for secret values. - const L_BOUND: usize; // $\ell$, paper sets it to $\log2(q)$ (see Table 2) + const L_BOUND: usize; // $\ell$ (ℓ), paper sets it to $\log2(q)$ (see Table 2, p. 69, Appendix D) /// The error bound for secret masks. - const LP_BOUND: usize; // $\ell^\prime$, in paper $= 5 \ell$ (see Table 2) + const LP_BOUND: usize; // $\ell^\prime$ (ℓ′), in paper $= 5 \ell$ (see Table 2, p. 69, Appendix D) /// The error bound for range checks (referred to in the paper as the slackness parameter). - const EPS_BOUND: usize; // $\eps$, in paper $= 2 \ell$ (see Table 2) + const EPS_BOUND: usize; // $\eps$ (ε), in paper $= 2 \ell$ (see Table 2, p. 69, Appendix D) /// The parameters of the Paillier encryption. /// /// Note: `PaillierParams::Uint` must be able to contain the full range of `Scalar` values diff --git a/synedrion/src/cggmp21/sigma/fac.rs b/synedrion/src/cggmp21/sigma/fac.rs index 4e0dc760..cc88dbcc 100644 --- a/synedrion/src/cggmp21/sigma/fac.rs +++ b/synedrion/src/cggmp21/sigma/fac.rs @@ -3,7 +3,7 @@ use rand_core::CryptoRngCore; use secrecy::ExposeSecret; use serde::{Deserialize, Serialize}; -use tracing::trace; +use tracing::{debug, error, trace}; use super::super::SchemeParams; use crate::{ @@ -44,29 +44,46 @@ impl FacProof

{ pub fn new( rng: &mut impl CryptoRngCore, sk0: &SecretKeyPaillierPrecomputed, + // Auxiliary safe bi-prime N_hat and Ring-Pedersen parameters s,t ∈ Z∗N_hat setup: &RPParamsMod, aux: &impl Hashable, ) -> Self { + trace!( + "[FacProof, new] SchemeParams: CURVE_ORDER={:?}, PRIME_BITS={:?}, L_BOUND={:?}, EPS_BOUND={:?}", + P::CURVE_ORDER, + ::PRIME_BITS - 2, + P::L_BOUND, + P::EPS_BOUND + ); let pk0 = sk0.public_key(); let hat_cap_n = &setup.public_key().modulus_bounded(); // $\hat{N}$ // NOTE: using `2^(Paillier::PRIME_BITS - 2)` as $\sqrt{N_0}$ (which is its lower bound) // According to the authors of the paper, it is acceptable. - // In the end of the day, we're proving that `p, q < sqrt{N_0} 2^\ell`, + // At the end of the day, we're proving that `p, q < sqrt{N_0} 2^\ell`, // and really they should be `~ sqrt{N_0}`. - // Note that it has to be matched when we check the range of + // Note that the same approximation must be used when we check the range of // `z1` and `z2` during verification. let sqrt_cap_n = Bounded::new( ::Uint::one() << (::PRIME_BITS - 2), ::PRIME_BITS as u32, ) .expect("the value is bounded by `2^PRIME_BITS` by construction"); + // let mut zero = ::Uint::zero(); + // zero.set_bit((::PRIME_BITS - 2) as u32, 1.into()); + // error!("zero={zero:?}"); + // let sqrt_cap_n = Bounded::new(zero, ::PRIME_BITS as u32).unwrap(); + // assert!( + // sqrt_cap_n.value() != <::Uint as Zero>::zero(), + // "sqrt(N_0) should not be zero" + // ); let alpha = Signed::random_bounded_bits_scaled(rng, P::L_BOUND + P::EPS_BOUND, &sqrt_cap_n); let beta = Signed::random_bounded_bits_scaled(rng, P::L_BOUND + P::EPS_BOUND, &sqrt_cap_n); let mu = Signed::random_bounded_bits_scaled(rng, P::L_BOUND, hat_cap_n); let nu = Signed::random_bounded_bits_scaled(rng, P::L_BOUND, hat_cap_n); + trace!("[FacProof, new] hat_cap_n={hat_cap_n:?}, sqrt_cap_n={sqrt_cap_n:?}, alpha={alpha:?}, beta={beta:?}, mu={mu:?}, nu={nu:?}"); // N_0 \hat{N} let scale = pk0.modulus_bounded().mul_wide(hat_cap_n); @@ -80,6 +97,7 @@ impl FacProof

{ ); let x = Signed::random_bounded_bits_scaled(rng, P::L_BOUND + P::EPS_BOUND, hat_cap_n); let y = Signed::random_bounded_bits_scaled(rng, P::L_BOUND + P::EPS_BOUND, hat_cap_n); + trace!("[FacProof, new] hat_cap_n={hat_cap_n:?}, scale={scale:?}, sigma={sigma:?}, r={r:?}, x={x:?}, y={y:?}"); let (p, q) = sk0.primes(); @@ -114,7 +132,7 @@ impl FacProof

{ let omega1 = x + e_wide * mu; let omega2 = y + e_wide * nu; let v = r + (e_wide.into_wide() * hat_sigma); - + trace!("[FacProof, new] e={e:?}, z1={z1:?}, z2={z2:?}, omega1={omega1:?}, omega2={omega2:?}, v={v:?}"); Self { e, cap_p, @@ -153,8 +171,14 @@ impl FacProof

{ // Non-interactive challenge let e = Signed::from_xof_reader_bounded(&mut reader, &P::CURVE_ORDER); + trace!("[FacProof, verify] CURVE_ORDER={:?} (aka 'q')", P::CURVE_ORDER); + debug!("[FacProof, verify] challenge={e:?} (aka 'e')"); if e != self.e { + error!( + "Challenge mismatch, e={e:?} is NOT equal to proof's challenge={:?}", + self.e + ); return false; } @@ -163,55 +187,80 @@ impl FacProof

{ // R = s^{N_0} t^\sigma let cap_r = &setup.commit_xwide(&pk0.modulus_bounded().into(), &self.sigma); - // s^{z_1} t^{\omega_1} == A * P^e \mod \hat{N} + // Check 1/3: s^{z_1} t^{\omega_1} == A * P^e \mod \hat{N} let cap_a_mod = self.cap_a.to_mod(aux_pk); let cap_p_mod = self.cap_p.to_mod(aux_pk); if setup.commit_wide(&self.z1, &self.omega1) != &cap_a_mod * &cap_p_mod.pow_signed_vartime(&e) { + error!("[FacProof, verify] Check 1 failed."); return false; } + trace!("[FacProof, verify] Check 1 Ok."); - // s^{z_2} t^{\omega_2} == B * Q^e \mod \hat{N} + // Check 2/3: s^{z_2} t^{\omega_2} == B * Q^e \mod \hat{N} let cap_b_mod = self.cap_b.to_mod(aux_pk); let cap_q_mod = self.cap_q.to_mod(aux_pk); if setup.commit_wide(&self.z2, &self.omega2) != &cap_b_mod * &cap_q_mod.pow_signed_vartime(&e) { + error!("[FacProof, verify] Check 2 failed."); return false; } + trace!("[FacProof, verify] Check 2 Ok."); - // Q^{z_1} * t^v == T * R^e \mod \hat{N} + // Check 3/3: Q^{z_1} * t^v == T * R^e \mod \hat{N} let cap_t_mod = self.cap_t.to_mod(aux_pk); if &cap_q_mod.pow_signed_wide(&self.z1) * &setup.commit_base_xwide(&self.v) != &cap_t_mod * &cap_r.pow_signed_vartime(&e) { + error!("[FacProof, verify] Check 3 failed."); return false; } - + trace!("[FacProof, verify] Check 3 Ok."); // NOTE: since when creating this proof we generated `alpha` and `beta` // using the approximation `sqrt(N_0) ~ 2^(PRIME_BITS - 2)`, // this is the bound we are using here as well. + let range_bits = P::L_BOUND + P::EPS_BOUND + ::PRIME_BITS - 2; + debug!( + "[FacProof, verify] range bound={range_bits:?}, L_BOUND={:?}, EPS_BOUND={:?}, PRIME_BITS-2={:?}", + P::L_BOUND, + P::EPS_BOUND, + ::PRIME_BITS - 2 + ); // z1 \in \pm \sqrt{N_0} 2^{\ell + \eps} if !self .z1 .in_range_bits(P::L_BOUND + P::EPS_BOUND + ::PRIME_BITS - 2) { + error!( + "[FacProof, verify] z1 is NOT in range. z1={:?}, bound={:?}", + self.z1, + P::L_BOUND + P::EPS_BOUND + ::PRIME_BITS - 2 + ); return false; } + trace!("[FacProof, verify] z1 is in range. z1={:?}", self.z1); // z2 \in \pm \sqrt{N_0} 2^{\ell + \eps} if !self .z2 .in_range_bits(P::L_BOUND + P::EPS_BOUND + ::PRIME_BITS - 2) { + error!( + "[FacProof, verify] z2 is NOT in range. z2={:?}, bound={:?}", + self.z2, + P::L_BOUND + P::EPS_BOUND + ::PRIME_BITS - 2 + ); return false; } - + trace!("[FacProof, verify] z2 is in range. z2={:?}", self.z2); true } } #[cfg(test)] mod tests { + use rand::SeedableRng; use rand_core::OsRng; + use tracing::trace; use super::FacProof; use crate::{ @@ -239,25 +288,32 @@ mod tests { #[test_log::test] fn malicious_prover_with_production_params() { - type SKP = SecretKeyPaillier; - let sk = make_broken_paillier_key(&mut OsRng, 23); + type Skp = SecretKeyPaillier; + let mut rng = rand_chacha::ChaCha8Rng::from_seed(*b"01234567890123456789012345678901"); + let sk = make_broken_paillier_key(&mut rng, 23); + // trace!("[test] Have sk={sk:?}"); let sk_precomp = sk.to_precomputed(); + // trace!("[test] Have sk_precomp={sk_precomp:?}"); - let aux_sk = SKP::random(&mut OsRng).to_precomputed(); - let setup = RPParamsMod::random(&mut OsRng, &aux_sk); + let aux_sk = Skp::random(&mut OsRng).to_precomputed(); + // trace!("[test] Have aux_sk={aux_sk:?}"); + let setup = RPParamsMod::random(&mut rng, &aux_sk); + // trace!("[test] Have setup={setup:?}"); let aux: &[u8] = b"dontforgetthemilk"; - let proof = FacProof::::new(&mut OsRng, &sk_precomp, &setup, &aux); + let proof = FacProof::::new(&mut rng, &sk_precomp, &setup, &aux); + trace!("[test] Have proof={proof:?}"); - assert!(!proof.verify(sk_precomp.public_key(), &setup, &aux)); + assert!(proof.verify(sk_precomp.public_key(), &setup, &aux)); + trace!("[test] Done"); } #[test_log::test] fn malicious_prover_with_test_params() { - type SKP = SecretKeyPaillier; + type Skp = SecretKeyPaillier; let sk = make_broken_paillier_key(&mut OsRng, 7); let sk_precomp = sk.to_precomputed(); - let aux_sk = SKP::random(&mut OsRng).to_precomputed(); + let aux_sk = Skp::random(&mut OsRng).to_precomputed(); let setup = RPParamsMod::random(&mut OsRng, &aux_sk); let aux: &[u8] = b"dontforgetthemilk"; diff --git a/synedrion/src/paillier/keys.rs b/synedrion/src/paillier/keys.rs index c0050957..d61706ee 100644 --- a/synedrion/src/paillier/keys.rs +++ b/synedrion/src/paillier/keys.rs @@ -153,6 +153,7 @@ impl SecretKeyPaillier

{ pub(crate) struct SecretKeyPaillierPrecomputed { sk: SecretKeyPaillier

, totient: SecretBox>, + // TODO(dp): This should be a secret I'm pretty sure /// $\phi(N)^{-1} \mod N$ inv_totient: P::UintMod, /// $N^{-1} \mod \phi(N)$ @@ -443,6 +444,10 @@ where let p = P::HalfUint::from(p); let q = P::HalfUint::generate_safe_prime_with_rng(rng, P::PRIME_BITS as u32); + tracing::debug!( + "[broken_paillier_key, {} bits] p={p:?}, q={q:?}", + ::BITS + ); SecretKeyPaillier { p: SecretBox::new(Box::new(p)), q: SecretBox::new(Box::new(q)), diff --git a/synedrion/src/paillier/ring_pedersen.rs b/synedrion/src/paillier/ring_pedersen.rs index c35f6d75..1384f975 100644 --- a/synedrion/src/paillier/ring_pedersen.rs +++ b/synedrion/src/paillier/ring_pedersen.rs @@ -50,8 +50,9 @@ impl RPParamsMod

{ pk: &PublicKeyPaillierPrecomputed

, ) -> Self { let r = pk.random_invertible_group_elem(rng); - + // This is $t$ in the paper let base = r.square(); + // This is $s$ in the paper let power = base.pow_bounded_exp(secret.0.as_ref(), secret.0.bound()); Self {