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/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/party1.rs b/src/kms/ecdsa/two_party/party1.rs index 4819b0e..4c81b90 100644 --- a/src/kms/ecdsa/two_party/party1.rs +++ b/src/kms/ecdsa/two_party/party1.rs @@ -15,17 +15,50 @@ 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 { 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, +} + +#[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); @@ -109,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().expect(""), + }; + let range_proof = party_one::PaillierKeyPair::generate_range_proof( &paillier_key_pair, &party_one_private, @@ -118,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, ) } diff --git a/src/kms/ecdsa/two_party/party2.rs b/src/kms/ecdsa/two_party/party2.rs index a095454..89301c1 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); @@ -121,17 +143,24 @@ impl MasterKey2 { &party_one_second_message.range_proof, ); - let (pdl_first_message, pdl_chal) = party_two_paillier.pdl_challenge( + + let correct_key_verify = party_one_second_message + .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(), + }; + + let (pdl_first_message, pdl_chal) = party_two_paillier_old.pdl_challenge( &party_one_second_message .ecdh_second_message .comm_witness .public_share, ); - let correct_key_verify = party_one_second_message - .correct_key_proof - .verify(&party_two_paillier.ek); - match range_proof_verify { Ok(_proof) => match correct_key_verify { Ok(_proof) => match party_two_second_message { @@ -140,7 +169,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(()), @@ -187,7 +216,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 +231,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 78634b7..097dc73 100644 --- a/src/kms/ecdsa/two_party/test.rs +++ b/src/kms/ecdsa/two_party/test.rs @@ -11,247 +11,18 @@ */ #![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}; - -#[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) = - (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( - &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: - - let (rotate_party_one_master_key, rotate_party_two_master_key) = - (party_one_master_key, party_two_master_key); - - //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 - ); -} - +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_get_child() { // compute master keys: @@ -305,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) = - (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) = @@ -422,3 +142,18 @@ 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()) +} + + + 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..d61d024 --- /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, Clone)] +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 773bd00..246e205 100644 --- a/src/party_one.rs +++ b/src/party_one.rs @@ -18,11 +18,11 @@ 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::Shl; +use std::ops::{Mul, 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}; @@ -254,7 +255,9 @@ pub struct PaillierKeyPair { pub ek: EncryptionKey, dk: DecryptionKey, pub encrypted_share: BigInt, + pub encrypted_share_minus_q_thirds: Option, randomness: BigInt, + randomness_q: Option, } #[derive(Debug, Serialize, Deserialize)] @@ -273,6 +276,7 @@ pub struct Signature { #[derive(Serialize, Debug, Deserialize, Clone)] pub struct Party1Private { x1: FE, + x1_minus_q_thirds: Option, paillier_priv: DecryptionKey, c_key_randomness: BigInt, } @@ -314,13 +318,21 @@ 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 = lower_bound.clone().mul(&BigInt::from(2)); + (lower_bound, upper_bound) + } + + 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 = ECScalar::new_random(); - //in Lindell's protocol range proof works only for x1 (KeyGenFirstMsg, CommWitness, EcKeyPair) { - //in Lindell's protocol range proof works only for x1 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 set_private_key(ec_key: &EcKeyPair, paillier_key: &PaillierKeyPair) -> Party1Private { + 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( + &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: ec_key.secret_share, + x1_minus_q_thirds: Some(x1_minus_lower_bound_fe), paillier_priv: paillier_key.dk.clone(), c_key_randomness: paillier_key.randomness.clone(), } @@ -442,8 +473,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()), @@ -452,11 +493,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: Some(encrypted_share_minus_q_thirds), randomness: randomness.0, + randomness_q: Some(randomness_q.0), } } @@ -464,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.clone(), - &party_one_private.x1.to_big_int(), - &paillier_context.randomness, + &encrypted_share_minus_q_thirds, + &x1_minus_q_thirds, + randomness_q, ) } diff --git a/src/test.rs b/src/test.rs index b753d30..c84dea4 100644 --- a/src/test.rs +++ b/src/test.rs @@ -2,12 +2,10 @@ #[cfg(test)] mod tests { - - use crate::curv::arithmetic::traits::Samplable; use crate::curv::elliptic::curves::traits::*; use crate::curv::BigInt; + use crate::party_one::Party1Private; use crate::*; - #[test] fn test_d_log_proof_party_two_party_one() { let (party_one_first_message, comm_witness, _ec_key_pair_party1) = @@ -30,9 +28,11 @@ mod tests { #[test] fn test_full_key_gen() { + 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( - &BigInt::sample(253), + &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( @@ -56,13 +56,14 @@ mod tests { party_one::PaillierKeyPair::generate_keypair_and_encrypted_share(&ec_key_pair_party1); 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 { 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().expect(""), }; + // zk proof of correct paillier key let correct_key_proof = party_one::PaillierKeyPair::generate_ni_proof_correct_key(&paillier_key_pair); @@ -70,8 +71,6 @@ mod tests { .verify(&party_two_paillier.ek) .expect("bad paillier key"); - // zk proof of correct paillier key - // zk range proof let range_proof = party_one::PaillierKeyPair::generate_range_proof( &paillier_key_pair, diff --git a/src/zk_paillier/zkproofs/range_proof.rs b/src/zk_paillier/zkproofs/range_proof.rs index 5ef4860..5d16db2 100644 --- a/src/zk_paillier/zkproofs/range_proof.rs +++ b/src/zk_paillier/zkproofs/range_proof.rs @@ -287,6 +287,7 @@ impl RangeProofTrait for RangeProof { } let mut flag = false; + if w1 < &range_scaled_third && w2 > &range_scaled_third && w2 < &range_scaled_two_thirds @@ -370,7 +371,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); @@ -418,7 +419,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);