diff --git a/Cargo.toml b/Cargo.toml index 292a34b..c864c40 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,10 +13,11 @@ sha3 = "0.10" sha2 = "0.10" hmac = "0.12" rayon = "1" -serde = "1" -serde_derive = "1.0" +serde = { version = "1.0.147", features = ["derive"] } +#serde_derive = "1.0" itertools = "0.10" bit-vec = "0.6" +typetag = "0.2.3" [dependencies.rust-gmp] version = "0.5.0" diff --git a/src/bulletproofs/proofs/inner_product.rs b/src/bulletproofs/proofs/inner_product.rs index 5689504..70f63e1 100644 --- a/src/bulletproofs/proofs/inner_product.rs +++ b/src/bulletproofs/proofs/inner_product.rs @@ -22,6 +22,7 @@ use crate::curv::cryptographic_primitives::hashing::traits::*; use crate::curv::elliptic::curves::traits::*; use crate::curv::BigInt; use crate::curv::{FE, GE}; +use serde::{Serialize,Deserialize}; use crate::bulletproofs::Errors::{self, InnerProductError}; diff --git a/src/bulletproofs/proofs/range_proof.rs b/src/bulletproofs/proofs/range_proof.rs index 23c7322..3ec0251 100644 --- a/src/bulletproofs/proofs/range_proof.rs +++ b/src/bulletproofs/proofs/range_proof.rs @@ -26,6 +26,8 @@ use crate::curv::BigInt; use crate::curv::{FE, GE}; use itertools::iterate; use std::ops::{Shl, Shr}; +use serde::{Serialize,Deserialize}; + #[derive(Debug, Serialize, Deserialize)] pub struct RangeProof { diff --git a/src/centipede/juggling/proof_system.rs b/src/centipede/juggling/proof_system.rs index 81453b5..10363d4 100644 --- a/src/centipede/juggling/proof_system.rs +++ b/src/centipede/juggling/proof_system.rs @@ -24,6 +24,7 @@ use crate::curv::arithmetic::traits::Converter; use crate::bulletproofs::proofs::range_proof::{RangeProof,generate_random_point}; use super::segmentation::Msegmentation; use crate::centipede::Errors::{self, ErrorProving}; +use serde::{Serialize,Deserialize}; #[derive(Serialize, Deserialize)] pub struct Helgamal { diff --git a/src/curv/arithmetic/big_gmp.rs b/src/curv/arithmetic/big_gmp.rs index 7decd15..b7b0905 100644 --- a/src/curv/arithmetic/big_gmp.rs +++ b/src/curv/arithmetic/big_gmp.rs @@ -21,7 +21,6 @@ use super::traits::{ }; use gmp::mpz::Mpz; use rand::RngCore; - use std::borrow::Borrow; pub type BigInt = Mpz; diff --git a/src/curv/cryptographic_primitives/proofs/sigma_correct_homomorphic_elgamal_enc.rs b/src/curv/cryptographic_primitives/proofs/sigma_correct_homomorphic_elgamal_enc.rs index d8a21ad..5187def 100644 --- a/src/curv/cryptographic_primitives/proofs/sigma_correct_homomorphic_elgamal_enc.rs +++ b/src/curv/cryptographic_primitives/proofs/sigma_correct_homomorphic_elgamal_enc.rs @@ -13,6 +13,7 @@ use crate::curv::elliptic::curves::traits::*; use crate::curv::FE; use crate::curv::GE; use zeroize::Zeroize; +use serde::{Serialize,Deserialize}; /// This is a proof of knowledge that a pair of group elements {D, E} /// form a valid homomorphic ElGamal encryption (”in the exponent”) using public key Y . diff --git a/src/curv/cryptographic_primitives/proofs/sigma_correct_homomorphic_elgamal_encryption_of_dlog.rs b/src/curv/cryptographic_primitives/proofs/sigma_correct_homomorphic_elgamal_encryption_of_dlog.rs index fd07114..8f085da 100644 --- a/src/curv/cryptographic_primitives/proofs/sigma_correct_homomorphic_elgamal_encryption_of_dlog.rs +++ b/src/curv/cryptographic_primitives/proofs/sigma_correct_homomorphic_elgamal_encryption_of_dlog.rs @@ -13,6 +13,7 @@ use crate::curv::elliptic::curves::traits::*; use crate::curv::FE; use crate::curv::GE; use zeroize::Zeroize; +use serde::{Serialize,Deserialize}; /// This is a proof of knowledge that a pair of group elements {D, E} /// form a valid homomorphic ElGamal encryption (”in the exponent”) using public key Y . diff --git a/src/curv/cryptographic_primitives/proofs/sigma_dlog.rs b/src/curv/cryptographic_primitives/proofs/sigma_dlog.rs index 8640973..36eaa4b 100644 --- a/src/curv/cryptographic_primitives/proofs/sigma_dlog.rs +++ b/src/curv/cryptographic_primitives/proofs/sigma_dlog.rs @@ -5,6 +5,8 @@ License MIT: https://github.com/KZen-networks/curv/blob/master/LICENSE */ +use std::any::Any; +use std::fmt::{Display, Formatter}; use super::ProofError; use crate::curv::FE; use crate::curv::GE; @@ -14,6 +16,8 @@ use crate::curv::elliptic::curves::traits::*; use crate::curv::cryptographic_primitives::hashing::hash_sha256::HSha256; use crate::curv::cryptographic_primitives::hashing::traits::Hash; use zeroize::Zeroize; +use crate::party_one::{Value}; +use serde::{Serialize,Deserialize}; /// This is implementation of Schnorr's identification protocol for elliptic curve groups or a /// sigma protocol for Proof of knowledge of the discrete log of an Elliptic-curve point: @@ -31,6 +35,19 @@ pub struct DLogProof { pub pk_t_rand_commitment: GE, pub challenge_response: FE, } +#[typetag::serde] +impl Value for DLogProof { + fn as_any(&self) -> &dyn Any { + self + } +} + +impl Display for DLogProof { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self) + } +} + pub trait ProveDLog { fn prove(sk: &FE) -> DLogProof; diff --git a/src/curv/cryptographic_primitives/proofs/sigma_ec_ddh.rs b/src/curv/cryptographic_primitives/proofs/sigma_ec_ddh.rs index 0606059..4cc7239 100644 --- a/src/curv/cryptographic_primitives/proofs/sigma_ec_ddh.rs +++ b/src/curv/cryptographic_primitives/proofs/sigma_ec_ddh.rs @@ -11,6 +11,7 @@ use crate::curv::cryptographic_primitives::hashing::traits::Hash; use crate::curv::elliptic::curves::traits::*; use crate::curv::{FE, GE}; use zeroize::Zeroize; +use serde::{Serialize,Deserialize}; /// This protocol is the elliptic curve form of the protocol from : /// D. Chaum, T. P. Pedersen. Transferred cash grows in size. In Advances in Cryptology, EUROCRYPT , volume 658 of Lecture Notes in Computer Science, pages 390 - 407, 1993. diff --git a/src/curv/cryptographic_primitives/proofs/sigma_valid_pedersen.rs b/src/curv/cryptographic_primitives/proofs/sigma_valid_pedersen.rs index e260906..1beb850 100644 --- a/src/curv/cryptographic_primitives/proofs/sigma_valid_pedersen.rs +++ b/src/curv/cryptographic_primitives/proofs/sigma_valid_pedersen.rs @@ -13,6 +13,7 @@ use crate::curv::cryptographic_primitives::hashing::traits::Hash; use crate::curv::elliptic::curves::traits::*; use crate::curv::{FE, GE}; use zeroize::Zeroize; +use serde::{Serialize,Deserialize}; /// protocol for proving that Pedersen commitment c was constructed correctly which is the same as /// proof of knowledge of (m,r) such that c = mG + rH. diff --git a/src/curv/cryptographic_primitives/proofs/sigma_valid_pedersen_blind.rs b/src/curv/cryptographic_primitives/proofs/sigma_valid_pedersen_blind.rs index 9d8b2c9..f598313 100644 --- a/src/curv/cryptographic_primitives/proofs/sigma_valid_pedersen_blind.rs +++ b/src/curv/cryptographic_primitives/proofs/sigma_valid_pedersen_blind.rs @@ -14,6 +14,7 @@ use crate::curv::elliptic::curves::traits::*; use crate::curv::{FE, GE}; use zeroize::Zeroize; +use serde::{Serialize,Deserialize}; /// protocol for proving that Pedersen commitment c was constructed correctly which is the same as /// proof of knowledge of (r) such that c = mG + rH. diff --git a/src/curv/cryptographic_primitives/twoparty/coin_flip_optimal_rounds.rs b/src/curv/cryptographic_primitives/twoparty/coin_flip_optimal_rounds.rs index 4029f63..9715573 100644 --- a/src/curv/cryptographic_primitives/twoparty/coin_flip_optimal_rounds.rs +++ b/src/curv/cryptographic_primitives/twoparty/coin_flip_optimal_rounds.rs @@ -11,6 +11,7 @@ use crate::curv::cryptographic_primitives::proofs::sigma_valid_pedersen_blind::P use crate::curv::cryptographic_primitives::proofs::sigma_valid_pedersen_blind::ProvePederesenBlind; use crate::curv::elliptic::curves::traits::*; use crate::curv::{FE, GE}; +use serde::{Serialize,Deserialize}; /// based on How To Simulate It – A Tutorial on the Simulation /// Proof Technique. protocol 7.3: Multiple coin tossing. which provide simulatble constant round diff --git a/src/curv/cryptographic_primitives/twoparty/dh_key_exchange.rs b/src/curv/cryptographic_primitives/twoparty/dh_key_exchange.rs index 14679e1..85d26d1 100644 --- a/src/curv/cryptographic_primitives/twoparty/dh_key_exchange.rs +++ b/src/curv/cryptographic_primitives/twoparty/dh_key_exchange.rs @@ -12,6 +12,7 @@ use crate::curv::elliptic::curves::traits::*; use crate::curv::FE; use crate::curv::GE; +use serde::{Serialize,Deserialize}; #[derive(Clone, Debug, Serialize, Deserialize)] pub struct EcKeyPair { diff --git a/src/curv/cryptographic_primitives/twoparty/dh_key_exchange_variant_with_pok_comm.rs b/src/curv/cryptographic_primitives/twoparty/dh_key_exchange_variant_with_pok_comm.rs index 55a565a..1161ece 100644 --- a/src/curv/cryptographic_primitives/twoparty/dh_key_exchange_variant_with_pok_comm.rs +++ b/src/curv/cryptographic_primitives/twoparty/dh_key_exchange_variant_with_pok_comm.rs @@ -5,6 +5,8 @@ License MIT: */ +use std::any::Any; +use std::fmt::{Display, Formatter}; /// in ECDH Alice chooses at random a secret "a" and sends Bob public key A = aG /// Bob chooses at random a secret "b" and sends to Alice B = bG. /// Both parties can compute a joint secret: C =aB = bA = abG which cannot be computed by @@ -22,22 +24,66 @@ use crate::curv::elliptic::curves::traits::*; use crate::curv::BigInt; use crate::curv::FE; use crate::curv::GE; +use serde::{Serialize,Deserialize}; +use crate::party_one::Value; +use crate::party_two::PDLFirstMessage; const SECURITY_BITS: usize = 256; + +#[typetag::serde] +impl Value for EcKeyPairDHPoK { + fn as_any(&self) -> &dyn Any { + self + } +} + +impl Display for EcKeyPairDHPoK { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self) + } +} + #[derive(Clone, Debug, Serialize, Deserialize)] -pub struct EcKeyPair { +pub struct EcKeyPairDHPoK { pub public_share: GE, secret_share: FE, } #[derive(Clone, Debug, Serialize, Deserialize)] -pub struct CommWitness { +pub struct CommWitnessDHPoK { pub pk_commitment_blind_factor: BigInt, pub zk_pok_blind_factor: BigInt, pub public_share: GE, pub d_log_proof: DLogProof, } + +#[typetag::serde] +impl Value for CommWitnessDHPoK { + fn as_any(&self) -> &dyn Any { + self + } +} + +impl Display for CommWitnessDHPoK { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self) + } +} + +#[typetag::serde] +impl Value for Party1FirstMessage { + fn as_any(&self) -> &dyn Any { + self + } +} + +impl Display for Party1FirstMessage { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self) + } +} + #[derive(Clone, Debug, Serialize, Deserialize)] pub struct Party1FirstMessage { pub pk_commitment: BigInt, @@ -51,14 +97,14 @@ pub struct Party2FirstMessage { #[derive(Debug, Serialize, Deserialize)] pub struct Party1SecondMessage { - pub comm_witness: CommWitness, + pub comm_witness: CommWitnessDHPoK, } #[derive(Debug, Serialize, Deserialize)] pub struct Party2SecondMessage {} impl Party1FirstMessage { - pub fn create_commitments() -> (Party1FirstMessage, CommWitness, EcKeyPair) { + pub fn create_commitments() -> (Party1FirstMessage, CommWitnessDHPoK, EcKeyPairDHPoK) { let base: GE = ECPoint::generator(); let secret_share: FE = ECScalar::new_random(); @@ -80,7 +126,7 @@ impl Party1FirstMessage { .bytes_compressed_to_big_int(), &zk_pok_blind_factor, ); - let ec_key_pair = EcKeyPair { + let ec_key_pair = EcKeyPairDHPoK { public_share, secret_share, }; @@ -89,7 +135,7 @@ impl Party1FirstMessage { pk_commitment, zk_pok_commitment, }, - CommWitness { + CommWitnessDHPoK { pk_commitment_blind_factor, zk_pok_blind_factor, public_share: ec_key_pair.public_share, @@ -101,7 +147,7 @@ impl Party1FirstMessage { pub fn create_commitments_with_fixed_secret_share( secret_share: FE, - ) -> (Party1FirstMessage, CommWitness, EcKeyPair) { + ) -> (Party1FirstMessage, CommWitnessDHPoK, EcKeyPairDHPoK) { let base: GE = ECPoint::generator(); let public_share = base * secret_share; @@ -121,7 +167,7 @@ impl Party1FirstMessage { &zk_pok_blind_factor, ); - let ec_key_pair = EcKeyPair { + let ec_key_pair = EcKeyPairDHPoK { public_share, secret_share, }; @@ -130,7 +176,7 @@ impl Party1FirstMessage { pk_commitment, zk_pok_commitment, }, - CommWitness { + CommWitnessDHPoK { pk_commitment_blind_factor, zk_pok_blind_factor, public_share: ec_key_pair.public_share, @@ -143,7 +189,7 @@ impl Party1FirstMessage { impl Party1SecondMessage { pub fn verify_and_decommit( - comm_witness: CommWitness, + comm_witness: CommWitnessDHPoK, proof: &DLogProof, ) -> Result { DLogProof::verify(proof)?; @@ -151,12 +197,12 @@ impl Party1SecondMessage { } } impl Party2FirstMessage { - pub fn create() -> (Party2FirstMessage, EcKeyPair) { + pub fn create() -> (Party2FirstMessage, EcKeyPairDHPoK) { let base: GE = ECPoint::generator(); let secret_share: FE = ECScalar::new_random(); let public_share = base * secret_share; let d_log_proof = DLogProof::prove(&secret_share); - let ec_key_pair = EcKeyPair { + let ec_key_pair = EcKeyPairDHPoK { public_share, secret_share, }; @@ -169,11 +215,11 @@ impl Party2FirstMessage { ) } - pub fn create_with_fixed_secret_share(secret_share: FE) -> (Party2FirstMessage, EcKeyPair) { + pub fn create_with_fixed_secret_share(secret_share: FE) -> (Party2FirstMessage, EcKeyPairDHPoK) { let base: GE = ECPoint::generator(); let public_share = base * secret_share; let d_log_proof = DLogProof::prove(&secret_share); - let ec_key_pair = EcKeyPair { + let ec_key_pair = EcKeyPairDHPoK { public_share, secret_share, }; @@ -228,7 +274,7 @@ impl Party2SecondMessage { Ok(Party2SecondMessage {}) } } -pub fn compute_pubkey(local_share: &EcKeyPair, other_share_public_share: &GE) -> GE { +pub fn compute_pubkey(local_share: &EcKeyPairDHPoK, other_share_public_share: &GE) -> GE { other_share_public_share * &local_share.secret_share } diff --git a/src/curv/elliptic/curves/secp256_k1.rs b/src/curv/elliptic/curves/secp256_k1.rs index c4bd3f3..beeefbe 100644 --- a/src/curv/elliptic/curves/secp256_k1.rs +++ b/src/curv/elliptic/curves/secp256_k1.rs @@ -16,6 +16,7 @@ // The Public Key codec: Point <> SecretKey // +use std::any::Any; use super::traits::{ECPoint, ECScalar}; use crate::curv::arithmetic::traits::{Converter, Modulo}; use crate::curv::cryptographic_primitives::hashing::hash_sha256::HSha256; @@ -33,10 +34,12 @@ use serde::ser::SerializeStruct; use serde::ser::{Serialize, Serializer}; use serde::{Deserialize, Deserializer}; use std::fmt; +use std::fmt::{Display, Formatter}; use std::ops::{Add, Mul}; use std::ptr; use std::sync::atomic; use zeroize::Zeroize; +use crate::party_one::{Value}; pub type SK = SecretKey; pub type PK = PublicKey; @@ -46,11 +49,26 @@ pub struct Secp256k1Scalar { purpose: &'static str, fe: SK, } + #[derive(Clone, Debug, Copy)] pub struct Secp256k1Point { purpose: &'static str, ge: PK, } + +#[typetag::serde] +impl Value for Secp256k1Point { + fn as_any(&self) -> &dyn Any { + self + } +} + +impl Display for Secp256k1Point { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self) + } +} + pub type GE = Secp256k1Point; pub type FE = Secp256k1Scalar; @@ -193,6 +211,7 @@ impl ECScalar for Secp256k1Scalar { ECScalar::from(&bn_inv) } } + impl Mul for Secp256k1Scalar { type Output = Secp256k1Scalar; fn mul(self, other: Secp256k1Scalar) -> Secp256k1Scalar { @@ -223,8 +242,8 @@ impl<'o> Add<&'o Secp256k1Scalar> for Secp256k1Scalar { impl Serialize for Secp256k1Scalar { fn serialize(&self, serializer: S) -> Result - where - S: Serializer, + where + S: Serializer, { serializer.serialize_str(&self.to_big_int().to_hex()) } @@ -232,8 +251,8 @@ impl Serialize for Secp256k1Scalar { impl<'de> Deserialize<'de> for Secp256k1Scalar { fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, + where + D: Deserializer<'de>, { deserializer.deserialize_str(Secp256k1ScalarVisitor) } @@ -502,8 +521,8 @@ impl<'o> Add<&'o Secp256k1Point> for &'o Secp256k1Point { impl Serialize for Secp256k1Point { fn serialize(&self, serializer: S) -> Result - where - S: Serializer, + where + S: Serializer, { let mut state = serializer.serialize_struct("Secp256k1Point", 2)?; state.serialize_field("x", &self.x_coor().unwrap().to_hex())?; @@ -514,8 +533,8 @@ impl Serialize for Secp256k1Point { impl<'de> Deserialize<'de> for Secp256k1Point { fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, + where + D: Deserializer<'de>, { let fields = &["x", "y"]; deserializer.deserialize_struct("Secp256k1Point", fields, Secp256k1PointVisitor) @@ -552,6 +571,7 @@ impl<'de> Visitor<'de> for Secp256k1PointVisitor { Ok(Secp256k1Point::from_coor(&bx, &by)) } } + #[cfg(test)] mod tests { use super::BigInt; @@ -672,6 +692,7 @@ mod tests { let ground_truth = Secp256k1Point::base_point2(); assert_eq!(result.unwrap(), ground_truth); } + #[test] fn test_from_bytes_3() { let test_vec = [ 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/chain_code/mod.rs b/src/kms/chain_code/mod.rs new file mode 100644 index 0000000..988e1b3 --- /dev/null +++ b/src/kms/chain_code/mod.rs @@ -0,0 +1 @@ +pub mod two_party; diff --git a/src/kms/chain_code/two_party/mod.rs b/src/kms/chain_code/two_party/mod.rs new file mode 100644 index 0000000..5096b3f --- /dev/null +++ b/src/kms/chain_code/two_party/mod.rs @@ -0,0 +1,16 @@ +/* + KMS + Copyright 2018 by Kzen Networks + This file is part of KMS library + (https://github.com/KZen-networks/kms) + Cryptography utilities is free software: you can redistribute + it and/or modify it under the terms of the GNU General Public + License as published by the Free Software Foundation, either + version 3 of the License, or (at your option) any later version. + @license GPL-3.0+ +*/ + +pub mod party1; +pub mod party2; + +pub mod test; diff --git a/src/kms/chain_code/two_party/party1.rs b/src/kms/chain_code/two_party/party1.rs new file mode 100644 index 0000000..aa5591c --- /dev/null +++ b/src/kms/chain_code/two_party/party1.rs @@ -0,0 +1,48 @@ +use std::any::Any; +use std::fmt::{Display, Formatter}; +use serde::{Deserialize, Serialize}; +use crate::curv::cryptographic_primitives::{ + proofs::sigma_dlog::DLogProof, + twoparty::dh_key_exchange_variant_with_pok_comm::{ + compute_pubkey, CommWitnessDHPoK, EcKeyPairDHPoK, Party1FirstMessage, Party1SecondMessage, + }, +}; +use crate::curv::{elliptic::curves::traits::ECPoint, BigInt, GE}; +use crate::party_one::{PDLdecommit, v, Value}; + +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +pub struct ChainCode1 { + pub chain_code: BigInt, +} +#[typetag::serde] +impl Value for ChainCode1 { + fn as_any(&self) -> &dyn Any { + self + } +} + +impl Display for ChainCode1 { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self) + } +} +impl ChainCode1 { + pub fn chain_code_first_message() -> (Party1FirstMessage, CommWitnessDHPoK, EcKeyPairDHPoK) { + Party1FirstMessage::create_commitments() + } + pub fn chain_code_second_message( + comm_witness: CommWitnessDHPoK, + proof: &DLogProof, + ) -> Party1SecondMessage { + Party1SecondMessage::verify_and_decommit(comm_witness, proof).expect("") + } + pub fn compute_chain_code( + ec_key_pair: &EcKeyPairDHPoK, + party2_first_message_public_share: &GE, + ) -> ChainCode1 { + ChainCode1 { + chain_code: compute_pubkey(ec_key_pair, party2_first_message_public_share) + .bytes_compressed_to_big_int(), + } + } +} diff --git a/src/kms/chain_code/two_party/party2.rs b/src/kms/chain_code/two_party/party2.rs new file mode 100644 index 0000000..e98266d --- /dev/null +++ b/src/kms/chain_code/two_party/party2.rs @@ -0,0 +1,40 @@ +use serde::{Deserialize, Serialize}; +use crate::curv::cryptographic_primitives::{ + proofs::ProofError, + twoparty::dh_key_exchange_variant_with_pok_comm::{ + compute_pubkey, EcKeyPairDHPoK, Party1FirstMessage, Party1SecondMessage, Party2FirstMessage, + Party2SecondMessage, + }, +}; +use crate::curv::{elliptic::curves::traits::ECPoint, BigInt, GE}; + +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +pub struct ChainCode2 { + pub chain_code: BigInt, +} + +impl ChainCode2 { + pub fn chain_code_first_message() -> (Party2FirstMessage, EcKeyPairDHPoK) { + Party2FirstMessage::create() + } + + pub fn chain_code_second_message( + party_one_first_message: &Party1FirstMessage, + party_one_second_message: &Party1SecondMessage, + ) -> Result { + Party2SecondMessage::verify_commitments_and_dlog_proof( + party_one_first_message, + party_one_second_message, + ) + } + + pub fn compute_chain_code( + ec_key_pair: &EcKeyPairDHPoK, + party1_second_message_public_share: &GE, + ) -> ChainCode2 { + ChainCode2 { + chain_code: compute_pubkey(ec_key_pair, party1_second_message_public_share) + .bytes_compressed_to_big_int(), + } + } +} diff --git a/src/kms/chain_code/two_party/test.rs b/src/kms/chain_code/two_party/test.rs new file mode 100644 index 0000000..a8788a3 --- /dev/null +++ b/src/kms/chain_code/two_party/test.rs @@ -0,0 +1,44 @@ +/* + KMS + Copyright 2018 by Kzen Networks + This file is part of KMS library + (https://github.com/KZen-networks/kms) + Cryptography utilities is free software: you can redistribute + it and/or modify it under the terms of the GNU General Public + License as published by the Free Software Foundation, either + version 3 of the License, or (at your option) any later version. + @license GPL-3.0+ +*/ +#![cfg(test)] +use super::{party1, party2}; + +#[test] +fn test_chain_code() { + // chain code + let (cc_party_one_first_message, cc_comm_witness, cc_ec_key_pair1) = + party1::ChainCode1::chain_code_first_message(); + let (cc_party_two_first_message, cc_ec_key_pair2) = + party2::ChainCode2::chain_code_first_message(); + let cc_party_one_second_message = party1::ChainCode1::chain_code_second_message( + cc_comm_witness, + &cc_party_two_first_message.d_log_proof, + ); + + let cc_party_two_second_message = party2::ChainCode2::chain_code_second_message( + &cc_party_one_first_message, + &cc_party_one_second_message, + ); + assert!(cc_party_two_second_message.is_ok()); + + let party1_cc = party1::ChainCode1::compute_chain_code( + &cc_ec_key_pair1, + &cc_party_two_first_message.public_share, + ); + + let party2_cc = party2::ChainCode2::compute_chain_code( + &cc_ec_key_pair2, + &cc_party_one_second_message.comm_witness.public_share, + ); + + assert_eq!(party1_cc.chain_code, party2_cc.chain_code); +} diff --git a/src/kms/ecdsa/mod.rs b/src/kms/ecdsa/mod.rs new file mode 100644 index 0000000..988e1b3 --- /dev/null +++ b/src/kms/ecdsa/mod.rs @@ -0,0 +1 @@ +pub mod two_party; diff --git a/src/kms/ecdsa/two_party/mod.rs b/src/kms/ecdsa/two_party/mod.rs new file mode 100644 index 0000000..1a0cc13 --- /dev/null +++ b/src/kms/ecdsa/two_party/mod.rs @@ -0,0 +1,99 @@ +use std::any::Any; +use std::fmt::{Display, Formatter}; +use serde::{Deserialize, Serialize}; +use crate::curv::arithmetic::traits::Converter; +use crate::curv::cryptographic_primitives::hashing::{hmac_sha512, traits::KeyedHash}; +use crate::curv::elliptic::curves::traits::{ECPoint, ECScalar}; +use crate::curv::{BigInt, FE, GE}; +use crate::{paillier::EncryptionKey, party_one, party_two}; +use crate::kms::chain_code::two_party::party1::ChainCode1; +use crate::party_one::Value; + +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +pub struct Party1Public { + pub q: GE, + pub p1: GE, + pub p2: GE, + pub paillier_pub: EncryptionKey, + pub c_key: BigInt, +} + +#[derive(Clone,Debug,Serialize, Deserialize)] +pub struct MasterKey1 { + pub public: Party1Public, + // Why is the field below public? See: https://github.com/KZen-networks/kms-secp256k1/issues/20 + pub private: party_one::Party1Private, + chain_code: BigInt, +} +#[typetag::serde] +impl Value for MasterKey1 { + fn as_any(&self) -> &dyn Any { + self + } +} + +impl Display for MasterKey1 { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self) + } +} + +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +pub struct Party2Public { + pub q: GE, + pub p2: GE, + pub p1: GE, + pub paillier_pub: EncryptionKey, + pub c_key: BigInt, +} + +#[derive(Clone,Debug,Serialize, Deserialize)] +pub struct MasterKey2 { + pub public: Party2Public, + pub private: party_two::Party2Private, + pub chain_code: BigInt, +} + +pub mod party1; +pub mod party2; +mod test; + +pub fn hd_key( + mut location_in_hir: Vec, + pubkey: &GE, + chain_code_bi: &BigInt, +) -> (GE, FE, GE) { + let mask = BigInt::from(2i32).pow(256) - BigInt::one(); + // let public_key = self.public.q.clone(); + + // calc first element: + let first = location_in_hir.remove(0); + let pub_key_bi = pubkey.bytes_compressed_to_big_int(); + let f = hmac_sha512::HMacSha512::create_hmac(chain_code_bi, &[&pub_key_bi, &first]); + let f_l = &f >> 256; + let f_r = &f & &mask; + let f_l_fe: FE = ECScalar::from(&f_l); + let f_r_fe: FE = ECScalar::from(&f_r); + + let bn_to_slice = BigInt::to_vec(chain_code_bi); + let chain_code = GE::from_bytes(&bn_to_slice[1..33]).unwrap() * f_r_fe; + let pub_key = pubkey * &f_l_fe; + + let (public_key_new_child, f_l_new, cc_new) = + location_in_hir + .iter() + .fold((pub_key, f_l_fe, chain_code), |acc, index| { + let pub_key_bi = acc.0.bytes_compressed_to_big_int(); + let f = hmac_sha512::HMacSha512::create_hmac( + &acc.2.bytes_compressed_to_big_int(), + &[&pub_key_bi, index], + ); + let f_l = &f >> 256; + let f_r = &f & &mask; + let f_l_fe: FE = ECScalar::from(&f_l); + let f_r_fe: FE = ECScalar::from(&f_r); + + (acc.0 * f_l_fe, f_l_fe * acc.1, acc.2 * f_r_fe) + }); + (public_key_new_child, f_l_new, cc_new) +} diff --git a/src/kms/ecdsa/two_party/party1.rs b/src/kms/ecdsa/two_party/party1.rs new file mode 100644 index 0000000..1ff3099 --- /dev/null +++ b/src/kms/ecdsa/two_party/party1.rs @@ -0,0 +1,300 @@ +use super::hd_key; +use super::party2::SignMessage; +use super::{MasterKey1, MasterKey2, Party1Public}; +use crate::kms::Errors::{self, SignError}; +use crate::curv::cryptographic_primitives::proofs::sigma_dlog::DLogProof; +use crate::curv::{elliptic::curves::traits::ECPoint, BigInt, FE, GE}; +use crate::party_two::{ + PDLFirstMessage as Party2PDLFirstMsg, PDLSecondMessage as Party2PDLSecondMsg, +}; +use crate::zk_paillier::zkproofs::{NICorrectKeyProof, RangeProofNi}; +use crate::{ + party_one, + party_two::{self, EphKeyGenFirstMsg}, + EncryptionKey, +}; + +use serde::{Deserialize, Serialize}; +use crate::curv::elliptic::curves::traits::ECScalar; +use crate::kms::rotation::two_party::Rotation; +use crate::party_one::Party1Private; + +#[derive(Debug, Serialize, Deserialize)] +pub struct KeyGenParty1Message2 { + pub ecdh_second_message: party_one::KeyGenSecondMsg, + pub ek: EncryptionKey, + pub 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); + + let public = Party1Public { + q: public_key_new_child, + p1: self.public.p1, + p2: self.public.p2 * f_l_new, + paillier_pub: self.public.paillier_pub.clone(), + c_key: self.public.c_key.clone(), + }; + MasterKey1 { + public, + private: self.private.clone(), + chain_code: cc_new.bytes_compressed_to_big_int(), + } + } + + pub fn set_master_key( + chain_code: &BigInt, + party_one_private: party_one::Party1Private, + party_one_public_ec_key: &GE, + party2_first_message_public_share: &GE, + paillier_key_pair: party_one::PaillierKeyPair, + ) -> MasterKey1 { + let party1_public = Party1Public { + q: party_one::compute_pubkey(&party_one_private, party2_first_message_public_share), + p1: *party_one_public_ec_key, + p2: *party2_first_message_public_share, + paillier_pub: paillier_key_pair.ek.clone(), + c_key: paillier_key_pair.encrypted_share, + }; + + MasterKey1 { + public: party1_public, + private: party_one_private, + chain_code: chain_code.clone(), + } + } + + // master key of party two from counter party recovery (party one recovers party two secret share) + pub fn counter_master_key_from_recovered_secret(&self, party_two_secret: FE) -> MasterKey2 { + let (_, ec_key_pair_party2) = + party_two::KeyGenFirstMsg::create_with_fixed_secret_share(party_two_secret); + let party_two_paillier = party_two::PaillierPublic { + ek: self.public.paillier_pub.clone(), + encrypted_secret_share: self.public.c_key.clone(), + }; + // set master keys: + MasterKey2::set_master_key( + &self.chain_code, + &ec_key_pair_party2, + &ec_key_pair_party2.public_share, + &party_two_paillier, + ) + } + + pub fn key_gen_first_message() -> ( + party_one::KeyGenFirstMsg, + party_one::CommWitness, + party_one::EcKeyPair, + ) { + party_one::KeyGenFirstMsg::create_commitments() + } + pub fn key_gen_second_message( + comm_witness: &party_one::CommWitness, + ec_key_pair_party1: &party_one::EcKeyPair, + proof: &DLogProof, + ) -> ( + KeyGenParty1Message2, + party_one::PaillierKeyPair, + party_one::Party1Private, + ) { + let key_gen_second_message = + party_one::KeyGenSecondMsg::verify_and_decommit(comm_witness.clone(), proof).expect(""); + + let paillier_key_pair = + party_one::PaillierKeyPair::generate_keypair_and_encrypted_share(ec_key_pair_party1); + + // party one set her private key: + let party_one_private = + party_one::Party1Private::set_private_key(ec_key_pair_party1, &paillier_key_pair); + + let range_proof = party_one::PaillierKeyPair::generate_range_proof( + &paillier_key_pair, + &party_one_private, + ); + let correct_key_proof = + party_one::PaillierKeyPair::generate_ni_proof_correct_key(&paillier_key_pair); + ( + KeyGenParty1Message2 { + ecdh_second_message: key_gen_second_message, + ek: paillier_key_pair.ek.clone(), + c_key: paillier_key_pair.encrypted_share.clone(), + correct_key_proof, + range_proof, + }, + paillier_key_pair, + party_one_private, + ) + } + + pub fn sign_first_message() -> (party_one::EphKeyGenFirstMsg, party_one::EphEcKeyPair) { + party_one::EphKeyGenFirstMsg::create() + } + + pub fn sign_second_message( + &self, + party_two_sign_message: &SignMessage, + eph_key_gen_first_message_party_two: &EphKeyGenFirstMsg, + eph_ec_key_pair_party1: &party_one::EphEcKeyPair, + message: &BigInt, + ) -> Result { + let verify_party_two_second_message = + party_one::EphKeyGenSecondMsg::verify_commitments_and_dlog_proof( + eph_key_gen_first_message_party_two, + &party_two_sign_message.second_message, + ) + .is_ok(); + + let signature_with_recid = party_one::Signature::compute_with_recid( + &self.private, + &party_two_sign_message.partial_sig.c3, + eph_ec_key_pair_party1, + &party_two_sign_message + .second_message + .comm_witness + .public_share, + ); + + // Creating a standard signature for the verification, currently discarding recid + // TODO: Investigate what verification could be done with recid + let signature = party_one::Signature { + r: signature_with_recid.r.clone(), + s: signature_with_recid.s.clone(), + }; + + + let verify = party_one::verify(&signature, &self.public.q, message).is_ok(); + if verify { + if verify_party_two_second_message { + Ok(signature_with_recid) + } else { + println!("Invalid commitments:{:?}", eph_key_gen_first_message_party_two); + println!("party_two_sign_message.second_message:{:?}", party_two_sign_message.second_message); + println!("sig_r: {}", signature.r); + println!("sig_s: {}", signature.s); + Err(SignError) + } + } else { + println!("Sig does not verify"); + println!("sig_r: {}", signature.r); + println!("sig_s: {}", signature.s); + Err(SignError) + } + } + + pub fn key_gen_third_message( + party_two_pdl_first_message: &Party2PDLFirstMsg, + party_one_private: &party_one::Party1Private, + ) -> (party_one::PDLFirstMessage, party_one::PDLdecommit, BigInt) { + party_one::PaillierKeyPair::pdl_first_stage( + &party_one_private, + &party_two_pdl_first_message, + ) + } + + pub fn key_gen_fourth_message( + pdl_party_two_first_message: &Party2PDLFirstMsg, + pdl_party_two_second_message: &Party2PDLSecondMsg, + party_one_private: party_one::Party1Private, + pdl_decommit: party_one::PDLdecommit, + alpha: BigInt, + ) -> Result { + party_one::PaillierKeyPair::pdl_second_stage( + pdl_party_two_first_message, + pdl_party_two_second_message, + party_one_private, + pdl_decommit, + alpha, + ) + } + pub fn rotation_first_message(self, cf: &Rotation) -> (RotationParty1Message1, Party1Private) { + 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, + }, + new_private.clone(), + ) + } + pub fn rotation_second_message( + rotate_party_two_message_one: &Party2PDLFirstMsg, + party_one_private: &party_one::Party1Private, + ) -> (party_one::PDLFirstMessage, party_one::PDLdecommit, BigInt) { + party_one::PaillierKeyPair::pdl_first_stage( + &party_one_private, + &rotate_party_two_message_one, + ) + } + + pub fn rotation_third_message( + self, + rotation_first_message: &RotationParty1Message1, + party_one_private_new: party_one::Party1Private, + cf: &Rotation, + rotate_party_two_first_message: &Party2PDLFirstMsg, + rotate_party_two_second_message: &Party2PDLSecondMsg, + pdl_decommit: party_one::PDLdecommit, + alpha: BigInt, + ) -> Result<((party_one::PDLSecondMessage, MasterKey1)), ()> { + let rotate_party_one_third_message = party_one::PaillierKeyPair::pdl_second_stage( + rotate_party_two_first_message, + rotate_party_two_second_message, + party_one_private_new.clone(), + pdl_decommit, + alpha, + ); + let master_key_new = self.rotate( + cf, + party_one_private_new, + &rotation_first_message.ek_new, + &rotation_first_message.c_key_new, + ); + match rotate_party_one_third_message { + Ok(x) => Ok((x, master_key_new)), + Err(_) => Err(()), + } + } +} diff --git a/src/kms/ecdsa/two_party/party2.rs b/src/kms/ecdsa/two_party/party2.rs new file mode 100644 index 0000000..ebbb5a2 --- /dev/null +++ b/src/kms/ecdsa/two_party/party2.rs @@ -0,0 +1,298 @@ +use super::{hd_key, party1::KeyGenParty1Message2, MasterKey1, MasterKey2, Party2Public}; + +use serde::{Deserialize, Serialize}; +use crate::curv::{ + elliptic::curves::traits::{ECPoint, ECScalar}, + BigInt, FE, GE, +}; +use crate::party_one::{ + EphKeyGenFirstMsg as Party1EphKeyGenFirstMsg, KeyGenFirstMsg as Party1KeyGenFirstMsg, + 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 { + pub partial_sig: party_two::PartialSig, + pub second_message: party_two::EphKeyGenSecondMsg, +} + +#[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); + + let public = Party2Public { + q: public_key_new_child, + p2: self.public.p2 * f_l_new, + p1: self.public.p1, + paillier_pub: self.public.paillier_pub.clone(), + c_key: self.public.c_key.clone(), + }; + MasterKey2 { + public, + private: party_two::Party2Private::update_private_key( + &self.private, + &f_l_new.to_big_int(), + ), + chain_code: cc_new.bytes_compressed_to_big_int(), + } + } + + pub fn set_master_key( + chain_code: &BigInt, + ec_key_pair_party2: &party_two::EcKeyPair, + party1_second_message_public_share: &GE, + paillier_public: &party_two::PaillierPublic, + ) -> MasterKey2 { + let party2_public = Party2Public { + q: party_two::compute_pubkey(ec_key_pair_party2, party1_second_message_public_share), + p2: ec_key_pair_party2.public_share, + p1: *party1_second_message_public_share, + paillier_pub: paillier_public.ek.clone(), + c_key: paillier_public.encrypted_secret_share.clone(), + }; + let party2_private = party_two::Party2Private::set_private_key(ec_key_pair_party2); + MasterKey2 { + public: party2_public, + private: party2_private, + chain_code: chain_code.clone(), + } + } + + // master key of party one from counter party recovery (party two recovers party one secret share) + pub fn counter_master_key_from_recovered_secret(&self, party_one_secret: FE) -> MasterKey1 { + let (_, _, ec_key_pair_party1) = + party_one::KeyGenFirstMsg::create_commitments_with_fixed_secret_share(party_one_secret); + let paillier_key_pair = + 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); + + // set master keys: + MasterKey1::set_master_key( + &self.chain_code, + party_one_private, + &ec_key_pair_party1.public_share, + &self.public.p2, + paillier_key_pair, + ) + } + + pub fn key_gen_first_message() -> (party_two::KeyGenFirstMsg, party_two::EcKeyPair) { + party_two::KeyGenFirstMsg::create() + } + + pub fn key_gen_second_message( + party_one_first_message: &Party1KeyGenFirstMsg, + party_one_second_message: &KeyGenParty1Message2, + ) -> Result< + ( + Party2SecondMessage, + party_two::PaillierPublic, + party_two::PDLchallenge, + ), + (), + > { + let paillier_encryption_key = party_one_second_message.ek.clone(); + let paillier_encrypted_share = party_one_second_message.c_key.clone(); + + let party_two_second_message = + party_two::KeyGenSecondMsg::verify_commitments_and_dlog_proof( + &party_one_first_message, + &party_one_second_message.ecdh_second_message, + ); + + let party_two_paillier = party_two::PaillierPublic { + ek: paillier_encryption_key.clone(), + encrypted_secret_share: paillier_encrypted_share.clone(), + }; + + let range_proof_verify = party_two::PaillierPublic::verify_range_proof( + &party_two_paillier, + &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 + .verify(&party_two_paillier.ek); + + match range_proof_verify { + Ok(_proof) => match correct_key_verify { + Ok(_proof) => match party_two_second_message { + Ok(t) => Ok(( + Party2SecondMessage { + key_gen_second_message: t, + pdl_first_message, + }, + party_two_paillier, + pdl_chal, + )), + Err(_verify_com_and_dlog_party_one) => Err(()), + }, + Err(_correct_key_error) => Err(()), + }, + Err(_range_proof_error) => Err(()), + } + } + + pub fn key_gen_third_message( + pdl_chal: &party_two::PDLchallenge, + ) -> party_two::PDLSecondMessage { + party_two::PaillierPublic::pdl_decommit_c_tag_tag(&pdl_chal) + } + + pub fn key_gen_fourth_message( + pdl_chal: &party_two::PDLchallenge, + party_one_pdl_first_message: &Party1PDLFirstMsg, + party_one_pdl_second_message: &Party1PDLSecondMsg, + ) -> Result<(), ()> { + party_two::PaillierPublic::verify_pdl( + pdl_chal, + party_one_pdl_first_message, + party_one_pdl_second_message, + ) + } + + pub fn sign_first_message() -> ( + party_two::EphKeyGenFirstMsg, + party_two::EphCommWitness, + party_two::EphEcKeyPair2, + ) { + party_two::EphKeyGenFirstMsg::create_commitments() + } + pub fn sign_second_message( + &self, + ec_key_pair_party2: &party_two::EphEcKeyPair2, + eph_comm_witness: party_two::EphCommWitness, + eph_party1_first_message: &Party1EphKeyGenFirstMsg, + message: &BigInt, + ) -> SignMessage { + let eph_key_gen_second_message = party_two::EphKeyGenSecondMsg::verify_and_decommit( + eph_comm_witness, + eph_party1_first_message, + ) + .expect(""); + + let partial_sig = party_two::PartialSig::compute( + &self.public.paillier_pub, + &self.public.c_key, + &self.private, + ec_key_pair_party2, + &eph_party1_first_message.public_share, + message, + ); + SignMessage { + partial_sig, + 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< + ( + party_two::PDLFirstMessage, + party_two::PDLchallenge, + party_two::PaillierPublic, + ), + (), + > { + 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); + let (pdl_first_message, pdl_chal) = + party_two_paillier.pdl_challenge(&(&self.public.p1 * &cf.rotation)); + + match range_proof_verify { + Ok(_proof) => match correct_key_verify { + Ok(_proof) => Ok((pdl_first_message, pdl_chal, party_two_paillier)), + Err(_correct_key_error) => Err(()), + }, + Err(_range_proof_error) => Err(()), + } + } + pub fn rotate_second_message( + pdl_chal: &party_two::PDLchallenge, + ) -> party_two::PDLSecondMessage { + party_two::PaillierPublic::pdl_decommit_c_tag_tag(&pdl_chal) + } + + pub fn rotate_third_message( + self, + cf: &Rotation, + party_two_paillier: &party_two::PaillierPublic, + pdl_chal: &party_two::PDLchallenge, + party_one_pdl_first_message: &Party1PDLFirstMsg, + party_one_pdl_second_message: &Party1PDLSecondMsg, + ) -> Result { + match party_two::PaillierPublic::verify_pdl( + pdl_chal, + party_one_pdl_first_message, + party_one_pdl_second_message, + ) { + Ok(_) => { + let master_key = self.rotate(cf, party_two_paillier); + Ok(master_key) + } + Err(_) => Err(()), + } + } +} diff --git a/src/kms/ecdsa/two_party/test.rs b/src/kms/ecdsa/two_party/test.rs new file mode 100644 index 0000000..f38c810 --- /dev/null +++ b/src/kms/ecdsa/two_party/test.rs @@ -0,0 +1,614 @@ +/* + KMS + Copyright 2018 by Kzen Networks + This file is part of KMS library + (https://github.com/KZen-networks/kms) + Cryptography utilities is free software: you can redistribute + it and/or modify it under the terms of the GNU General Public + License as published by the Free Software Foundation, either + version 3 of the License, or (at your option) any later version. + @license GPL-3.0+ +*/ +#![allow(non_snake_case)] +#![cfg(test)] + +use std::cell::RefCell; +use std::sync::Arc; +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::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: + let (party_one_master_key, party_two_master_key) = test_key_gen(); + + let new_party_two_master_key = + party_two_master_key.get_child(vec![BigInt::from(10), BigInt::from(5)]); + let new_party_one_master_key = + party_one_master_key.get_child(vec![BigInt::from(10), BigInt::from(5)]); + 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"); +} + +#[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) = + MasterKey1::key_gen_first_message(); + let (kg_party_two_first_message, kg_ec_key_pair_party2) = MasterKey2::key_gen_first_message(); + let (kg_party_one_second_message, party_one_paillier_key_pair, party_one_private) = + MasterKey1::key_gen_second_message( + &kg_comm_witness.clone(), + &kg_ec_key_pair_party1, + &kg_party_two_first_message.d_log_proof, + ); + + let key_gen_second_message = MasterKey2::key_gen_second_message( + &kg_party_one_first_message, + &kg_party_one_second_message, + ); + + assert!(key_gen_second_message.is_ok()); + + let (_, party_two_paillier, _) = key_gen_second_message.unwrap(); + + // chain code + let (cc_party_one_first_message, cc_comm_witness, cc_ec_key_pair1) = + party1::ChainCode1::chain_code_first_message(); + let (cc_party_two_first_message, cc_ec_key_pair2) = + party2::ChainCode2::chain_code_first_message(); + let cc_party_one_second_message = party1::ChainCode1::chain_code_second_message( + cc_comm_witness, + &cc_party_two_first_message.d_log_proof, + ); + + let cc_party_two_second_message = party2::ChainCode2::chain_code_second_message( + &cc_party_one_first_message, + &cc_party_one_second_message, + ); + assert!(cc_party_two_second_message.is_ok()); + + let party1_cc = party1::ChainCode1::compute_chain_code( + &cc_ec_key_pair1, + &cc_party_two_first_message.public_share, + ); + + let party2_cc = party2::ChainCode2::compute_chain_code( + &cc_ec_key_pair2, + &cc_party_one_second_message.comm_witness.public_share, + ); + // set master keys: + let party_one_master_key = MasterKey1::set_master_key( + &party1_cc.chain_code, + party_one_private, + &kg_comm_witness.public_share, + &kg_party_two_first_message.public_share, + party_one_paillier_key_pair, + ); + + let party_two_master_key = MasterKey2::set_master_key( + &party2_cc.chain_code, + &kg_ec_key_pair_party2, + &kg_party_one_second_message + .ecdh_second_message + .comm_witness + .public_share, + &party_two_paillier, + ); + (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"); +} + +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 +*/ + +pub mod chain_code; +pub mod ecdsa; +pub mod rotation; +pub mod poc; + +#[derive(Copy, PartialEq, Eq, Clone, Debug)] +pub enum Errors { + KeyGenError, + SignError, +} diff --git a/src/kms/mod.rs b/src/kms/mod.rs new file mode 100644 index 0000000..c0751d7 --- /dev/null +++ b/src/kms/mod.rs @@ -0,0 +1,10 @@ +pub mod chain_code; +pub mod ecdsa; +pub mod rotation; +pub mod poc; + +#[derive(Copy, PartialEq, Eq, Clone, Debug)] +pub enum Errors { + KeyGenError, + SignError, +} \ No newline at end of file diff --git a/src/kms/poc.rs b/src/kms/poc.rs new file mode 100644 index 0000000..5adaa4e --- /dev/null +++ b/src/kms/poc.rs @@ -0,0 +1,76 @@ +/* + KMS + + Copyright 2018 by Kzen Networks + + This file is part of KMS library + (https://github.com/KZen-networks/kms) + + KMS is free software: you can redistribute + it and/or modify it under the terms of the GNU General Public + License as published by the Free Software Foundation, either + version 3 of the License, or (at your option) any later version. + + @license GPL-3.0+ +*/ +#![allow(non_snake_case)] +#![cfg(test)] + +use crate::kms::ecdsa::two_party::{MasterKey1 as EcdsaMasterKey1, MasterKey2 as EcdsaMasterKey2}; +use crate::centipede::juggling::{proof_system::Proof, segmentation::Msegmentation}; +use crate::curv::{ + elliptic::curves::traits::{ECPoint, ECScalar}, + FE, GE, +}; + +#[test] +fn poc_schnorr_ecdsa() { + // generate random secret share: + let ss: FE = ECScalar::new_random(); + // party 2 is a client + + // backup: VE under public key Y (=yG): + let segment_size = 8; + let y: FE = ECScalar::new_random(); + let G: GE = ECPoint::generator(); + let Y = G * y; + let Q = G * ss; + // encryption + let (segments, encryptions) = + Msegmentation::to_encrypted_segments(&ss, &segment_size, 32, &Y, &G); + // provable encryption + let proof = Proof::prove(&segments, &encryptions, &G, &Y, &segment_size); + + // party two verifier the backup zk proof + let result = proof.verify(&encryptions, &G, &Y, &Q, &segment_size); + assert!(result.is_ok()); + + // full ecdsa key gen: + + // key gen + let (kg_party_one_first_message, kg_comm_witness, kg_ec_key_pair_party1) = + EcdsaMasterKey1::key_gen_first_message(); + let (kg_party_two_first_message, _kg_ec_key_pair_party2) = + EcdsaMasterKey2::key_gen_first_message(); + let (kg_party_one_second_message, _paillier_key_pair, _party_one_private) = + EcdsaMasterKey1::key_gen_second_message( + &kg_comm_witness.clone(), + &kg_ec_key_pair_party1, + &kg_party_two_first_message.d_log_proof, + ); + + let key_gen_second_message = EcdsaMasterKey2::key_gen_second_message( + &kg_party_one_first_message, + &kg_party_one_second_message, + ); + + assert!(key_gen_second_message.is_ok()); + + let _party_two_paillier = key_gen_second_message.unwrap(); + + // recovery party two: + let secret_decrypted = Msegmentation::decrypt(&encryptions, &G, &y, &segment_size); + + // debug test + assert_eq!(ss.get_element(), secret_decrypted.unwrap().get_element()); +} 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/lib.rs b/src/lib.rs index 38e2e92..443ed7f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,8 +15,8 @@ */ const SECURITY_BITS: usize = 256; -#[macro_use] -extern crate serde_derive; +// #[macro_use] +// extern crate serde_derive; pub mod bulletproofs; pub mod centipede; @@ -25,9 +25,12 @@ pub mod paillier; pub mod party_one; pub mod party_two; pub mod zk_paillier; +pub mod kms; mod test; +use serde::{Serialize,Deserialize}; + pub use crate::centipede::juggling::proof_system::{Helgamal, Helgamalsegmented, Witness}; pub use crate::curv::cryptographic_primitives::proofs::{sigma_ec_ddh::ECDDHProof, ProofError}; pub use crate::curv::elliptic::curves::secp256_k1::{Secp256k1Point, Secp256k1Scalar}; diff --git a/src/paillier/encoding/mod.rs b/src/paillier/encoding/mod.rs index 712edde..f58b997 100644 --- a/src/paillier/encoding/mod.rs +++ b/src/paillier/encoding/mod.rs @@ -5,6 +5,7 @@ use std::marker::PhantomData; use crate::curv::arithmetic::traits::ConvertFrom; use crate::curv::BigInt; pub mod integral; +use serde::{Serialize,Deserialize}; /// Encrypted message with type information. #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] diff --git a/src/paillier/mod.rs b/src/paillier/mod.rs index a24a992..1da9563 100644 --- a/src/paillier/mod.rs +++ b/src/paillier/mod.rs @@ -12,6 +12,7 @@ pub use self::traits::*; pub use keygen::*; use std::borrow::Cow; +use serde::{Serialize,Deserialize}; /// Main struct onto which most operations are added. pub struct Paillier; diff --git a/src/party_one.rs b/src/party_one.rs index 8c5fbe1..f366599 100644 --- a/src/party_one.rs +++ b/src/party_one.rs @@ -19,8 +19,10 @@ use crate::paillier::{DecryptionKey, EncryptionKey, Randomness, RawCiphertext, R use crate::zk_paillier::zkproofs::{NICorrectKeyProof, RangeProofNi}; use std::cmp; 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::*; @@ -44,9 +46,144 @@ use crate::centipede::juggling::segmentation::Msegmentation; use crate::curv::BigInt; use crate::curv::FE; use crate::curv::GE; +use std::any::{Any}; +use secp256k1::Secp256k1; use crate::Error::{self, InvalidSig}; +#[typetag::serde] +pub trait Value: Sync + Send + Any { + fn as_any(&self) -> &dyn Any; +} + +#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)] +pub struct HDPos { + pub pos: u32, +} + +#[derive(Clone, Serialize, Deserialize, Debug)] +pub struct v { + pub value: String, +} + +#[typetag::serde] +impl Value for HDPos { + fn as_any(&self) -> &dyn Any { + self + } +} + +#[typetag::serde] +impl Value for KeyGenFirstMsg { + fn as_any(&self) -> &dyn Any { + self + } +} + +#[typetag::serde] +impl Value for CommWitness { + fn as_any(&self) -> &dyn Any { + self + } +} + +#[typetag::serde] +impl Value for EcKeyPair { + fn as_any(&self) -> &dyn Any { + self + } +} + +#[typetag::serde] +impl Value for v { + fn as_any(&self) -> &dyn Any { + self + } +} + +#[typetag::serde] +impl Value for PaillierKeyPair { + fn as_any(&self) -> &dyn Any { + self + } +} + +#[typetag::serde] +impl Value for Party1Private { + fn as_any(&self) -> &dyn Any { + self + } +} + +#[typetag::serde] +impl Value for PDLdecommit { + fn as_any(&self) -> &dyn Any { + self + } +} + +#[typetag::serde] +impl Value for EphEcKeyPair { + fn as_any(&self) -> &dyn Any { + self + } +} + +impl Display for EphEcKeyPair { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self) + } +} + +impl Display for v { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self) + } +} + +impl Display for CommWitness { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self) + } +} + + +impl Display for PDLdecommit { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self) + } +} + +impl Display for KeyGenFirstMsg { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self) + } +} + +impl Display for EcKeyPair { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self) + } +} + +impl Display for PaillierKeyPair { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self) + } +} + +impl Display for Party1Private { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self) + } +} + +impl Display for HDPos { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self) + } +} + //****************** Begin: Party One structs ******************// #[derive(Clone, Debug, Serialize, Deserialize)] pub struct EcKeyPair { @@ -54,6 +191,7 @@ pub struct EcKeyPair { secret_share: FE, } + #[derive(Clone, Debug, Serialize, Deserialize)] pub struct CommWitness { pub pk_commitment_blind_factor: BigInt, @@ -62,18 +200,20 @@ pub struct CommWitness { pub d_log_proof: DLogProof, } + #[derive(Clone, Debug, Serialize, Deserialize)] pub struct KeyGenFirstMsg { pub pk_commitment: BigInt, pub zk_pok_commitment: BigInt, } + #[derive(Debug, Serialize, Deserialize)] pub struct KeyGenSecondMsg { pub comm_witness: CommWitness, } -#[derive(Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct PaillierKeyPair { pub ek: EncryptionKey, dk: DecryptionKey, @@ -101,17 +241,19 @@ pub struct Party1Private { c_key_randomness: BigInt, } + #[derive(Debug, Serialize, Deserialize)] pub struct PDLFirstMessage { pub c_hat: BigInt, } -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct PDLdecommit { pub q_hat: GE, pub blindness: BigInt, } + #[derive(Debug, Serialize, Deserialize)] pub struct PDLSecondMessage { pub decommit: PDLdecommit, @@ -241,6 +383,65 @@ pub fn compute_pubkey(party_one_private: &Party1Private, other_share_public_shar } impl Party1Private { + pub fn check_rotated_key_bounds( + party_one_private: &Party1Private, + factor: &BigInt, + ) -> 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, + ) -> ( + 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, @@ -271,8 +472,8 @@ impl PaillierKeyPair { RawPlaintext::from(keygen.secret_share.to_big_int()), &randomness, ) - .0 - .into_owned(); + .0 + .into_owned(); PaillierKeyPair { ek, diff --git a/src/party_two.rs b/src/party_two.rs index c2b24fa..c1b84b4 100644 --- a/src/party_two.rs +++ b/src/party_two.rs @@ -13,6 +13,8 @@ @license GPL-3.0+ */ +use std::any::Any; +use std::fmt::{Display, Formatter}; use super::SECURITY_BITS; use crate::curv::arithmetic::traits::*; @@ -35,7 +37,7 @@ use crate::curv::FE; use crate::curv::GE; use crate::paillier::traits::{Add, Encrypt, Mul}; use crate::paillier::{EncryptionKey, Paillier, RawCiphertext, RawPlaintext}; -use crate::party_one::EphKeyGenFirstMsg as Party1EphKeyGenFirstMsg; +use crate::party_one::{ EphKeyGenFirstMsg as Party1EphKeyGenFirstMsg, Value}; use crate::party_one::KeyGenFirstMsg as Party1KeyGenFirstMessage; use crate::party_one::KeyGenSecondMsg as Party1KeyGenSecondMessage; use crate::zk_paillier::zkproofs::{RangeProofError, RangeProofNi}; @@ -43,6 +45,7 @@ use crate::zk_paillier::zkproofs::{RangeProofError, RangeProofNi}; use crate::centipede::juggling::proof_system::{Helgamalsegmented, Witness}; use crate::centipede::juggling::segmentation::Msegmentation; use std::ops::Shl; +use serde::{Serialize,Deserialize}; //****************** Begin: Party Two structs ******************// @@ -72,13 +75,24 @@ pub struct PartialSig { pub c3: BigInt, } -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Debug, Deserialize, Clone)] pub struct Party2Private { x2: FE, } +#[typetag::serde] +impl Value for EphEcKeyPair2 { + fn as_any(&self) -> &dyn Any { + self + } +} +impl Display for EphEcKeyPair2 { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self) + } +} #[derive(Clone, Debug, Serialize, Deserialize)] -pub struct EphEcKeyPair { +pub struct EphEcKeyPair2 { pub public_share: GE, secret_share: FE, } @@ -98,6 +112,19 @@ pub struct EphKeyGenFirstMsg { pub zk_pok_commitment: BigInt, } +#[typetag::serde] +impl Value for EphKeyGenFirstMsg { + fn as_any(&self) -> &dyn Any { + self + } +} + +impl Display for EphKeyGenFirstMsg { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self) + } +} + #[derive(Clone, Debug, Serialize, Deserialize)] pub struct EphKeyGenSecondMsg { pub comm_witness: EphCommWitness, @@ -109,18 +136,60 @@ pub struct PDLFirstMessage { pub c_tag_tag: BigInt, } + +#[typetag::serde] +impl Value for PDLFirstMessage { + fn as_any(&self) -> &dyn Any { + self + } +} + +impl Display for PDLFirstMessage { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self) + } +} + #[derive(Debug, Serialize, Deserialize)] -pub struct PDLdecommit { +pub struct PDL2decommit { pub a: BigInt, pub b: BigInt, pub blindness: BigInt, } + +#[typetag::serde] +impl Value for PDL2decommit { + fn as_any(&self) -> &dyn Any { + self + } +} + +impl Display for PDL2decommit { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self) + } +} + #[derive(Debug, Serialize, Deserialize)] pub struct PDLSecondMessage { - pub decommit: PDLdecommit, + pub decommit: PDL2decommit, } + +#[typetag::serde] +impl Value for PDLSecondMessage { + fn as_any(&self) -> &dyn Any { + self + } +} +impl Display for PDLSecondMessage { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self) + } +} + + #[derive(Debug)] pub struct PDLchallenge { pub c_tag: BigInt, @@ -284,7 +353,7 @@ impl PaillierPublic { } pub fn pdl_decommit_c_tag_tag(pdl_chal: &PDLchallenge) -> PDLSecondMessage { - let decommit = PDLdecommit { + let decommit = PDL2decommit { a: pdl_chal.a.clone(), b: pdl_chal.b.clone(), blindness: pdl_chal.blindness.clone(), @@ -315,7 +384,7 @@ impl PaillierPublic { } impl EphKeyGenFirstMsg { - pub fn create_commitments() -> (EphKeyGenFirstMsg, EphCommWitness, EphEcKeyPair) { + pub fn create_commitments() -> (EphKeyGenFirstMsg, EphCommWitness, EphEcKeyPair2) { let base: GE = ECPoint::generator(); let secret_share: FE = ECScalar::new_random(); @@ -346,7 +415,7 @@ impl EphKeyGenFirstMsg { &zk_pok_blind_factor, ); - let ec_key_pair = EphEcKeyPair { + let ec_key_pair = EphEcKeyPair2 { public_share, secret_share, }; @@ -388,7 +457,7 @@ impl PartialSig { ek: &EncryptionKey, encrypted_secret_share: &BigInt, local_share: &Party2Private, - ephemeral_local_share: &EphEcKeyPair, + ephemeral_local_share: &EphEcKeyPair2, ephemeral_other_public_share: &GE, message: &BigInt, ) -> PartialSig { diff --git a/src/zk_paillier/zkproofs/correct_key_ni.rs b/src/zk_paillier/zkproofs/correct_key_ni.rs index b8b2670..26cf914 100644 --- a/src/zk_paillier/zkproofs/correct_key_ni.rs +++ b/src/zk_paillier/zkproofs/correct_key_ni.rs @@ -20,6 +20,8 @@ use crate::curv::arithmetic::traits::*; use crate::curv::BigInt; use crate::paillier::{extract_nroot, DecryptionKey, EncryptionKey}; use rayon::prelude::*; +use serde::{Serialize,Deserialize}; + // This protocol is based on the NIZK protocol in https://eprint.iacr.org/2018/057.pdf // for parameters = e = N, m2 = 11, alpha = 6379 see https://eprint.iacr.org/2018/987.pdf 6.2.3 // for full details. diff --git a/src/zk_paillier/zkproofs/range_proof.rs b/src/zk_paillier/zkproofs/range_proof.rs index 72243be..5ef4860 100644 --- a/src/zk_paillier/zkproofs/range_proof.rs +++ b/src/zk_paillier/zkproofs/range_proof.rs @@ -26,6 +26,7 @@ use crate::curv::BigInt; use crate::paillier::EncryptWithChosenRandomness; use crate::paillier::Paillier; use crate::paillier::{EncryptionKey, Randomness, RawCiphertext, RawPlaintext}; +use serde::{Serialize,Deserialize}; #[derive(Default, Debug, Serialize, Deserialize)] pub struct EncryptedPairs { diff --git a/src/zk_paillier/zkproofs/range_proof_ni.rs b/src/zk_paillier/zkproofs/range_proof_ni.rs index 738a6bd..ee0f53c 100644 --- a/src/zk_paillier/zkproofs/range_proof_ni.rs +++ b/src/zk_paillier/zkproofs/range_proof_ni.rs @@ -21,6 +21,8 @@ use crate::paillier::EncryptionKey; use std::error::Error; use std::fmt; const SECURITY_PARAMETER: usize = 128; +use serde::{Serialize,Deserialize}; + /// Zero-knowledge range proof that a value x