From 692114d38c9b847a70dc467fef7c88b309b5c5ef Mon Sep 17 00:00:00 2001 From: Max Leibovich Date: Thu, 13 Jul 2023 11:41:26 +0300 Subject: [PATCH 01/21] move x1 to range {q/3 , ... , 2q/3} for create_commitments --- src/party_one.rs | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/party_one.rs b/src/party_one.rs index 7d6162b..364c5e3 100644 --- a/src/party_one.rs +++ b/src/party_one.rs @@ -18,6 +18,7 @@ use crate::paillier::{Decrypt, EncryptWithChosenRandomness, KeyGeneration}; use crate::paillier::{DecryptionKey, EncryptionKey, Randomness, RawCiphertext, RawPlaintext}; use crate::zk_paillier::zkproofs::{NICorrectKeyProof, RangeProofNi}; use std::cmp; +use std::ops::Mul; use super::SECURITY_BITS; pub use crate::curv::arithmetic::traits::*; @@ -135,10 +136,25 @@ impl KeyGenFirstMsg { pub fn create_commitments() -> (KeyGenFirstMsg, CommWitness, EcKeyPair) { let base: GE = ECPoint::generator(); - let secret_share: FE = ECScalar::new_random(); - //in Lindell's protocol range proof works only for x1 q/3 + if tmp.gt(&lower_bound) { + break; + } else { + secret_share = ECScalar::new_random(); + } + } + let public_share = base.scalar_mul(&secret_share.get_element()); From 55a83ad9549b6fccb12dae80014803b5e3396483 Mon Sep 17 00:00:00 2001 From: Max Leibovich Date: Thu, 13 Jul 2023 12:38:26 +0300 Subject: [PATCH 02/21] "use" update --- src/party_one.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/party_one.rs b/src/party_one.rs index 9ace47d..dfec234 100644 --- a/src/party_one.rs +++ b/src/party_one.rs @@ -18,7 +18,7 @@ use crate::paillier::{Decrypt, EncryptWithChosenRandomness, KeyGeneration}; use crate::paillier::{DecryptionKey, EncryptionKey, Randomness, RawCiphertext, RawPlaintext}; use crate::zk_paillier::zkproofs::{NICorrectKeyProof, RangeProofNi}; use std::cmp; -use std::ops::Mul; +use std::ops::{Mul, Shl}; use super::SECURITY_BITS; pub use crate::curv::arithmetic::traits::*; From 56b3e7550d141c91e705577144974584f0eda933 Mon Sep 17 00:00:00 2001 From: Max Leibovich Date: Thu, 13 Jul 2023 18:14:34 +0300 Subject: [PATCH 03/21] add is_secret_share_in_range --- src/party_one.rs | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/party_one.rs b/src/party_one.rs index dfec234..5f2e095 100644 --- a/src/party_one.rs +++ b/src/party_one.rs @@ -136,28 +136,31 @@ pub struct EphKeyGenSecondMsg {} //****************** End: Party One structs ******************// impl KeyGenFirstMsg { + + //in Lindell's protocol range proof works only for x1 \in {q/3 , ... , 2q/3} + fn is_secret_share_in_range(secret_share: &FE) -> bool { + let lower_bound: BigInt = FE::q().div_floor(&BigInt::from(3)); + let upper_bound: BigInt = FE::q().mul(&BigInt::from(2)) + .div_floor(&BigInt::from(3)); + + return if secret_share.to_big_int().gt(&lower_bound) && + secret_share.to_big_int().lt(&upper_bound) { + true + } else { + false + } + } + pub fn create_commitments() -> (KeyGenFirstMsg, CommWitness, EcKeyPair) { let base: GE = ECPoint::generator(); - //in Lindell's protocol range proof works only for x1 \in {q/3 , ... , 2q/3} let mut secret_share: FE = ECScalar::new_random(); - let lower_bound = FE::q().div_floor(&BigInt::from(3)); // q/3 - - loop { - // secret_share \in {0 , ... , 2q/3} - let tmp = &secret_share.to_big_int() - .mul(&BigInt::from(2)) - .mul(&FE::q()) - .div_floor(&BigInt::from(3)); - - // secret_share > q/3 - if tmp.gt(&lower_bound) { - break; - } else { - secret_share = ECScalar::new_random(); - } - } + secret_share = ECScalar::from(&secret_share.to_big_int()); + while !Self::is_secret_share_in_range(&secret_share) { + secret_share = ECScalar::new_random(); + secret_share = ECScalar::from(&secret_share.to_big_int()); + } let public_share = base.scalar_mul(&secret_share.get_element()); @@ -198,10 +201,7 @@ impl KeyGenFirstMsg { pub fn create_commitments_with_fixed_secret_share( secret_share: FE, ) -> (KeyGenFirstMsg, CommWitness, EcKeyPair) { - //in Lindell's protocol range proof works only for x1 Date: Sat, 15 Jul 2023 21:10:38 +0300 Subject: [PATCH 04/21] change in test_full_key_gen to new range --- src/party_one.rs | 15 ++++++++++----- src/test.rs | 3 ++- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/party_one.rs b/src/party_one.rs index 5f2e095..094c6bb 100644 --- a/src/party_one.rs +++ b/src/party_one.rs @@ -138,22 +138,20 @@ pub struct EphKeyGenSecondMsg {} impl KeyGenFirstMsg { //in Lindell's protocol range proof works only for x1 \in {q/3 , ... , 2q/3} - fn is_secret_share_in_range(secret_share: &FE) -> bool { + pub fn is_secret_share_in_range(secret_share: &FE) -> bool { let lower_bound: BigInt = FE::q().div_floor(&BigInt::from(3)); let upper_bound: BigInt = FE::q().mul(&BigInt::from(2)) .div_floor(&BigInt::from(3)); return if secret_share.to_big_int().gt(&lower_bound) && - secret_share.to_big_int().lt(&upper_bound) { + secret_share.to_big_int().lt(&upper_bound) { true } else { false } } - pub fn create_commitments() -> (KeyGenFirstMsg, CommWitness, EcKeyPair) { - let base: GE = ECPoint::generator(); - + pub fn get_secret_share_in_range() -> FE { let mut secret_share: FE = ECScalar::new_random(); secret_share = ECScalar::from(&secret_share.to_big_int()); @@ -162,6 +160,12 @@ impl KeyGenFirstMsg { secret_share = ECScalar::from(&secret_share.to_big_int()); } + return secret_share; + } + + pub fn create_commitments() -> (KeyGenFirstMsg, CommWitness, EcKeyPair) { + let base: GE = ECPoint::generator(); + let secret_share: FE = Self::get_secret_share_in_range(); let public_share = base.scalar_mul(&secret_share.get_element()); let d_log_proof = DLogProof::prove(&secret_share); @@ -201,6 +205,7 @@ impl KeyGenFirstMsg { pub fn create_commitments_with_fixed_secret_share( secret_share: FE, ) -> (KeyGenFirstMsg, CommWitness, EcKeyPair) { + assert!(Self::is_secret_share_in_range(&secret_share)); let base: GE = ECPoint::generator(); let public_share = base.scalar_mul(&secret_share.get_element()); diff --git a/src/test.rs b/src/test.rs index b753d30..6cdad56 100644 --- a/src/test.rs +++ b/src/test.rs @@ -7,6 +7,7 @@ mod tests { use crate::curv::elliptic::curves::traits::*; use crate::curv::BigInt; use crate::*; + use crate::party_one::KeyGenFirstMsg; #[test] fn test_d_log_proof_party_two_party_one() { @@ -32,7 +33,7 @@ mod tests { fn test_full_key_gen() { let (party_one_first_message, comm_witness, ec_key_pair_party1) = party_one::KeyGenFirstMsg::create_commitments_with_fixed_secret_share(ECScalar::from( - &BigInt::sample(253), + &KeyGenFirstMsg::get_secret_share_in_range().to_big_int() )); let (party_two_first_message, _ec_key_pair_party2) = party_two::KeyGenFirstMsg::create_with_fixed_secret_share(ECScalar::from( From 2f41e69672145281ab024f477bb084590c48a80e Mon Sep 17 00:00:00 2001 From: Max Leibovich Date: Tue, 18 Jul 2023 10:25:47 +0300 Subject: [PATCH 05/21] use BigInt::sample_range --- src/party_one.rs | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/src/party_one.rs b/src/party_one.rs index 094c6bb..65c5b8f 100644 --- a/src/party_one.rs +++ b/src/party_one.rs @@ -138,29 +138,16 @@ pub struct EphKeyGenSecondMsg {} impl KeyGenFirstMsg { //in Lindell's protocol range proof works only for x1 \in {q/3 , ... , 2q/3} - pub fn is_secret_share_in_range(secret_share: &FE) -> bool { + pub fn get_secret_share_bounds() -> (BigInt, BigInt) { let lower_bound: BigInt = FE::q().div_floor(&BigInt::from(3)); let upper_bound: BigInt = FE::q().mul(&BigInt::from(2)) .div_floor(&BigInt::from(3)); - - return if secret_share.to_big_int().gt(&lower_bound) && - secret_share.to_big_int().lt(&upper_bound) { - true - } else { - false - } + (lower_bound, upper_bound) } pub fn get_secret_share_in_range() -> FE { - let mut secret_share: FE = ECScalar::new_random(); - secret_share = ECScalar::from(&secret_share.to_big_int()); - - while !Self::is_secret_share_in_range(&secret_share) { - secret_share = ECScalar::new_random(); - secret_share = ECScalar::from(&secret_share.to_big_int()); - } - - return secret_share; + let bounds: (BigInt, BigInt) = Self::get_secret_share_bounds(); + ECScalar::from(&BigInt::sample_range(&bounds.0, &bounds.1)) } pub fn create_commitments() -> (KeyGenFirstMsg, CommWitness, EcKeyPair) { @@ -205,8 +192,10 @@ impl KeyGenFirstMsg { pub fn create_commitments_with_fixed_secret_share( secret_share: FE, ) -> (KeyGenFirstMsg, CommWitness, EcKeyPair) { + let bounds: (BigInt, BigInt) = Self::get_secret_share_bounds(); + assert!(secret_share.to_big_int().gt(&bounds.0) && + secret_share.to_big_int().lt(&bounds.1)); - assert!(Self::is_secret_share_in_range(&secret_share)); let base: GE = ECPoint::generator(); let public_share = base.scalar_mul(&secret_share.get_element()); From cce62df592112f3bab493315b81d20677c0cf0c2 Mon Sep 17 00:00:00 2001 From: Max Leibovich Date: Tue, 18 Jul 2023 10:38:47 +0300 Subject: [PATCH 06/21] use BigInt::sample_range --- src/party_one.rs | 13 +++++++------ src/test.rs | 3 ++- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/party_one.rs b/src/party_one.rs index 65c5b8f..e30fb90 100644 --- a/src/party_one.rs +++ b/src/party_one.rs @@ -138,21 +138,22 @@ pub struct EphKeyGenSecondMsg {} impl KeyGenFirstMsg { //in Lindell's protocol range proof works only for x1 \in {q/3 , ... , 2q/3} - pub fn get_secret_share_bounds() -> (BigInt, BigInt) { + pub fn get_lindell_secret_share_bounds() -> (BigInt, BigInt) { let lower_bound: BigInt = FE::q().div_floor(&BigInt::from(3)); let upper_bound: BigInt = FE::q().mul(&BigInt::from(2)) .div_floor(&BigInt::from(3)); (lower_bound, upper_bound) } - pub fn get_secret_share_in_range() -> FE { - let bounds: (BigInt, BigInt) = Self::get_secret_share_bounds(); - ECScalar::from(&BigInt::sample_range(&bounds.0, &bounds.1)) + pub fn get_secret_share_in_range(lower_bound: &BigInt,upper_bound: &BigInt) -> FE { + ECScalar::from(&BigInt::sample_range(&lower_bound, &upper_bound)) } pub fn create_commitments() -> (KeyGenFirstMsg, CommWitness, EcKeyPair) { let base: GE = ECPoint::generator(); - let secret_share: FE = Self::get_secret_share_in_range(); + let bounds = Self::get_lindell_secret_share_bounds(); + let secret_share: FE = Self::get_secret_share_in_range(&bounds.0, &bounds.1); + let public_share = base.scalar_mul(&secret_share.get_element()); let d_log_proof = DLogProof::prove(&secret_share); @@ -192,7 +193,7 @@ impl KeyGenFirstMsg { pub fn create_commitments_with_fixed_secret_share( secret_share: FE, ) -> (KeyGenFirstMsg, CommWitness, EcKeyPair) { - let bounds: (BigInt, BigInt) = Self::get_secret_share_bounds(); + let bounds: (BigInt, BigInt) = Self::get_lindell_secret_share_bounds(); assert!(secret_share.to_big_int().gt(&bounds.0) && secret_share.to_big_int().lt(&bounds.1)); diff --git a/src/test.rs b/src/test.rs index 6cdad56..f43deed 100644 --- a/src/test.rs +++ b/src/test.rs @@ -31,9 +31,10 @@ mod tests { #[test] fn test_full_key_gen() { + let bounds = KeyGenFirstMsg::get_lindell_secret_share_bounds(); let (party_one_first_message, comm_witness, ec_key_pair_party1) = party_one::KeyGenFirstMsg::create_commitments_with_fixed_secret_share(ECScalar::from( - &KeyGenFirstMsg::get_secret_share_in_range().to_big_int() + &KeyGenFirstMsg::get_secret_share_in_range(&bounds.0, &bounds.1).to_big_int() )); let (party_two_first_message, _ec_key_pair_party2) = party_two::KeyGenFirstMsg::create_with_fixed_secret_share(ECScalar::from( From f22090f9334ae33f532e26bc9459ba1e4f8b8218 Mon Sep 17 00:00:00 2001 From: Iraklis Leontiadis Date: Fri, 4 Aug 2023 12:37:54 +0300 Subject: [PATCH 07/21] progress --- src/party_one.rs | 17 +++++++- src/test.rs | 54 +++++++++++++++++++------ src/zk_paillier/zkproofs/range_proof.rs | 4 +- 3 files changed, 60 insertions(+), 15 deletions(-) diff --git a/src/party_one.rs b/src/party_one.rs index e30fb90..36b074d 100644 --- a/src/party_one.rs +++ b/src/party_one.rs @@ -78,7 +78,7 @@ pub struct PaillierKeyPair { pub ek: EncryptionKey, dk: DecryptionKey, pub encrypted_share: BigInt, - randomness: BigInt, + pub randomness: BigInt, } #[derive(Debug, Serialize, Deserialize)] @@ -259,6 +259,21 @@ impl Party1Private { } } + pub fn tweak_x1_for_range_proof(ec_key: &EcKeyPair, paillier_key: &PaillierKeyPair) -> Party1Private { + let lower_bound: BigInt = FE::q().div_floor(&BigInt::from(3)); + let order = FE::q(); + let minus_lower_bound = BigInt::mod_sub(&order, &lower_bound, &order); + let x1_minus_lower_bound = BigInt::mod_add(&ec_key.secret_share.to_big_int(), &minus_lower_bound, &order); + let x1_minus_lower_bound_fe: FE = ECScalar::from(&x1_minus_lower_bound); + + + Party1Private { + x1: x1_minus_lower_bound_fe, + paillier_priv: paillier_key.dk.clone(), + c_key_randomness: paillier_key.randomness.clone(), + } + } + // used for verifiable recovery pub fn to_encrypted_segment( &self, diff --git a/src/test.rs b/src/test.rs index f43deed..8378ef9 100644 --- a/src/test.rs +++ b/src/test.rs @@ -2,13 +2,11 @@ #[cfg(test)] mod tests { - - use crate::curv::arithmetic::traits::Samplable; use crate::curv::elliptic::curves::traits::*; use crate::curv::BigInt; use crate::*; - use crate::party_one::KeyGenFirstMsg; - + use crate::party_one::{Modulo, Party1Private}; + use crate::paillier::{Paillier, Randomness, RawCiphertext, RawPlaintext}; #[test] fn test_d_log_proof_party_two_party_one() { let (party_one_first_message, comm_witness, _ec_key_pair_party1) = @@ -31,10 +29,10 @@ mod tests { #[test] fn test_full_key_gen() { - let bounds = KeyGenFirstMsg::get_lindell_secret_share_bounds(); + let bounds = party_one::KeyGenFirstMsg::get_lindell_secret_share_bounds(); let (party_one_first_message, comm_witness, ec_key_pair_party1) = party_one::KeyGenFirstMsg::create_commitments_with_fixed_secret_share(ECScalar::from( - &KeyGenFirstMsg::get_secret_share_in_range(&bounds.0, &bounds.1).to_big_int() + &party_one::KeyGenFirstMsg::get_secret_share_in_range(&bounds.0, &bounds.1).to_big_int() )); let (party_two_first_message, _ec_key_pair_party2) = party_two::KeyGenFirstMsg::create_with_fixed_secret_share(ECScalar::from( @@ -54,17 +52,43 @@ mod tests { .expect("failed to verify commitments and DLog proof"); // init paillier keypair: - let paillier_key_pair = + let mut paillier_key_pair = party_one::PaillierKeyPair::generate_keypair_and_encrypted_share(&ec_key_pair_party1); + //order of curve + let order = FE::q(); + + //Big int q/3 + let lower_bound: BigInt = order.div_floor(&BigInt::from(3)); + + //Bigint -q/3 + let minus_lower_bound = BigInt::mod_sub(&order, &lower_bound, &order); + + //encrypt -q/3 + // let c1 = Paillier::encrypt(&paillier_key_pair.ek, RawPlaintext::from(minus_lower_bound)); + // put chosen randomness because it is needed raw in the proof generation + let randomness = Randomness::sample(&paillier_key_pair.ek); + + let c1 = Paillier::encrypt_with_chosen_randomness( + &paillier_key_pair.ek, + RawPlaintext::from(minus_lower_bound.clone()), + &randomness, + ); + + //compute x1-q/3 in the ciphertext space + let x = Paillier::add(&paillier_key_pair.ek,RawCiphertext::from(paillier_key_pair.encrypted_share.clone()),c1); + let party_one_private = - party_one::Party1Private::set_private_key(&ec_key_pair_party1, &paillier_key_pair); + Party1Private::set_private_key(&ec_key_pair_party1, &paillier_key_pair); - let party_two_paillier = party_two::PaillierPublic { + let party_one_private_for_range_proof = Party1Private::tweak_x1_for_range_proof(&ec_key_pair_party1, &paillier_key_pair); + + let mut party_two_paillier = party_two::PaillierPublic { ek: paillier_key_pair.ek.clone(), - encrypted_secret_share: paillier_key_pair.encrypted_share.clone(), + encrypted_secret_share: paillier_key_pair.encrypted_share.clone() }; + // zk proof of correct paillier key let correct_key_proof = party_one::PaillierKeyPair::generate_ni_proof_correct_key(&paillier_key_pair); @@ -72,12 +96,18 @@ mod tests { .verify(&party_two_paillier.ek) .expect("bad paillier key"); - // zk proof of correct paillier key + //tweak c to c-q/3 for the soundness proof + paillier_key_pair.encrypted_share = x.clone().0.into_owned(); + //tweak r to r*r' where r' is the randomness used to encrypt -q/3 + paillier_key_pair.randomness = (paillier_key_pair.randomness * randomness.0.clone()) % &paillier_key_pair.ek.n; + //tweak c to c-q/3 for the soundness proof + //TODO duplicate element here, is it needed? + party_two_paillier.encrypted_secret_share = x.clone().0.into_owned(); // zk range proof let range_proof = party_one::PaillierKeyPair::generate_range_proof( &paillier_key_pair, - &party_one_private, + &party_one_private_for_range_proof, ); party_two::PaillierPublic::verify_range_proof(&party_two_paillier, &range_proof) .expect("range proof error"); diff --git a/src/zk_paillier/zkproofs/range_proof.rs b/src/zk_paillier/zkproofs/range_proof.rs index 72243be..d6c27a3 100644 --- a/src/zk_paillier/zkproofs/range_proof.rs +++ b/src/zk_paillier/zkproofs/range_proof.rs @@ -369,7 +369,7 @@ mod tests { let range = BigInt::sample(RANGE_BITS); // prover: let (ek, _dk) = test_keypair().keys(); - let (verifier_ek, verifier_dk) = test_keypair().keys(); + let (_verifier_ek, _verifier_dk) = test_keypair().keys(); // prover: let (encrypted_pairs, data_and_randmoness_pairs) = RangeProof::generate_encrypted_pairs(&ek, &range, STATISTICAL_ERROR_FACTOR); @@ -417,7 +417,7 @@ mod tests { let range = BigInt::sample(RANGE_BITS); // prover: let (ek, _dk) = test_keypair().keys(); - let (verifier_ek, _verifier_dk) = test_keypair().keys(); + let (_verifier_ek, _verifier_dk) = test_keypair().keys(); // prover: let (encrypted_pairs, data_and_randmoness_pairs) = RangeProof::generate_encrypted_pairs(&ek, &range, STATISTICAL_ERROR_FACTOR); From 8e1183eeda9ed74791a2a6601b00053b267d605a Mon Sep 17 00:00:00 2001 From: Iraklis Leontiadis Date: Fri, 4 Aug 2023 12:56:02 +0300 Subject: [PATCH 08/21] progress --- .../hashing/hmac_sha512.rs | 7 ++- src/party_one.rs | 23 ++++--- src/test.rs | 62 +++++++++++-------- 3 files changed, 54 insertions(+), 38 deletions(-) diff --git a/src/curv/cryptographic_primitives/hashing/hmac_sha512.rs b/src/curv/cryptographic_primitives/hashing/hmac_sha512.rs index 528bf2e..a8325ee 100644 --- a/src/curv/cryptographic_primitives/hashing/hmac_sha512.rs +++ b/src/curv/cryptographic_primitives/hashing/hmac_sha512.rs @@ -9,16 +9,17 @@ use crate::curv::BigInt; use super::traits::KeyedHash; use crate::curv::arithmetic::traits::Converter; -use zeroize::Zeroize; -use sha2::Sha512; use hmac::{Hmac, Mac}; +use sha2::Sha512; +use zeroize::Zeroize; pub struct HMacSha512; impl KeyedHash for HMacSha512 { fn create_hmac(key: &BigInt, data: &[&BigInt]) -> BigInt { let mut key_bytes: Vec = key.into(); - let mut ctx = Hmac::::new_from_slice(&key_bytes).expect("HMAC can take key of any size"); + let mut ctx = + Hmac::::new_from_slice(&key_bytes).expect("HMAC can take key of any size"); for value in data { ctx.update(&BigInt::to_vec(value)); } diff --git a/src/party_one.rs b/src/party_one.rs index 36b074d..dd2e4f0 100644 --- a/src/party_one.rs +++ b/src/party_one.rs @@ -136,16 +136,14 @@ pub struct EphKeyGenSecondMsg {} //****************** End: Party One structs ******************// impl KeyGenFirstMsg { - //in Lindell's protocol range proof works only for x1 \in {q/3 , ... , 2q/3} pub fn get_lindell_secret_share_bounds() -> (BigInt, BigInt) { let lower_bound: BigInt = FE::q().div_floor(&BigInt::from(3)); - let upper_bound: BigInt = FE::q().mul(&BigInt::from(2)) - .div_floor(&BigInt::from(3)); + let upper_bound: BigInt = FE::q().mul(&BigInt::from(2)).div_floor(&BigInt::from(3)); (lower_bound, upper_bound) } - pub fn get_secret_share_in_range(lower_bound: &BigInt,upper_bound: &BigInt) -> FE { + pub fn get_secret_share_in_range(lower_bound: &BigInt, upper_bound: &BigInt) -> FE { ECScalar::from(&BigInt::sample_range(&lower_bound, &upper_bound)) } @@ -194,8 +192,7 @@ impl KeyGenFirstMsg { secret_share: FE, ) -> (KeyGenFirstMsg, CommWitness, EcKeyPair) { let bounds: (BigInt, BigInt) = Self::get_lindell_secret_share_bounds(); - assert!(secret_share.to_big_int().gt(&bounds.0) && - secret_share.to_big_int().lt(&bounds.1)); + assert!(secret_share.to_big_int().gt(&bounds.0) && secret_share.to_big_int().lt(&bounds.1)); let base: GE = ECPoint::generator(); let public_share = base.scalar_mul(&secret_share.get_element()); @@ -259,14 +256,20 @@ impl Party1Private { } } - pub fn tweak_x1_for_range_proof(ec_key: &EcKeyPair, paillier_key: &PaillierKeyPair) -> Party1Private { - let lower_bound: BigInt = FE::q().div_floor(&BigInt::from(3)); + pub fn tweak_x1_for_range_proof( + ec_key: &EcKeyPair, + paillier_key: &PaillierKeyPair, + ) -> Party1Private { let order = FE::q(); + let lower_bound: BigInt = order.div_floor(&BigInt::from(3)); let minus_lower_bound = BigInt::mod_sub(&order, &lower_bound, &order); - let x1_minus_lower_bound = BigInt::mod_add(&ec_key.secret_share.to_big_int(), &minus_lower_bound, &order); + let x1_minus_lower_bound = BigInt::mod_add( + &ec_key.secret_share.to_big_int(), + &minus_lower_bound, + &order, + ); let x1_minus_lower_bound_fe: FE = ECScalar::from(&x1_minus_lower_bound); - Party1Private { x1: x1_minus_lower_bound_fe, paillier_priv: paillier_key.dk.clone(), diff --git a/src/test.rs b/src/test.rs index 8378ef9..3c5ed9f 100644 --- a/src/test.rs +++ b/src/test.rs @@ -4,9 +4,10 @@ mod tests { use crate::curv::elliptic::curves::traits::*; use crate::curv::BigInt; - use crate::*; - use crate::party_one::{Modulo, Party1Private}; use crate::paillier::{Paillier, Randomness, RawCiphertext, RawPlaintext}; + use crate::party_one::{Modulo, Party1Private}; + use crate::*; + use std::borrow::Borrow; #[test] fn test_d_log_proof_party_two_party_one() { let (party_one_first_message, comm_witness, _ec_key_pair_party1) = @@ -32,7 +33,8 @@ mod tests { let bounds = party_one::KeyGenFirstMsg::get_lindell_secret_share_bounds(); let (party_one_first_message, comm_witness, ec_key_pair_party1) = party_one::KeyGenFirstMsg::create_commitments_with_fixed_secret_share(ECScalar::from( - &party_one::KeyGenFirstMsg::get_secret_share_in_range(&bounds.0, &bounds.1).to_big_int() + &party_one::KeyGenFirstMsg::get_secret_share_in_range(&bounds.0, &bounds.1) + .to_big_int(), )); let (party_two_first_message, _ec_key_pair_party2) = party_two::KeyGenFirstMsg::create_with_fixed_secret_share(ECScalar::from( @@ -55,6 +57,22 @@ mod tests { let mut paillier_key_pair = party_one::PaillierKeyPair::generate_keypair_and_encrypted_share(&ec_key_pair_party1); + let party_one_private = + Party1Private::set_private_key(&ec_key_pair_party1, &paillier_key_pair); + + let mut party_two_paillier = party_two::PaillierPublic { + ek: paillier_key_pair.ek.clone(), + encrypted_secret_share: paillier_key_pair.encrypted_share.clone(), + }; + + // zk proof of correct paillier key + let correct_key_proof = + party_one::PaillierKeyPair::generate_ni_proof_correct_key(&paillier_key_pair); + + correct_key_proof + .verify(&party_two_paillier.ek) + .expect("bad paillier key"); + //order of curve let order = FE::q(); @@ -76,33 +94,27 @@ mod tests { ); //compute x1-q/3 in the ciphertext space - let x = Paillier::add(&paillier_key_pair.ek,RawCiphertext::from(paillier_key_pair.encrypted_share.clone()),c1); - - let party_one_private = - Party1Private::set_private_key(&ec_key_pair_party1, &paillier_key_pair); - - let party_one_private_for_range_proof = Party1Private::tweak_x1_for_range_proof(&ec_key_pair_party1, &paillier_key_pair); - - let mut party_two_paillier = party_two::PaillierPublic { - ek: paillier_key_pair.ek.clone(), - encrypted_secret_share: paillier_key_pair.encrypted_share.clone() - }; - - // zk proof of correct paillier key - let correct_key_proof = - party_one::PaillierKeyPair::generate_ni_proof_correct_key(&paillier_key_pair); - - correct_key_proof - .verify(&party_two_paillier.ek) - .expect("bad paillier key"); + let new_cipher_x1_minus_q_thirds = Paillier::add( + &paillier_key_pair.ek, + RawCiphertext::from(paillier_key_pair.encrypted_share.clone()), + c1, + ); //tweak c to c-q/3 for the soundness proof - paillier_key_pair.encrypted_share = x.clone().0.into_owned(); + paillier_key_pair.encrypted_share = new_cipher_x1_minus_q_thirds.clone().0.into_owned(); //tweak r to r*r' where r' is the randomness used to encrypt -q/3 - paillier_key_pair.randomness = (paillier_key_pair.randomness * randomness.0.clone()) % &paillier_key_pair.ek.n; + paillier_key_pair.randomness = BigInt::mod_mul( + paillier_key_pair.randomness.borrow(), + &randomness.0, + &paillier_key_pair.ek.n, + ); //tweak c to c-q/3 for the soundness proof //TODO duplicate element here, is it needed? - party_two_paillier.encrypted_secret_share = x.clone().0.into_owned(); + party_two_paillier.encrypted_secret_share = + new_cipher_x1_minus_q_thirds.clone().0.into_owned(); + + let party_one_private_for_range_proof = + Party1Private::tweak_x1_for_range_proof(&ec_key_pair_party1, &paillier_key_pair); // zk range proof let range_proof = party_one::PaillierKeyPair::generate_range_proof( From 6e24f31454b919bda939e3129a59eda7503fe4f3 Mon Sep 17 00:00:00 2001 From: Iraklis Leontiadis Date: Fri, 4 Aug 2023 13:09:56 +0300 Subject: [PATCH 09/21] progress --- src/test.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test.rs b/src/test.rs index 3c5ed9f..39962c7 100644 --- a/src/test.rs +++ b/src/test.rs @@ -86,7 +86,6 @@ mod tests { // let c1 = Paillier::encrypt(&paillier_key_pair.ek, RawPlaintext::from(minus_lower_bound)); // put chosen randomness because it is needed raw in the proof generation let randomness = Randomness::sample(&paillier_key_pair.ek); - let c1 = Paillier::encrypt_with_chosen_randomness( &paillier_key_pair.ek, RawPlaintext::from(minus_lower_bound.clone()), @@ -113,6 +112,7 @@ mod tests { party_two_paillier.encrypted_secret_share = new_cipher_x1_minus_q_thirds.clone().0.into_owned(); + //assign x = x - q/3 let party_one_private_for_range_proof = Party1Private::tweak_x1_for_range_proof(&ec_key_pair_party1, &paillier_key_pair); From 97fd3058fb6269f56eff76505f06d773523cdacc Mon Sep 17 00:00:00 2001 From: Iraklis Leontiadis Date: Mon, 14 Aug 2023 15:00:59 +0300 Subject: [PATCH 10/21] fix --- src/party_one.rs | 59 +++++++++------ src/test.rs | 95 +++++++++++++------------ src/zk_paillier/zkproofs/range_proof.rs | 1 + 3 files changed, 87 insertions(+), 68 deletions(-) diff --git a/src/party_one.rs b/src/party_one.rs index dd2e4f0..62b7483 100644 --- a/src/party_one.rs +++ b/src/party_one.rs @@ -76,9 +76,11 @@ pub struct KeyGenSecondMsg { #[derive(Debug, Serialize, Deserialize)] pub struct PaillierKeyPair { pub ek: EncryptionKey, - dk: DecryptionKey, + pub dk: DecryptionKey, pub encrypted_share: BigInt, + pub encrypted_share_minus_q_thirds: BigInt, pub randomness: BigInt, + pub randomness_q: BigInt, } #[derive(Debug, Serialize, Deserialize)] @@ -97,6 +99,7 @@ pub struct Signature { #[derive(Serialize, Debug, Deserialize, Clone)] pub struct Party1Private { x1: FE, + x1_minus_q_thirds: FE, paillier_priv: DecryptionKey, c_key_randomness: BigInt, } @@ -139,7 +142,7 @@ impl KeyGenFirstMsg { //in Lindell's protocol range proof works only for x1 \in {q/3 , ... , 2q/3} pub fn get_lindell_secret_share_bounds() -> (BigInt, BigInt) { let lower_bound: BigInt = FE::q().div_floor(&BigInt::from(3)); - let upper_bound: BigInt = FE::q().mul(&BigInt::from(2)).div_floor(&BigInt::from(3)); + let upper_bound: BigInt = lower_bound.clone().mul(&BigInt::from(2)); (lower_bound, upper_bound) } @@ -249,29 +252,18 @@ pub fn compute_pubkey(party_one_private: &Party1Private, other_share_public_shar impl Party1Private { pub fn set_private_key(ec_key: &EcKeyPair, paillier_key: &PaillierKeyPair) -> Party1Private { - Party1Private { - x1: ec_key.secret_share, - paillier_priv: paillier_key.dk.clone(), - c_key_randomness: paillier_key.randomness.clone(), - } - } - - pub fn tweak_x1_for_range_proof( - ec_key: &EcKeyPair, - paillier_key: &PaillierKeyPair, - ) -> Party1Private { let order = FE::q(); let lower_bound: BigInt = order.div_floor(&BigInt::from(3)); - let minus_lower_bound = BigInt::mod_sub(&order, &lower_bound, &order); - let x1_minus_lower_bound = BigInt::mod_add( - &ec_key.secret_share.to_big_int(), - &minus_lower_bound, + //x1-q/3 + let x1_minus_lower_bound = BigInt::mod_sub( + &ec_key.secret_share.to_big_int().clone(), + &lower_bound, &order, ); let x1_minus_lower_bound_fe: FE = ECScalar::from(&x1_minus_lower_bound); - Party1Private { - x1: x1_minus_lower_bound_fe, + x1: ec_key.secret_share, + x1_minus_q_thirds: x1_minus_lower_bound_fe, paillier_priv: paillier_key.dk.clone(), c_key_randomness: paillier_key.randomness.clone(), } @@ -292,8 +284,18 @@ impl Party1Private { impl PaillierKeyPair { pub fn generate_keypair_and_encrypted_share(keygen: &EcKeyPair) -> PaillierKeyPair { let (ek, dk) = Paillier::keypair().keys(); + let order = FE::q(); + let lower_bound: BigInt = order.div_floor(&BigInt::from(3)); + //x1-q/3 + let x1_minus_lower_bound = BigInt::mod_sub( + &keygen.secret_share.to_big_int().clone(), + &lower_bound, + &order, + ); + let randomness = Randomness::sample(&ek); + //encrypt x1 let encrypted_share = Paillier::encrypt_with_chosen_randomness( &ek, RawPlaintext::from(keygen.secret_share.to_big_int()), @@ -302,11 +304,24 @@ impl PaillierKeyPair { .0 .into_owned(); + //encrypt x1-q/3 + let randomness_q = Randomness::sample(&ek); + + let encrypted_share_minus_q_thirds = Paillier::encrypt_with_chosen_randomness( + &ek, + RawPlaintext::from(x1_minus_lower_bound.clone()), + &randomness_q, + ) + .0 + .into_owned(); + PaillierKeyPair { ek, dk, encrypted_share, + encrypted_share_minus_q_thirds, randomness: randomness.0, + randomness_q: randomness_q.0, } } @@ -317,9 +332,9 @@ impl PaillierKeyPair { RangeProofNi::prove( &paillier_context.ek, &FE::q(), - &paillier_context.encrypted_share.clone(), - &party_one_private.x1.to_big_int(), - &paillier_context.randomness, + &paillier_context.encrypted_share_minus_q_thirds.clone(), + &party_one_private.x1_minus_q_thirds.to_big_int(), + &paillier_context.randomness_q, ) } diff --git a/src/test.rs b/src/test.rs index 39962c7..fcab2b2 100644 --- a/src/test.rs +++ b/src/test.rs @@ -4,10 +4,8 @@ mod tests { use crate::curv::elliptic::curves::traits::*; use crate::curv::BigInt; - use crate::paillier::{Paillier, Randomness, RawCiphertext, RawPlaintext}; - use crate::party_one::{Modulo, Party1Private}; + use crate::party_one::Party1Private; use crate::*; - use std::borrow::Borrow; #[test] fn test_d_log_proof_party_two_party_one() { let (party_one_first_message, comm_witness, _ec_key_pair_party1) = @@ -54,15 +52,15 @@ mod tests { .expect("failed to verify commitments and DLog proof"); // init paillier keypair: - let mut paillier_key_pair = + let paillier_key_pair = party_one::PaillierKeyPair::generate_keypair_and_encrypted_share(&ec_key_pair_party1); let party_one_private = Party1Private::set_private_key(&ec_key_pair_party1, &paillier_key_pair); - let mut party_two_paillier = party_two::PaillierPublic { + let party_two_paillier = party_two::PaillierPublic { ek: paillier_key_pair.ek.clone(), - encrypted_secret_share: paillier_key_pair.encrypted_share.clone(), + encrypted_secret_share: paillier_key_pair.encrypted_share_minus_q_thirds.clone(), }; // zk proof of correct paillier key @@ -73,53 +71,58 @@ mod tests { .verify(&party_two_paillier.ek) .expect("bad paillier key"); - //order of curve - let order = FE::q(); - - //Big int q/3 - let lower_bound: BigInt = order.div_floor(&BigInt::from(3)); - - //Bigint -q/3 - let minus_lower_bound = BigInt::mod_sub(&order, &lower_bound, &order); + // //order of curve + // let order = FE::q(); + // + // //Big int q/3 + // let lower_bound: BigInt = order.div_floor(&BigInt::from(3)); + // + // //Bigint -q/3 + // let minus_lower_bound = BigInt::mod_sub(&order, &lower_bound, &order); //encrypt -q/3 // let c1 = Paillier::encrypt(&paillier_key_pair.ek, RawPlaintext::from(minus_lower_bound)); - // put chosen randomness because it is needed raw in the proof generation - let randomness = Randomness::sample(&paillier_key_pair.ek); - let c1 = Paillier::encrypt_with_chosen_randomness( - &paillier_key_pair.ek, - RawPlaintext::from(minus_lower_bound.clone()), - &randomness, - ); - - //compute x1-q/3 in the ciphertext space - let new_cipher_x1_minus_q_thirds = Paillier::add( - &paillier_key_pair.ek, - RawCiphertext::from(paillier_key_pair.encrypted_share.clone()), - c1, - ); - - //tweak c to c-q/3 for the soundness proof - paillier_key_pair.encrypted_share = new_cipher_x1_minus_q_thirds.clone().0.into_owned(); - //tweak r to r*r' where r' is the randomness used to encrypt -q/3 - paillier_key_pair.randomness = BigInt::mod_mul( - paillier_key_pair.randomness.borrow(), - &randomness.0, - &paillier_key_pair.ek.n, - ); - //tweak c to c-q/3 for the soundness proof - //TODO duplicate element here, is it needed? - party_two_paillier.encrypted_secret_share = - new_cipher_x1_minus_q_thirds.clone().0.into_owned(); - - //assign x = x - q/3 - let party_one_private_for_range_proof = - Party1Private::tweak_x1_for_range_proof(&ec_key_pair_party1, &paillier_key_pair); + // // put chosen randomness because it is needed raw in the proof generation + // let randomness = Randomness::sample(&paillier_key_pair.ek); + // let c1 = Paillier::encrypt_with_chosen_randomness( + // &paillier_key_pair.ek, + // RawPlaintext::from(minus_lower_bound.clone()), + // &randomness, + // ); + + // //compute x1-q/3 in the ciphertext space + // let new_cipher_x1_minus_q_thirds = Paillier::add( + // &paillier_key_pair.ek, + // RawCiphertext::from(paillier_key_pair.encrypted_share.clone()), + // c1, + // ); + + // //tweak c to c-q/3 for the soundness proof + // paillier_key_pair.encrypted_share = new_cipher_x1_minus_q_thirds.clone().0.into_owned(); + // //tweak r to r*r' where r' is the randomness used to encrypt -q/3 + // paillier_key_pair.randomness= BigInt::mod_mul( + // paillier_key_pair.randomness.borrow(), + // &randomness.0.clone(), + // &paillier_key_pair.ek.n, + // ); + // println!("r*r plain ={:?}",paillier_key_pair.randomness); + // let (m, r) = Paillier::open(&paillier_key_pair.dk, &new_cipher_x1_minus_q_thirds); + // println!("r*r after decryption = {:?}",r.0); + + // println!("after decryption x1-q/3 = {:?}",m.0); + + //tweak c to c-q/3 for the soundness proof for P2 + // party_two_paillier.encrypted_secret_share = paillier_key_pair.encrypted_share_minus_q_thirds.clone(); + // new_cipher_x1_minus_q_thirds.clone().0.into_owned(); + + // //assign x = x - q/3 + // let party_one_private_for_range_proof = + // Party1Private::tweak_x1_for_range_proof(&ec_key_pair_party1, &paillier_key_pair); // zk range proof let range_proof = party_one::PaillierKeyPair::generate_range_proof( &paillier_key_pair, - &party_one_private_for_range_proof, + &party_one_private, ); party_two::PaillierPublic::verify_range_proof(&party_two_paillier, &range_proof) .expect("range proof error"); diff --git a/src/zk_paillier/zkproofs/range_proof.rs b/src/zk_paillier/zkproofs/range_proof.rs index d6c27a3..4c3cde5 100644 --- a/src/zk_paillier/zkproofs/range_proof.rs +++ b/src/zk_paillier/zkproofs/range_proof.rs @@ -286,6 +286,7 @@ impl RangeProofTrait for RangeProof { } let mut flag = false; + if w1 < &range_scaled_third && w2 > &range_scaled_third && w2 < &range_scaled_two_thirds From 96b3055584b510cea5cc808fc843c146a1515097 Mon Sep 17 00:00:00 2001 From: Iraklis Leontiadis Date: Mon, 14 Aug 2023 15:03:24 +0300 Subject: [PATCH 11/21] cleaning --- src/test.rs | 50 +------------------------------------------------- 1 file changed, 1 insertion(+), 49 deletions(-) diff --git a/src/test.rs b/src/test.rs index fcab2b2..f572ddc 100644 --- a/src/test.rs +++ b/src/test.rs @@ -70,55 +70,7 @@ mod tests { correct_key_proof .verify(&party_two_paillier.ek) .expect("bad paillier key"); - - // //order of curve - // let order = FE::q(); - // - // //Big int q/3 - // let lower_bound: BigInt = order.div_floor(&BigInt::from(3)); - // - // //Bigint -q/3 - // let minus_lower_bound = BigInt::mod_sub(&order, &lower_bound, &order); - - //encrypt -q/3 - // let c1 = Paillier::encrypt(&paillier_key_pair.ek, RawPlaintext::from(minus_lower_bound)); - - // // put chosen randomness because it is needed raw in the proof generation - // let randomness = Randomness::sample(&paillier_key_pair.ek); - // let c1 = Paillier::encrypt_with_chosen_randomness( - // &paillier_key_pair.ek, - // RawPlaintext::from(minus_lower_bound.clone()), - // &randomness, - // ); - - // //compute x1-q/3 in the ciphertext space - // let new_cipher_x1_minus_q_thirds = Paillier::add( - // &paillier_key_pair.ek, - // RawCiphertext::from(paillier_key_pair.encrypted_share.clone()), - // c1, - // ); - - // //tweak c to c-q/3 for the soundness proof - // paillier_key_pair.encrypted_share = new_cipher_x1_minus_q_thirds.clone().0.into_owned(); - // //tweak r to r*r' where r' is the randomness used to encrypt -q/3 - // paillier_key_pair.randomness= BigInt::mod_mul( - // paillier_key_pair.randomness.borrow(), - // &randomness.0.clone(), - // &paillier_key_pair.ek.n, - // ); - // println!("r*r plain ={:?}",paillier_key_pair.randomness); - // let (m, r) = Paillier::open(&paillier_key_pair.dk, &new_cipher_x1_minus_q_thirds); - // println!("r*r after decryption = {:?}",r.0); - - // println!("after decryption x1-q/3 = {:?}",m.0); - - //tweak c to c-q/3 for the soundness proof for P2 - // party_two_paillier.encrypted_secret_share = paillier_key_pair.encrypted_share_minus_q_thirds.clone(); - // new_cipher_x1_minus_q_thirds.clone().0.into_owned(); - - // //assign x = x - q/3 - // let party_one_private_for_range_proof = - // Party1Private::tweak_x1_for_range_proof(&ec_key_pair_party1, &paillier_key_pair); + // zk range proof let range_proof = party_one::PaillierKeyPair::generate_range_proof( &paillier_key_pair, From e187cb3e45875a377783d8c38a2a68ad019da416 Mon Sep 17 00:00:00 2001 From: Iraklis Leontiadis Date: Fri, 15 Sep 2023 10:58:26 +0300 Subject: [PATCH 12/21] cleaning --- src/party_one.rs | 6 +++--- src/test.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/party_one.rs b/src/party_one.rs index 62b7483..47d73a8 100644 --- a/src/party_one.rs +++ b/src/party_one.rs @@ -76,11 +76,11 @@ pub struct KeyGenSecondMsg { #[derive(Debug, Serialize, Deserialize)] pub struct PaillierKeyPair { pub ek: EncryptionKey, - pub dk: DecryptionKey, + dk: DecryptionKey, pub encrypted_share: BigInt, pub encrypted_share_minus_q_thirds: BigInt, - pub randomness: BigInt, - pub randomness_q: BigInt, + randomness: BigInt, + randomness_q: BigInt, } #[derive(Debug, Serialize, Deserialize)] diff --git a/src/test.rs b/src/test.rs index f572ddc..428d24d 100644 --- a/src/test.rs +++ b/src/test.rs @@ -70,7 +70,7 @@ mod tests { correct_key_proof .verify(&party_two_paillier.ek) .expect("bad paillier key"); - + // zk range proof let range_proof = party_one::PaillierKeyPair::generate_range_proof( &paillier_key_pair, From 621b57172773c1973a1bdfa77f7089da6813ba84 Mon Sep 17 00:00:00 2001 From: Iraklis Leontiadis Date: Wed, 13 Dec 2023 16:26:58 +0100 Subject: [PATCH 13/21] init --- src/kms/ecdsa/two_party/test.rs | 93 +++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/src/kms/ecdsa/two_party/test.rs b/src/kms/ecdsa/two_party/test.rs index 78634b7..7fa3d74 100644 --- a/src/kms/ecdsa/two_party/test.rs +++ b/src/kms/ecdsa/two_party/test.rs @@ -11,12 +11,20 @@ */ #![allow(non_snake_case)] #![cfg(test)] + +use sha2::Sha512; +use hmac::{Hmac, Mac}; +use zeroize::Zeroize; + +pub struct HMacSha512; use super::{MasterKey1, MasterKey2}; use crate::kms::chain_code::two_party::{party1, party2}; use crate::centipede::juggling::{proof_system::Proof, segmentation::Msegmentation}; use crate::curv::arithmetic::traits::Converter; use crate::curv::elliptic::curves::traits::{ECPoint, ECScalar}; use crate::curv::{BigInt, FE, GE}; +use crate::curv::cryptographic_primitives::hashing::hmac_sha512; +use crate::curv::cryptographic_primitives::hashing::traits::KeyedHash; #[test] fn test_recovery_from_openssl() { @@ -422,3 +430,88 @@ pub fn test_key_gen() -> (MasterKey1, MasterKey2) { ); (party_one_master_key, party_two_master_key) } + + +fn compute_hmac(key: &BigInt,input: &str) -> BigInt { + //init key + let mut key_bytes: Vec = key.into(); + let mut ctx = Hmac::::new_from_slice(&key_bytes).expect("HMAC can take key of any size"); + + //hash input + ctx.update(input.as_ref()); + key_bytes.zeroize(); + BigInt::from(ctx.finalize().into_bytes().as_ref()) + +} + +#[test] +fn test_hd_multipath_derivation() { + + + // compute master keys: + let (party_one_master_key, party_two_master_key) = test_key_gen(); + let pub_key_bi = party_one_master_key.public.q.bytes_compressed_to_big_int(); + + + + let new_party_two_master_key = + party_two_master_key.get_child(vec![BigInt::from(10), BigInt::from(5),compute_hmac(&pub_key_bi,"vault"),compute_hmac(&pub_key_bi,"friends"),compute_hmac(&pub_key_bi,"Max")]); + let new_party_one_master_key = + party_one_master_key.get_child(vec![BigInt::from(10), BigInt::from(5)]); + + //make sure that keys are not the same after the multipath derivation run only by one party + assert_ne!( + new_party_one_master_key.public.q, + new_party_two_master_key.public.q + ); + //derive the proper path for the server as the client did + //the path is expected to be in BigInts, so the way we achieve that is hmac(key,input) to a BigInt. Anything like + //a good collision hash function works . We used hmac keyed with the public key as a domain separator. + let new_party_one_master_key = + party_one_master_key.get_child(vec![BigInt::from(10), BigInt::from(5),compute_hmac(&pub_key_bi,"vault"),compute_hmac(&pub_key_bi,"friends"),compute_hmac(&pub_key_bi,"Max")]); + +//make sure that the public keys are equal + assert_eq!( + new_party_one_master_key.public.q, + new_party_two_master_key.public.q + ); + + + //test signing: + let message = BigInt::from(1234); + let (sign_party_two_first_message, eph_comm_witness, eph_ec_key_pair_party2) = + MasterKey2::sign_first_message(); + let (sign_party_one_first_message, eph_ec_key_pair_party1) = MasterKey1::sign_first_message(); + let sign_party_two_second_message = party_two_master_key.sign_second_message( + &eph_ec_key_pair_party2, + eph_comm_witness, + &sign_party_one_first_message, + &message, + ); + let sign_party_one_second_message = party_one_master_key.sign_second_message( + &sign_party_two_second_message, + &sign_party_two_first_message, + &eph_ec_key_pair_party1, + &message, + ); + sign_party_one_second_message.expect("bad signature"); + + // test sign for child + let message = BigInt::from(1234); + let (sign_party_two_first_message, eph_comm_witness, eph_ec_key_pair_party2) = + MasterKey2::sign_first_message(); + let (sign_party_one_first_message, eph_ec_key_pair_party1) = MasterKey1::sign_first_message(); + let sign_party_two_second_message = new_party_two_master_key.sign_second_message( + &eph_ec_key_pair_party2, + eph_comm_witness, + &sign_party_one_first_message, + &message, + ); + let sign_party_one_second_message = new_party_one_master_key.sign_second_message( + &sign_party_two_second_message, + &sign_party_two_first_message, + &eph_ec_key_pair_party1, + &message, + ); + sign_party_one_second_message.expect("bad signature"); +} From ea39420437fdd9eba45be5c4abb1c940381db5fa Mon Sep 17 00:00:00 2001 From: Iraklis Leontiadis Date: Thu, 14 Dec 2023 14:53:36 +0100 Subject: [PATCH 14/21] rangeproof not stable for rotation --- src/kms/ecdsa/two_party/party1.rs | 50 ++++++++++++++++++++++ src/kms/ecdsa/two_party/party2.rs | 62 +++++++++++++++++++++++++++- src/kms/ecdsa/two_party/test.rs | 52 ++++++++++++++++++----- src/kms/lib.rs | 2 +- src/kms/mod.rs | 2 +- src/kms/rotation/mod.rs | 1 + src/kms/rotation/two_party/mod.rs | 11 +++++ src/kms/rotation/two_party/party1.rs | 31 ++++++++++++++ src/kms/rotation/two_party/party2.rs | 27 ++++++++++++ src/kms/rotation/two_party/test.rs | 24 +++++++++++ src/party_one.rs | 55 +++++++++++++++++++++++- 11 files changed, 300 insertions(+), 17 deletions(-) create mode 100644 src/kms/rotation/mod.rs create mode 100644 src/kms/rotation/two_party/mod.rs create mode 100644 src/kms/rotation/two_party/party1.rs create mode 100644 src/kms/rotation/two_party/party2.rs create mode 100644 src/kms/rotation/two_party/test.rs diff --git a/src/kms/ecdsa/two_party/party1.rs b/src/kms/ecdsa/two_party/party1.rs index 4819b0e..af7f996 100644 --- a/src/kms/ecdsa/two_party/party1.rs +++ b/src/kms/ecdsa/two_party/party1.rs @@ -15,6 +15,8 @@ use crate::{ }; use serde::{Deserialize, Serialize}; +use crate::curv::elliptic::curves::traits::ECScalar; +use crate::kms::rotation::two_party::Rotation; #[derive(Debug, Serialize, Deserialize)] pub struct KeyGenParty1Message2 { @@ -25,7 +27,36 @@ pub struct KeyGenParty1Message2 { pub range_proof: RangeProofNi, } +#[derive(Debug, Serialize, Deserialize)] +pub struct RotationParty1Message1 { + pub ek_new: EncryptionKey, + pub c_key_new: BigInt, + pub correct_key_proof: NICorrectKeyProof, + pub range_proof: RangeProofNi, +} + impl MasterKey1 { + // before rotation make sure both parties have the same key + pub fn rotate( + self, + cf: &Rotation, + party_one_private: party_one::Party1Private, + ek_new: &EncryptionKey, + c_key_new: &BigInt, + ) -> MasterKey1 { + let public = Party1Public { + q: self.public.q, + p1: &self.public.p1 * &cf.rotation, + p2: &self.public.p2 * &cf.rotation.invert(), + paillier_pub: ek_new.clone(), + c_key: c_key_new.clone(), + }; + MasterKey1 { + public, + private: party_one_private, + chain_code: self.chain_code, + } + } pub fn get_child(&self, location_in_hir: Vec) -> MasterKey1 { let (public_key_new_child, f_l_new, cc_new) = hd_key(location_in_hir, &self.public.q, &self.chain_code); @@ -208,4 +239,23 @@ impl MasterKey1 { alpha, ) } + pub fn rotation_first_message(self, cf: &Rotation) -> (RotationParty1Message1, MasterKey1) { + let ( + ek_new, + c_key_new, + new_private, + correct_key_proof, + range_proof + ) = party_one::Party1Private::refresh_private_key(&self.private, &cf.rotation.to_big_int()); + let master_key_new = self.rotate(cf, new_private, &ek_new, &c_key_new); + ( + RotationParty1Message1 { + ek_new, + c_key_new, + correct_key_proof, + range_proof, + }, + master_key_new, + ) + } } diff --git a/src/kms/ecdsa/two_party/party2.rs b/src/kms/ecdsa/two_party/party2.rs index a095454..329e184 100644 --- a/src/kms/ecdsa/two_party/party2.rs +++ b/src/kms/ecdsa/two_party/party2.rs @@ -10,6 +10,8 @@ use crate::party_one::{ PDLFirstMessage as Party1PDLFirstMsg, PDLSecondMessage as Party1PDLSecondMsg, }; use crate::{party_one, party_two}; +use crate::kms::ecdsa::two_party::party1::RotationParty1Message1; +use crate::kms::rotation::two_party::Rotation; #[derive(Debug, Serialize, Deserialize)] pub struct SignMessage { @@ -18,13 +20,33 @@ pub struct SignMessage { } #[derive(Debug, Serialize, Deserialize)] - pub struct Party2SecondMessage { pub key_gen_second_message: party_two::KeyGenSecondMsg, pub pdl_first_message: party_two::PDLFirstMessage, } impl MasterKey2 { + pub fn rotate(self, cf: &Rotation, new_paillier: &party_two::PaillierPublic) -> MasterKey2 { + let rand_str_invert_fe = cf.rotation.invert(); + let c_key_new = new_paillier.encrypted_secret_share.clone(); + + //TODO: use proper set functions + let public = Party2Public { + q: self.public.q, + p1: self.public.p1.clone() * &cf.rotation, + p2: &self.public.p2 * &cf.rotation.invert(), + paillier_pub: new_paillier.ek.clone(), + c_key: c_key_new, + }; + MasterKey2 { + public, + private: party_two::Party2Private::update_private_key( + &self.private, + &rand_str_invert_fe.to_big_int(), + ), + chain_code: self.chain_code, + } + } pub fn get_child(&self, location_in_hir: Vec) -> MasterKey2 { let (public_key_new_child, f_l_new, cc_new) = hd_key(location_in_hir, &self.public.q, &self.chain_code); @@ -187,7 +209,7 @@ impl MasterKey2 { eph_comm_witness, eph_party1_first_message, ) - .expect(""); + .expect(""); let partial_sig = party_two::PartialSig::compute( &self.public.paillier_pub, @@ -202,4 +224,40 @@ impl MasterKey2 { second_message: eph_key_gen_second_message, } } + // party2 receives new paillier key and new c_key = Enc(x1_new) = Enc(r*x_1). + // party2 can compute locally the updated Q1. This is why this set of messages + // is rotation and not new key gen. + // party2 needs to verify range proof on c_key_new and correct key proof on the new paillier keys + pub fn rotate_first_message( + self, + cf: &Rotation, + party_one_rotation_first_message: &RotationParty1Message1) -> Result { + let party_two_paillier = party_two::PaillierPublic { + ek: party_one_rotation_first_message.ek_new.clone(), + encrypted_secret_share: party_one_rotation_first_message.c_key_new.clone(), + }; + + let range_proof_verify = party_two::PaillierPublic::verify_range_proof( + &party_two_paillier, + &party_one_rotation_first_message.range_proof, + ); + + println!("range_proof_verify = {:?}",range_proof_verify); + + let correct_key_verify = party_one_rotation_first_message + .correct_key_proof + .verify(&party_two_paillier.ek); + + println!("correct_key_verify = {:?}",correct_key_verify); + + let master_key = self.rotate(cf, &party_two_paillier); + + match range_proof_verify { + Ok(_proof) => match correct_key_verify { + Ok(_proof) => Ok(master_key), + Err(_correct_key_error) => Err(()), + }, + Err(_range_proof_error) => Err(()), + } + } } diff --git a/src/kms/ecdsa/two_party/test.rs b/src/kms/ecdsa/two_party/test.rs index 7fa3d74..ef28ea0 100644 --- a/src/kms/ecdsa/two_party/test.rs +++ b/src/kms/ecdsa/two_party/test.rs @@ -17,14 +17,16 @@ use hmac::{Hmac, Mac}; use zeroize::Zeroize; pub struct HMacSha512; + use super::{MasterKey1, MasterKey2}; use crate::kms::chain_code::two_party::{party1, party2}; use crate::centipede::juggling::{proof_system::Proof, segmentation::Msegmentation}; use crate::curv::arithmetic::traits::Converter; use crate::curv::elliptic::curves::traits::{ECPoint, ECScalar}; use crate::curv::{BigInt, FE, GE}; -use crate::curv::cryptographic_primitives::hashing::hmac_sha512; -use crate::curv::cryptographic_primitives::hashing::traits::KeyedHash; +pub use crate::kms::rotation::two_party::party1::Rotation1; +pub use crate::kms::rotation::two_party::party2::Rotation2; +pub use crate::kms::rotation::two_party::Rotation; #[test] fn test_recovery_from_openssl() { @@ -209,7 +211,7 @@ fn test_commutativity_rotate_get_child() { sign_party_one_second_message.expect("bad signature"); let (cr_party_one_master_key, cr_party_two_master_key) = - (new_party_one_master_key, new_party_two_master_key); + test_rotation(new_party_one_master_key, new_party_two_master_key); // sign with child and rotated keys let sign_party_two_second_message = cr_party_two_master_key.sign_second_message( @@ -229,8 +231,8 @@ fn test_commutativity_rotate_get_child() { // rotate_and_get_child: let (rotate_party_one_master_key, rotate_party_two_master_key) = - (party_one_master_key, party_two_master_key); - + test_rotation(party_one_master_key, party_two_master_key); + println!(" rotate_and_get_child:"); //get child: let rc_party_one_master_key = rotate_party_one_master_key.get_child(vec![BigInt::from(10_i32)]); let rc_party_two_master_key = rotate_party_two_master_key.get_child(vec![BigInt::from(10_i32)]); @@ -341,7 +343,7 @@ fn test_flip_masters() { // rotation let (party_one_master_key_rotated, party_two_master_key_rotated) = - (party_one_master_key, party_two_master_key); + test_rotation(party_one_master_key, party_two_master_key); // sign after rotate: //test signing: @@ -432,7 +434,7 @@ pub fn test_key_gen() -> (MasterKey1, MasterKey2) { } -fn compute_hmac(key: &BigInt,input: &str) -> BigInt { +fn compute_hmac(key: &BigInt, input: &str) -> BigInt { //init key let mut key_bytes: Vec = key.into(); let mut ctx = Hmac::::new_from_slice(&key_bytes).expect("HMAC can take key of any size"); @@ -441,7 +443,6 @@ fn compute_hmac(key: &BigInt,input: &str) -> BigInt { ctx.update(input.as_ref()); key_bytes.zeroize(); BigInt::from(ctx.finalize().into_bytes().as_ref()) - } #[test] @@ -453,9 +454,8 @@ fn test_hd_multipath_derivation() { let pub_key_bi = party_one_master_key.public.q.bytes_compressed_to_big_int(); - let new_party_two_master_key = - party_two_master_key.get_child(vec![BigInt::from(10), BigInt::from(5),compute_hmac(&pub_key_bi,"vault"),compute_hmac(&pub_key_bi,"friends"),compute_hmac(&pub_key_bi,"Max")]); + party_two_master_key.get_child(vec![BigInt::from(10), BigInt::from(5), compute_hmac(&pub_key_bi, "vault"), compute_hmac(&pub_key_bi, "friends"), compute_hmac(&pub_key_bi, "Max")]); let new_party_one_master_key = party_one_master_key.get_child(vec![BigInt::from(10), BigInt::from(5)]); @@ -468,7 +468,7 @@ fn test_hd_multipath_derivation() { //the path is expected to be in BigInts, so the way we achieve that is hmac(key,input) to a BigInt. Anything like //a good collision hash function works . We used hmac keyed with the public key as a domain separator. let new_party_one_master_key = - party_one_master_key.get_child(vec![BigInt::from(10), BigInt::from(5),compute_hmac(&pub_key_bi,"vault"),compute_hmac(&pub_key_bi,"friends"),compute_hmac(&pub_key_bi,"Max")]); + party_one_master_key.get_child(vec![BigInt::from(10), BigInt::from(5), compute_hmac(&pub_key_bi, "vault"), compute_hmac(&pub_key_bi, "friends"), compute_hmac(&pub_key_bi, "Max")]); //make sure that the public keys are equal assert_eq!( @@ -515,3 +515,33 @@ fn test_hd_multipath_derivation() { ); sign_party_one_second_message.expect("bad signature"); } + +pub fn test_rotation( + party_one_master_key: MasterKey1, + party_two_master_key: MasterKey2, +) -> (MasterKey1, MasterKey2) { + //coin flip: + let (party1_first_message, m1, r1) = Rotation1::key_rotate_first_message(); + let party2_first_message = Rotation2::key_rotate_first_message(&party1_first_message); + let (party1_second_message, random1) = + Rotation1::key_rotate_second_message(&party2_first_message, &m1, &r1); + let random2 = Rotation2::key_rotate_second_message( + &party1_second_message, + &party2_first_message, + &party1_first_message, + ); + + //rotation: + let (rotation_party_one_first_message, party_one_master_key_rotated) = + party_one_master_key.rotation_first_message(&random1); + + let result_rotate_party_two = + party_two_master_key.rotate_first_message(&random2, &rotation_party_one_first_message); + assert!(result_rotate_party_two.is_ok()); + + ( + party_one_master_key_rotated, + result_rotate_party_two.unwrap(), + ) +} + diff --git a/src/kms/lib.rs b/src/kms/lib.rs index bf696bf..4cee334 100644 --- a/src/kms/lib.rs +++ b/src/kms/lib.rs @@ -16,7 +16,7 @@ pub mod chain_code; pub mod ecdsa; - +pub mod rotation; pub mod poc; #[derive(Copy, PartialEq, Eq, Clone, Debug)] diff --git a/src/kms/mod.rs b/src/kms/mod.rs index cbe250c..c0751d7 100644 --- a/src/kms/mod.rs +++ b/src/kms/mod.rs @@ -1,6 +1,6 @@ pub mod chain_code; pub mod ecdsa; - +pub mod rotation; pub mod poc; #[derive(Copy, PartialEq, Eq, Clone, Debug)] diff --git a/src/kms/rotation/mod.rs b/src/kms/rotation/mod.rs new file mode 100644 index 0000000..9919d19 --- /dev/null +++ b/src/kms/rotation/mod.rs @@ -0,0 +1 @@ +pub mod two_party; \ No newline at end of file diff --git a/src/kms/rotation/two_party/mod.rs b/src/kms/rotation/two_party/mod.rs new file mode 100644 index 0000000..52d2308 --- /dev/null +++ b/src/kms/rotation/two_party/mod.rs @@ -0,0 +1,11 @@ +use serde::{Deserialize, Serialize}; +use crate::curv::elliptic::curves::secp256_k1::FE; + +pub mod party1; +pub mod party2; +pub mod test; + +#[derive(Debug, Serialize, Deserialize)] +pub struct Rotation { + pub rotation: FE, +} \ No newline at end of file diff --git a/src/kms/rotation/two_party/party1.rs b/src/kms/rotation/two_party/party1.rs new file mode 100644 index 0000000..7637eca --- /dev/null +++ b/src/kms/rotation/two_party/party1.rs @@ -0,0 +1,31 @@ +use super::Rotation; +use crate::curv::cryptographic_primitives::twoparty::coin_flip_optimal_rounds; +use crate::curv::elliptic::curves::secp256_k1::{Secp256k1Scalar, GE}; + + +pub struct Rotation1 {} + +impl Rotation1 { + //TODO: implmenet sid / state machine + pub fn key_rotate_first_message() -> ( + coin_flip_optimal_rounds::Party1FirstMessage, + Secp256k1Scalar, + Secp256k1Scalar, + ) { + coin_flip_optimal_rounds::Party1FirstMessage::commit() + } + + pub fn key_rotate_second_message( + party2_first_message: &coin_flip_optimal_rounds::Party2FirstMessage, + m1: &Secp256k1Scalar, + r1: &Secp256k1Scalar, + ) -> (coin_flip_optimal_rounds::Party1SecondMessage, Rotation) { + let (res1, res2) = coin_flip_optimal_rounds::Party1SecondMessage::reveal( + &party2_first_message.seed, + m1, + r1, + ); + + (res1, Rotation { rotation: res2 }) + } +} \ No newline at end of file diff --git a/src/kms/rotation/two_party/party2.rs b/src/kms/rotation/two_party/party2.rs new file mode 100644 index 0000000..cf98177 --- /dev/null +++ b/src/kms/rotation/two_party/party2.rs @@ -0,0 +1,27 @@ +use crate::curv::cryptographic_primitives::twoparty::coin_flip_optimal_rounds; +use crate::curv::elliptic::curves::secp256_k1::GE; + +use super::Rotation; + +pub struct Rotation2 {} + +impl Rotation2 { + pub fn key_rotate_first_message( + party1_first_message: &coin_flip_optimal_rounds::Party1FirstMessage, + ) -> coin_flip_optimal_rounds::Party2FirstMessage { + coin_flip_optimal_rounds::Party2FirstMessage::share(&party1_first_message.proof) + } + + pub fn key_rotate_second_message( + party1_second_message: &coin_flip_optimal_rounds::Party1SecondMessage, + party2_first_message: &coin_flip_optimal_rounds::Party2FirstMessage, + party1_first_message: &coin_flip_optimal_rounds::Party1FirstMessage, + ) -> Rotation { + let rotation = coin_flip_optimal_rounds::finalize( + &party1_second_message.proof, + &party2_first_message.seed, + &party1_first_message.proof.com, + ); + Rotation { rotation } + } +} \ No newline at end of file diff --git a/src/kms/rotation/two_party/test.rs b/src/kms/rotation/two_party/test.rs new file mode 100644 index 0000000..26d2364 --- /dev/null +++ b/src/kms/rotation/two_party/test.rs @@ -0,0 +1,24 @@ +#[cfg(test)] +mod tests { + use crate::curv::elliptic::curves::traits::ECScalar; + use crate::kms::rotation::two_party::party1::Rotation1; + use crate::kms::rotation::two_party::party2::Rotation2; + + #[test] + fn test_coin_flip() { + //coin flip: + let (party1_first_message, m1, r1) = Rotation1::key_rotate_first_message(); + let party2_first_message = Rotation2::key_rotate_first_message(&party1_first_message); + let (party1_second_message, random1) = + Rotation1::key_rotate_second_message(&party2_first_message, &m1, &r1); + let random2 = Rotation2::key_rotate_second_message( + &party1_second_message, + &party2_first_message, + &party1_first_message, + ); + assert_eq!( + random1.rotation.get_element(), + random2.rotation.get_element() + ); + } +} \ No newline at end of file diff --git a/src/party_one.rs b/src/party_one.rs index bb5ad70..67d96b4 100644 --- a/src/party_one.rs +++ b/src/party_one.rs @@ -22,7 +22,7 @@ use std::ops::Shl; use std::fmt::{Debug, Display, Formatter}; use serde::{Serialize, Deserialize}; -use super::SECURITY_BITS; +use super::{party_one, SECURITY_BITS}; pub use crate::curv::arithmetic::traits::*; use crate::curv::elliptic::curves::traits::*; @@ -46,7 +46,8 @@ use crate::centipede::juggling::segmentation::Msegmentation; use crate::curv::BigInt; use crate::curv::FE; use crate::curv::GE; -use std::any::{Any, TypeId}; +use std::any::{Any}; +use secp256k1::Secp256k1; use crate::Error::{self, InvalidSig}; @@ -382,6 +383,56 @@ pub fn compute_pubkey(party_one_private: &Party1Private, other_share_public_shar } impl Party1Private { + pub fn refresh_private_key( + party_one_private: &Party1Private, + factor: &BigInt, + ) -> ( + EncryptionKey, + BigInt, + Party1Private, + NICorrectKeyProof, + RangeProofNi + ) { + let (ek_new, dk_new) = Paillier::keypair().keys(); + let randomness = Randomness::sample(&ek_new.clone()); + let factor_fe: FE = ECScalar::from(factor); + let x1_new: FE = *&party_one_private.x1 * factor_fe; + let c_key_new = Paillier::encrypt_with_chosen_randomness( + &ek_new.clone(), + RawPlaintext::from(x1_new.to_big_int()), + &randomness, + ) + .0 + .into_owned(); + + let party_one_private_new = Party1Private { + x1: x1_new.clone(), + paillier_priv: dk_new.clone(), + c_key_randomness: randomness.0.clone(), + }; + + let paillier_key_pair = PaillierKeyPair { + ek: ek_new.clone(), + dk: dk_new.clone(), + encrypted_share: c_key_new.clone(), + randomness: randomness.0.clone(), + }; + let correct_key_proof = + PaillierKeyPair::generate_ni_proof_correct_key(&paillier_key_pair); + + + let range_proof = party_one::PaillierKeyPair::generate_range_proof( + &paillier_key_pair, + &party_one_private_new, + ); + ( + ek_new.clone(), + c_key_new.clone(), + party_one_private_new, + correct_key_proof, + range_proof + ) + } pub fn set_private_key(ec_key: &EcKeyPair, paillier_key: &PaillierKeyPair) -> Party1Private { Party1Private { x1: ec_key.secret_share, From b61cb57771c405367dc27ec10f5a7312468a20c1 Mon Sep 17 00:00:00 2001 From: Iraklis Leontiadis <120665504+leontiadZen@users.noreply.github.com> Date: Thu, 28 Dec 2023 11:45:06 +0200 Subject: [PATCH 15/21] rotate --- src/curv/elliptic/test.rs | 360 ++++++++++++++++++++++++++++++ src/kms/ecdsa/two_party/test.rs | 47 +++- src/kms/rotation/two_party/mod.rs | 2 +- src/party_one.rs | 9 + 4 files changed, 409 insertions(+), 9 deletions(-) create mode 100644 src/curv/elliptic/test.rs diff --git a/src/curv/elliptic/test.rs b/src/curv/elliptic/test.rs new file mode 100644 index 0000000..3bf4bb2 --- /dev/null +++ b/src/curv/elliptic/test.rs @@ -0,0 +1,360 @@ +#![allow(non_snake_case)] + +use std::iter; + +use rand::{rngs::OsRng, Rng}; + +use crate::arithmetic::*; +use crate::test_for_all_curves; + +use super::traits::*; + +fn random_nonzero_scalar() -> S { + loop { + let s = S::random(); + if !s.is_zero() { + break s; + } + } +} + +test_for_all_curves!(valid_zero_point); +fn valid_zero_point() { + let zero = E::Scalar::zero(); + assert!(zero.is_zero()); + assert_eq!(zero, E::Scalar::zero()); +} + +test_for_all_curves!(zero_point_arithmetic); +fn zero_point_arithmetic() { + let zero_point = E::Point::zero(); + let point = E::Point::generator().scalar_mul(&random_nonzero_scalar()); + + assert_eq!(zero_point.add_point(&point), point, "O + P = P"); + assert_eq!(point.add_point(&zero_point), point, "P + O = P"); + + let point_neg = point.neg_point(); + assert!(point.add_point(&point_neg).is_zero(), "P + (-P) = O"); + assert!(point.sub_point(&point).is_zero(), "P - P = O"); + + let zero_scalar = E::Scalar::zero(); + assert!(point.scalar_mul(&zero_scalar).is_zero(), "P * 0 = O"); + let scalar = random_nonzero_scalar(); + assert!(zero_point.scalar_mul(&scalar).is_zero(), "O * s = O") +} + +test_for_all_curves!(scalar_modulo_curve_order); +fn scalar_modulo_curve_order() { + let n = E::Scalar::group_order(); + let s = E::Scalar::from_bigint(n); + assert!(s.is_zero()); + + let s = E::Scalar::from_bigint(&(n + 1)); + assert_eq!(s, E::Scalar::from_bigint(&BigInt::from(1))); +} + +test_for_all_curves!(zero_scalar_arithmetic); +fn zero_scalar_arithmetic() { + let s: E::Scalar = random_nonzero_scalar(); + let z = E::Scalar::zero(); + assert!(s.mul(&z).is_zero()); + assert!(z.mul(&s).is_zero()); + assert_eq!(s.add(&z), s); + assert_eq!(z.add(&s), s); +} + +test_for_all_curves!(point_addition_multiplication); +fn point_addition_multiplication() { + let point = E::Point::generator().scalar_mul(&random_nonzero_scalar()); + assert!(!point.is_zero(), "G * s != O"); + + let addition = iter::successors(Some(point.clone()), |p| Some(p.add_point(&point))) + .take(10) + .collect::>(); + let multiplication = (1..=10) + .map(|i| E::Scalar::from_bigint(&BigInt::from(i))) + .map(|s| point.scalar_mul(&s)) + .collect::>(); + assert_eq!(addition, multiplication); +} + +test_for_all_curves!(serialize_deserialize_point); +fn serialize_deserialize_point() { + let rand_point = ::generator().scalar_mul(&random_nonzero_scalar()); + let zero = E::Point::zero(); + for point in [rand_point, zero] { + let bytes = point.serialize_compressed(); + let deserialized = ::deserialize(bytes.as_ref()).unwrap(); + assert_eq!(point, deserialized); + let bytes = point.serialize_uncompressed(); + let deserialized = ::deserialize(bytes.as_ref()).unwrap(); + assert_eq!(point, deserialized); + } +} + +test_for_all_curves!(zero_point_serialization); +fn zero_point_serialization() { + let point: E::Point = ECPoint::zero(); + let bytes = point.serialize_compressed(); + let point_from_compressed: E::Point = ECPoint::deserialize(bytes.as_ref()).unwrap(); + assert_eq!(point, point_from_compressed); + + let bytes = point.serialize_uncompressed(); + let point_from_uncompressed: E::Point = ECPoint::deserialize(bytes.as_ref()).unwrap(); + assert_eq!(point, point_from_uncompressed); +} + +test_for_all_curves!(generator_mul_curve_order_is_zero); +fn generator_mul_curve_order_is_zero() { + let g: &E::Point = ECPoint::generator(); + let n = E::Scalar::group_order() - 1; + let s = E::Scalar::from_bigint(&n); + assert!(g.scalar_mul(&s).add_point(g).is_zero()); +} + +test_for_all_curves!(scalar_behaves_the_same_as_bigint); +fn scalar_behaves_the_same_as_bigint() { + let mut rng = OsRng; + let q = E::Scalar::group_order(); + + let mut n = BigInt::zero(); + let mut s: E::Scalar = ECScalar::zero(); + + for _ in 0..100 { + let operation = rng.gen_range(0, 4); + if operation == 0 { + let n_inv = BigInt::mod_inv(&n, q); + let s_inv = s.invert().map(|s| s.to_bigint()); + + assert_eq!( + s_inv, + n_inv, + "{}^-1 = {} (got {})", + n, + n_inv + .as_ref() + .map(|i| i.to_string()) + .unwrap_or_else(|| "None".to_string()), + s_inv + .as_ref() + .map(|i| i.to_string()) + .unwrap_or_else(|| "None".to_string()), + ); + } else { + let n_was = n.clone(); + let k = BigInt::sample_below(&(q * 2)); + let k_s: E::Scalar = ECScalar::from_bigint(&k); + let op; + + match operation { + 1 => { + op = "+"; + n = BigInt::mod_add(&n, &k, q); + + let s_no_assign = s.add(&k_s); + s.add_assign(&k_s); + assert_eq!(s, s_no_assign); + } + 2 => { + op = "*"; + n = BigInt::mod_mul(&n, &k, q); + + let s_no_assign = s.mul(&k_s); + s.mul_assign(&k_s); + assert_eq!(s, s_no_assign); + } + 3 => { + op = "-"; + n = BigInt::mod_sub(&n, &k, q); + + let s_no_assign = s.sub(&k_s); + s.sub_assign(&k_s); + assert_eq!(s, s_no_assign); + } + _ => unreachable!(), + } + + assert_eq!( + s.to_bigint(), + n.modulus(q), + "{} {} {} = {} (got {})", + n_was, + op, + k, + n, + s.to_bigint() + ); + } + } +} + +test_for_all_curves!(from_coords_produces_the_same_point); +fn from_coords_produces_the_same_point() { + if E::CURVE_NAME == "ristretto" { + // This curve is exception. + return; + } + let s: E::Scalar = random_nonzero_scalar(); + println!("s={}", s.to_bigint()); + + let p: E::Point = ::generator().scalar_mul(&s); + let coords = p.coords().unwrap(); + let p2: E::Point = ECPoint::from_coords(&coords.x, &coords.y).unwrap(); + assert_eq!(p, p2); +} + +test_for_all_curves!(test_point_addition); +fn test_point_addition() { + let a: E::Scalar = random_nonzero_scalar(); + let b: E::Scalar = random_nonzero_scalar(); + + let aG: E::Point = ECPoint::generator_mul(&a); + let bG: E::Point = ECPoint::generator_mul(&b); + let a_plus_b = a.add(&b); + let a_plus_b_G: E::Point = ECPoint::generator_mul(&a_plus_b); + + assert_eq!(aG.add_point(&bG), a_plus_b_G); +} + +test_for_all_curves!(test_point_assign_addition); +fn test_point_assign_addition() { + let a: E::Scalar = random_nonzero_scalar(); + let b: E::Scalar = random_nonzero_scalar(); + + let aG: E::Point = ECPoint::generator_mul(&a); + let bG: E::Point = ECPoint::generator_mul(&b); + + let a_plus_b_G_1 = aG.add_point(&bG); + let a_plus_b_G_2 = { + let mut aG = aG; + aG.add_point_assign(&bG); + aG + }; + + assert_eq!(a_plus_b_G_1, a_plus_b_G_2); +} + +test_for_all_curves!(test_point_subtraction); +fn test_point_subtraction() { + let a: E::Scalar = random_nonzero_scalar(); + let b: E::Scalar = random_nonzero_scalar(); + + let aG: E::Point = ECPoint::generator_mul(&a); + let bG: E::Point = ECPoint::generator_mul(&b); + let a_minus_b = a.sub(&b); + let a_minus_b_G: E::Point = ECPoint::generator_mul(&a_minus_b); + + assert_eq!(aG.sub_point(&bG), a_minus_b_G); +} + +test_for_all_curves!(test_point_assign_subtraction); +fn test_point_assign_subtraction() { + let a: E::Scalar = random_nonzero_scalar(); + let b: E::Scalar = random_nonzero_scalar(); + + let aG: E::Point = ECPoint::generator_mul(&a); + let bG: E::Point = ECPoint::generator_mul(&b); + + let a_minus_b_G_1: E::Point = aG.sub_point(&bG); + let a_minus_b_G_2 = { + let mut aG = aG; + aG.sub_point_assign(&bG); + aG + }; + + assert_eq!(a_minus_b_G_1, a_minus_b_G_2); +} + +test_for_all_curves!(test_multiplication_point_at_scalar); +fn test_multiplication_point_at_scalar() { + let a: E::Scalar = random_nonzero_scalar(); + let b: E::Scalar = random_nonzero_scalar(); + + let aG: E::Point = ECPoint::generator_mul(&a); + let abG: E::Point = aG.scalar_mul(&b); + let a_mul_b = a.mul(&b); + let a_mul_b_G: E::Point = ECPoint::generator_mul(&a_mul_b); + + assert_eq!(abG, a_mul_b_G); +} + +test_for_all_curves!(test_assign_multiplication_point_at_scalar); +fn test_assign_multiplication_point_at_scalar() { + let a: E::Scalar = random_nonzero_scalar(); + let b: E::Scalar = random_nonzero_scalar(); + + let aG: E::Point = ECPoint::generator_mul(&a); + + let abG_1: E::Point = aG.scalar_mul(&b); + let abG_2 = { + let mut aG = aG; + aG.scalar_mul_assign(&b); + aG + }; + + assert_eq!(abG_1, abG_2); +} + +test_for_all_curves!(serialize_deserialize_scalar); +fn serialize_deserialize_scalar() { + let rand_point: E::Scalar = random_nonzero_scalar(); + let zero = E::Scalar::zero(); + for scalar in [rand_point, zero] { + let bytes = scalar.serialize(); + let deserialized = ::deserialize(bytes.as_ref()).unwrap(); + assert_eq!(scalar, deserialized); + } +} + +test_for_all_curves!(scalar_invert); +fn scalar_invert() { + let n: E::Scalar = random_nonzero_scalar(); + + let n_inv = n.invert().unwrap(); + assert_eq!(n.mul(&n_inv), ECScalar::from_bigint(&BigInt::one())) +} + +test_for_all_curves!(zero_scalar_invert); +fn zero_scalar_invert() { + let n: E::Scalar = ECScalar::zero(); + let n_inv = n.invert(); + assert!(n_inv.is_none()) +} + +test_for_all_curves!(point_negation); +fn point_negation() { + let p1 = ::generator_mul(&random_nonzero_scalar()); + let p2 = p1.neg_point(); + assert_eq!(p1.add_point(&p2), ECPoint::zero()); +} + +test_for_all_curves!(point_assign_negation); +fn point_assign_negation() { + let p = ::generator_mul(&random_nonzero_scalar()); + let p_neg_1 = p.neg_point(); + let p_neg_2 = { + let mut p = p; + p.neg_point_assign(); + p + }; + assert_eq!(p_neg_1, p_neg_2); +} + +test_for_all_curves!(scalar_negation); +fn scalar_negation() { + let s1: E::Scalar = random_nonzero_scalar(); + let s2 = s1.neg(); + assert_eq!(s1.add(&s2), E::Scalar::zero()); +} + +test_for_all_curves!(scalar_assign_negation); +fn scalar_assign_negation() { + let s: E::Scalar = random_nonzero_scalar(); + let s_neg_1 = s.neg(); + let s_neg_2 = { + let mut s = s; + s.neg_assign(); + s + }; + assert_eq!(s_neg_1, s_neg_2); +} diff --git a/src/kms/ecdsa/two_party/test.rs b/src/kms/ecdsa/two_party/test.rs index ef28ea0..52b20bf 100644 --- a/src/kms/ecdsa/two_party/test.rs +++ b/src/kms/ecdsa/two_party/test.rs @@ -12,6 +12,8 @@ #![allow(non_snake_case)] #![cfg(test)] +use std::cell::RefCell; +use std::sync::Arc; use sha2::Sha512; use hmac::{Hmac, Mac}; use zeroize::Zeroize; @@ -24,9 +26,12 @@ use crate::centipede::juggling::{proof_system::Proof, segmentation::Msegmentatio use crate::curv::arithmetic::traits::Converter; use crate::curv::elliptic::curves::traits::{ECPoint, ECScalar}; use crate::curv::{BigInt, FE, GE}; +use crate::curv::cryptographic_primitives::twoparty::coin_flip_optimal_rounds; pub use crate::kms::rotation::two_party::party1::Rotation1; pub use crate::kms::rotation::two_party::party2::Rotation2; pub use crate::kms::rotation::two_party::Rotation; +use crate::party_one::Party1Private; +use crate::Secp256k1Scalar; #[test] fn test_recovery_from_openssl() { @@ -212,6 +217,7 @@ fn test_commutativity_rotate_get_child() { let (cr_party_one_master_key, cr_party_two_master_key) = test_rotation(new_party_one_master_key, new_party_two_master_key); + println!("br1"); // sign with child and rotated keys let sign_party_two_second_message = cr_party_two_master_key.sign_second_message( @@ -229,10 +235,11 @@ fn test_commutativity_rotate_get_child() { sign_party_one_second_message.expect("bad signature"); // rotate_and_get_child: + println!("br2"); let (rotate_party_one_master_key, rotate_party_two_master_key) = test_rotation(party_one_master_key, party_two_master_key); - println!(" rotate_and_get_child:"); + println!(" rotate_and_get_child:"); //get child: let rc_party_one_master_key = rotate_party_one_master_key.get_child(vec![BigInt::from(10_i32)]); let rc_party_two_master_key = rotate_party_two_master_key.get_child(vec![BigInt::from(10_i32)]); @@ -520,24 +527,48 @@ pub fn test_rotation( party_one_master_key: MasterKey1, party_two_master_key: MasterKey2, ) -> (MasterKey1, MasterKey2) { - //coin flip: + //coin flip:there is a delicate case x1*r to be out of the range proof bounds so extra care is needed + //P1 should check whether x1.r bool { + let factor_fe: FE = ECScalar::from(factor); + let x1_new: FE = factor_fe * party_one_private.x1; + + (x1_new.to_big_int() >= FE::q().div_floor(&BigInt::from(3))) + } pub fn refresh_private_key( party_one_private: &Party1Private, factor: &BigInt, From 9a7ad75aad3211a2a205ae778894d198ea577960 Mon Sep 17 00:00:00 2001 From: Iraklis Leontiadis <120665504+leontiadZen@users.noreply.github.com> Date: Tue, 2 Jan 2024 14:35:58 +0200 Subject: [PATCH 16/21] tests --- src/kms/ecdsa/two_party/party1.rs | 20 +- src/kms/ecdsa/two_party/test.rs | 419 ------------------------------ src/party_one.rs | 49 ---- 3 files changed, 1 insertion(+), 487 deletions(-) diff --git a/src/kms/ecdsa/two_party/party1.rs b/src/kms/ecdsa/two_party/party1.rs index af7f996..d22dd3b 100644 --- a/src/kms/ecdsa/two_party/party1.rs +++ b/src/kms/ecdsa/two_party/party1.rs @@ -239,23 +239,5 @@ impl MasterKey1 { alpha, ) } - pub fn rotation_first_message(self, cf: &Rotation) -> (RotationParty1Message1, MasterKey1) { - let ( - ek_new, - c_key_new, - new_private, - correct_key_proof, - range_proof - ) = party_one::Party1Private::refresh_private_key(&self.private, &cf.rotation.to_big_int()); - let master_key_new = self.rotate(cf, new_private, &ek_new, &c_key_new); - ( - RotationParty1Message1 { - ek_new, - c_key_new, - correct_key_proof, - range_proof, - }, - master_key_new, - ) - } + } diff --git a/src/kms/ecdsa/two_party/test.rs b/src/kms/ecdsa/two_party/test.rs index 52b20bf..097dc73 100644 --- a/src/kms/ecdsa/two_party/test.rs +++ b/src/kms/ecdsa/two_party/test.rs @@ -11,9 +11,6 @@ */ #![allow(non_snake_case)] #![cfg(test)] - -use std::cell::RefCell; -use std::sync::Arc; use sha2::Sha512; use hmac::{Hmac, Mac}; use zeroize::Zeroize; @@ -22,253 +19,10 @@ pub struct HMacSha512; use super::{MasterKey1, MasterKey2}; use crate::kms::chain_code::two_party::{party1, party2}; -use crate::centipede::juggling::{proof_system::Proof, segmentation::Msegmentation}; -use crate::curv::arithmetic::traits::Converter; -use crate::curv::elliptic::curves::traits::{ECPoint, ECScalar}; use crate::curv::{BigInt, FE, GE}; -use crate::curv::cryptographic_primitives::twoparty::coin_flip_optimal_rounds; pub use crate::kms::rotation::two_party::party1::Rotation1; pub use crate::kms::rotation::two_party::party2::Rotation2; pub use crate::kms::rotation::two_party::Rotation; -use crate::party_one::Party1Private; -use crate::Secp256k1Scalar; - -#[test] -fn test_recovery_from_openssl() { - // script for keygen: - /* - #create EC private key - openssl ecparam -genkey -name secp256k1 -out pri1.pem - #derive EC public key - openssl ec -in pri1.pem -outform PEM -pubout -out pub1.pem - */ - // key gen - let (party_one_master_key, party_two_master_key) = test_key_gen(); - // backup by party one of his private secret share: - let segment_size = 8; - let G: GE = GE::generator(); - /* - -----BEGIN PUBLIC KEY----- - MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAELP9n+oNPDoHhEfJoYk8mFMGx4AupPEER - dzwcJIxeqP/xMujsMEDU2mc3fzN9OGbLFnqCqgxBAe31rT84mOfrfA== - -----END PUBLIC KEY----- - */ - let Y_hex = "2CFF67FA834F0E81E111F268624F2614C1B1E00BA93C4111773C1C248C5EA8FFF132E8EC3040D4DA67377F337D3866CB167A82AA0C4101ED\ - F5AD3F3898E7EB7C"; - let Y_bn = BigInt::from_str_radix(Y_hex, 16).unwrap(); - let Y_vec = BigInt::to_vec(&Y_bn); - let Y: GE = ECPoint::from_bytes(&Y_vec[..]).unwrap(); - - /* - - -----BEGIN EC PARAMETERS----- - BgUrgQQACg== - -----END EC PARAMETERS----- - -----BEGIN EC PRIVATE KEY----- - MHQCAQEEIH0Ia1QLbiBwu10eY365nfI0PJhgyL+OgzDiz99KdjIZoAcGBSuBBAAK - oUQDQgAELP9n+oNPDoHhEfJoYk8mFMGx4AupPEERdzwcJIxeqP/xMujsMEDU2mc3 - fzN9OGbLFnqCqgxBAe31rT84mOfrfA== - -----END EC PRIVATE KEY----- - */ - let y_hex = "7D086B540B6E2070BB5D1E637EB99DF2343C9860C8BF8E8330E2CFDF4A763219"; - let y_bn = BigInt::from_str_radix(y_hex, 16).unwrap(); - let y: FE = ECScalar::from(&y_bn); - assert_eq!(Y.clone(), G * y); - - // encryption - let (segments, encryptions_secret_party1) = - party_one_master_key - .private - .to_encrypted_segment(&segment_size, 32, &Y, &G); - // proof and verify test: - - let proof = Proof::prove(&segments, &encryptions_secret_party1, &G, &Y, &segment_size); - let verify = proof.verify( - &encryptions_secret_party1, - &G, - &Y, - &party_two_master_key.public.p1, - &segment_size, - ); - assert!(verify.is_ok()); - - // encryption - - // first case: party one is dead, party two wants to recover the full key. - // In practice party two will recover party_one_master_key and from that point will run both logic parties locally - let secret_decrypted_party_one = - Msegmentation::decrypt(&encryptions_secret_party1, &G, &y, &segment_size); - let _party_one_master_key_recovered = party_two_master_key - .counter_master_key_from_recovered_secret(secret_decrypted_party_one.unwrap()); -} - -#[test] -fn test_recovery_scenarios() { - // key gen - let (party_one_master_key, party_two_master_key) = test_key_gen(); - // backup by party one of his private secret share: (we skip the verifiable part of proof and later verify) - let segment_size = 8; - let y: FE = FE::new_random(); - let G: GE = GE::generator(); - let Y = G * y; - // encryption - let (_, encryptions_secret_party1) = - party_one_master_key - .private - .to_encrypted_segment(&segment_size, 32, &Y, &G); - // encryption - let (_, encryptions_secret_party2) = - party_two_master_key - .private - .to_encrypted_segment(&segment_size, 32, &Y, &G); - - // first case: party one is dead, party two wants to recover the full key. - // In practice party two will recover party_one_master_key and from that point will run both logic parties locally - let secret_decrypted_party_one = - Msegmentation::decrypt(&encryptions_secret_party1, &G, &y, &segment_size); - let _party_one_master_key_recovered = party_two_master_key - .counter_master_key_from_recovered_secret(secret_decrypted_party_one.unwrap()); - - // second case: party two wants to self-recover. public data and chain code of party two are assumed to exist locally or sent from party one - let _secret_decrypted_party_two = - Msegmentation::decrypt(&encryptions_secret_party2, &G, &y, &segment_size); - - // third case: party two is dead, party two wants to recover the full key. - // In practice party one will recover party_two_master_key and from that point will run both logic parties locally - let secret_decrypted_party_two = - Msegmentation::decrypt(&encryptions_secret_party2, &G, &y, &segment_size); - let _party_two_master_key_recovered = party_one_master_key - .counter_master_key_from_recovered_secret(secret_decrypted_party_two.unwrap()); - /* - assert_eq!( - party_two_master_key_recovered.private, - party_two_master_key.private - ); - */ - // fourth case: party one wants ro self-recover. to do so we first generate "half" party one master key from the recovered secret share - // then we run rotation but with coin flip = 1. because our specific rotation includes generating new paillier key with all the zk - proofs. - // the result is that both parties will go through rotation and have a new paillier data in the master keys. we show that signing works the same - let _secret_decrypted_party_one = - Msegmentation::decrypt(&encryptions_secret_party1, &G, &y, &segment_size); - - //test by signing: - let message = BigInt::from(1234i32); - let (sign_party_two_first_message, eph_comm_witness, eph_ec_key_pair_party2) = - MasterKey2::sign_first_message(); - let (sign_party_one_first_message, eph_ec_key_pair_party1) = MasterKey1::sign_first_message(); - let sign_party_two_second_message = party_two_master_key.sign_second_message( - &eph_ec_key_pair_party2, - eph_comm_witness, - &sign_party_one_first_message, - &message, - ); - let sign_party_one_second_message = party_one_master_key.sign_second_message( - &sign_party_two_second_message, - &sign_party_two_first_message, - &eph_ec_key_pair_party1, - &message, - ); - - sign_party_one_second_message.expect("bad signature"); -} - -#[test] -fn test_commutativity_rotate_get_child() { - // key gen - let (party_one_master_key, party_two_master_key) = test_key_gen(); - - // child and rotate: - //test signing: - let message = BigInt::from(1234_i32); - let (sign_party_two_first_message, eph_comm_witness, eph_ec_key_pair_party2) = - MasterKey2::sign_first_message(); - let (sign_party_one_first_message, eph_ec_key_pair_party1) = MasterKey1::sign_first_message(); - let sign_party_two_second_message = party_two_master_key.sign_second_message( - &eph_ec_key_pair_party2, - eph_comm_witness.clone(), - &sign_party_one_first_message, - &message, - ); - let sign_party_one_second_message = party_one_master_key.sign_second_message( - &sign_party_two_second_message, - &sign_party_two_first_message, - &eph_ec_key_pair_party1, - &message, - ); - sign_party_one_second_message.expect("bad signature"); - - let new_party_one_master_key = party_one_master_key.get_child(vec![BigInt::from(10_i32)]); - let new_party_two_master_key = party_two_master_key.get_child(vec![BigInt::from(10_i32)]); - - // sign with child keys - let sign_party_two_second_message = new_party_two_master_key.sign_second_message( - &eph_ec_key_pair_party2, - eph_comm_witness.clone(), - &sign_party_one_first_message, - &message, - ); - let sign_party_one_second_message = new_party_one_master_key.sign_second_message( - &sign_party_two_second_message, - &sign_party_two_first_message, - &eph_ec_key_pair_party1, - &message, - ); - sign_party_one_second_message.expect("bad signature"); - - let (cr_party_one_master_key, cr_party_two_master_key) = - test_rotation(new_party_one_master_key, new_party_two_master_key); - println!("br1"); - - // sign with child and rotated keys - let sign_party_two_second_message = cr_party_two_master_key.sign_second_message( - &eph_ec_key_pair_party2, - eph_comm_witness, - &sign_party_one_first_message, - &message, - ); - let sign_party_one_second_message = cr_party_one_master_key.sign_second_message( - &sign_party_two_second_message, - &sign_party_two_first_message, - &eph_ec_key_pair_party1, - &message, - ); - sign_party_one_second_message.expect("bad signature"); - - // rotate_and_get_child: - println!("br2"); - - let (rotate_party_one_master_key, rotate_party_two_master_key) = - test_rotation(party_one_master_key, party_two_master_key); - println!(" rotate_and_get_child:"); - //get child: - let rc_party_one_master_key = rotate_party_one_master_key.get_child(vec![BigInt::from(10_i32)]); - let rc_party_two_master_key = rotate_party_two_master_key.get_child(vec![BigInt::from(10_i32)]); - - // sign with rotated and child keys - let message = BigInt::from(1234_i32); - let (sign_party_two_first_message, eph_comm_witness, eph_ec_key_pair_party2) = - MasterKey2::sign_first_message(); - let (sign_party_one_first_message, eph_ec_key_pair_party1) = MasterKey1::sign_first_message(); - - let sign_party_two_second_message = rc_party_two_master_key.sign_second_message( - &eph_ec_key_pair_party2, - eph_comm_witness, - &sign_party_one_first_message, - &message, - ); - let sign_party_one_second_message = rc_party_one_master_key.sign_second_message( - &sign_party_two_second_message, - &sign_party_two_first_message, - &eph_ec_key_pair_party1, - &message, - ); - sign_party_one_second_message.expect("bad signature"); - assert_eq!( - rc_party_one_master_key.public.q, - cr_party_one_master_key.public.q - ); -} - #[test] fn test_get_child() { // compute master keys: @@ -322,57 +76,6 @@ fn test_get_child() { sign_party_one_second_message.expect("bad signature"); } -#[test] -fn test_flip_masters() { - // for this test to work party2 MasterKey private need to be changed to pub - // key gen - let (party_one_master_key, party_two_master_key) = test_key_gen(); - - //signing & verifying before rotation: - //test signing: - let message = BigInt::from(1234_i32); - let (sign_party_two_first_message, eph_comm_witness, eph_ec_key_pair_party2) = - MasterKey2::sign_first_message(); - let (sign_party_one_first_message, eph_ec_key_pair_party1) = MasterKey1::sign_first_message(); - let sign_party_two_second_message = party_two_master_key.sign_second_message( - &eph_ec_key_pair_party2, - eph_comm_witness, - &sign_party_one_first_message, - &message, - ); - let sign_party_one_second_message = party_one_master_key.sign_second_message( - &sign_party_two_second_message, - &sign_party_two_first_message, - &eph_ec_key_pair_party1, - &message, - ); - sign_party_one_second_message.expect("bad signature"); - - // rotation - let (party_one_master_key_rotated, party_two_master_key_rotated) = - test_rotation(party_one_master_key, party_two_master_key); - - // sign after rotate: - //test signing: - let message = BigInt::from(1234); - let (sign_party_two_first_message, eph_comm_witness, eph_ec_key_pair_party2) = - MasterKey2::sign_first_message(); - let (sign_party_one_first_message, eph_ec_key_pair_party1) = MasterKey1::sign_first_message(); - let sign_party_two_second_message = party_two_master_key_rotated.sign_second_message( - &eph_ec_key_pair_party2, - eph_comm_witness, - &sign_party_one_first_message, - &message, - ); - let sign_party_one_second_message = party_one_master_key_rotated.sign_second_message( - &sign_party_two_second_message, - &sign_party_two_first_message, - &eph_ec_key_pair_party1, - &message, - ); - sign_party_one_second_message.expect("bad signature"); -} - pub fn test_key_gen() -> (MasterKey1, MasterKey2) { // key gen let (kg_party_one_first_message, kg_comm_witness, kg_ec_key_pair_party1) = @@ -452,127 +155,5 @@ fn compute_hmac(key: &BigInt, input: &str) -> BigInt { BigInt::from(ctx.finalize().into_bytes().as_ref()) } -#[test] -fn test_hd_multipath_derivation() { - - - // compute master keys: - let (party_one_master_key, party_two_master_key) = test_key_gen(); - let pub_key_bi = party_one_master_key.public.q.bytes_compressed_to_big_int(); - - - let new_party_two_master_key = - party_two_master_key.get_child(vec![BigInt::from(10), BigInt::from(5), compute_hmac(&pub_key_bi, "vault"), compute_hmac(&pub_key_bi, "friends"), compute_hmac(&pub_key_bi, "Max")]); - let new_party_one_master_key = - party_one_master_key.get_child(vec![BigInt::from(10), BigInt::from(5)]); - - //make sure that keys are not the same after the multipath derivation run only by one party - assert_ne!( - new_party_one_master_key.public.q, - new_party_two_master_key.public.q - ); - //derive the proper path for the server as the client did - //the path is expected to be in BigInts, so the way we achieve that is hmac(key,input) to a BigInt. Anything like - //a good collision hash function works . We used hmac keyed with the public key as a domain separator. - let new_party_one_master_key = - party_one_master_key.get_child(vec![BigInt::from(10), BigInt::from(5), compute_hmac(&pub_key_bi, "vault"), compute_hmac(&pub_key_bi, "friends"), compute_hmac(&pub_key_bi, "Max")]); - -//make sure that the public keys are equal - assert_eq!( - new_party_one_master_key.public.q, - new_party_two_master_key.public.q - ); - - - //test signing: - let message = BigInt::from(1234); - let (sign_party_two_first_message, eph_comm_witness, eph_ec_key_pair_party2) = - MasterKey2::sign_first_message(); - let (sign_party_one_first_message, eph_ec_key_pair_party1) = MasterKey1::sign_first_message(); - let sign_party_two_second_message = party_two_master_key.sign_second_message( - &eph_ec_key_pair_party2, - eph_comm_witness, - &sign_party_one_first_message, - &message, - ); - let sign_party_one_second_message = party_one_master_key.sign_second_message( - &sign_party_two_second_message, - &sign_party_two_first_message, - &eph_ec_key_pair_party1, - &message, - ); - sign_party_one_second_message.expect("bad signature"); - - // test sign for child - let message = BigInt::from(1234); - let (sign_party_two_first_message, eph_comm_witness, eph_ec_key_pair_party2) = - MasterKey2::sign_first_message(); - let (sign_party_one_first_message, eph_ec_key_pair_party1) = MasterKey1::sign_first_message(); - let sign_party_two_second_message = new_party_two_master_key.sign_second_message( - &eph_ec_key_pair_party2, - eph_comm_witness, - &sign_party_one_first_message, - &message, - ); - let sign_party_one_second_message = new_party_one_master_key.sign_second_message( - &sign_party_two_second_message, - &sign_party_two_first_message, - &eph_ec_key_pair_party1, - &message, - ); - sign_party_one_second_message.expect("bad signature"); -} - -pub fn test_rotation( - party_one_master_key: MasterKey1, - party_two_master_key: MasterKey2, -) -> (MasterKey1, MasterKey2) { - //coin flip:there is a delicate case x1*r to be out of the range proof bounds so extra care is needed - //P1 should check whether x1.r = FE::q().div_floor(&BigInt::from(3))) } - pub fn refresh_private_key( - party_one_private: &Party1Private, - factor: &BigInt, - ) -> ( - EncryptionKey, - BigInt, - Party1Private, - NICorrectKeyProof, - RangeProofNi - ) { - let (ek_new, dk_new) = Paillier::keypair().keys(); - let randomness = Randomness::sample(&ek_new.clone()); - let factor_fe: FE = ECScalar::from(factor); - let x1_new: FE = *&party_one_private.x1 * factor_fe; - let c_key_new = Paillier::encrypt_with_chosen_randomness( - &ek_new.clone(), - RawPlaintext::from(x1_new.to_big_int()), - &randomness, - ) - .0 - .into_owned(); - - let party_one_private_new = Party1Private { - x1: x1_new.clone(), - paillier_priv: dk_new.clone(), - c_key_randomness: randomness.0.clone(), - }; - - let paillier_key_pair = PaillierKeyPair { - ek: ek_new.clone(), - dk: dk_new.clone(), - encrypted_share: c_key_new.clone(), - randomness: randomness.0.clone(), - }; - let correct_key_proof = - PaillierKeyPair::generate_ni_proof_correct_key(&paillier_key_pair); - - let range_proof = party_one::PaillierKeyPair::generate_range_proof( - &paillier_key_pair, - &party_one_private_new, - ); - ( - ek_new.clone(), - c_key_new.clone(), - party_one_private_new, - correct_key_proof, - range_proof - ) - } pub fn set_private_key(ec_key: &EcKeyPair, paillier_key: &PaillierKeyPair) -> Party1Private { let order = FE::q(); let lower_bound: BigInt = order.div_floor(&BigInt::from(3)); From 31f0bc01c2556f133ee240bfde5ec8fbcf8f2644 Mon Sep 17 00:00:00 2001 From: Iraklis Leontiadis <120665504+leontiadZen@users.noreply.github.com> Date: Thu, 4 Jan 2024 13:33:18 +0200 Subject: [PATCH 17/21] align it with integration tests and engine --- src/kms/ecdsa/two_party/party1.rs | 16 ++++++++++++---- src/kms/ecdsa/two_party/party2.rs | 8 +++++++- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/kms/ecdsa/two_party/party1.rs b/src/kms/ecdsa/two_party/party1.rs index d22dd3b..411b1e4 100644 --- a/src/kms/ecdsa/two_party/party1.rs +++ b/src/kms/ecdsa/two_party/party1.rs @@ -23,6 +23,8 @@ pub struct KeyGenParty1Message2 { pub ecdh_second_message: party_one::KeyGenSecondMsg, pub ek: EncryptionKey, pub c_key: BigInt, + pub old_ek: EncryptionKey, + pub old_c_key: BigInt, pub correct_key_proof: NICorrectKeyProof, pub range_proof: RangeProofNi, } @@ -140,6 +142,11 @@ impl MasterKey1 { let party_one_private = party_one::Party1Private::set_private_key(ec_key_pair_party1, &paillier_key_pair); + let party_two_paillier = party_two::PaillierPublic { + ek: paillier_key_pair.ek.clone(), + encrypted_secret_share: paillier_key_pair.encrypted_share_minus_q_thirds.clone(), + }; + let range_proof = party_one::PaillierKeyPair::generate_range_proof( &paillier_key_pair, &party_one_private, @@ -149,12 +156,14 @@ impl MasterKey1 { ( KeyGenParty1Message2 { ecdh_second_message: key_gen_second_message, - ek: paillier_key_pair.ek.clone(), - c_key: paillier_key_pair.encrypted_share.clone(), + ek: party_two_paillier.ek.clone(), + c_key: party_two_paillier.encrypted_secret_share.clone(), + old_ek: paillier_key_pair.ek.clone(), + old_c_key: paillier_key_pair.encrypted_share.clone(), correct_key_proof, range_proof, }, - paillier_key_pair, + paillier_key_pair.clone(), party_one_private, ) } @@ -239,5 +248,4 @@ impl MasterKey1 { alpha, ) } - } diff --git a/src/kms/ecdsa/two_party/party2.rs b/src/kms/ecdsa/two_party/party2.rs index 329e184..fe49654 100644 --- a/src/kms/ecdsa/two_party/party2.rs +++ b/src/kms/ecdsa/two_party/party2.rs @@ -154,6 +154,12 @@ impl MasterKey2 { .correct_key_proof .verify(&party_two_paillier.ek); + //restore paillier old public key and ciphertext + let party_two_paillier_old = party_two::PaillierPublic { + ek: party_one_second_message.old_ek.clone(), + encrypted_secret_share: party_one_second_message.old_c_key.clone(), + }; + match range_proof_verify { Ok(_proof) => match correct_key_verify { Ok(_proof) => match party_two_second_message { @@ -162,7 +168,7 @@ impl MasterKey2 { key_gen_second_message: t, pdl_first_message, }, - party_two_paillier, + party_two_paillier_old, pdl_chal, )), Err(_verify_com_and_dlog_party_one) => Err(()), From b627997eafa6b12f69820ea23f3b7fdd62623be7 Mon Sep 17 00:00:00 2001 From: Iraklis Leontiadis <120665504+leontiadZen@users.noreply.github.com> Date: Mon, 22 Jan 2024 15:08:54 +0200 Subject: [PATCH 18/21] correct-pdl --- src/party_one.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/party_one.rs b/src/party_one.rs index 76e2e31..804170a 100644 --- a/src/party_one.rs +++ b/src/party_one.rs @@ -569,7 +569,7 @@ impl PaillierKeyPair { let ab_concat = a.clone() + b.clone().shl(a.bit_length()); let c_tag_tag_test = HashCommitment::create_commitment_with_user_defined_randomness(&ab_concat, &blindness); - let ax1 = a * party_one_private.x1.to_big_int(); + let ax1 = a * party_one_private.x1_minus_q_thirds.to_big_int(); let alpha_test = ax1 + b; if alpha_test == alpha && pdl_party_two_first_message.c_tag_tag.clone() == c_tag_tag_test { Ok(PDLSecondMessage { From a5ed1cea75149a3de768f750037c1a8c05d04059 Mon Sep 17 00:00:00 2001 From: Iraklis Leontiadis <120665504+leontiadZen@users.noreply.github.com> Date: Mon, 22 Jan 2024 18:17:51 +0200 Subject: [PATCH 19/21] fix --- src/kms/ecdsa/two_party/party1.rs | 2 +- src/kms/ecdsa/two_party/party2.rs | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/kms/ecdsa/two_party/party1.rs b/src/kms/ecdsa/two_party/party1.rs index 411b1e4..e6baf59 100644 --- a/src/kms/ecdsa/two_party/party1.rs +++ b/src/kms/ecdsa/two_party/party1.rs @@ -144,7 +144,7 @@ impl MasterKey1 { let party_two_paillier = party_two::PaillierPublic { ek: paillier_key_pair.ek.clone(), - encrypted_secret_share: paillier_key_pair.encrypted_share_minus_q_thirds.clone(), + encrypted_secret_share: paillier_key_pair.encrypted_share.clone(), }; let range_proof = party_one::PaillierKeyPair::generate_range_proof( diff --git a/src/kms/ecdsa/two_party/party2.rs b/src/kms/ecdsa/two_party/party2.rs index fe49654..89301c1 100644 --- a/src/kms/ecdsa/two_party/party2.rs +++ b/src/kms/ecdsa/two_party/party2.rs @@ -143,12 +143,6 @@ impl MasterKey2 { &party_one_second_message.range_proof, ); - let (pdl_first_message, pdl_chal) = party_two_paillier.pdl_challenge( - &party_one_second_message - .ecdh_second_message - .comm_witness - .public_share, - ); let correct_key_verify = party_one_second_message .correct_key_proof @@ -160,6 +154,13 @@ impl MasterKey2 { encrypted_secret_share: party_one_second_message.old_c_key.clone(), }; + let (pdl_first_message, pdl_chal) = party_two_paillier_old.pdl_challenge( + &party_one_second_message + .ecdh_second_message + .comm_witness + .public_share, + ); + match range_proof_verify { Ok(_proof) => match correct_key_verify { Ok(_proof) => match party_two_second_message { From bfdba3ea37ab9cbde482240f8cf405022f8ba627 Mon Sep 17 00:00:00 2001 From: Iraklis Leontiadis <120665504+leontiadZen@users.noreply.github.com> Date: Mon, 22 Jan 2024 18:25:30 +0200 Subject: [PATCH 20/21] fix --- src/kms/ecdsa/two_party/party1.rs | 2 +- src/party_one.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/kms/ecdsa/two_party/party1.rs b/src/kms/ecdsa/two_party/party1.rs index e6baf59..411b1e4 100644 --- a/src/kms/ecdsa/two_party/party1.rs +++ b/src/kms/ecdsa/two_party/party1.rs @@ -144,7 +144,7 @@ impl MasterKey1 { let party_two_paillier = party_two::PaillierPublic { ek: paillier_key_pair.ek.clone(), - encrypted_secret_share: paillier_key_pair.encrypted_share.clone(), + encrypted_secret_share: paillier_key_pair.encrypted_share_minus_q_thirds.clone(), }; let range_proof = party_one::PaillierKeyPair::generate_range_proof( diff --git a/src/party_one.rs b/src/party_one.rs index 804170a..76e2e31 100644 --- a/src/party_one.rs +++ b/src/party_one.rs @@ -569,7 +569,7 @@ impl PaillierKeyPair { let ab_concat = a.clone() + b.clone().shl(a.bit_length()); let c_tag_tag_test = HashCommitment::create_commitment_with_user_defined_randomness(&ab_concat, &blindness); - let ax1 = a * party_one_private.x1_minus_q_thirds.to_big_int(); + let ax1 = a * party_one_private.x1.to_big_int(); let alpha_test = ax1 + b; if alpha_test == alpha && pdl_party_two_first_message.c_tag_tag.clone() == c_tag_tag_test { Ok(PDLSecondMessage { From 7863d43e92e3216a93761db094a745dedf950a40 Mon Sep 17 00:00:00 2001 From: Max Leibovich <138369969+max-zengo@users.noreply.github.com> Date: Thu, 25 Jan 2024 10:39:15 +0200 Subject: [PATCH 21/21] add Option to new fields --- src/kms/ecdsa/two_party/party1.rs | 2 +- src/party_one.rs | 23 +++++++++++++---------- src/test.rs | 2 +- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/kms/ecdsa/two_party/party1.rs b/src/kms/ecdsa/two_party/party1.rs index 411b1e4..4c81b90 100644 --- a/src/kms/ecdsa/two_party/party1.rs +++ b/src/kms/ecdsa/two_party/party1.rs @@ -144,7 +144,7 @@ impl MasterKey1 { let party_two_paillier = party_two::PaillierPublic { ek: paillier_key_pair.ek.clone(), - encrypted_secret_share: paillier_key_pair.encrypted_share_minus_q_thirds.clone(), + encrypted_secret_share: paillier_key_pair.encrypted_share_minus_q_thirds.clone().expect(""), }; let range_proof = party_one::PaillierKeyPair::generate_range_proof( diff --git a/src/party_one.rs b/src/party_one.rs index 76e2e31..246e205 100644 --- a/src/party_one.rs +++ b/src/party_one.rs @@ -255,9 +255,9 @@ pub struct PaillierKeyPair { pub ek: EncryptionKey, dk: DecryptionKey, pub encrypted_share: BigInt, - pub encrypted_share_minus_q_thirds: BigInt, + pub encrypted_share_minus_q_thirds: Option, randomness: BigInt, - randomness_q: BigInt, + randomness_q: Option, } #[derive(Debug, Serialize, Deserialize)] @@ -276,7 +276,7 @@ pub struct Signature { #[derive(Serialize, Debug, Deserialize, Clone)] pub struct Party1Private { x1: FE, - x1_minus_q_thirds: FE, + x1_minus_q_thirds: Option, paillier_priv: DecryptionKey, c_key_randomness: BigInt, } @@ -437,7 +437,7 @@ impl Party1Private { let factor_fe: FE = ECScalar::from(factor); let x1_new: FE = factor_fe * party_one_private.x1; - (x1_new.to_big_int() >= FE::q().div_floor(&BigInt::from(3))) + x1_new.to_big_int() >= FE::q().div_floor(&BigInt::from(3)) } pub fn set_private_key(ec_key: &EcKeyPair, paillier_key: &PaillierKeyPair) -> Party1Private { @@ -452,7 +452,7 @@ impl Party1Private { let x1_minus_lower_bound_fe: FE = ECScalar::from(&x1_minus_lower_bound); Party1Private { x1: ec_key.secret_share, - x1_minus_q_thirds: x1_minus_lower_bound_fe, + x1_minus_q_thirds: Some(x1_minus_lower_bound_fe), paillier_priv: paillier_key.dk.clone(), c_key_randomness: paillier_key.randomness.clone(), } @@ -508,9 +508,9 @@ impl PaillierKeyPair { ek, dk, encrypted_share, - encrypted_share_minus_q_thirds, + encrypted_share_minus_q_thirds: Some(encrypted_share_minus_q_thirds), randomness: randomness.0, - randomness_q: randomness_q.0, + randomness_q: Some(randomness_q.0), } } @@ -518,12 +518,15 @@ impl PaillierKeyPair { paillier_context: &PaillierKeyPair, party_one_private: &Party1Private, ) -> RangeProofNi { + let x1_minus_q_thirds = party_one_private.x1_minus_q_thirds.as_ref().expect("x1_minus_q_thirds").to_big_int(); + let encrypted_share_minus_q_thirds = paillier_context.encrypted_share_minus_q_thirds.as_ref().expect("encrypted_share_minus_q_thirds").clone(); + let randomness_q = paillier_context.randomness_q.as_ref().expect("randomness_q"); RangeProofNi::prove( &paillier_context.ek, &FE::q(), - &paillier_context.encrypted_share_minus_q_thirds.clone(), - &party_one_private.x1_minus_q_thirds.to_big_int(), - &paillier_context.randomness_q, + &encrypted_share_minus_q_thirds, + &x1_minus_q_thirds, + randomness_q, ) } diff --git a/src/test.rs b/src/test.rs index 428d24d..c84dea4 100644 --- a/src/test.rs +++ b/src/test.rs @@ -60,7 +60,7 @@ mod tests { let party_two_paillier = party_two::PaillierPublic { ek: paillier_key_pair.ek.clone(), - encrypted_secret_share: paillier_key_pair.encrypted_share_minus_q_thirds.clone(), + encrypted_secret_share: paillier_key_pair.encrypted_share_minus_q_thirds.clone().expect(""), }; // zk proof of correct paillier key