diff --git a/Cargo.lock b/Cargo.lock index 405da444..c7d507b2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -619,6 +619,7 @@ dependencies = [ "structopt", "thiserror", "tokio 1.32.0", + "tss-core", "uuid 0.8.2", "zeroize", "zk-paillier", @@ -1429,6 +1430,7 @@ dependencies = [ "serde", "sha2 0.9.9", "thiserror", + "tss-core", "zeroize", "zk-paillier", ] @@ -2456,6 +2458,7 @@ dependencies = [ "surf", "thiserror", "tokio 1.32.0", + "tss-core", "uuid 0.8.2", "zeroize", "zk-paillier", @@ -4468,6 +4471,23 @@ dependencies = [ "cfg-if 0.1.10", ] +[[package]] +name = "tss-core" +version = "0.1.0" +dependencies = [ + "bincode", + "curv-kzen", + "kzen-paillier", + "merlin", + "rand 0.8.5", + "rand_chacha 0.3.1", + "serde", + "serde_repr", + "serde_with", + "sha2 0.9.9", + "zeroize", +] + [[package]] name = "typenum" version = "1.17.0" diff --git a/Cargo.toml b/Cargo.toml index b7bd8ec3..b9eab12f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ authors = [ members = [ "multi-party-ecdsa", "fs-dkr", + "tss-core", ] [workspace.dependencies] @@ -22,6 +23,9 @@ serde = { version = "1.0", features = ["derive"] } zeroize = "1" round-based = { git = "https://github.com/webb-tools/round-based-protocol", version = "0.1.4", features = ["dev"] } thiserror = "1.0.23" +tss-core = { path = "tss-core" } +rand_chacha = "0.3.1" +rand = "0.8.5" [workspace.dependencies.multi-party-ecdsa] version = "0.8" @@ -44,13 +48,14 @@ zeroize.workspace = true paillier.workspace = true round-based.workspace = true thiserror.workspace = true +rand.workspace = true +rand_chacha.workspace = true fs-dkr = { path = "fs-dkr", default-features = false } bincode = "1.3.3" digest = "0.9" generic-array = "0.14" -rand_chacha = "0.3.1" -rand = "0.8.5" getrandom = { version = "0.2", optional = true } +tss-core.workspace = true [dev-dependencies] criterion = "0.3" diff --git a/fs-dkr/Cargo.toml b/fs-dkr/Cargo.toml index 708da36f..8f14074d 100644 --- a/fs-dkr/Cargo.toml +++ b/fs-dkr/Cargo.toml @@ -17,6 +17,7 @@ round-based.workspace = true serde.workspace = true zeroize.workspace = true thiserror.workspace = true +tss-core.workspace = true [dependencies.multi-party-ecdsa] workspace = true diff --git a/fs-dkr/src/add_party_message.rs b/fs-dkr/src/add_party_message.rs index 9737969e..1aeaf519 100644 --- a/fs-dkr/src/add_party_message.rs +++ b/fs-dkr/src/add_party_message.rs @@ -29,74 +29,51 @@ use curv::{ elliptic::curves::{Curve, Point, Scalar}, BigInt, }; -use multi_party_ecdsa::gg_2020::party_i::generate_h1_h2_N_tilde; use multi_party_ecdsa::protocols::multi_party_ecdsa::gg_2020::{ party_i::{Keys, SharedKeys}, state_machine::keygen::LocalKey, }; -use multi_party_ecdsa::utilities::zk_composite_dlog::{ - CompositeDLogProof, CompositeDLogStatement, CompositeDLogWitness, -}; use paillier::{Decrypt, EncryptionKey, Paillier}; use serde::{Deserialize, Serialize}; -use std::{collections::HashMap, fmt::Debug}; +use std::{collections::HashMap, fmt::Debug, marker::PhantomData}; use zk_paillier::zkproofs::NiCorrectKeyProof; -use crate::ring_pedersen_proof::{RingPedersenProof, RingPedersenStatement}; +use tss_core::utilities::generate_safe_h1_h2_N_tilde; +use tss_core::zkproof::prm::{PiPrmProof, PiPrmStatement, PiPrmWitness}; /// Message used by new parties to join the protocol. #[derive(Clone, Deserialize, Serialize, Debug)] #[serde(bound = "E: Curve, H: Digest + Clone")] -pub struct JoinMessage { +pub struct JoinMessage { pub(crate) ek: EncryptionKey, pub(crate) dk_correctness_proof: NiCorrectKeyProof, pub(crate) party_index: Option, - pub(crate) dlog_statement: CompositeDLogStatement, - pub(crate) composite_dlog_proof_base_h1: CompositeDLogProof, - pub(crate) composite_dlog_proof_base_h2: CompositeDLogProof, - pub(crate) ring_pedersen_statement: RingPedersenStatement, - pub(crate) ring_pedersen_proof: RingPedersenProof, + pub(crate) dlog_statement: PiPrmStatement, + pub(crate) composite_dlog_proof_base_h1: PiPrmProof, + pub(crate) composite_dlog_proof_base_h2: PiPrmProof, + pub(crate) ring_pedersen_pi_prm_statement: PiPrmStatement, + pub(crate) ring_pedersen_pi_prm_proof: PiPrmProof, + pub phantom: PhantomData<(E, H)>, } /// Generates the DlogStatement and CompositeProofs using the parameters /// generated by [generate_h1_h2_n_tilde] -fn generate_dlog_statement_proofs() -> FsDkrResult<( - CompositeDLogStatement, - CompositeDLogProof, - CompositeDLogProof, -)> { - let (n_tilde, h1, h2, xhi, xhi_inv, phi) = generate_h1_h2_N_tilde(); +fn generate_dlog_statement_proofs( +) -> FsDkrResult<(PiPrmStatement, PiPrmProof, PiPrmProof)> { + let (rpparam, rpwitness) = generate_safe_h1_h2_N_tilde(); - let dlog_statement_base_h1 = CompositeDLogStatement { - modulus: n_tilde.clone(), - base: h1.clone(), - value: h2.clone(), - }; - let dlog_witness_base_h1 = CompositeDLogWitness { - exponent: xhi, - totient: phi.clone(), - }; + let dlog_statement_base_h1 = PiPrmStatement::from(&rpparam); + let dlog_witness_base_h1 = PiPrmWitness::from(&rpwitness); - let dlog_statement_base_h2 = CompositeDLogStatement { - modulus: n_tilde, - base: h2, - value: h1, - }; - let dlog_witness_base_h2 = CompositeDLogWitness { - exponent: xhi_inv, - totient: phi.clone(), - }; + let dlog_statement_base_h2 = PiPrmStatement::inverse_from(&rpparam); + let dlog_witness_base_h2 = PiPrmWitness::inverse_from(&rpwitness); - let composite_dlog_proof_base_h1 = CompositeDLogProof::prove( - &dlog_statement_base_h1, - &dlog_witness_base_h1, - ) - .map_err(|_| FsDkrError::CompositeDLogProofGeneration)?; - let composite_dlog_proof_base_h2 = CompositeDLogProof::prove( - &dlog_statement_base_h2, - &dlog_witness_base_h2, - ) - .map_err(|_| FsDkrError::CompositeDLogProofGeneration)?; + let composite_dlog_proof_base_h1 = + PiPrmProof::prove(&dlog_statement_base_h1, &dlog_witness_base_h1) + .map_err(|_| FsDkrError::CompositeDLogProofGeneration)?; + let composite_dlog_proof_base_h2 = + PiPrmProof::prove(&dlog_statement_base_h2, &dlog_witness_base_h2) + .map_err(|_| FsDkrError::CompositeDLogProofGeneration)?; Ok(( dlog_statement_base_h1, @@ -105,7 +82,7 @@ fn generate_dlog_statement_proofs() -> FsDkrResult<( )) } -impl JoinMessage { +impl JoinMessage { pub fn set_party_index(&mut self, new_party_index: u16) { self.party_index = Some(new_party_index); } @@ -121,13 +98,12 @@ impl JoinMessage { composite_dlog_proof_base_h2, ) = generate_dlog_statement_proofs()?; - let (ring_pedersen_statement, ring_pedersen_witness) = - RingPedersenStatement::generate(); - - let ring_pedersen_proof = RingPedersenProof::prove( - &ring_pedersen_witness, - &ring_pedersen_statement, - ); + let (rpparam, rpwitness) = generate_safe_h1_h2_N_tilde(); + let pi_prm_statement = PiPrmStatement::from(&rpparam); + let pi_prm_witness = PiPrmWitness::from(&rpwitness); + let pi_prm_proof = + PiPrmProof::prove(&pi_prm_statement, &pi_prm_witness) + .map_err(|_| FsDkrError::RingPedersenProofError {})?; let join_message = JoinMessage { // in a join message, we only care about the ek and the correctness @@ -140,9 +116,10 @@ impl JoinMessage { dlog_statement, composite_dlog_proof_base_h1, composite_dlog_proof_base_h2, - ring_pedersen_statement, - ring_pedersen_proof, + ring_pedersen_pi_prm_statement: pi_prm_statement, + ring_pedersen_pi_prm_proof: pi_prm_proof, party_index: None, + phantom: PhantomData {}, }; Ok((join_message, paillier_key_pair)) @@ -162,9 +139,9 @@ impl JoinMessage { /// (multiple parties can be added/replaced at once). pub fn collect( &self, - refresh_messages: &[RefreshMessage], + refresh_messages: &[RefreshMessage], paillier_key: Keys, - join_messages: &[JoinMessage], + join_messages: &[JoinMessage], new_t: u16, new_n: u16, current_t: u16, @@ -172,29 +149,21 @@ impl JoinMessage { RefreshMessage::validate_collect(refresh_messages, current_t, new_n)?; for refresh_message in refresh_messages.iter() { - RingPedersenProof::verify( - &refresh_message.ring_pedersen_proof, - &refresh_message.ring_pedersen_statement, - ) - .map_err(|_| { - FsDkrError::RingPedersenProofValidation { + refresh_message + .ring_pedersen_pi_prm_proof + .verify(&refresh_message.ring_pedersen_pi_prm_statement) + .map_err(|_| FsDkrError::RingPedersenProofValidation { party_index: refresh_message.party_index, - } - })?; + })?; } for join_message in join_messages.iter() { - RingPedersenProof::verify( - &join_message.ring_pedersen_proof, - &join_message.ring_pedersen_statement, - ) - .map_err(|e| { - if let Some(party_index) = join_message.party_index { - FsDkrError::RingPedersenProofValidation { party_index } - } else { - e - } - })?; + join_message + .ring_pedersen_pi_prm_proof + .verify(&join_message.ring_pedersen_pi_prm_statement) + .map_err(|_| FsDkrError::RingPedersenProofValidation { + party_index: join_message.party_index.unwrap_or(0), + })?; } // check if a party_index has been assigned to the current party @@ -261,7 +230,7 @@ impl JoinMessage { // TODO: submit the statement the dlog proof as well! // check what parties are assigned in the current rotation and associate // their DLogStatements and check their CompositeDlogProofs. - let available_h1_h2_ntilde_vec: HashMap = + let available_h1_h2_ntilde_vec: HashMap = refresh_messages .iter() .map(|msg| (msg.party_index, &msg.dlog_statement)) @@ -289,7 +258,7 @@ impl JoinMessage { }) .collect(); // generate the DLogStatement vec needed for the LocalKey generation. - let mut h1_h2_ntilde_vec: Vec = + let mut h1_h2_ntilde_vec: Vec = Vec::with_capacity(new_n as usize); for party in 1..new_n + 1 { let statement = available_h1_h2_ntilde_vec.get(&party); diff --git a/fs-dkr/src/lib.rs b/fs-dkr/src/lib.rs index f98b985f..1215a167 100644 --- a/fs-dkr/src/lib.rs +++ b/fs-dkr/src/lib.rs @@ -18,7 +18,6 @@ pub mod add_party_message; pub mod error; pub mod range_proofs; pub mod refresh_message; -pub mod ring_pedersen_proof; pub mod zk_pdl_with_slack; mod test; diff --git a/fs-dkr/src/range_proofs.rs b/fs-dkr/src/range_proofs.rs index 30c5b0c3..175b7ffa 100644 --- a/fs-dkr/src/range_proofs.rs +++ b/fs-dkr/src/range_proofs.rs @@ -19,10 +19,10 @@ use curv::{ elliptic::curves::{Curve, Point, Scalar, Secp256k1}, BigInt, }; -use multi_party_ecdsa::utilities::zk_composite_dlog::CompositeDLogStatement; use paillier::{EncryptionKey, Randomness}; use serde::{Deserialize, Serialize}; use std::{borrow::Borrow, marker::PhantomData}; +use tss_core::zkproof::prm::PiPrmStatement; use zeroize::Zeroize; /// Represents the first round of the interactive version of the proof @@ -41,7 +41,7 @@ struct AliceZkpRound1 { impl AliceZkpRound1 { fn from( alice_ek: &EncryptionKey, - dlog_statement: &CompositeDLogStatement, + dlog_statement: &PiPrmStatement, a: &BigInt, q: &BigInt, ) -> Self { @@ -118,7 +118,7 @@ impl AliceProof { &self, cipher: &BigInt, alice_ek: &EncryptionKey, - dlog_statement: &CompositeDLogStatement, + dlog_statement: &PiPrmStatement, ) -> bool { let N = &alice_ek.n; let NN = &alice_ek.nn; @@ -178,7 +178,7 @@ impl AliceProof { a: &BigInt, cipher: &BigInt, alice_ek: &EncryptionKey, - dlog_statement: &CompositeDLogStatement, + dlog_statement: &PiPrmStatement, r: &BigInt, ) -> Self { let q = Scalar::::group_order(); @@ -257,7 +257,7 @@ impl BobZkpRound1 { /// `a_encrypted` - Alice's secret encrypted by Alice fn from( alice_ek: &EncryptionKey, - dlog_statement: &CompositeDLogStatement, + dlog_statement: &PiPrmStatement, b: &Scalar, beta_prim: &BigInt, a_encrypted: &BigInt, @@ -378,7 +378,7 @@ impl BobProof { a_enc: &BigInt, mta_avc_out: &BigInt, alice_ek: &EncryptionKey, - dlog_statement: &CompositeDLogStatement, + dlog_statement: &PiPrmStatement, check: Option<&BobCheck>, ) -> bool { let N = &alice_ek.n; @@ -474,7 +474,7 @@ impl BobProof { b: &Scalar, beta_prim: &BigInt, alice_ek: &EncryptionKey, - dlog_statement: &CompositeDLogStatement, + dlog_statement: &PiPrmStatement, r: &Randomness, check: bool, ) -> (BobProof, Option>) { @@ -552,7 +552,7 @@ impl BobProofExt { a_enc: &BigInt, mta_avc_out: &BigInt, alice_ek: &EncryptionKey, - dlog_statement: &CompositeDLogStatement, + dlog_statement: &PiPrmStatement, X: &Point, ) -> bool { // check basic proof first @@ -590,7 +590,7 @@ impl BobProofExt { b: &Scalar, beta_prim: &BigInt, alice_ek: &EncryptionKey, - dlog_statement: &CompositeDLogStatement, + dlog_statement: &PiPrmStatement, r: &Randomness, ) -> BobProofExt { // proving a basic proof (with modified hash) @@ -651,7 +651,7 @@ pub(crate) mod tests { type FE = Secp256k1Scalar; pub(crate) fn generate_init( - ) -> (CompositeDLogStatement, EncryptionKey, DecryptionKey) { + ) -> (PiPrmStatement, EncryptionKey, DecryptionKey) { let (ek_tilde, dk_tilde) = Paillier::keypair_with_modulus_size(crate::PAILLIER_KEY_SIZE) .keys(); @@ -670,7 +670,7 @@ pub(crate) mod tests { let (ek, dk) = Paillier::keypair_with_modulus_size(crate::PAILLIER_KEY_SIZE) .keys(); - let dlog_statement = CompositeDLogStatement { + let dlog_statement = PiPrmStatement { base: h1, value: h2, modulus: ek_tilde.n, diff --git a/fs-dkr/src/refresh_message.rs b/fs-dkr/src/refresh_message.rs index c6e21ad2..1985c83e 100644 --- a/fs-dkr/src/refresh_message.rs +++ b/fs-dkr/src/refresh_message.rs @@ -23,14 +23,15 @@ use serde::{Deserialize, Serialize}; use std::{borrow::Borrow, collections::HashMap, fmt::Debug}; use zeroize::Zeroize; use zk_paillier::zkproofs::{NiCorrectKeyProof, SALT_STRING}; -use multi_party_ecdsa::utilities::zk_composite_dlog::CompositeDLogStatement; - -use crate::ring_pedersen_proof::{RingPedersenProof, RingPedersenStatement}; +use tss_core::{ + utilities::generate_safe_h1_h2_N_tilde, + zkproof::prm::{PiPrmStatement, PiPrmWitness, PiPrmProof}, +}; // Everything here can be broadcasted #[derive(Debug, Clone, Deserialize, Serialize)] #[serde(bound = "E: Curve, H: Digest + Clone")] -pub struct RefreshMessage { +pub struct RefreshMessage { pub(crate) old_party_index: u16, pub(crate) party_index: u16, pdl_proof_vec: Vec>, @@ -39,23 +40,23 @@ pub struct RefreshMessage { pub(crate) points_committed_vec: Vec>, points_encrypted_vec: Vec, dk_correctness_proof: NiCorrectKeyProof, - pub(crate) dlog_statement: CompositeDLogStatement, + pub(crate) dlog_statement: PiPrmStatement, pub(crate) ek: EncryptionKey, pub(crate) remove_party_indices: Vec, pub(crate) public_key: Point, - pub(crate) ring_pedersen_statement: RingPedersenStatement, - pub(crate) ring_pedersen_proof: RingPedersenProof, + pub(crate) ring_pedersen_pi_prm_statement: PiPrmStatement, + pub(crate) ring_pedersen_pi_prm_proof: PiPrmProof, #[serde(skip)] pub hash_choice: HashChoice, } -impl RefreshMessage { +impl RefreshMessage { pub fn distribute( old_party_index: u16, local_key: &mut LocalKey, new_t: u16, new_n: u16, - ) -> FsDkrResult<(RefreshMessage, DecryptionKey)> { + ) -> FsDkrResult<(RefreshMessage, DecryptionKey)> { assert!(new_t <= new_n / 2); let secret = local_key.keys_linear.x_i.clone(); // secret share old key @@ -125,14 +126,13 @@ impl RefreshMessage { Paillier::keypair_with_modulus_size(crate::PAILLIER_KEY_SIZE) .keys(); let dk_correctness_proof = NiCorrectKeyProof::proof(&dk, None); + let (rpparam, rpwitness) = generate_safe_h1_h2_N_tilde(); + let pi_prm_statement = PiPrmStatement::from(&rpparam); + let pi_prm_witness = PiPrmWitness::from(&rpwitness); + let pi_prm_proof = + PiPrmProof::prove(&pi_prm_statement, &pi_prm_witness) + .map_err(|_| FsDkrError::RingPedersenProofError {})?; - let (ring_pedersen_statement, ring_pedersen_witness) = - RingPedersenStatement::generate(); - - let ring_pedersen_proof = RingPedersenProof::prove( - &ring_pedersen_witness, - &ring_pedersen_statement, - ); Ok(( RefreshMessage { old_party_index, @@ -149,8 +149,8 @@ impl RefreshMessage { ek, remove_party_indices: Vec::new(), public_key: local_key.y_sum_s.clone(), - ring_pedersen_statement, - ring_pedersen_proof, + ring_pedersen_pi_prm_statement: pi_prm_statement, + ring_pedersen_pi_prm_proof: pi_prm_proof, hash_choice: HashChoice::new(), }, dk, @@ -263,7 +263,7 @@ impl RefreshMessage { } pub fn replace( - new_parties: &[JoinMessage], + new_parties: &[JoinMessage], key: &mut LocalKey, old_to_new_map: &HashMap, new_t: u16, @@ -272,7 +272,7 @@ impl RefreshMessage { let current_len = key.paillier_key_vec.len() as u16; let mut paillier_key_h1_h2_n_tilde_hash_map: HashMap< u16, - (EncryptionKey, CompositeDLogStatement), + (EncryptionKey, PiPrmStatement), > = HashMap::new(); for old_party_index in old_to_new_map.keys() { let paillier_key = key @@ -355,7 +355,7 @@ impl RefreshMessage { refresh_messages: &[Self], local_key: &mut LocalKey, new_dk: DecryptionKey, - join_messages: &[JoinMessage], + join_messages: &[JoinMessage], current_t: u16, ) -> FsDkrResult<()> { let new_n = refresh_messages.len() + join_messages.len(); @@ -389,17 +389,21 @@ impl RefreshMessage { // Verify ring-pedersen parameters for refresh_message in refresh_messages.iter() { - RingPedersenProof::verify( - &refresh_message.ring_pedersen_proof, - &refresh_message.ring_pedersen_statement, - )?; + refresh_message + .ring_pedersen_pi_prm_proof + .verify(&refresh_message.ring_pedersen_pi_prm_statement) + .map_err(|_| FsDkrError::RingPedersenProofValidation { + party_index: refresh_message.party_index, + })?; } for join_message in join_messages.iter() { - RingPedersenProof::verify( - &join_message.ring_pedersen_proof, - &join_message.ring_pedersen_statement, - )?; + join_message + .ring_pedersen_pi_prm_proof + .verify(&join_message.ring_pedersen_pi_prm_statement) + .map_err(|_| FsDkrError::RingPedersenProofValidation { + party_index: join_message.party_index.unwrap_or(0), + })?; } let old_ek = @@ -452,7 +456,7 @@ impl RefreshMessage { } // creating an inverse dlog statement - let dlog_statement_base_h2 = CompositeDLogStatement { + let dlog_statement_base_h2 = PiPrmStatement { modulus: join_message.dlog_statement.modulus.clone(), // Base and value are swapped because we're using h1's statement. base: join_message.dlog_statement.value.clone(), diff --git a/fs-dkr/src/ring_pedersen_proof.rs b/fs-dkr/src/ring_pedersen_proof.rs deleted file mode 100644 index ccb81fd3..00000000 --- a/fs-dkr/src/ring_pedersen_proof.rs +++ /dev/null @@ -1,186 +0,0 @@ -#![allow(non_snake_case)] - -/* - Ring Pedersen Proof - Copyright 2022 by Webb Technologies. - - ring_pedersen_proof.rs 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+ -*/ - -use bitvec::prelude::*; -use curv::{ - arithmetic::traits::*, - cryptographic_primitives::hashing::{Digest, DigestExt}, - elliptic::curves::Curve, - BigInt, -}; -use paillier::{EncryptionKey, KeyGeneration, Paillier}; -use serde::{Deserialize, Serialize}; -use std::marker::PhantomData; - -use crate::error::{FsDkrError, FsDkrResult}; - -#[derive(Clone, Debug, Serialize, Deserialize)] -#[serde(bound = "E: Curve, H: Digest + Clone")] -pub struct RingPedersenStatement { - pub S: BigInt, - pub T: BigInt, - pub N: BigInt, - phi: BigInt, - pub ek: EncryptionKey, - #[serde(skip)] - phantom: PhantomData<(E, H)>, -} - -pub struct RingPedersenWitness { - p: BigInt, - q: BigInt, - lambda: BigInt, - phantom: PhantomData<(E, H)>, -} - -impl RingPedersenStatement { - pub fn generate() -> (Self, RingPedersenWitness) { - let (ek_tilde, dk_tilde) = - Paillier::keypair_with_modulus_size(crate::PAILLIER_KEY_SIZE) - .keys(); - let one = BigInt::one(); - let phi = (&dk_tilde.p - &one) * (&dk_tilde.q - &one); - let r = BigInt::sample_below(&ek_tilde.n); - let lambda = BigInt::sample_below(&phi); - let t = BigInt::mod_pow(&r, &BigInt::from(2), &ek_tilde.n); - let s = BigInt::mod_pow(&t, &lambda, &ek_tilde.n); - - ( - Self { - S: s, - T: t, - N: ek_tilde.clone().n, - phi, - ek: ek_tilde, - phantom: PhantomData, - }, - RingPedersenWitness { - p: dk_tilde.p, - q: dk_tilde.q, - lambda, - phantom: PhantomData, - }, - ) - } -} - -#[derive(Clone, Debug, Serialize, Deserialize)] -#[serde(bound = "E: Curve, H: Digest + Clone")] -pub struct RingPedersenProof { - A: Vec, - Z: Vec, - #[serde(skip)] - phantom: PhantomData<(E, H)>, -} - -// Link to the UC non-interactive threshold ECDSA paper -impl RingPedersenProof { - pub fn prove( - witness: &RingPedersenWitness, - statement: &RingPedersenStatement, - ) -> RingPedersenProof { - // 1. Sample alphas from 1 -> m from \phi(N) - let mut a = [(); M].map(|_| BigInt::zero()); - let mut A = [(); M].map(|_| BigInt::zero()); - let mut hash = H::new(); - for i in 0..M { - // TODO: Consider ensuring we get a unit element of this subgroup - let a_i = BigInt::sample_below(&statement.phi); - a[i] = a_i.clone(); - let A_i = BigInt::mod_pow(&statement.T, &a_i, &statement.N); - A[i] = A_i.clone(); - hash = H::chain_bigint(hash, &A_i); - } - - let e: BigInt = hash.result_bigint(); - let bitwise_e: BitVec = BitVec::from_vec(e.to_bytes()); - - let mut Z = [(); M].map(|_| BigInt::zero()); - for i in 0..M { - let e_i = if bitwise_e[i] { - BigInt::one() - } else { - BigInt::zero() - }; - let z_i = BigInt::mod_add( - &a[i], - &(e_i * &witness.lambda), - &statement.phi, - ); - Z[i] = z_i; - } - - Self { - A: A.to_vec(), - Z: Z.to_vec(), - phantom: PhantomData, - } - } - - pub fn verify( - proof: &RingPedersenProof, - statement: &RingPedersenStatement, - ) -> FsDkrResult<()> { - let mut hash = H::new(); - for i in 0..M { - hash = H::chain_bigint(hash, &proof.A[i]); - } - - let e: BigInt = hash.result_bigint(); - let bitwise_e: BitVec = BitVec::from_vec(e.to_bytes()); - - for i in 0..M { - let mut e_i = 0; - if bitwise_e[i] { - e_i = 1; - } - - if BigInt::mod_pow(&statement.T, &proof.Z[i], &statement.N) - == BigInt::mod_mul( - &proof.A[i], - &BigInt::mod_pow( - &statement.S, - &BigInt::from(e_i), - &statement.N, - ), - &statement.N, - ) - { - continue; - } else { - return Err(FsDkrError::RingPedersenProofError); - } - } - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use curv::elliptic::curves::secp256_k1::Secp256k1; - use sha2::Sha256; - - #[test] - fn test_ring_pedersen() { - let (statement, witness) = - RingPedersenStatement::::generate(); - let proof = RingPedersenProof::::prove( - &witness, &statement, - ); - assert!(RingPedersenProof::::verify( - &proof, &statement - ) - .is_ok()); - } -} diff --git a/fs-dkr/src/test.rs b/fs-dkr/src/test.rs index 0e744033..2cf28998 100644 --- a/fs-dkr/src/test.rs +++ b/fs-dkr/src/test.rs @@ -39,7 +39,7 @@ mod tests { let mut keys = simulate_keygen(t, n); let old_keys = keys.clone(); - simulate_dkr::<{ crate::M_SECURITY }>(&mut keys, None); + simulate_dkr(&mut keys, None); // check that sum of old keys is equal to sum of new keys let old_linear_secret_key: Vec<_> = (0..old_keys.len()) @@ -78,10 +78,10 @@ mod tests { let mut keys = simulate_keygen(2, 5); let offline_sign = simulate_offline_stage(keys.clone(), &[1, 2, 3]); simulate_signing(offline_sign, b"ZenGo"); - simulate_dkr::<{ crate::M_SECURITY }>(&mut keys, None); + simulate_dkr(&mut keys, None); let offline_sign = simulate_offline_stage(keys.clone(), &[2, 3, 4]); simulate_signing(offline_sign, b"ZenGo"); - simulate_dkr::<{ crate::M_SECURITY }>(&mut keys, None); + simulate_dkr(&mut keys, None); let offline_sign = simulate_offline_stage(keys, &[1, 3, 5]); simulate_signing(offline_sign, b"ZenGo"); } @@ -91,35 +91,26 @@ mod tests { let mut keys = simulate_keygen(2, 5); let offline_sign = simulate_offline_stage(keys.clone(), &[1, 2, 3]); simulate_signing(offline_sign, b"ZenGo"); - simulate_dkr_removal::<{ crate::M_SECURITY }>( - &mut keys, - [1].to_vec(), - None, - ); + simulate_dkr_removal(&mut keys, [1].to_vec(), None); let offline_sign = simulate_offline_stage(keys.clone(), &[2, 3, 4]); simulate_signing(offline_sign, b"ZenGo"); - simulate_dkr_removal::<{ crate::M_SECURITY }>( - &mut keys, - [1, 2].to_vec(), - None, - ); + simulate_dkr_removal(&mut keys, [1, 2].to_vec(), None); let offline_sign = simulate_offline_stage(keys, &[3, 4, 5]); simulate_signing(offline_sign, b"ZenGo"); } #[test] fn test_add_party_with_permute() { - fn simulate_replace( + fn simulate_replace( keys: &mut Vec>, party_indices: &[u16], old_to_new_map: &HashMap, t: u16, n: u16, ) -> FsDkrResult<()> { - fn generate_join_messages_and_keys( + fn generate_join_messages_and_keys( number_of_new_parties: usize, - ) -> (Vec>, Vec) - { + ) -> (Vec>, Vec) { // the new party generates it's join message to start joining // the computation (0..number_of_new_parties) @@ -127,14 +118,12 @@ mod tests { .unzip() } - fn generate_refresh_parties_replace( + fn generate_refresh_parties_replace( keys: &mut [LocalKey], old_to_new_map: &HashMap, - join_messages: &[JoinMessage], - ) -> ( - Vec>, - Vec, - ) { + join_messages: &[JoinMessage], + ) -> (Vec>, Vec) + { let new_n = (&keys.len() + join_messages.len()) as u16; keys.iter_mut() .map(|key| { @@ -153,9 +142,7 @@ mod tests { // each party that wants to join generates a join message and a pair // of paillier keys. let (mut join_messages, new_keys) = - generate_join_messages_and_keys::<{ crate::M_SECURITY }>( - party_indices.len(), - ); + generate_join_messages_and_keys(party_indices.len()); // each new party has to be informed through offchannel // communication what party index it has been assigned @@ -229,14 +216,7 @@ mod tests { old_to_new_map.insert(6, 5); // Simulate the replace - simulate_replace::<{ crate::M_SECURITY }>( - &mut keys, - &[2, 7], - &old_to_new_map, - t, - n, - ) - .unwrap(); + simulate_replace(&mut keys, &[2, 7], &old_to_new_map, t, n).unwrap(); // check that sum of old keys is equal to sum of new keys let old_linear_secret_key: Vec<_> = (0..all_keys.len()) .map(|i| all_keys[i].keys_linear.x_i.clone()) @@ -278,11 +258,11 @@ mod tests { let offline_sign = simulate_offline_stage(keys.clone(), &[1, 2, 3]); simulate_signing(offline_sign, b"ZenGo"); // Change threshold to 1 (i.e quorum size = 2). - simulate_dkr::<{ crate::M_SECURITY }>(&mut keys, Some(1)); + simulate_dkr(&mut keys, Some(1)); let offline_sign = simulate_offline_stage(keys.clone(), &[3, 4]); simulate_signing(offline_sign, b"ZenGo"); // Change threshold to back to 2 (i.e quorum size = 3). - simulate_dkr::<{ crate::M_SECURITY }>(&mut keys, Some(2)); + simulate_dkr(&mut keys, Some(2)); let offline_sign = simulate_offline_stage(keys, &[1, 3, 5]); simulate_signing(offline_sign, b"ZenGo"); } @@ -299,17 +279,17 @@ mod tests { simulation.run().unwrap() } - fn simulate_dkr_removal( + fn simulate_dkr_removal( keys: &mut Vec>, remove_party_indices: Vec, new_t_option: Option, ) { let mut broadcast_messages: HashMap< usize, - Vec>, + Vec>, > = HashMap::new(); let mut new_dks: HashMap = HashMap::new(); - let mut refresh_messages: Vec> = + let mut refresh_messages: Vec> = Vec::new(); let mut party_key: HashMap> = HashMap::new(); // TODO: Verify this is correct @@ -389,14 +369,11 @@ mod tests { } } - fn simulate_dkr( + fn simulate_dkr( keys: &mut Vec>, new_t_option: Option, - ) -> ( - Vec>, - Vec, - ) { - let mut broadcast_vec: Vec> = + ) -> (Vec>, Vec) { + let mut broadcast_vec: Vec> = Vec::new(); let mut new_dks: Vec = Vec::new(); let keys_len = keys.len(); diff --git a/multi-party-ecdsa/Cargo.toml b/multi-party-ecdsa/Cargo.toml index 00befa25..918af85a 100644 --- a/multi-party-ecdsa/Cargo.toml +++ b/multi-party-ecdsa/Cargo.toml @@ -37,6 +37,7 @@ zk-paillier.workspace = true sha2.workspace = true paillier.workspace = true round-based.workspace = true +tss-core.workspace = true thiserror.workspace = true serde.workspace = true zeroize.workspace = true diff --git a/multi-party-ecdsa/src/gg_2020/party_i.rs b/multi-party-ecdsa/src/gg_2020/party_i.rs index ce1e94cd..ce143c59 100644 --- a/multi-party-ecdsa/src/gg_2020/party_i.rs +++ b/multi-party-ecdsa/src/gg_2020/party_i.rs @@ -47,18 +47,19 @@ use zk_paillier::zkproofs::NiCorrectKeyProof; use crate::{ protocols::multi_party_ecdsa::gg_2020::ErrorType, - utilities::zk_composite_dlog::{ - CompositeDLogProof, CompositeDLogStatement, - }, utilities::zk_pdl_with_slack::{ PDLwSlackProof, PDLwSlackStatement, PDLwSlackWitness, }, }; use curv::cryptographic_primitives::proofs::sigma_valid_pedersen::PedersenProof; -use crate::utilities::zk_composite_dlog::CompositeDLogWitness; use std::convert::TryInto; +use tss_core::{ + utilities::{generate_normal_h1_h2_N_tilde, generate_safe_h1_h2_N_tilde}, + zkproof::prm::{PiPrmProof, PiPrmStatement, PiPrmWitness}, +}; + const SECURITY: usize = 256; const PAILLIER_MIN_BIT_LENGTH: usize = 2047; const PAILLIER_MAX_BIT_LENGTH: usize = 2048; @@ -94,11 +95,11 @@ pub struct PartyPrivate { #[derive(Clone, Debug, Serialize, Deserialize)] pub struct KeyGenBroadcastMessage1 { pub e: EncryptionKey, - pub dlog_statement: CompositeDLogStatement, + pub dlog_statement: PiPrmStatement, pub com: BigInt, pub correct_key_proof: NiCorrectKeyProof, - pub composite_dlog_proof_base_h1: CompositeDLogProof, - pub composite_dlog_proof_base_h2: CompositeDLogProof, + pub composite_dlog_proof_base_h1: PiPrmProof, + pub composite_dlog_proof_base_h2: PiPrmProof, } #[derive(Clone, Debug, Serialize, Deserialize)] @@ -149,40 +150,12 @@ pub struct SignatureRecid { pub recid: u8, } -pub fn generate_h1_h2_N_tilde( -) -> (BigInt, BigInt, BigInt, BigInt, BigInt, BigInt) { - // Uses safe primes in production. - #[cfg(all(not(test), not(feature = "dev")))] - let (ek_tilde, dk_tilde) = Paillier::keypair_safe_primes().keys(); - // Doesn't use safe primes in tests (for speed). - #[cfg(any(test, feature = "dev"))] - let (ek_tilde, dk_tilde) = Paillier::keypair().keys(); - - // Generate h1 and h2 (s and t in CGGMP20) following section 6.4.1 (and Figure 6) of CGGMP20 . - // Ref: . - let one = BigInt::one(); - let phi = (&dk_tilde.p - &one) * (&dk_tilde.q - &one); - let tau = BigInt::sample_below(&ek_tilde.n); - let h1 = BigInt::mod_pow(&tau, &BigInt::from(2), &ek_tilde.n); - // For GG18/20 implementation, we need the inverse of lambda as well. - let (lambda, lambda_inv) = loop { - let lambda_ = BigInt::sample_below(&phi); - match BigInt::mod_inv(&lambda_, &phi) { - Some(inv) => break (lambda_, inv), - None => continue, - } - }; - let h2 = BigInt::mod_pow(&h1, &lambda, &ek_tilde.n); - - (ek_tilde.n, h1, h2, lambda, lambda_inv, phi) -} - impl Keys { pub fn create(index: usize) -> Self { let u = Scalar::::random(); let y = Point::generator() * &u; let (ek, dk) = Paillier::keypair().keys(); - let (N_tilde, h1, h2, xhi, xhi_inv, phi) = generate_h1_h2_N_tilde(); + let (rpparam, rpwitness) = generate_safe_h1_h2_N_tilde(); Self { u_i: u, @@ -190,12 +163,12 @@ impl Keys { dk, ek, party_index: index, - N_tilde, - h1, - h2, - xhi, - xhi_inv, - phi, + N_tilde: rpparam.N, + h1: rpparam.s, + h2: rpparam.t, + xhi: rpwitness.lambda, + xhi_inv: rpwitness.lambdaInv, + phi: rpwitness.phi, } } @@ -205,7 +178,7 @@ impl Keys { let y = Point::generator() * &u; let (ek, dk) = Paillier::keypair_safe_primes().keys(); - let (N_tilde, h1, h2, xhi, xhi_inv, phi) = generate_h1_h2_N_tilde(); + let (rpparam, rpwitness) = generate_safe_h1_h2_N_tilde(); Self { u_i: u, @@ -213,18 +186,18 @@ impl Keys { dk, ek, party_index: index, - N_tilde, - h1, - h2, - xhi, - xhi_inv, - phi, + N_tilde: rpparam.N, + h1: rpparam.s, + h2: rpparam.t, + xhi: rpwitness.lambda, + xhi_inv: rpwitness.lambdaInv, + phi: rpwitness.phi, } } pub fn create_from(u: Scalar, index: usize) -> Self { let y = Point::generator() * &u; let (ek, dk) = Paillier::keypair().keys(); - let (N_tilde, h1, h2, xhi, xhi_inv, phi) = generate_h1_h2_N_tilde(); + let (rpparam, rpwitness) = generate_normal_h1_h2_N_tilde(); Self { u_i: u, @@ -232,12 +205,12 @@ impl Keys { dk, ek, party_index: index, - N_tilde, - h1, - h2, - xhi, - xhi_inv, - phi, + N_tilde: rpparam.N, + h1: rpparam.s, + h2: rpparam.t, + xhi: rpwitness.lambda, + xhi_inv: rpwitness.lambdaInv, + phi: rpwitness.phi, } } @@ -248,22 +221,22 @@ impl Keys { let blind_factor = BigInt::sample(SECURITY); let correct_key_proof = NiCorrectKeyProof::proof(&self.dk, None); - let dlog_statement_base_h1 = CompositeDLogStatement { + let dlog_statement_base_h1 = PiPrmStatement { modulus: self.N_tilde.clone(), base: self.h1.clone(), value: self.h2.clone(), }; - let dlog_witness_base_h1 = CompositeDLogWitness { + let dlog_witness_base_h1 = PiPrmWitness { exponent: self.xhi.clone(), totient: self.phi.clone(), }; - let dlog_statement_base_h2 = CompositeDLogStatement { + let dlog_statement_base_h2 = PiPrmStatement { modulus: self.N_tilde.clone(), base: self.h2.clone(), value: self.h1.clone(), }; - let dlog_witness_base_h2 = CompositeDLogWitness { + let dlog_witness_base_h2 = PiPrmWitness { exponent: self.xhi_inv.clone(), totient: self.phi.clone(), }; @@ -273,16 +246,12 @@ impl Keys { bad_actors: vec![], data: vec![], }; - let composite_dlog_proof_base_h1 = CompositeDLogProof::prove( - &dlog_statement_base_h1, - &dlog_witness_base_h1, - ) - .map_err(|_| dlog_proof_error.clone())?; - let composite_dlog_proof_base_h2 = CompositeDLogProof::prove( - &dlog_statement_base_h2, - &dlog_witness_base_h2, - ) - .map_err(|_| dlog_proof_error)?; + let composite_dlog_proof_base_h1 = + PiPrmProof::prove(&dlog_statement_base_h1, &dlog_witness_base_h1) + .map_err(|_| dlog_proof_error.clone())?; + let composite_dlog_proof_base_h2 = + PiPrmProof::prove(&dlog_statement_base_h2, &dlog_witness_base_h2) + .map_err(|_| dlog_proof_error)?; let com = HashCommitment::::create_commitment_with_user_defined_randomness( &BigInt::from_bytes(self.y_i.to_bytes(true).as_ref()), @@ -320,7 +289,7 @@ impl Keys { // decommitments let correct_key_correct_decom_all = (0..bc1_vec.len()) .map(|i| { - let dlog_statement_base_h2 = CompositeDLogStatement { + let dlog_statement_base_h2 = PiPrmStatement { modulus: bc1_vec[i].dlog_statement.modulus.clone(), // Base and value are swapped because we're using h1's statement. base: bc1_vec[i].dlog_statement.value.clone(), @@ -578,7 +547,7 @@ impl PartyPrivate { let y = Point::generator() * &u; let (ek, dk) = Paillier::keypair().keys(); - let (N_tilde, h1, h2, xhi, xhi_inv, phi) = generate_h1_h2_N_tilde(); + let (rpparam, rpwitness) = generate_normal_h1_h2_N_tilde(); Keys { u_i: u, @@ -586,12 +555,12 @@ impl PartyPrivate { dk, ek, party_index: index, - N_tilde, - h1, - h2, - xhi, - xhi_inv, - phi, + N_tilde: rpparam.N, + h1: rpparam.s, + h2: rpparam.t, + xhi: rpwitness.lambda, + xhi_inv: rpwitness.lambdaInv, + phi: rpwitness.phi, } } @@ -605,7 +574,7 @@ impl PartyPrivate { let y = Point::generator() * &u; let (ek, dk) = Paillier::keypair_safe_primes().keys(); - let (N_tilde, h1, h2, xhi, xhi_inv, phi) = generate_h1_h2_N_tilde(); + let (rpparam, rpwitness) = generate_safe_h1_h2_N_tilde(); Keys { u_i: u, @@ -613,12 +582,12 @@ impl PartyPrivate { dk, ek, party_index: index, - N_tilde, - h1, - h2, - xhi, - xhi_inv, - phi, + N_tilde: rpparam.N, + h1: rpparam.s, + h2: rpparam.t, + xhi: rpwitness.lambda, + xhi_inv: rpwitness.lambdaInv, + phi: rpwitness.phi, } } @@ -830,7 +799,7 @@ impl LocalSignature { ek: &EncryptionKey, k_i: &Scalar, k_enc_randomness: &BigInt, - dlog_statement: &CompositeDLogStatement, + dlog_statement: &PiPrmStatement, ) -> PDLwSlackProof { // Generate PDL with slack statement, witness and proof let pdl_w_slack_statement = PDLwSlackStatement { @@ -857,7 +826,7 @@ impl LocalSignature { R: &Point, k_ciphertext: &BigInt, ek: &EncryptionKey, - dlog_statement: &[CompositeDLogStatement], + dlog_statement: &[PiPrmStatement], s: &[usize], i: usize, ) -> Result<(), ErrorType> { diff --git a/multi-party-ecdsa/src/gg_2020/state_machine/keygen/rounds.rs b/multi-party-ecdsa/src/gg_2020/state_machine/keygen/rounds.rs index d7470ead..f4283dad 100644 --- a/multi-party-ecdsa/src/gg_2020/state_machine/keygen/rounds.rs +++ b/multi-party-ecdsa/src/gg_2020/state_machine/keygen/rounds.rs @@ -25,7 +25,7 @@ use crate::protocols::multi_party_ecdsa::gg_2020::{ party_i::{KeyGenBroadcastMessage1, KeyGenDecommitMessage1, Keys}, ErrorType, VerifiableSS, }; -use crate::utilities::zk_composite_dlog::CompositeDLogStatement; +use tss_core::zkproof::prm::PiPrmStatement; pub struct Round0 { pub party_i: u16, @@ -316,7 +316,7 @@ impl Round4 { .bc_vec .iter() .map(|bc1| bc1.dlog_statement.clone()) - .collect::>(); + .collect::>(); let (head, tail) = self.y_vec.split_at(1); let y_sum = tail.iter().fold(head[0].clone(), |acc, x| acc + x); @@ -359,7 +359,7 @@ pub struct LocalKey { pub keys_linear: gg_2020::party_i::SharedKeys, pub paillier_key_vec: Vec, pub y_sum_s: Point, - pub h1_h2_n_tilde_vec: Vec, + pub h1_h2_n_tilde_vec: Vec, pub vss_scheme: VerifiableSS, pub i: u16, pub t: u16, diff --git a/multi-party-ecdsa/src/gg_2020/test.rs b/multi-party-ecdsa/src/gg_2020/test.rs index 059a1184..a6aa317d 100644 --- a/multi-party-ecdsa/src/gg_2020/test.rs +++ b/multi-party-ecdsa/src/gg_2020/test.rs @@ -33,7 +33,6 @@ use curv::arithmetic::traits::Converter; use crate::{ protocols::multi_party_ecdsa::gg_2020::ErrorType, - utilities::zk_composite_dlog::CompositeDLogStatement, utilities::zk_pdl_with_slack::PDLwSlackProof, }; use curv::{ @@ -45,6 +44,7 @@ use curv::{ }; use paillier::*; use sha2::Sha256; +use tss_core::zkproof::prm::PiPrmStatement; #[test] fn test_keygen_t1_n2() { @@ -167,7 +167,7 @@ fn keygen_t_n_parties( Point, VerifiableSS, Vec, - Vec, + Vec, ), ErrorType, > { @@ -190,7 +190,7 @@ fn keygen_t_n_parties( let h1_h2_N_tilde_vec = bc1_vec .iter() .map(|bc1| bc1.dlog_statement.clone()) - .collect::>(); + .collect::>(); let y_vec = (0..n) .map(|i| decom_vec[i].y_i.clone()) .collect::>>(); @@ -340,7 +340,7 @@ fn sign( // for simplicity let signers_dlog_statements = (0..ttag) .map(|i| dlog_statement_vec[s[i]].clone()) - .collect::>(); + .collect::>(); // each party i BROADCASTS encryption of k_i under her Paillier key // m_a_vec = [ma_0;ma_1;,...] diff --git a/multi-party-ecdsa/src/utilities/mod.rs b/multi-party-ecdsa/src/utilities/mod.rs index 40fe8bcf..867fce30 100644 --- a/multi-party-ecdsa/src/utilities/mod.rs +++ b/multi-party-ecdsa/src/utilities/mod.rs @@ -1,4 +1,3 @@ pub mod mta; -pub mod zk_composite_dlog; pub mod zk_pdl; pub mod zk_pdl_with_slack; diff --git a/multi-party-ecdsa/src/utilities/mta/mod.rs b/multi-party-ecdsa/src/utilities/mta/mod.rs index 1edf0675..d6d22523 100644 --- a/multi-party-ecdsa/src/utilities/mta/mod.rs +++ b/multi-party-ecdsa/src/utilities/mta/mod.rs @@ -32,9 +32,9 @@ use sha2::Sha256; use crate::{ protocols::multi_party_ecdsa::gg_2020::party_i::PartyPrivate, utilities::mta::range_proofs::AliceProof, - utilities::zk_composite_dlog::CompositeDLogStatement, Error::{self, InvalidKey}, }; +use tss_core::zkproof::prm::PiPrmStatement; #[derive(Clone, Debug, Serialize, Deserialize)] pub struct MessageA { @@ -61,7 +61,7 @@ impl MessageA { pub fn a( a: &Scalar, alice_ek: &EncryptionKey, - dlog_statements: &[CompositeDLogStatement], + dlog_statements: &[PiPrmStatement], ) -> (Self, BigInt) { let randomness = BigInt::sample_below(&alice_ek.n); let m_a = MessageA::a_with_predefined_randomness( @@ -77,7 +77,7 @@ impl MessageA { a: &Scalar, alice_ek: &EncryptionKey, randomness: &BigInt, - dlog_statements: &[CompositeDLogStatement], + dlog_statements: &[PiPrmStatement], ) -> Self { let c_a = Paillier::encrypt_with_chosen_randomness( alice_ek, @@ -112,7 +112,7 @@ impl MessageB { b: &Scalar, alice_ek: &EncryptionKey, m_a: MessageA, - dlog_statements: &[CompositeDLogStatement], + dlog_statements: &[PiPrmStatement], ) -> Result<(Self, Scalar, BigInt, BigInt), Error> { let beta_tag = BigInt::sample_below(&alice_ek.n); let randomness = BigInt::sample_below(&alice_ek.n); @@ -134,7 +134,7 @@ impl MessageB { m_a: MessageA, randomness: &BigInt, beta_tag: &BigInt, - dlog_statements: &[CompositeDLogStatement], + dlog_statements: &[PiPrmStatement], ) -> Result<(Self, Scalar), Error> { if m_a.range_proofs.len() != dlog_statements.len() { return Err(InvalidKey); diff --git a/multi-party-ecdsa/src/utilities/mta/range_proofs.rs b/multi-party-ecdsa/src/utilities/mta/range_proofs.rs index e96508c8..ab87ce85 100644 --- a/multi-party-ecdsa/src/utilities/mta/range_proofs.rs +++ b/multi-party-ecdsa/src/utilities/mta/range_proofs.rs @@ -25,7 +25,7 @@ use serde::{Deserialize, Serialize}; use std::borrow::Borrow; use zeroize::Zeroize; -use crate::utilities::zk_composite_dlog::CompositeDLogStatement; +use tss_core::zkproof::prm::PiPrmStatement; /// Represents the first round of the interactive version of the proof #[derive(Zeroize)] @@ -43,7 +43,7 @@ struct AliceZkpRound1 { impl AliceZkpRound1 { fn from( alice_ek: &EncryptionKey, - dlog_statement: &CompositeDLogStatement, + dlog_statement: &PiPrmStatement, a: &BigInt, q: &BigInt, ) -> Self { @@ -115,7 +115,7 @@ impl AliceProof { &self, cipher: &BigInt, alice_ek: &EncryptionKey, - dlog_statement: &CompositeDLogStatement, + dlog_statement: &PiPrmStatement, ) -> bool { let N = &alice_ek.n; let NN = &alice_ek.nn; @@ -174,7 +174,7 @@ impl AliceProof { a: &BigInt, cipher: &BigInt, alice_ek: &EncryptionKey, - dlog_statement: &CompositeDLogStatement, + dlog_statement: &PiPrmStatement, r: &BigInt, ) -> Self { let round1 = AliceZkpRound1::from( @@ -230,7 +230,7 @@ impl BobZkpRound1 { /// `a_encrypted` - Alice's secret encrypted by Alice fn from( alice_ek: &EncryptionKey, - dlog_statement: &CompositeDLogStatement, + dlog_statement: &PiPrmStatement, b: &Scalar, beta_prim: &BigInt, a_encrypted: &BigInt, @@ -343,7 +343,7 @@ impl BobProof { a_enc: &BigInt, mta_avc_out: &BigInt, alice_ek: &EncryptionKey, - dlog_statement: &CompositeDLogStatement, + dlog_statement: &PiPrmStatement, check: Option<&BobCheck>, ) -> bool { let N = &alice_ek.n; @@ -444,7 +444,7 @@ impl BobProof { b: &Scalar, beta_prim: &BigInt, alice_ek: &EncryptionKey, - dlog_statement: &CompositeDLogStatement, + dlog_statement: &PiPrmStatement, r: &Randomness, check: bool, ) -> (BobProof, Option>) { @@ -528,7 +528,7 @@ impl BobProofExt { a_enc: &BigInt, mta_avc_out: &BigInt, alice_ek: &EncryptionKey, - dlog_statement: &CompositeDLogStatement, + dlog_statement: &PiPrmStatement, X: &Point, ) -> bool { // check basic proof first @@ -597,7 +597,7 @@ pub(crate) mod tests { b: &Scalar, beta_prim: &BigInt, alice_ek: &EncryptionKey, - dlog_statement: &CompositeDLogStatement, + dlog_statement: &PiPrmStatement, r: &Randomness, ) -> BobProofExt { // proving a basic proof (with modified hash) @@ -619,7 +619,7 @@ pub(crate) mod tests { } pub(crate) fn generate_init( - ) -> (CompositeDLogStatement, EncryptionKey, DecryptionKey) { + ) -> (PiPrmStatement, EncryptionKey, DecryptionKey) { let (ek_tilde, dk_tilde) = Paillier::keypair().keys(); let one = BigInt::one(); let phi = (&dk_tilde.p - &one) * (&dk_tilde.q - &one); @@ -634,7 +634,7 @@ pub(crate) mod tests { let h2 = BigInt::mod_pow(&h1, &xhi, &ek_tilde.n); let (ek, dk) = Paillier::keypair().keys(); - let dlog_statement = CompositeDLogStatement { + let dlog_statement = PiPrmStatement { base: h1, value: h2, modulus: ek_tilde.n, diff --git a/src/party_i.rs b/src/party_i.rs index 43244602..33358e51 100644 --- a/src/party_i.rs +++ b/src/party_i.rs @@ -57,9 +57,9 @@ pub use crate::mpc_ecdsa::{ PDLwSlackProof, PDLwSlackStatement, PDLwSlackWitness, }, }; -use multi_party_ecdsa::gg_2020::party_i::generate_h1_h2_N_tilde; -use multi_party_ecdsa::utilities::zk_composite_dlog::{ - CompositeDLogProof, CompositeDLogStatement, CompositeDLogWitness, +use tss_core::{ + utilities::{generate_normal_h1_h2_N_tilde, generate_safe_h1_h2_N_tilde}, + zkproof::prm::{PiPrmProof, PiPrmStatement, PiPrmWitness}, }; const SECURITY: usize = 256; @@ -136,7 +136,7 @@ impl Keys { let u = Scalar::::random(); let y = Point::generator() * &u; let (ek, dk) = Paillier::keypair().keys(); - let (N_tilde, h1, h2, xhi, xhi_inv, phi) = generate_h1_h2_N_tilde(); + let (rpparam, rpwitness) = generate_safe_h1_h2_N_tilde(); Self { u_i: u, @@ -144,12 +144,12 @@ impl Keys { dk, ek, party_index: index, - N_tilde, - h1, - h2, - xhi, - xhi_inv, - phi, + N_tilde: rpparam.N, + h1: rpparam.s, + h2: rpparam.t, + xhi: rpwitness.lambda, + xhi_inv: rpwitness.lambdaInv, + phi: rpwitness.phi, } } @@ -159,7 +159,7 @@ impl Keys { let y = Point::generator() * &u; let (ek, dk) = Paillier::keypair_safe_primes().keys(); - let (N_tilde, h1, h2, xhi, xhi_inv, phi) = generate_h1_h2_N_tilde(); + let (rpparam, rpwitness) = generate_safe_h1_h2_N_tilde(); Self { u_i: u, @@ -167,18 +167,18 @@ impl Keys { dk, ek, party_index: index, - N_tilde, - h1, - h2, - xhi, - xhi_inv, - phi, + N_tilde: rpparam.N, + h1: rpparam.s, + h2: rpparam.t, + xhi: rpwitness.lambda, + xhi_inv: rpwitness.lambdaInv, + phi: rpwitness.phi, } } pub fn create_from(u: Scalar, index: usize) -> Self { let y = Point::generator() * &u; let (ek, dk) = Paillier::keypair().keys(); - let (N_tilde, h1, h2, xhi, xhi_inv, phi) = generate_h1_h2_N_tilde(); + let (rpparam, rpwitness) = generate_normal_h1_h2_N_tilde(); Self { u_i: u, @@ -186,12 +186,12 @@ impl Keys { dk, ek, party_index: index, - N_tilde, - h1, - h2, - xhi, - xhi_inv, - phi, + N_tilde: rpparam.N, + h1: rpparam.s, + h2: rpparam.t, + xhi: rpwitness.lambda, + xhi_inv: rpwitness.lambdaInv, + phi: rpwitness.phi, } } @@ -202,22 +202,22 @@ impl Keys { let blind_factor = BigInt::sample(SECURITY); let correct_key_proof = NiCorrectKeyProof::proof(&self.dk, None); - let dlog_statement_base_h1 = CompositeDLogStatement { + let dlog_statement_base_h1 = PiPrmStatement { modulus: self.N_tilde.clone(), base: self.h1.clone(), value: self.h2.clone(), }; - let dlog_witness_base_h1 = CompositeDLogWitness { + let dlog_witness_base_h1 = PiPrmWitness { exponent: self.xhi.clone(), totient: self.phi.clone(), }; - let dlog_statement_base_h2 = CompositeDLogStatement { + let dlog_statement_base_h2 = PiPrmStatement { modulus: self.N_tilde.clone(), base: self.h2.clone(), value: self.h1.clone(), }; - let dlog_witness_base_h2 = CompositeDLogWitness { + let dlog_witness_base_h2 = PiPrmWitness { exponent: self.xhi_inv.clone(), totient: self.phi.clone(), }; @@ -227,16 +227,12 @@ impl Keys { bad_actors: vec![], data: vec![], }; - let composite_dlog_proof_base_h1 = CompositeDLogProof::prove( - &dlog_statement_base_h1, - &dlog_witness_base_h1, - ) - .map_err(|_| dlog_proof_error.clone())?; - let composite_dlog_proof_base_h2 = CompositeDLogProof::prove( - &dlog_statement_base_h2, - &dlog_witness_base_h2, - ) - .map_err(|_| dlog_proof_error)?; + let composite_dlog_proof_base_h1 = + PiPrmProof::prove(&dlog_statement_base_h1, &dlog_witness_base_h1) + .map_err(|_| dlog_proof_error.clone())?; + let composite_dlog_proof_base_h2 = + PiPrmProof::prove(&dlog_statement_base_h2, &dlog_witness_base_h2) + .map_err(|_| dlog_proof_error)?; let com = HashCommitment::::create_commitment_with_user_defined_randomness( &BigInt::from_bytes(self.y_i.to_bytes(true).as_ref()), @@ -279,7 +275,7 @@ impl Keys { // decommitments let correct_key_correct_decom_all = (0..bc1_vec.len()) .map(|i| { - let dlog_statement_base_h2 = CompositeDLogStatement { + let dlog_statement_base_h2 = PiPrmStatement { modulus: bc1_vec[i].dlog_statement.modulus.clone(), // Base and value are swapped because we're using h1's statement. base: bc1_vec[i].dlog_statement.value.clone(), @@ -487,7 +483,7 @@ impl PartyPrivate { let y = Point::generator() * &u; let (ek, dk) = Paillier::keypair().keys(); - let (N_tilde, h1, h2, xhi, xhi_inv, phi) = generate_h1_h2_N_tilde(); + let (rpparam, rpwitness) = generate_normal_h1_h2_N_tilde(); Keys { u_i: u, @@ -495,12 +491,12 @@ impl PartyPrivate { dk, ek, party_index: index, - N_tilde, - h1, - h2, - xhi, - xhi_inv, - phi, + N_tilde: rpparam.N, + h1: rpparam.s, + h2: rpparam.t, + xhi: rpwitness.lambda, + xhi_inv: rpwitness.lambdaInv, + phi: rpwitness.phi, } } @@ -514,7 +510,7 @@ impl PartyPrivate { let y = Point::generator() * &u; let (ek, dk) = Paillier::keypair_safe_primes().keys(); - let (N_tilde, h1, h2, xhi, xhi_inv, phi) = generate_h1_h2_N_tilde(); + let (rpparam, rpwitness) = generate_safe_h1_h2_N_tilde(); Keys { u_i: u, @@ -522,12 +518,12 @@ impl PartyPrivate { dk, ek, party_index: index, - N_tilde, - h1, - h2, - xhi, - xhi_inv, - phi, + N_tilde: rpparam.N, + h1: rpparam.s, + h2: rpparam.t, + xhi: rpwitness.lambda, + xhi_inv: rpwitness.lambdaInv, + phi: rpwitness.phi, } } diff --git a/src/presign/mod.rs b/src/presign/mod.rs index beb3237a..614d45c7 100644 --- a/src/presign/mod.rs +++ b/src/presign/mod.rs @@ -25,19 +25,11 @@ use multi_party_ecdsa::protocols::multi_party_ecdsa::gg_2020::state_machine::key use paillier::{DecryptionKey, EncryptionKey}; use sha2::Sha256; -use crate::utilities::{ - aff_g::{ - PaillierAffineOpWithGroupComInRangeProof, - PaillierAffineOpWithGroupComInRangeStatement, - }, - dec_q::{PaillierDecryptionModQProof, PaillierDecryptionModQStatement}, - enc::{PaillierEncryptionInRangeProof, PaillierEncryptionInRangeStatement}, - log_star::{ - KnowledgeOfExponentPaillierEncryptionProof, - KnowledgeOfExponentPaillierEncryptionStatement, - }, - mul::{PaillierMulProof, PaillierMulStatement}, -}; +use tss_core::zkproof::aff_g::{PiAffGProof, PiAffGStatement}; +use tss_core::zkproof::dec::{PiDecProof, PiDecStatement}; +use tss_core::zkproof::enc::{PiEncProof, PiEncStatement}; +use tss_core::zkproof::log_star::{PiLogStarProof, PiLogStarStatement}; +use tss_core::zkproof::mul::{PiMulProof, PiMulStatement}; use serde::{Deserialize, Serialize}; use zeroize::Zeroize; @@ -123,8 +115,8 @@ pub struct PreSigningP2PMessage1 { pub K_i: BigInt, pub G_i: BigInt, pub ek: EncryptionKey, - pub psi_0_j_i: PaillierEncryptionInRangeProof, - pub enc_j_statement: PaillierEncryptionInRangeStatement, + pub psi_0_j_i: PiEncProof, + pub enc_j_statement: PiEncStatement, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -136,15 +128,12 @@ pub struct PreSigningP2PMessage2 { pub F_j_i: BigInt, pub D_hat_j_i: BigInt, pub F_hat_j_i: BigInt, - pub psi_j_i: PaillierAffineOpWithGroupComInRangeProof, - pub statement_psi_j_i: - PaillierAffineOpWithGroupComInRangeStatement, - pub psi_hat_j_i: PaillierAffineOpWithGroupComInRangeProof, - pub statement_psi_hat_j_i: - PaillierAffineOpWithGroupComInRangeStatement, - pub psi_prime_j_i: KnowledgeOfExponentPaillierEncryptionProof, - pub statement_psi_prime_j_i: - KnowledgeOfExponentPaillierEncryptionStatement, + pub psi_j_i: PiAffGProof, + pub statement_psi_j_i: PiAffGStatement, + pub psi_hat_j_i: PiAffGProof, + pub statement_psi_hat_j_i: PiAffGStatement, + pub psi_prime_j_i: PiLogStarProof, + pub statement_psi_prime_j_i: PiLogStarStatement, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -153,10 +142,8 @@ pub struct PreSigningP2PMessage3 { pub i: u16, pub delta_i: BigInt, pub Delta_i: Point, - pub psi_prime_prime_j_i: - KnowledgeOfExponentPaillierEncryptionProof, - pub statement_psi_prime_prime_j_i: - KnowledgeOfExponentPaillierEncryptionStatement, + pub psi_prime_prime_j_i: PiLogStarProof, + pub statement_psi_prime_prime_j_i: PiLogStarStatement, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -225,17 +212,10 @@ pub struct PresigningTranscript { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct IdentifiableAbortBroadcastMessage { pub i: u16, - pub statements_D_j_i: HashMap< - (u16, u16), - PaillierAffineOpWithGroupComInRangeStatement, - >, - pub proofs_D_j_i: HashMap< - (u16, u16), - PaillierAffineOpWithGroupComInRangeProof, - >, - pub statement_H_i: PaillierMulStatement, - pub proof_H_i: PaillierMulProof, - pub statement_delta_i: - HashMap>, - pub proof_delta_i: HashMap>, + pub statements_D_j_i: HashMap<(u16, u16), PiAffGStatement>, + pub proofs_D_j_i: HashMap<(u16, u16), PiAffGProof>, + pub statement_H_i: PiMulStatement, + pub proof_H_i: PiMulProof, + pub statement_delta_i: HashMap>, + pub proof_delta_i: HashMap>, } diff --git a/src/presign/rounds.rs b/src/presign/rounds.rs index ecf7515f..3b993b6f 100644 --- a/src/presign/rounds.rs +++ b/src/presign/rounds.rs @@ -16,43 +16,28 @@ use std::{collections::HashMap, marker::PhantomData}; -use crate::{ - utilities::{ - aff_g::{ - PaillierAffineOpWithGroupComInRangeProof, - PaillierAffineOpWithGroupComInRangeStatement, - PaillierAffineOpWithGroupComInRangeWitness, - }, - dec_q::{ - PaillierDecryptionModQProof, PaillierDecryptionModQStatement, - PaillierDecryptionModQWitness, - }, - enc::{ - PaillierEncryptionInRangeProof, PaillierEncryptionInRangeStatement, - PaillierEncryptionInRangeWitness, - }, - log_star::{ - KnowledgeOfExponentPaillierEncryptionProof, - KnowledgeOfExponentPaillierEncryptionStatement, - KnowledgeOfExponentPaillierEncryptionWitness, - }, - mul::{PaillierMulProof, PaillierMulStatement, PaillierMulWitness}, - sample_relatively_prime_integer, L_PRIME, - }, - ErrorType, ProofVerificationErrorData, -}; - use super::{ IdentifiableAbortBroadcastMessage, PreSigningP2PMessage1, PreSigningP2PMessage2, PreSigningP2PMessage3, PreSigningSecrets, PresigningOutput, PresigningTranscript, DEFAULT_ENCRYPTION_KEY, SSID, }; +use crate::{ErrorType, ProofVerificationErrorData}; use curv::{ arithmetic::{traits::*, Modulo, Samplable}, cryptographic_primitives::secret_sharing::feldman_vss::VerifiableSS, elliptic::curves::{Point, Scalar, Secp256k1}, BigInt, }; +use tss_core::security_level::L_PRIME; +use tss_core::utilities::sample_relatively_prime_integer; +use tss_core::utilities::RingPedersenParams; +use tss_core::zkproof::aff_g::{PiAffGProof, PiAffGStatement, PiAffGWitness}; +use tss_core::zkproof::dec::{PiDecProof, PiDecStatement, PiDecWitness}; +use tss_core::zkproof::enc::{PiEncProof, PiEncStatement, PiEncWitness}; +use tss_core::zkproof::log_star::{ + PiLogStarProof, PiLogStarStatement, PiLogStarWitness, +}; +use tss_core::zkproof::mul::{PiMulProof, PiMulStatement, PiMulWitness}; use paillier::{ Add, Decrypt, EncryptWithChosenRandomness, EncryptionKey, Mul, Paillier, @@ -108,29 +93,29 @@ impl Round0 { &Randomness(rho_i.clone()), ) .into(); - let witness_psi_0_j_i = - PaillierEncryptionInRangeWitness::new(k_i.clone(), rho_i.clone()); + let witness_psi_0_j_i = PiEncWitness::new(k_i.clone(), rho_i.clone()); for j in self.ssid.P.iter() { if *j != self.ssid.X.i { - let statement_psi_0_j_i = PaillierEncryptionInRangeStatement { + let statement_psi_0_j_i = PiEncStatement { N0: self.secrets.ek.n.clone(), NN0: self.secrets.ek.nn.clone(), K: K_i.clone(), - s: self.S.get(j).unwrap_or(&BigInt::zero()).clone(), - t: self.T.get(j).unwrap_or(&BigInt::zero()).clone(), - N_hat: self - .N_hats - .get(j) - .unwrap_or(&BigInt::zero()) - .clone(), + RPParam: tss_core::utilities::RingPedersenParams { + N: self + .N_hats + .get(j) + .unwrap_or(&BigInt::zero()) + .clone(), + s: self.S.get(j).unwrap_or(&BigInt::zero()).clone(), + t: self.T.get(j).unwrap_or(&BigInt::zero()).clone(), + }, phantom: PhantomData, }; - let psi_0_j_i = - PaillierEncryptionInRangeProof::::prove( - &witness_psi_0_j_i, - &statement_psi_0_j_i, - ); + let psi_0_j_i = PiEncProof::::prove( + &witness_psi_0_j_i, + &statement_psi_0_j_i, + ); let body = PreSigningP2PMessage1 { ssid: self.ssid.clone(), @@ -224,7 +209,7 @@ impl Round1 { let psi_0_i_j = msg.psi_0_j_i; let enc_i_statement = msg.enc_j_statement; // Verify psi_0_i_j proof - if PaillierEncryptionInRangeProof::::verify( + if PiEncProof::::verify( &psi_0_i_j, &enc_i_statement, ) @@ -409,139 +394,131 @@ impl Round1 { F_hat_j.insert(*j, F_hat_j_i.clone()); // psi_j_i - let witness_psi_j_i = - PaillierAffineOpWithGroupComInRangeWitness::new( - self.gamma_i.clone(), - // See reasoning documented under F_j_i for why we - // multiply beta_i_j by -1. - BigInt::from(-1).mul(&beta_i_j.clone()), - s_i_j.clone(), - r_i_j.clone(), - ); - let statement_psi_j_i = - PaillierAffineOpWithGroupComInRangeStatement { - S: self.S.get(j).unwrap_or(&BigInt::zero()).clone(), - T: self.T.get(j).unwrap_or(&BigInt::zero()).clone(), - N_hat: self + let witness_psi_j_i = PiAffGWitness::new( + self.gamma_i.clone(), + // See reasoning documented under F_j_i for why we + // multiply beta_i_j by -1. + BigInt::from(-1).mul(&beta_i_j.clone()), + s_i_j.clone(), + r_i_j.clone(), + ); + let statement_psi_j_i = PiAffGStatement { + RPParam: RingPedersenParams { + N: self .N_hats .get(j) .unwrap_or(&BigInt::zero()) .clone(), - N0: eks - .get(j) - .unwrap_or(&DEFAULT_ENCRYPTION_KEY()) - .n - .clone(), - N1: self.secrets.ek.n.clone(), - NN0: eks - .get(j) - .unwrap_or(&DEFAULT_ENCRYPTION_KEY()) - .nn - .clone(), - NN1: self.secrets.ek.nn.clone(), - C: K.get(j).unwrap_or(&BigInt::zero()).clone(), - D: D_j_i.clone(), - Y: F_j_i.clone(), - X: Gamma_i.clone(), - ek_prover: self.secrets.ek.clone(), - ek_verifier: eks - .get(j) - .unwrap_or(&DEFAULT_ENCRYPTION_KEY()) - .clone(), - phantom: PhantomData, - }; - let psi_j_i = PaillierAffineOpWithGroupComInRangeProof::< - Secp256k1, - Sha256, - >::prove( - &witness_psi_j_i, &statement_psi_j_i + s: self.S.get(j).unwrap_or(&BigInt::zero()).clone(), + t: self.T.get(j).unwrap_or(&BigInt::zero()).clone(), + }, + N0: eks + .get(j) + .unwrap_or(&DEFAULT_ENCRYPTION_KEY()) + .n + .clone(), + N1: self.secrets.ek.n.clone(), + NN0: eks + .get(j) + .unwrap_or(&DEFAULT_ENCRYPTION_KEY()) + .nn + .clone(), + NN1: self.secrets.ek.nn.clone(), + C: K.get(j).unwrap_or(&BigInt::zero()).clone(), + D: D_j_i.clone(), + Y: F_j_i.clone(), + X: Gamma_i.clone(), + ek_prover: self.secrets.ek.clone(), + ek_verifier: eks + .get(j) + .unwrap_or(&DEFAULT_ENCRYPTION_KEY()) + .clone(), + phantom: PhantomData, + }; + let psi_j_i = PiAffGProof::::prove( + &witness_psi_j_i, + &statement_psi_j_i, ); // psi_hat_j_i - let witness_psi_hat_j_i = - PaillierAffineOpWithGroupComInRangeWitness::new( - // We use omega_i in place of x_i, see doc on omega_i - // definition for explanation. - omega_i.clone(), - // See reasoning documented under F_j_i for why we - // multiply beta_hat_i_j by -1. - BigInt::from(-1).mul(&beta_hat_i_j.clone()), - s_hat_i_j.clone(), - r_hat_i_j.clone(), - ); - let statement_psi_hat_j_i = - PaillierAffineOpWithGroupComInRangeStatement { - S: self.S.get(j).unwrap_or(&BigInt::zero()).clone(), - T: self.T.get(j).unwrap_or(&BigInt::zero()).clone(), - N_hat: self + let witness_psi_hat_j_i = PiAffGWitness::new( + // We use omega_i in place of x_i, see doc on omega_i + // definition for explanation. + omega_i.clone(), + // See reasoning documented under F_j_i for why we + // multiply beta_hat_i_j by -1. + BigInt::from(-1).mul(&beta_hat_i_j.clone()), + s_hat_i_j.clone(), + r_hat_i_j.clone(), + ); + let statement_psi_hat_j_i = PiAffGStatement { + RPParam: RingPedersenParams { + N: self .N_hats .get(j) .unwrap_or(&BigInt::zero()) .clone(), - N0: eks - .get(j) - .unwrap_or(&DEFAULT_ENCRYPTION_KEY()) - .n - .clone(), - N1: self.secrets.ek.n.clone(), - NN0: eks - .get(j) - .unwrap_or(&DEFAULT_ENCRYPTION_KEY()) - .nn - .clone(), - NN1: self.secrets.ek.nn.clone(), - C: K.get(j).unwrap_or(&BigInt::zero()).clone(), - D: D_hat_j_i.clone(), - Y: F_hat_j_i.clone(), - // We use omega_i in place of x_i, see doc on omega_i - // definition for explanation. - X: Point::::generator().as_point() - * Scalar::from_bigint(&omega_i), - ek_prover: self.secrets.ek.clone(), - ek_verifier: eks - .get(j) - .unwrap_or(&DEFAULT_ENCRYPTION_KEY()) - .clone(), - phantom: PhantomData, - }; - let psi_hat_j_i = PaillierAffineOpWithGroupComInRangeProof::< - Secp256k1, - Sha256, - >::prove( + s: self.S.get(j).unwrap_or(&BigInt::zero()).clone(), + t: self.T.get(j).unwrap_or(&BigInt::zero()).clone(), + }, + N0: eks + .get(j) + .unwrap_or(&DEFAULT_ENCRYPTION_KEY()) + .n + .clone(), + N1: self.secrets.ek.n.clone(), + NN0: eks + .get(j) + .unwrap_or(&DEFAULT_ENCRYPTION_KEY()) + .nn + .clone(), + NN1: self.secrets.ek.nn.clone(), + C: K.get(j).unwrap_or(&BigInt::zero()).clone(), + D: D_hat_j_i.clone(), + Y: F_hat_j_i.clone(), + // We use omega_i in place of x_i, see doc on omega_i + // definition for explanation. + X: Point::::generator().as_point() + * Scalar::from_bigint(&omega_i), + ek_prover: self.secrets.ek.clone(), + ek_verifier: eks + .get(j) + .unwrap_or(&DEFAULT_ENCRYPTION_KEY()) + .clone(), + phantom: PhantomData, + }; + let psi_hat_j_i = PiAffGProof::::prove( &witness_psi_hat_j_i, &statement_psi_hat_j_i, ); // psi_prime_j_i - let witness_psi_prime_j_i = - KnowledgeOfExponentPaillierEncryptionWitness::new( - self.gamma_i.clone(), - self.nu_i.clone(), - ); - let statement_psi_prime_j_i = - KnowledgeOfExponentPaillierEncryptionStatement { - N0: self.secrets.ek.n.clone(), - NN0: self.secrets.ek.nn.clone(), - C: self.G_i.clone(), - X: Gamma_i.clone(), - // g is not always the secp256k1 generator, so we have - // to pass it explicitly. - // See [`KnowledgeOfExponentPaillierEncryptionStatement`] inline doc for g field - // for details. - g: Point::generator().to_point(), - s: self.S.get(j).unwrap_or(&BigInt::zero()).clone(), - t: self.T.get(j).unwrap_or(&BigInt::zero()).clone(), - N_hat: self + let witness_psi_prime_j_i = PiLogStarWitness::new( + self.gamma_i.clone(), + self.nu_i.clone(), + ); + let statement_psi_prime_j_i = PiLogStarStatement { + N0: self.secrets.ek.n.clone(), + NN0: self.secrets.ek.nn.clone(), + C: self.G_i.clone(), + X: Gamma_i.clone(), + // g is not always the secp256k1 generator, so we have + // to pass it explicitly. + // See [`PiLogStarStatement`] inline doc for g field + // for details. + g: Point::generator().to_point(), + RPParams: RingPedersenParams { + N: self .N_hats .get(j) .unwrap_or(&BigInt::zero()) .clone(), - phantom: PhantomData, - }; - let psi_prime_j_i = KnowledgeOfExponentPaillierEncryptionProof::< - Secp256k1, - Sha256, - >::prove( + s: self.S.get(j).unwrap_or(&BigInt::zero()).clone(), + t: self.T.get(j).unwrap_or(&BigInt::zero()).clone(), + }, + phantom: PhantomData, + }; + let psi_prime_j_i = PiLogStarProof::::prove( &witness_psi_prime_j_i, &statement_psi_prime_j_i, ); @@ -679,62 +656,62 @@ impl Round2 { let psi_i_j = msg.psi_j_i; let statement_psi_i_j = msg.statement_psi_j_i; // Verify psi_i_j - if PaillierAffineOpWithGroupComInRangeProof::::verify( - &psi_i_j, - &statement_psi_i_j, - ) - .is_err() - { - let error_data = ProofVerificationErrorData { - proof_symbol: "psi_i_j".to_string(), - verifying_party: self.ssid.X.i, - }; - return Err(PresignError::ProofVerificationError(ErrorType { - error_type: "aff-g".to_string(), - bad_actors: vec![j.into()], - data: bincode::serialize(&error_data).unwrap(), - })) - } + if PiAffGProof::::verify( + &psi_i_j, + &statement_psi_i_j, + ) + .is_err() + { + let error_data = ProofVerificationErrorData { + proof_symbol: "psi_i_j".to_string(), + verifying_party: self.ssid.X.i, + }; + return Err(PresignError::ProofVerificationError(ErrorType { + error_type: "aff-g".to_string(), + bad_actors: vec![j.into()], + data: bincode::serialize(&error_data).unwrap(), + })); + } // Verify psi_hat_i_j let psi_hat_i_j = msg.psi_hat_j_i; let statement_psi_hat_i_j = msg.statement_psi_hat_j_i; - if PaillierAffineOpWithGroupComInRangeProof::::verify( - &psi_hat_i_j, - &statement_psi_hat_i_j, - ) - .is_err() - { - let error_data = ProofVerificationErrorData { - proof_symbol: "psi_hat_i_j".to_string(), - verifying_party: self.ssid.X.i, - }; - return Err(PresignError::ProofVerificationError(ErrorType { - error_type: "aff-g".to_string(), - bad_actors: vec![j.into()], - data: bincode::serialize(&error_data).unwrap(), - })) - } + if PiAffGProof::::verify( + &psi_hat_i_j, + &statement_psi_hat_i_j, + ) + .is_err() + { + let error_data = ProofVerificationErrorData { + proof_symbol: "psi_hat_i_j".to_string(), + verifying_party: self.ssid.X.i, + }; + return Err(PresignError::ProofVerificationError(ErrorType { + error_type: "aff-g".to_string(), + bad_actors: vec![j.into()], + data: bincode::serialize(&error_data).unwrap(), + })); + } // Verify psi_prime_i_j let psi_prime_i_j = msg.psi_prime_j_i; let statement_psi_prime_i_j = msg.statement_psi_prime_j_i; - if KnowledgeOfExponentPaillierEncryptionProof::::verify( - &psi_prime_i_j, - &statement_psi_prime_i_j, - ) - .is_err() - { - let error_data = ProofVerificationErrorData { - proof_symbol: "psi_prime_i_j".to_string(), - verifying_party: self.ssid.X.i, - }; - return Err(PresignError::ProofVerificationError(ErrorType { - error_type: "log*".to_string(), - bad_actors: vec![j.into()], - data: bincode::serialize(&error_data).unwrap(), - })) - } + if PiLogStarProof::::verify( + &psi_prime_i_j, + &statement_psi_prime_i_j, + ) + .is_err() + { + let error_data = ProofVerificationErrorData { + proof_symbol: "psi_prime_i_j".to_string(), + verifying_party: self.ssid.X.i, + }; + return Err(PresignError::ProofVerificationError(ErrorType { + error_type: "log*".to_string(), + bad_actors: vec![j.into()], + data: bincode::serialize(&error_data).unwrap(), + })); + } } // Gamma = Prod_j (Gamma_j) @@ -825,36 +802,31 @@ impl Round2 { if j != &self.ssid.X.i.clone() { // Compute psi_prime_prime_j_i let witness_psi_prime_prime_j_i = - KnowledgeOfExponentPaillierEncryptionWitness::new( - self.k_i.clone(), - self.rho_i.clone(), - ); + PiLogStarWitness::new(self.k_i.clone(), self.rho_i.clone()); - let statement_psi_prime_prime_j_i = - KnowledgeOfExponentPaillierEncryptionStatement { - N0: self.secrets.ek.n.clone(), - NN0: self.secrets.ek.nn.clone(), - C: self.K_i.clone(), - X: Delta_i.clone(), - // From the Delta_i = Gamma^{k_i} and Πlog∗ stating X = - // g^x, Since x = k_i and X = - // Delta_i, :- g = Gamma - // (see Figure 7, Round 3 and Figure 25 in paper). - g: Gamma.clone(), - s: self.S.get(j).unwrap_or(&BigInt::zero()).clone(), - t: self.T.get(j).unwrap_or(&BigInt::zero()).clone(), - N_hat: self + let statement_psi_prime_prime_j_i = PiLogStarStatement { + N0: self.secrets.ek.n.clone(), + NN0: self.secrets.ek.nn.clone(), + C: self.K_i.clone(), + X: Delta_i.clone(), + // From the Delta_i = Gamma^{k_i} and Πlog∗ stating X = + // g^x, Since x = k_i and X = + // Delta_i, :- g = Gamma + // (see Figure 7, Round 3 and Figure 25 in paper). + g: Gamma.clone(), + RPParams: RingPedersenParams { + N: self .N_hats .get(j) .unwrap_or(&BigInt::zero()) .clone(), - phantom: PhantomData, - }; + s: self.S.get(j).unwrap_or(&BigInt::zero()).clone(), + t: self.T.get(j).unwrap_or(&BigInt::zero()).clone(), + }, + phantom: PhantomData, + }; let psi_prime_prime_j_i = - KnowledgeOfExponentPaillierEncryptionProof::< - Secp256k1, - Sha256, - >::prove( + PiLogStarProof::::prove( &witness_psi_prime_prime_j_i, &statement_psi_prime_prime_j_i, ); @@ -984,22 +956,22 @@ impl Round3 { let statement_psi_prime_prime_i_j = msg.statement_psi_prime_prime_j_i; - if KnowledgeOfExponentPaillierEncryptionProof::::verify( - &psi_prime_prime_i_j, - &statement_psi_prime_prime_i_j, - ) - .is_err() - { - let error_data = ProofVerificationErrorData { - proof_symbol: "psi_prime_prime_i_j".to_string(), - verifying_party: self.ssid.X.i, - }; - return Err(PresignError::ProofVerificationError(ErrorType { - error_type: "log*".to_string(), - bad_actors: vec![j.into()], - data: bincode::serialize(&error_data).unwrap(), - })) - } + if PiLogStarProof::::verify( + &psi_prime_prime_i_j, + &statement_psi_prime_prime_i_j, + ) + .is_err() + { + let error_data = ProofVerificationErrorData { + proof_symbol: "psi_prime_prime_i_j".to_string(), + verifying_party: self.ssid.X.i, + }; + return Err(PresignError::ProofVerificationError(ErrorType { + error_type: "log*".to_string(), + bad_actors: vec![j.into()], + data: bincode::serialize(&error_data).unwrap(), + })); + } // Insert into deltas and Deltas deltas.insert(j, msg.delta_i); @@ -1089,13 +1061,13 @@ impl Round3 { // (l,j) to proof for D_j_i let mut proofs_D_j_i: HashMap< (u16, u16), - PaillierAffineOpWithGroupComInRangeProof, + PiAffGProof, > = HashMap::new(); // (l,j) to statement for D_j_i let mut statements_D_j_i: HashMap< (u16, u16), - PaillierAffineOpWithGroupComInRangeStatement, + PiAffGStatement, > = HashMap::new(); self.ssid @@ -1110,75 +1082,63 @@ impl Round3 { // F_j_i = enc_i(beta_i_j, r_i_j) let F_j_i = self.F_j.get(&self.ssid.X.i).unwrap(); - let witness_D_j_i = - PaillierAffineOpWithGroupComInRangeWitness::new( - self.gamma_i.clone(), - self.beta_i - .get(j) - .unwrap_or(&BigInt::zero()) - .clone(), - self.s_i - .get(j) - .unwrap_or(&BigInt::zero()) - .clone(), - self.r_i - .get(j) + let witness_D_j_i = PiAffGWitness::new( + self.gamma_i.clone(), + self.beta_i + .get(j) + .unwrap_or(&BigInt::zero()) + .clone(), + self.s_i.get(j).unwrap_or(&BigInt::zero()).clone(), + self.r_i.get(j).unwrap_or(&BigInt::zero()).clone(), + ); + let statement_D_j_i = PiAffGStatement { + RPParam: RingPedersenParams { + N: self + .N_hats + .get(l) .unwrap_or(&BigInt::zero()) .clone(), - ); - let statement_D_j_i = - PaillierAffineOpWithGroupComInRangeStatement { - S: self + s: self .S .get(l) .unwrap_or(&BigInt::zero()) .clone(), - T: self + t: self .T .get(l) .unwrap_or(&BigInt::zero()) .clone(), - N_hat: self - .N_hats - .get(l) - .unwrap_or(&BigInt::zero()) - .clone(), - N0: self.secrets.ek.n.clone(), - N1: self - .eks - .get(j) - .unwrap_or(&DEFAULT_ENCRYPTION_KEY()) - .n - .clone(), - NN0: self.secrets.ek.nn.clone(), - NN1: self - .eks - .get(j) - .unwrap_or(&DEFAULT_ENCRYPTION_KEY()) - .nn - .clone(), - C: D_j_i.clone(), - D: self - .K - .get(j) - .unwrap_or(&BigInt::zero()) - .clone(), - Y: F_j_i.clone(), - X: self.Gamma_i.clone(), - ek_prover: self.secrets.ek.clone(), - ek_verifier: self - .eks - .get(j) - .unwrap_or(&DEFAULT_ENCRYPTION_KEY()) - .clone(), - phantom: PhantomData, - }; + }, + N0: self.secrets.ek.n.clone(), + N1: self + .eks + .get(j) + .unwrap_or(&DEFAULT_ENCRYPTION_KEY()) + .n + .clone(), + NN0: self.secrets.ek.nn.clone(), + NN1: self + .eks + .get(j) + .unwrap_or(&DEFAULT_ENCRYPTION_KEY()) + .nn + .clone(), + C: D_j_i.clone(), + D: self.K.get(j).unwrap_or(&BigInt::zero()).clone(), + Y: F_j_i.clone(), + X: self.Gamma_i.clone(), + ek_prover: self.secrets.ek.clone(), + ek_verifier: self + .eks + .get(j) + .unwrap_or(&DEFAULT_ENCRYPTION_KEY()) + .clone(), + phantom: PhantomData, + }; let D_j_i_proof = - PaillierAffineOpWithGroupComInRangeProof::< - Secp256k1, - Sha256, - >::prove( - &witness_D_j_i, &statement_D_j_i + PiAffGProof::::prove( + &witness_D_j_i, + &statement_D_j_i, ); proofs_D_j_i.insert((*l, *j), D_j_i_proof); statements_D_j_i.insert((*l, *j), statement_D_j_i); @@ -1195,12 +1155,12 @@ impl Round3 { ) .into(); - let witness_H_i = PaillierMulWitness::new( + let witness_H_i = PiMulWitness::new( self.k_i, self.nu_i.clone(), self.nu_i.mul(&self.gamma_i), ); - let statement_H_i = PaillierMulStatement { + let statement_H_i = PiMulStatement { N: self.secrets.ek.n.clone(), NN: self.secrets.ek.nn.clone(), C: self.G_i, @@ -1210,7 +1170,7 @@ impl Round3 { phantom: PhantomData, }; - let proof_H_i = PaillierMulProof::::prove( + let proof_H_i = PiMulProof::::prove( &witness_H_i, &statement_H_i, ); @@ -1235,7 +1195,7 @@ impl Round3 { } }); - let witness_delta_i = PaillierDecryptionModQWitness::new( + let witness_delta_i = PiDecWitness::new( Paillier::decrypt( &self.secrets.dk, RawCiphertext::from(ciphertext_delta_i.clone()), @@ -1247,25 +1207,25 @@ impl Round3 { // l to statement let mut statement_delta_i: HashMap< u16, - PaillierDecryptionModQStatement, + PiDecStatement, > = HashMap::new(); // l to proof - let mut proof_delta_i: HashMap< - u16, - PaillierDecryptionModQProof, - > = HashMap::new(); + let mut proof_delta_i: HashMap> = + HashMap::new(); self.ssid.P.iter().for_each(|l| { if *l != self.ssid.X.i { - let statement_delta_l_i = PaillierDecryptionModQStatement { - S: self.S.get(l).unwrap_or(&BigInt::zero()).clone(), - T: self.T.get(l).unwrap_or(&BigInt::zero()).clone(), - N_hat: self - .N_hats - .get(l) - .unwrap_or(&BigInt::zero()) - .clone(), + let statement_delta_l_i = PiDecStatement { + RPParams: RingPedersenParams { + N: self + .N_hats + .get(l) + .unwrap_or(&BigInt::zero()) + .clone(), + s: self.S.get(l).unwrap_or(&BigInt::zero()).clone(), + t: self.T.get(l).unwrap_or(&BigInt::zero()).clone(), + }, N0: self.secrets.ek.n.clone(), NN0: self.secrets.ek.nn.clone(), C: ciphertext_delta_i.clone(), @@ -1278,7 +1238,7 @@ impl Round3 { proof_delta_i.insert( *l, - PaillierDecryptionModQProof::::prove( + PiDecProof::::prove( &witness_delta_i, &statement_delta_l_i, ), @@ -1351,11 +1311,9 @@ impl Round4 { .get(&(self.ssid.X.i, *j)) .unwrap(); - if PaillierAffineOpWithGroupComInRangeProof::< - Secp256k1, - Sha256, - >::verify( - D_si_j_proof, statement_D_si_j + if PiAffGProof::::verify( + D_si_j_proof, + statement_D_si_j, ) .is_err() { @@ -1381,9 +1339,7 @@ impl Round4 { let proof_H_si = msg.proof_H_i; let statement_H_si = msg.statement_H_i; - if PaillierMulProof::verify(&proof_H_si, &statement_H_si) - .is_err() - { + if PiMulProof::verify(&proof_H_si, &statement_H_si).is_err() { let error_data = ProofVerificationErrorData { proof_symbol: "H_si".to_string(), verifying_party: self.ssid.X.i, @@ -1402,11 +1358,8 @@ impl Round4 { let statement_delta_si = msg.statement_delta_i.get(&self.ssid.X.i).unwrap(); - if PaillierDecryptionModQProof::verify( - proof_delta_si, - statement_delta_si, - ) - .is_err() + if PiDecProof::verify(proof_delta_si, statement_delta_si) + .is_err() { let error_data = ProofVerificationErrorData { proof_symbol: "delta_si".to_string(), diff --git a/src/presign/state_machine.rs b/src/presign/state_machine.rs index 31db8b0f..fa1ba118 100644 --- a/src/presign/state_machine.rs +++ b/src/presign/state_machine.rs @@ -608,11 +608,11 @@ pub mod test { cryptographic_primitives::secret_sharing::feldman_vss::VerifiableSS, elliptic::curves::{Point, Scalar}, }; - use fs_dkr::ring_pedersen_proof::RingPedersenStatement; use multi_party_ecdsa::protocols::multi_party_ecdsa::gg_2020::state_machine::keygen::{ Keygen, LocalKey, }; use round_based::dev::Simulation; + use tss_core::utilities::generate_safe_h1_h2_N_tilde; use std::ops::Deref; fn simulate_keygen(t: u16, n: u16) -> Vec> { @@ -736,11 +736,10 @@ pub mod test { let mut aux_ring_pedersen_s_values = HashMap::with_capacity(keys.len()); let mut aux_ring_pedersen_t_values = HashMap::with_capacity(keys.len()); for idx in 1..=p { - let (ring_pedersen_params, _) = - RingPedersenStatement::::generate(); - aux_ring_pedersen_n_hat_values.insert(idx, ring_pedersen_params.N); - aux_ring_pedersen_s_values.insert(idx, ring_pedersen_params.S); - aux_ring_pedersen_t_values.insert(idx, ring_pedersen_params.T); + let (rpparam, _) = generate_safe_h1_h2_N_tilde(); + aux_ring_pedersen_n_hat_values.insert(idx, rpparam.N); + aux_ring_pedersen_s_values.insert(idx, rpparam.s); + aux_ring_pedersen_t_values.insert(idx, rpparam.t); } // Creates pre-signing inputs and auxiliary parameters for ZK proofs. diff --git a/src/refresh/rounds.rs b/src/refresh/rounds.rs index c9f38949..f29d7f8f 100644 --- a/src/refresh/rounds.rs +++ b/src/refresh/rounds.rs @@ -15,13 +15,7 @@ use crate::utilities::sha2::Sha256; pub enum PartyType { Existing(Box>), - New( - Box<( - JoinMessage, - Keys, - u16, - )>, - ), + New(Box<(JoinMessage, Keys, u16)>), } use super::state_machine::{Round0Messages, Round1Messages}; @@ -38,17 +32,7 @@ pub struct Round0 { impl Round0 { pub fn proceed(self, mut output: O) -> Result where - O: Push< - Msg< - Option< - JoinMessage< - Secp256k1, - Sha256, - { crate::utilities::STAT_PARAM }, - >, - >, - >, - >, + O: Push>>>, { match self.local_key_option { Some(local_key) => { @@ -112,34 +96,15 @@ pub struct Round1 { impl Round1 { pub fn proceed( self, - input: BroadcastMsgs< - Option< - JoinMessage< - Secp256k1, - Sha256, - { crate::utilities::STAT_PARAM }, - >, - >, - >, + input: BroadcastMsgs>>, mut output: O, ) -> Result where - O: Push< - Msg< - Option< - RefreshMessage< - Secp256k1, - Sha256, - { crate::utilities::STAT_PARAM }, - >, - >, - >, - >, + O: Push>>>, { let join_message_option_vec = input.into_vec(); - let mut join_message_vec: Vec< - JoinMessage, - > = Vec::new(); + let mut join_message_vec: Vec> = + Vec::new(); for join_message_option in join_message_option_vec.into_iter().flatten() { join_message_vec.push(join_message_option) @@ -210,11 +175,8 @@ impl Round1 { pub struct Round2 { pub party_type: PartyType, - pub join_messages: - Vec>, - pub refresh_message: Option< - RefreshMessage, - >, + pub join_messages: Vec>, + pub refresh_message: Option>, pub new_paillier_decryption_key: DecryptionKey, new_t: u16, new_n: u16, @@ -224,21 +186,12 @@ pub struct Round2 { impl Round2 { pub fn proceed( self, - input: BroadcastMsgs< - Option< - RefreshMessage< - Secp256k1, - Sha256, - { crate::utilities::STAT_PARAM }, - >, - >, - >, + input: BroadcastMsgs>>, ) -> Result> { let refresh_message_option_vec = input.into_vec_including_me(self.refresh_message); - let mut refresh_message_vec: Vec< - RefreshMessage, - > = Vec::new(); + let mut refresh_message_vec: Vec> = + Vec::new(); for refresh_message_option in refresh_message_option_vec.into_iter().flatten() { diff --git a/src/refresh/state_machine.rs b/src/refresh/state_machine.rs index e4bccf0b..1d23c51a 100644 --- a/src/refresh/state_machine.rs +++ b/src/refresh/state_machine.rs @@ -19,20 +19,10 @@ use crate::utilities::sha2::Sha256; use std::{collections::HashMap, fmt, mem::replace, time::Duration}; use thiserror::Error; -pub type Round0Messages = Store< - BroadcastMsgs< - Option< - JoinMessage, - >, - >, ->; -pub type Round1Messages = Store< - BroadcastMsgs< - Option< - RefreshMessage, - >, - >, ->; +pub type Round0Messages = + Store>>>; +pub type Round1Messages = + Store>>>; pub struct KeyRefresh { // Current round @@ -401,16 +391,8 @@ pub struct ProtocolMessage(M); #[derive(Debug, Clone, Serialize, Deserialize)] #[allow(clippy::large_enum_variant)] enum M { - Round1( - Option< - JoinMessage, - >, - ), - Round2( - Option< - RefreshMessage, - >, - ), + Round1(Option>), + Round2(Option>), } // Error diff --git a/src/sign/mod.rs b/src/sign/mod.rs index 79bcd48c..2fd84009 100644 --- a/src/sign/mod.rs +++ b/src/sign/mod.rs @@ -20,17 +20,9 @@ use serde::{Deserialize, Serialize}; use sha2::Sha256; -use crate::utilities::{ - aff_g::{ - PaillierAffineOpWithGroupComInRangeProof, - PaillierAffineOpWithGroupComInRangeStatement, - }, - dec_q::{PaillierDecryptionModQProof, PaillierDecryptionModQStatement}, - mul_star::{ - PaillierMultiplicationVersusGroupProof, - PaillierMultiplicationVersusGroupStatement, - }, -}; +use tss_core::zkproof::aff_g::{PiAffGProof, PiAffGStatement}; +use tss_core::zkproof::dec::{PiDecProof, PiDecStatement}; +use tss_core::zkproof::mul_star::{PiMulStarProof, PiMulStarStatement}; use crate::presign::SSID; pub mod rounds; @@ -54,19 +46,10 @@ pub struct SigningOutput { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct SigningIdentifiableAbortMessage { pub i: u16, - pub proofs_D_hat_j_i: HashMap< - (u16, u16), - PaillierAffineOpWithGroupComInRangeProof, - >, - pub statements_D_hat_j_i: HashMap< - (u16, u16), - PaillierAffineOpWithGroupComInRangeStatement, - >, - pub proof_H_hat_i: - HashMap>, - pub statement_H_hat_i: - HashMap>, - pub proof_sigma_i: HashMap>, - pub statement_sigma_i: - HashMap>, + pub proofs_D_hat_j_i: HashMap<(u16, u16), PiAffGProof>, + pub statements_D_hat_j_i: HashMap<(u16, u16), PiAffGStatement>, + pub proof_H_hat_i: HashMap>, + pub statement_H_hat_i: HashMap>, + pub proof_sigma_i: HashMap>, + pub statement_sigma_i: HashMap>, } diff --git a/src/sign/rounds.rs b/src/sign/rounds.rs index 69b6505f..ae08b324 100644 --- a/src/sign/rounds.rs +++ b/src/sign/rounds.rs @@ -30,26 +30,17 @@ use paillier::*; use crate::{ presign::{PresigningOutput, PresigningTranscript, DEFAULT_ENCRYPTION_KEY}, - utilities::{ - aff_g::{ - PaillierAffineOpWithGroupComInRangeProof, - PaillierAffineOpWithGroupComInRangeStatement, - PaillierAffineOpWithGroupComInRangeWitness, - }, - dec_q::{ - PaillierDecryptionModQProof, PaillierDecryptionModQStatement, - PaillierDecryptionModQWitness, - }, - mul_star::{ - PaillierMultiplicationVersusGroupProof, - PaillierMultiplicationVersusGroupStatement, - PaillierMultiplicationVersusGroupWitness, - }, - sample_relatively_prime_integer, - }, ErrorType, NoOfflineStageErrorData, ProofVerificationErrorData, }; use thiserror::Error; +use tss_core::utilities::{ + sample_relatively_prime_integer, RingPedersenParams, +}; +use tss_core::zkproof::aff_g::{PiAffGProof, PiAffGStatement, PiAffGWitness}; +use tss_core::zkproof::dec::{PiDecProof, PiDecStatement, PiDecWitness}; +use tss_core::zkproof::mul_star::{ + PiMulStarProof, PiMulStarStatement, PiMulStarWitness, +}; use zeroize::Zeroize; @@ -183,13 +174,13 @@ impl Round1 { // (l,j) to proof for D_j_i let mut proofs_D_hat_j_i: HashMap< (u16, u16), - PaillierAffineOpWithGroupComInRangeProof, + PiAffGProof, > = HashMap::new(); // (l,j) to statement for D_j_i let mut statements_D_hat_j_i: HashMap< (u16, u16), - PaillierAffineOpWithGroupComInRangeStatement, + PiAffGStatement, > = HashMap::new(); self.ssid @@ -213,85 +204,95 @@ impl Round1 { .unwrap() .clone(); - let witness_D_hat_j_i = - PaillierAffineOpWithGroupComInRangeWitness::new( - self.presigning_transcript.secrets.x_i.clone(), - self.presigning_transcript - .beta_hat_i - .get(j) + let witness_D_hat_j_i = PiAffGWitness::new( + self.presigning_transcript.secrets.x_i.clone(), + self.presigning_transcript + .beta_hat_i + .get(j) + .unwrap_or(&BigInt::zero()) + .clone(), + self.presigning_transcript + .s_hat_i + .get(j) + .unwrap_or(&BigInt::zero()) + .clone(), + self.presigning_transcript + .r_hat_i + .get(j) + .unwrap_or(&BigInt::zero()) + .clone(), + ); + let statement_D_hat_j_i = PiAffGStatement { + RPParam: RingPedersenParams { + N: self + .presigning_transcript + .N_hats + .get(l) .unwrap_or(&BigInt::zero()) .clone(), - self.presigning_transcript - .s_hat_i - .get(j) + s: self + .presigning_transcript + .S + .get(l) .unwrap_or(&BigInt::zero()) .clone(), - self.presigning_transcript - .r_hat_i - .get(j) + t: self + .presigning_transcript + .T + .get(l) .unwrap_or(&BigInt::zero()) .clone(), - ); - let statement_D_hat_j_i = - crate::utilities::aff_g::PaillierAffineOpWithGroupComInRangeStatement { - S: self - .presigning_transcript - .S - .get(l) - .unwrap_or(&BigInt::zero()) - .clone(), - T: self - .presigning_transcript - .T - .get(l) - .unwrap_or(&BigInt::zero()) - .clone(), - N_hat: self - .presigning_transcript - .N_hats - .get(l) - .unwrap_or(&BigInt::zero()) - .clone(), - N0: self.presigning_transcript.secrets.ek.n.clone(), - N1: self - .presigning_transcript - .eks - .get(j) - .unwrap_or(&DEFAULT_ENCRYPTION_KEY()) - .n - .clone(), - NN0: self.presigning_transcript.secrets.ek.nn.clone(), - NN1: self - .presigning_transcript - .eks - .get(j) - .unwrap_or(&DEFAULT_ENCRYPTION_KEY()) - .nn - .clone(), - C: D_hat_j_i, - D: self - .presigning_transcript - .K - .get(j) - .unwrap_or(&BigInt::zero()) - .clone(), - Y: F_hat_j_i, - X: Point::::generator().as_point() * - Scalar::from_bigint(&self.presigning_transcript.secrets.x_i), - ek_prover: self.presigning_transcript.secrets.ek.clone(), - ek_verifier: self - .presigning_transcript - .eks - .get(j) - .unwrap_or(&DEFAULT_ENCRYPTION_KEY()) - .clone(), - phantom: PhantomData, - }; - let proof_D_hat_j_i = - crate::utilities::aff_g::PaillierAffineOpWithGroupComInRangeProof::< - Secp256k1, - Sha256, - >::prove(&witness_D_hat_j_i, &statement_D_hat_j_i); + }, + N0: self.presigning_transcript.secrets.ek.n.clone(), + N1: self + .presigning_transcript + .eks + .get(j) + .unwrap_or(&DEFAULT_ENCRYPTION_KEY()) + .n + .clone(), + NN0: self + .presigning_transcript + .secrets + .ek + .nn + .clone(), + NN1: self + .presigning_transcript + .eks + .get(j) + .unwrap_or(&DEFAULT_ENCRYPTION_KEY()) + .nn + .clone(), + C: D_hat_j_i, + D: self + .presigning_transcript + .K + .get(j) + .unwrap_or(&BigInt::zero()) + .clone(), + Y: F_hat_j_i, + X: Point::::generator().as_point() + * Scalar::from_bigint( + &self.presigning_transcript.secrets.x_i, + ), + ek_prover: self + .presigning_transcript + .secrets + .ek + .clone(), + ek_verifier: self + .presigning_transcript + .eks + .get(j) + .unwrap_or(&DEFAULT_ENCRYPTION_KEY()) + .clone(), + phantom: PhantomData, + }; + let proof_D_hat_j_i = PiAffGProof::prove( + &witness_D_hat_j_i, + &statement_D_hat_j_i, + ); proofs_D_hat_j_i.insert((*l, *j), proof_D_hat_j_i); statements_D_hat_j_i .insert((*l, *j), statement_D_hat_j_i); @@ -312,7 +313,7 @@ impl Round1 { &Randomness::from(H_hat_i_randomness.clone()), ) .into(); - let witness_H_hat_i = PaillierMultiplicationVersusGroupWitness::new( + let witness_H_hat_i = PiMulStarWitness::new( self.presigning_transcript.secrets.x_i.clone(), self.presigning_transcript.rho_i.mul(&H_hat_i_randomness), ); @@ -322,28 +323,23 @@ impl Round1 { let mut proof_H_hat_i: HashMap< u16, - PaillierMultiplicationVersusGroupProof, + PiMulStarProof, > = HashMap::new(); let mut statement_H_hat_i: HashMap< u16, - PaillierMultiplicationVersusGroupStatement, + PiMulStarStatement, > = HashMap::new(); self.ssid.P.iter().for_each(|l| { if *l != self.ssid.X.i { - let statement_H_hat_l_i = - PaillierMultiplicationVersusGroupStatement { - N0: self.presigning_transcript.secrets.ek.n.clone(), - NN0: self - .presigning_transcript - .secrets - .ek - .nn - .clone(), - C: self.presigning_transcript.K_i.clone(), - D: H_hat_i.clone(), - X: X_i.clone(), - N_hat: self + let statement_H_hat_l_i = PiMulStarStatement { + N0: self.presigning_transcript.secrets.ek.n.clone(), + NN0: self.presigning_transcript.secrets.ek.nn.clone(), + C: self.presigning_transcript.K_i.clone(), + D: H_hat_i.clone(), + X: X_i.clone(), + RPParams: RingPedersenParams { + N: self .presigning_transcript .N_hats .get(l) @@ -361,18 +357,17 @@ impl Round1 { .get(l) .unwrap_or(&BigInt::zero()) .clone(), - phantom: PhantomData, - }; + }, + phantom: PhantomData, + }; statement_H_hat_i.insert(*l, statement_H_hat_l_i.clone()); proof_H_hat_i.insert( *l, - PaillierMultiplicationVersusGroupProof::< - Secp256k1, - Sha256, - >::prove( - &witness_H_hat_i, &statement_H_hat_l_i + PiMulStarProof::::prove( + &witness_H_hat_i, + &statement_H_hat_l_i, ), ); } @@ -427,7 +422,7 @@ impl Round1 { &self.presigning_transcript.secrets.ek.nn, )); - let witness_sigma_i = PaillierDecryptionModQWitness::new( + let witness_sigma_i = PiDecWitness::new( Paillier::decrypt( &self.presigning_transcript.secrets.dk, RawCiphertext::from(ciphertext.clone()), @@ -439,36 +434,36 @@ impl Round1 { // l to statement let mut statement_sigma_i: HashMap< u16, - PaillierDecryptionModQStatement, + PiDecStatement, > = HashMap::new(); // l to proof - let mut proof_sigma_i: HashMap< - u16, - PaillierDecryptionModQProof, - > = HashMap::new(); + let mut proof_sigma_i: HashMap> = + HashMap::new(); self.ssid.P.iter().for_each(|l| { if *l != self.ssid.X.i { - let statement_sigma_l_i = PaillierDecryptionModQStatement { - S: self - .presigning_transcript - .S - .get(l) - .unwrap_or(&BigInt::zero()) - .clone(), - T: self - .presigning_transcript - .T - .get(l) - .unwrap_or(&BigInt::zero()) - .clone(), - N_hat: self - .presigning_transcript - .N_hats - .get(l) - .unwrap_or(&BigInt::zero()) - .clone(), + let statement_sigma_l_i = PiDecStatement { + RPParams: RingPedersenParams { + N: self + .presigning_transcript + .N_hats + .get(l) + .unwrap_or(&BigInt::zero()) + .clone(), + s: self + .presigning_transcript + .S + .get(l) + .unwrap_or(&BigInt::zero()) + .clone(), + t: self + .presigning_transcript + .T + .get(l) + .unwrap_or(&BigInt::zero()) + .clone(), + }, N0: self.presigning_transcript.secrets.ek.n.clone(), NN0: self.presigning_transcript.secrets.ek.nn.clone(), C: ciphertext.clone(), @@ -485,7 +480,7 @@ impl Round1 { proof_sigma_i.insert( *l, - PaillierDecryptionModQProof::::prove( + PiDecProof::::prove( &witness_sigma_i, &statement_sigma_l_i, ), @@ -556,11 +551,9 @@ impl Round2 { .get(&(self.ssid.X.i, *j)) .unwrap(); - if PaillierAffineOpWithGroupComInRangeProof::< - Secp256k1, - Sha256, - >::verify( - D_hat_si_j_proof, statement_D_hat_si_j + if PiAffGProof::::verify( + D_hat_si_j_proof, + statement_D_hat_si_j, ) .is_err() { @@ -586,11 +579,8 @@ impl Round2 { let statement_H_hat_si = msg.statement_H_hat_i.get(&self.ssid.X.i).unwrap(); - if PaillierMultiplicationVersusGroupProof::verify( - proof_H_hat_si, - statement_H_hat_si, - ) - .is_err() + if PiMulStarProof::verify(proof_H_hat_si, statement_H_hat_si) + .is_err() { let error_data = ProofVerificationErrorData { proof_symbol: "H_hat_si".to_string(), @@ -608,11 +598,8 @@ impl Round2 { let statement_sigma_si = msg.statement_sigma_i.get(&self.ssid.X.i).unwrap(); - if PaillierDecryptionModQProof::verify( - proof_sigma_si, - statement_sigma_si, - ) - .is_err() + if PiDecProof::verify(proof_sigma_si, statement_sigma_si) + .is_err() { let error_data = ProofVerificationErrorData { proof_symbol: "sigma_si".to_string(), diff --git a/src/utilities/aff_g/test.rs b/src/utilities/aff_g/test.rs deleted file mode 100644 index e69de29b..00000000 diff --git a/src/utilities/enc/test.rs b/src/utilities/enc/test.rs deleted file mode 100644 index e69de29b..00000000 diff --git a/src/utilities/mod.rs b/src/utilities/mod.rs index d320c009..62488e3a 100644 --- a/src/utilities/mod.rs +++ b/src/utilities/mod.rs @@ -1,91 +1 @@ -use curv::{ - arithmetic::{BasicOps, Integer, Modulo, NumberTests, Samplable, Zero}, - BigInt, -}; - -pub mod aff_g; -pub mod dec_q; -pub mod enc; -pub mod log_star; -pub mod mul; -pub mod mul_star; pub mod sha2; - -/// Extend or truncate a vector of bytes to a fixed length array. -/// -/// If the length is less than the target amount `N` leading zeroes -/// are prepended, if the length exceeds `N` it is truncated. -/// -/// The `ChaChaRng::from_seed()` function requires a `[u8; 32]` but the -/// chaining of the BigInt's does not guarantee the length -/// of the underlying bytes so we use this to ensure we seed the RNG -/// using the correct number of bytes. -pub fn fixed_array( - mut seed: Vec, -) -> Result<[u8; 32], Vec> { - use std::cmp::Ordering; - match seed.len().cmp(&N) { - Ordering::Greater => { - seed.truncate(N); - } - Ordering::Less => { - let padding = vec![0; N - seed.len()]; - seed.splice(..0, padding.iter().cloned()); - } - _ => {} - } - seed.try_into() -} - -pub fn sample_relatively_prime_integer(n: &BigInt) -> BigInt { - let mut sample = BigInt::sample_below(n); - while BigInt::gcd(&sample, n) != BigInt::from(1) { - sample = BigInt::sample_below(n); - } - sample -} - -pub fn mod_pow_with_negative( - v: &BigInt, - pow: &BigInt, - modulus: &BigInt, -) -> BigInt { - if BigInt::is_negative(pow) { - let temp = BigInt::mod_pow(v, &pow.abs(), modulus); - BigInt::mod_inv(&temp, modulus).unwrap_or_else(BigInt::zero) - } else { - BigInt::mod_pow(v, pow, modulus) - } -} - -pub const SEC_PARAM: usize = 256; -pub const SEC_BYTES: usize = SEC_PARAM / 8; -pub const OT_PARAM: usize = 128; -pub const OT_BYTES: usize = OT_PARAM / 8; -pub const STAT_PARAM: usize = 80; - -// ZK_MOD_ITERATIONS is the number of iterations that are performed to prove the -// validity of a Paillier-Blum modulus N. -// Theoretically, the number of iterations corresponds to the statistical -// security parameter, and would be 80. -// The way it is used in the refresh protocol ensures that the prover cannot -// guess in advance the secret ρ used to instantiate the hash function. -// Since sampling primes is expensive, we argue that the security can be -// reduced. -pub const ZK_MOD_ITERATIONS: usize = 12; - -#[allow(clippy::identity_op)] -pub const L: usize = 1 * SEC_PARAM; // = 256 -pub const L_PRIME: usize = 5 * SEC_PARAM; // = 1280 -pub const EPSILON: usize = 2 * SEC_PARAM; // = 512 -pub const L_PLUS_EPSILON: usize = L + EPSILON; // = 768 -pub const L_PRIME_PLUS_EPSILON: usize = L_PRIME + EPSILON; // = 1792 - -pub const BITS_INT_MODN: usize = 8 * SEC_PARAM; // = 2048 -pub const BYTES_INT_MODN: usize = BITS_INT_MODN / 8; // = 256 - -pub const BITS_BLUM_PRIME: usize = 4 * SEC_PARAM; // = 1024 -pub const BITS_PAILLIER: usize = 2 * BITS_BLUM_PRIME; // = 2048 - -pub const BYTES_PAILLIER: usize = BITS_PAILLIER / 8; // = 256 -pub const BYTES_CIPHERTEXT: usize = 2 * BYTES_PAILLIER; // = 512 diff --git a/tss-core/Cargo.toml b/tss-core/Cargo.toml new file mode 100644 index 00000000..260bc22e --- /dev/null +++ b/tss-core/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "tss-core" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +curv-kzen.workspace = true +serde.workspace = true +zeroize.workspace = true +paillier.workspace = true +sha2.workspace = true +rand_chacha.workspace = true +rand.workspace = true + +bincode = "1.3.3" +merlin = "3.0.0" +serde_repr = "0.1.16" +serde_with = "3.3.0" + +# [dependencies.multi-party-ecdsa] +# workspace = true +# default-features = false# + +# [dev-dependencies.multi-party-ecdsa] +# workspace = true +# default-features = false +# features = ["dev"] + +[features] +default = ["curv-kzen/rust-gmp-kzen"] \ No newline at end of file diff --git a/tss-core/src/lib.rs b/tss-core/src/lib.rs new file mode 100644 index 00000000..be248a6a --- /dev/null +++ b/tss-core/src/lib.rs @@ -0,0 +1,3 @@ +pub mod security_level; +pub mod utilities; +pub mod zkproof; diff --git a/tss-core/src/security_level/mod.rs b/tss-core/src/security_level/mod.rs new file mode 100644 index 00000000..cc9a71e1 --- /dev/null +++ b/tss-core/src/security_level/mod.rs @@ -0,0 +1,72 @@ +pub struct SecurityLevel { + // pub param: usize, + // pub zk_iterations: usize, + pub paillier_key_size: usize, + // pub paillier_min_bit_length: usize, + // pub paillier_max_bit_length: usize, + // pub length: usize, + // pub blind_factor: usize, + // pub ot_param: usize, +} + +pub const LEVEL1: SecurityLevel = SecurityLevel { + // param: 256, + // ot_param: 256, + // zk_iterations: 80, + paillier_key_size: 2048, + // paillier_min_bit_length: 2047, + // paillier_max_bit_length: 2048, + // blind_factor: 256, + // length: 256, +}; + +pub const LEVEL0: SecurityLevel = SecurityLevel { + // param: 64, + // zk_iterations: 80, + paillier_key_size: 256, + // paillier_min_bit_length: 255, + // paillier_max_bit_length: 256, + // blind_factor: 64, + // length: 64, + // ot_param: 64, +}; + +#[cfg(all(not(test), not(feature = "dev")))] +pub const DEFAULT_LEVEL: SecurityLevel = LEVEL1; +#[cfg(any(test, feature = "dev"))] +pub const DEFAULT_LEVEL: SecurityLevel = LEVEL0; + +// placeholders. Use until we can merge the levels. There is some mismatch +// between the levels between different crates. + +pub const SEC_PARAM: usize = 256; +pub const SEC_BYTES: usize = SEC_PARAM / 8; +pub const OT_PARAM: usize = 128; +pub const OT_BYTES: usize = OT_PARAM / 8; +pub const STAT_PARAM: usize = 80; + +// ZK_MOD_ITERATIONS is the number of iterations that are performed to prove the +// validity of a Paillier-Blum modulus N. +// Theoretically, the number of iterations corresponds to the statistical +// security parameter, and would be 80. +// The way it is used in the refresh protocol ensures that the prover cannot +// guess in advance the secret ρ used to instantiate the hash function. +// Since sampling primes is expensive, we argue that the security can be +// reduced. +pub const ZK_MOD_ITERATIONS: usize = 12; + +#[allow(clippy::identity_op)] +pub const L: usize = 1 * SEC_PARAM; // = 256 +pub const L_PRIME: usize = 5 * SEC_PARAM; // = 1280 +pub const EPSILON: usize = 2 * SEC_PARAM; // = 512 +pub const L_PLUS_EPSILON: usize = L + EPSILON; // = 768 +pub const L_PRIME_PLUS_EPSILON: usize = L_PRIME + EPSILON; // = 1792 + +pub const BITS_INT_MODN: usize = 8 * SEC_PARAM; // = 2048 +pub const BYTES_INT_MODN: usize = BITS_INT_MODN / 8; // = 256 + +pub const BITS_BLUM_PRIME: usize = 4 * SEC_PARAM; // = 1024 +pub const BITS_PAILLIER: usize = 2 * BITS_BLUM_PRIME; // = 2048 + +pub const BYTES_PAILLIER: usize = BITS_PAILLIER / 8; // = 256 +pub const BYTES_CIPHERTEXT: usize = 2 * BYTES_PAILLIER; // = 512 diff --git a/tss-core/src/utilities/mod.rs b/tss-core/src/utilities/mod.rs new file mode 100644 index 00000000..84e5508c --- /dev/null +++ b/tss-core/src/utilities/mod.rs @@ -0,0 +1,198 @@ +#![allow(non_snake_case)] + +use curv::arithmetic::traits::*; +use curv::BigInt; +use paillier::{DecryptionKey, EncryptionKey, KeyGeneration, Paillier}; +use serde::{Deserialize, Serialize}; + +use crate::security_level::DEFAULT_LEVEL; + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct RingPedersenParams { + // modulus N = p*q, where p,q are either safe primes or normal primes + pub N: BigInt, + // s and t such that t is in the subgroup generateb s. + pub s: BigInt, + pub t: BigInt, +} + +// RingPedersenWitness provides witness values for proving correctness of RingPedersenParams +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct RingPedersenWitness { + pub lambda: BigInt, + pub lambdaInv: BigInt, + pub phi: BigInt, + // we need p and q for computing square root mod N (composite) + pub p: BigInt, + pub q: BigInt, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum RingPedersenError { + NoSqrt, +} + +pub fn generate_safe_h1_h2_N_tilde() -> (RingPedersenParams, RingPedersenWitness) +{ + let (ek_tilde, dk_tilde) = Paillier::keypair_safe_primes_with_modulus_size( + DEFAULT_LEVEL.paillier_key_size, + ) + .keys(); + get_related_values(&ek_tilde, &dk_tilde) +} + +// generate_normal_h1_h2_N_tilde generates Paillier modulus N = p*q and related +// values h1 and h2 such that h2 = h1^lambda and h1=h2^lambda_inv. +pub fn generate_normal_h1_h2_N_tilde( +) -> (RingPedersenParams, RingPedersenWitness) { + let (ek_tilde, dk_tilde) = + Paillier::keypair_with_modulus_size(DEFAULT_LEVEL.paillier_key_size) + .keys(); + get_related_values(&ek_tilde, &dk_tilde) +} + +fn get_related_values( + ek: &EncryptionKey, + dk: &DecryptionKey, +) -> (RingPedersenParams, RingPedersenWitness) { + // Generate h1 and h2 (s and t in CGGMP20) following section 6.4.1 (and Figure 6) of CGGMP20 . + // Ref: . + let one = BigInt::one(); + let phi = (&dk.p - &one) * (&dk.q - &one); + let tau = BigInt::sample_below(&ek.n); + let h1 = BigInt::mod_pow(&tau, &BigInt::from(2), &ek.n); + // For GG18/20 implementation, we need the inverse of lambda as well. + let (lambda, lambdaInv) = loop { + let lambda_ = BigInt::sample_below(&phi); + match BigInt::mod_inv(&lambda_, &phi) { + Some(inv) => break (lambda_, inv), + None => continue, + } + }; + let h2 = BigInt::mod_pow(&h1, &lambda, &ek.n); + ( + RingPedersenParams { + N: ek.n.clone(), + s: h1, + t: h2, + }, + RingPedersenWitness { + lambda, + lambdaInv, + phi, + p: dk.p.clone(), + q: dk.q.clone(), + }, + ) +} + +pub fn sample_relatively_prime_integer(n: &BigInt) -> BigInt { + let mut sample = BigInt::sample_below(n); + while BigInt::gcd(&sample, n) != BigInt::from(1) { + sample = BigInt::sample_below(n); + } + sample +} + +pub fn mod_pow_with_negative( + v: &BigInt, + pow: &BigInt, + modulus: &BigInt, +) -> BigInt { + if BigInt::is_negative(pow) { + let temp = BigInt::mod_pow(v, &pow.abs(), modulus); + BigInt::mod_inv(&temp, modulus).unwrap_or_else(BigInt::zero) + } else { + BigInt::mod_pow(v, pow, modulus) + } +} + +pub fn legendre(a: &BigInt, modulus: &BigInt) -> BigInt { + let one = BigInt::from(1); + let two = BigInt::from(2); + let exp = (modulus - &one) / &two; + let l = BigInt::mod_pow(a, &exp, modulus); + if &l + &one == *modulus { + return BigInt::from(-1); + } + l +} + +/// Extend or truncate a vector of bytes to a fixed length array. +/// +/// If the length is less than the target amount `N` leading zeroes +/// are prepended, if the length exceeds `N` it is truncated. +/// +/// The `ChaChaRng::from_seed()` function requires a `[u8; 32]` but the +/// chaining of the BigInt's does not guarantee the length +/// of the underlying bytes so we use this to ensure we seed the RNG +/// using the correct number of bytes. +pub fn fixed_array( + mut seed: Vec, +) -> Result<[u8; 32], Vec> { + use std::cmp::Ordering; + match seed.len().cmp(&N) { + Ordering::Greater => { + seed.truncate(N); + } + Ordering::Less => { + let padding = vec![0; N - seed.len()]; + seed.splice(..0, padding.iter().cloned()); + } + _ => {} + } + seed.try_into() +} + +pub fn sqrt_comp( + x: &BigInt, + p: &BigInt, + q: &BigInt, +) -> Result { + let one = BigInt::from(1); + let two = BigInt::from(2); + let three = BigInt::from(3); + let four = BigInt::from(4); + if p % &four != three { + return Err(RingPedersenError::NoSqrt); + } + if q % &four != three { + return Err(RingPedersenError::NoSqrt); + } + // instead of checking Legendre symbol, we check that the square of parts equals input + let x_mod_p = BigInt::modulus(x, p); + let x_mod_q = BigInt::modulus(x, q); + let p_exp = (p + &one) / &four; + let q_exp = (q + &one) / &four; + let lpart = BigInt::mod_pow(&x_mod_p, &p_exp, p); + let rpart = BigInt::mod_pow(&x_mod_q, &q_exp, q); + if BigInt::mod_pow(&lpart, &two, p) != x_mod_p { + return Err(RingPedersenError::NoSqrt); + } + if BigInt::mod_pow(&rpart, &two, q) != x_mod_q { + return Err(RingPedersenError::NoSqrt); + } + let pinv = BigInt::mod_inv(p, q).unwrap(); + let xsqrt = &lpart + p * ((&rpart - &lpart) * &pinv); + Ok(xsqrt) +} + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn test_sqrt() { + let (rpparams, rpwitness) = generate_safe_h1_h2_N_tilde(); + let mut x = BigInt::sample_below(&rpparams.N); + while legendre(&x, &rpwitness.p) != BigInt::from(1) + || legendre(&x, &rpwitness.q) != BigInt::from(1) + { + x = BigInt::sample_below(&rpparams.N); + } + let xsqrtres = sqrt_comp(&x, &rpwitness.p, &rpwitness.q); + assert!(xsqrtres.is_ok()); + let xsqrt = xsqrtres.unwrap(); + let xx = BigInt::mod_pow(&xsqrt, &BigInt::from(2), &rpparams.N); + assert_eq!(x, xx); + } +} diff --git a/src/utilities/aff_g/mod.rs b/tss-core/src/zkproof/aff_g/mod.rs similarity index 69% rename from src/utilities/aff_g/mod.rs rename to tss-core/src/zkproof/aff_g/mod.rs index 1ddeedf6..c0568d9a 100644 --- a/src/utilities/aff_g/mod.rs +++ b/tss-core/src/zkproof/aff_g/mod.rs @@ -33,13 +33,11 @@ //! and //! D = C^{x} · (1+N0)^{y} · ρ^{N0} mod N0^{2}. -use super::sample_relatively_prime_integer; -use crate::{ - utilities::{ - fixed_array, mod_pow_with_negative, L, L_PLUS_EPSILON, L_PRIME, - L_PRIME_PLUS_EPSILON, - }, - Error, +use crate::security_level::{L, L_PLUS_EPSILON, L_PRIME, L_PRIME_PLUS_EPSILON}; +use crate::utilities::fixed_array; +use crate::utilities::RingPedersenParams; +use crate::utilities::{ + mod_pow_with_negative, sample_relatively_prime_integer, }; use curv::{ arithmetic::{traits::*, Modulo}, @@ -57,13 +55,8 @@ use serde::{Deserialize, Serialize}; use std::marker::PhantomData; #[derive(Clone, Debug, Serialize, Deserialize)] -pub struct PaillierAffineOpWithGroupComInRangeStatement< - E: Curve, - H: Digest + Clone, -> { - pub S: BigInt, - pub T: BigInt, - pub N_hat: BigInt, +pub struct PiAffGStatement { + pub RPParam: RingPedersenParams, pub N0: BigInt, pub N1: BigInt, pub NN0: BigInt, @@ -77,10 +70,16 @@ pub struct PaillierAffineOpWithGroupComInRangeStatement< pub phantom: PhantomData<(E, H)>, } -pub struct PaillierAffineOpWithGroupComInRangeWitness< - E: Curve, - H: Digest + Clone, -> { +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum PiAffGError { + Serialization, + Validation, + Challenge, + Proof, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct PiAffGWitness { x: BigInt, y: BigInt, rho: BigInt, @@ -88,11 +87,9 @@ pub struct PaillierAffineOpWithGroupComInRangeWitness< phantom: PhantomData<(E, H)>, } -impl - PaillierAffineOpWithGroupComInRangeWitness -{ +impl PiAffGWitness { pub fn new(x: BigInt, y: BigInt, rho: BigInt, rho_y: BigInt) -> Self { - PaillierAffineOpWithGroupComInRangeWitness { + PiAffGWitness { x, y, rho, @@ -102,20 +99,16 @@ impl } } -impl - PaillierAffineOpWithGroupComInRangeStatement -{ +impl PiAffGStatement { #[allow(clippy::too_many_arguments)] pub fn generate( - S: BigInt, - T: BigInt, - N_hat: BigInt, + rpparam: RingPedersenParams, rho: BigInt, rho_y: BigInt, prover: EncryptionKey, verifier: EncryptionKey, C: BigInt, - ) -> (Self, PaillierAffineOpWithGroupComInRangeWitness) { + ) -> (Self, PiAffGWitness) { // Set up exponents let l_exp = BigInt::pow(&BigInt::from(2), L as u32); let lprime_exp = BigInt::pow(&BigInt::from(2), L_PRIME as u32); @@ -156,9 +149,7 @@ impl ( Self { - S, - T, - N_hat, + RPParam: rpparam, N0, N1, NN0, @@ -171,7 +162,7 @@ impl ek_verifier, phantom: PhantomData, }, - PaillierAffineOpWithGroupComInRangeWitness { + PiAffGWitness { x, y, rho, @@ -183,7 +174,7 @@ impl } #[derive(Clone, Debug, Serialize, Deserialize)] -pub struct PaillierAffineOpWithGroupComInRangeCommitment { +pub struct PiAffGCommitment { A: BigInt, B_x: Point, B_y: BigInt, @@ -194,26 +185,23 @@ pub struct PaillierAffineOpWithGroupComInRangeCommitment { } #[derive(Clone, Debug, Serialize, Deserialize)] -pub struct PaillierAffineOpWithGroupComInRangeProof -{ +pub struct PiAffGProof { z1: BigInt, z2: BigInt, z3: BigInt, z4: BigInt, w: BigInt, wy: BigInt, - commitment: PaillierAffineOpWithGroupComInRangeCommitment, + commitment: PiAffGCommitment, phantom: PhantomData<(E, H)>, } // Link to the UC non-interactive threshold ECDSA paper -impl - PaillierAffineOpWithGroupComInRangeProof -{ +impl PiAffGProof { pub fn prove( - witness: &PaillierAffineOpWithGroupComInRangeWitness, - statement: &PaillierAffineOpWithGroupComInRangeStatement, - ) -> PaillierAffineOpWithGroupComInRangeProof { + witness: &PiAffGWitness, + statement: &PiAffGStatement, + ) -> PiAffGProof { // Set up exponents let l_exp = BigInt::pow(&BigInt::from(2), L as u32); let lplus_exp = BigInt::pow(&BigInt::from(2), L_PLUS_EPSILON as u32); @@ -233,23 +221,23 @@ impl let ry = sample_relatively_prime_integer(&statement.N1); // γ ← ± 2^{l+ε} · Nˆ let gamma = BigInt::sample_range( - &BigInt::from(-1).mul(&lplus_exp).mul(&statement.N_hat), - &lplus_exp.mul(&statement.N_hat), + &BigInt::from(-1).mul(&lplus_exp).mul(&statement.RPParam.N), + &lplus_exp.mul(&statement.RPParam.N), ); // m ← ± 2l · Nˆ let m = BigInt::sample_range( - &BigInt::from(-1).mul(&l_exp).mul(&statement.N_hat), - &l_exp.mul(&statement.N_hat), + &BigInt::from(-1).mul(&l_exp).mul(&statement.RPParam.N), + &l_exp.mul(&statement.RPParam.N), ); // δ ← ± 2^{l+ε} · Nˆ let delta = BigInt::sample_range( - &BigInt::from(-1).mul(&lplus_exp).mul(&statement.N_hat), - &lplus_exp.mul(&statement.N_hat), + &BigInt::from(-1).mul(&lplus_exp).mul(&statement.RPParam.N), + &lplus_exp.mul(&statement.RPParam.N), ); // mu ← ± 2l · Nˆ let mu = BigInt::sample_range( - &BigInt::from(-1).mul(&l_exp).mul(&statement.N_hat), - &l_exp.mul(&statement.N_hat), + &BigInt::from(-1).mul(&l_exp).mul(&statement.RPParam.N), + &l_exp.mul(&statement.RPParam.N), ); // A = C^α · (1 + N0)^β · r^N0 mod N0^2 let A = { @@ -275,27 +263,59 @@ impl ); // E = s^α · t^γ mod Nˆ let E = BigInt::mod_mul( - &mod_pow_with_negative(&statement.S, &alpha, &statement.N_hat), - &mod_pow_with_negative(&statement.T, &gamma, &statement.N_hat), - &statement.N_hat, + &mod_pow_with_negative( + &statement.RPParam.s, + &alpha, + &statement.RPParam.N, + ), + &mod_pow_with_negative( + &statement.RPParam.t, + &gamma, + &statement.RPParam.N, + ), + &statement.RPParam.N, ); // big S = s^x · t^m mod Nˆ let big_S = BigInt::mod_mul( - &mod_pow_with_negative(&statement.S, &witness.x, &statement.N_hat), - &mod_pow_with_negative(&statement.T, &m, &statement.N_hat), - &statement.N_hat, + &mod_pow_with_negative( + &statement.RPParam.s, + &witness.x, + &statement.RPParam.N, + ), + &mod_pow_with_negative( + &statement.RPParam.t, + &m, + &statement.RPParam.N, + ), + &statement.RPParam.N, ); // F = s^β · t^δ mod Nˆ let F = BigInt::mod_mul( - &mod_pow_with_negative(&statement.S, &beta, &statement.N_hat), - &mod_pow_with_negative(&statement.T, &delta, &statement.N_hat), - &statement.N_hat, + &mod_pow_with_negative( + &statement.RPParam.s, + &beta, + &statement.RPParam.N, + ), + &mod_pow_with_negative( + &statement.RPParam.t, + &delta, + &statement.RPParam.N, + ), + &statement.RPParam.N, ); // big T = s^y · t^mu mod Nˆ let big_T = BigInt::mod_mul( - &mod_pow_with_negative(&statement.S, &witness.y, &statement.N_hat), - &mod_pow_with_negative(&statement.T, &mu, &statement.N_hat), - &statement.N_hat, + &mod_pow_with_negative( + &statement.RPParam.s, + &witness.y, + &statement.RPParam.N, + ), + &mod_pow_with_negative( + &statement.RPParam.t, + &mu, + &statement.RPParam.N, + ), + &statement.RPParam.N, ); // Hash all prover messages to generate NIZK challenge let mut e: BigInt = H::new() @@ -315,7 +335,7 @@ impl .add(&BigInt::one()) .mul(&e); // Compute Fiat-Shamir commitment preimage - let commitment = PaillierAffineOpWithGroupComInRangeCommitment:: { + let commitment = PiAffGCommitment:: { A, B_x, B_y: B_y.clone().into(), @@ -358,9 +378,9 @@ impl } pub fn verify( - proof: &PaillierAffineOpWithGroupComInRangeProof, - statement: &PaillierAffineOpWithGroupComInRangeStatement, - ) -> Result<(), Error> { + proof: &PiAffGProof, + statement: &PiAffGStatement, + ) -> Result<(), PiAffGError> { // Hash all prover messages to generate NIZK challenge let mut e: BigInt = H::new() .chain_bigint(&proof.commitment.big_S.clone()) @@ -383,17 +403,13 @@ impl RANGE CHECKS */ // z1 ∈ [-2^{l+ε}, 2^{l+ε}] - assert!( - proof.z1.bit_length() <= L_PLUS_EPSILON, - "z1 is too large {:?}", - proof.z1.bit_length() - ); + if proof.z1.bit_length() > L_PLUS_EPSILON { + return Err(PiAffGError::Validation); + } // z2 ∈ [-2^{l'+ε}, 2^{l'+ε}] - assert!( - proof.z2.bit_length() <= L_PRIME_PLUS_EPSILON, - "z2 is too large {:?}", - proof.z2.bit_length() - ); + if proof.z2.bit_length() > L_PRIME_PLUS_EPSILON { + return Err(PiAffGError::Validation); + } /* FIRST EQUALITY CHECK @@ -418,7 +434,9 @@ impl &statement.NN0, ); // Assert left == right - assert!(left_1 == right_1); + if left_1 != right_1 { + return Err(PiAffGError::Proof); + } /* SECOND EQUALITY CHECK */ @@ -428,7 +446,9 @@ impl let right_2 = proof.commitment.B_x.clone() + (statement.X.clone() * Scalar::from_bigint(&e)); // Assert left == right - assert!(left_2 == right_2); + if left_2 != right_2 { + return Err(PiAffGError::Proof); + } /* THIRD EQUALITY CHECK */ @@ -446,71 +466,85 @@ impl &statement.NN1, ); // Assert left == right - assert!(left_3.mod_floor(&statement.NN1) == right_3); + if left_3.mod_floor(&statement.NN1) != right_3 { + return Err(PiAffGError::Proof); + } /* FOURTH EQUALITY CHECK */ - // s^{z1} · t^{z3} = E · big_S^e mod N_hat + // s^{z1} · t^{z3} = E · big_S^e mod RPParam.N let left_4 = { - // s^{z1} mod N_hat^2 + // s^{z1} mod RPParam.N^2 let temp_left_4_1 = mod_pow_with_negative( - &statement.S, + &statement.RPParam.s, &proof.z1, - &statement.N_hat, + &statement.RPParam.N, ); - // t^{z3} mod N_hat^2 + // t^{z3} mod RPParam.N^2 let temp_left_4_2 = mod_pow_with_negative( - &statement.T, + &statement.RPParam.t, &proof.z3, - &statement.N_hat, + &statement.RPParam.N, ); - // s^{z1} · t^{z3} mod N_hat^2 - BigInt::mod_mul(&temp_left_4_1, &temp_left_4_2, &statement.N_hat) + // s^{z1} · t^{z3} mod RPParam.N^2 + BigInt::mod_mul( + &temp_left_4_1, + &temp_left_4_2, + &statement.RPParam.N, + ) }; - // E · big_S^e mod N_hat^2 + // E · big_S^e mod RPParam.N^2 let right_4 = BigInt::mod_mul( &proof.commitment.E, &mod_pow_with_negative( &proof.commitment.big_S, &e, - &statement.N_hat, + &statement.RPParam.N, ), - &statement.N_hat, + &statement.RPParam.N, ); // Assert left == right - assert!(left_4 == right_4); + if left_4 != right_4 { + return Err(PiAffGError::Proof); + } /* FIFTH EQUALITY CHECK */ - // s^{z2} · t^{z4} = F · big_T^e mod N_hat + // s^{z2} · t^{z4} = F · big_T^e mod RPParam.N let left_5 = { - // s^{z2} mod N_hat^2 + // s^{z2} mod RPParam.N^2 let temp_left_5_1 = mod_pow_with_negative( - &statement.S, + &statement.RPParam.s, &proof.z2, - &statement.N_hat, + &statement.RPParam.N, ); - // t^{z4} mod N_hat^2 + // t^{z4} mod RPParam.N^2 let temp_left_5_2 = mod_pow_with_negative( - &statement.T, + &statement.RPParam.t, &proof.z4, - &statement.N_hat, + &statement.RPParam.N, ); - // s^{z2} · t^{z4} mod N_hat^2 - BigInt::mod_mul(&temp_left_5_1, &temp_left_5_2, &statement.N_hat) + // s^{z2} · t^{z4} mod RPParam.N^2 + BigInt::mod_mul( + &temp_left_5_1, + &temp_left_5_2, + &statement.RPParam.N, + ) }; - // F · big_T^e mod N_hat^2 + // F · big_T^e mod RPParam.N^2 let right_5 = BigInt::mod_mul( &proof.commitment.F, &mod_pow_with_negative( &proof.commitment.big_T, &e, - &statement.N_hat, + &statement.RPParam.N, ), - &statement.N_hat, + &statement.RPParam.N, ); // Assert left == right - assert!(left_5 == right_5); + if left_5 != right_5 { + return Err(PiAffGError::Proof); + } Ok(()) } } @@ -518,49 +552,38 @@ impl #[cfg(test)] mod tests { use super::*; - use crate::{ - mpc_ecdsa::utilities::mta::range_proofs::SampleFromMultiplicativeGroup, - utilities::BITS_PAILLIER, - }; + use crate::security_level::BITS_PAILLIER; + use crate::utilities::generate_safe_h1_h2_N_tilde; use curv::elliptic::curves::secp256_k1::Secp256k1; - use fs_dkr::ring_pedersen_proof::RingPedersenStatement; use paillier::{Encrypt, KeyGeneration, Paillier, RawPlaintext}; use sha2::Sha256; #[test] fn test_affine_g_proof() { - let (ring_pedersen_statement, _witness) = - RingPedersenStatement::::generate(); + let (rpparam, _) = generate_safe_h1_h2_N_tilde(); let (ek_prover, _) = Paillier::keypair_with_modulus_size(BITS_PAILLIER).keys(); let (ek_verifier, _) = Paillier::keypair_with_modulus_size(BITS_PAILLIER).keys(); - let rho: BigInt = BigInt::from_paillier_key(&ek_verifier); - let rho_y: BigInt = BigInt::from_paillier_key(&ek_prover); + let rho: BigInt = sample_relatively_prime_integer(&ek_verifier.n); + let rho_y: BigInt = sample_relatively_prime_integer(&ek_prover.n); let C = Paillier::encrypt( &ek_verifier, RawPlaintext::from(BigInt::from(12)), ); - let (statement, witness) = PaillierAffineOpWithGroupComInRangeStatement::< - Secp256k1, - Sha256, - >::generate( - ring_pedersen_statement.S, - ring_pedersen_statement.T, - ring_pedersen_statement.N, - rho, - rho_y, - ek_prover, - ek_verifier, - C.0.into_owned(), - ); - let proof = PaillierAffineOpWithGroupComInRangeProof::::prove( - &witness, &statement, - ); - assert!(PaillierAffineOpWithGroupComInRangeProof::::verify( - &proof, &statement - ) - .is_ok()); + let (statement, witness) = + PiAffGStatement::::generate( + rpparam, + rho, + rho_y, + ek_prover, + ek_verifier, + C.0.into_owned(), + ); + let proof = + PiAffGProof::::prove(&witness, &statement); + assert!(PiAffGProof::::verify(&proof, &statement) + .is_ok()); } } diff --git a/src/utilities/dec_q/mod.rs b/tss-core/src/zkproof/dec/mod.rs similarity index 68% rename from src/utilities/dec_q/mod.rs rename to tss-core/src/zkproof/dec/mod.rs index e9ea5636..d8af4f81 100644 --- a/src/utilities/dec_q/mod.rs +++ b/tss-core/src/zkproof/dec/mod.rs @@ -15,10 +15,10 @@ @license GPL-3.0+ */ -use super::{sample_relatively_prime_integer, L, L_PLUS_EPSILON}; -use crate::{ - utilities::{fixed_array, mod_pow_with_negative}, - Error, +use crate::security_level::{L, L_PLUS_EPSILON}; +use crate::utilities::RingPedersenParams; +use crate::utilities::{ + fixed_array, mod_pow_with_negative, sample_relatively_prime_integer, }; use curv::{ arithmetic::{traits::*, Modulo}, @@ -36,10 +36,13 @@ use serde::{Deserialize, Serialize}; use std::marker::PhantomData; #[derive(Clone, Debug, Serialize, Deserialize)] -pub struct PaillierDecryptionModQStatement { - pub S: BigInt, - pub T: BigInt, - pub N_hat: BigInt, +pub enum PiDecError { + Proof, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct PiDecStatement { + pub RPParams: RingPedersenParams, pub N0: BigInt, pub NN0: BigInt, pub C: BigInt, @@ -48,15 +51,15 @@ pub struct PaillierDecryptionModQStatement { pub phantom: PhantomData<(E, H)>, } -pub struct PaillierDecryptionModQWitness { +pub struct PiDecWitness { y: BigInt, rho: BigInt, phantom: PhantomData<(E, H)>, } -impl PaillierDecryptionModQWitness { +impl PiDecWitness { pub fn new(y: BigInt, rho: BigInt) -> Self { - PaillierDecryptionModQWitness { + PiDecWitness { y, rho, phantom: PhantomData, @@ -64,15 +67,13 @@ impl PaillierDecryptionModQWitness { } } -impl PaillierDecryptionModQStatement { +impl PiDecStatement { #[allow(clippy::too_many_arguments)] pub fn generate( - S: BigInt, - T: BigInt, - N_hat: BigInt, + rpparams: RingPedersenParams, rho: BigInt, prover: EncryptionKey, - ) -> (Self, PaillierDecryptionModQWitness) { + ) -> (Self, PiDecWitness) { let ek_prover = prover.clone(); // y <- Z_N let y = BigInt::sample_below(&prover.n); @@ -89,9 +90,7 @@ impl PaillierDecryptionModQStatement { let x = BigInt::mod_floor(&y, Scalar::::group_order()); ( Self { - S, - T, - N_hat, + RPParams: rpparams, N0: prover.n, NN0: prover.nn, C, @@ -99,7 +98,7 @@ impl PaillierDecryptionModQStatement { ek_prover, phantom: PhantomData, }, - PaillierDecryptionModQWitness { + PiDecWitness { y, rho, phantom: PhantomData, @@ -109,7 +108,7 @@ impl PaillierDecryptionModQStatement { } #[derive(Clone, Debug, Serialize, Deserialize)] -pub struct PaillierDecryptionModQCommitment { +pub struct PiDecCommitment { A: BigInt, gamma: BigInt, big_S: BigInt, @@ -117,20 +116,20 @@ pub struct PaillierDecryptionModQCommitment { } #[derive(Clone, Debug, Serialize, Deserialize)] -pub struct PaillierDecryptionModQProof { +pub struct PiDecProof { z1: BigInt, z2: BigInt, w: BigInt, - commitment: PaillierDecryptionModQCommitment, + commitment: PiDecCommitment, phantom: PhantomData<(E, H)>, } // Link to the UC non-interactive threshold ECDSA paper -impl PaillierDecryptionModQProof { +impl PiDecProof { pub fn prove( - witness: &PaillierDecryptionModQWitness, - statement: &PaillierDecryptionModQStatement, - ) -> PaillierDecryptionModQProof { + witness: &PiDecWitness, + statement: &PiDecStatement, + ) -> PiDecProof { // Set up exponents let l_exp = BigInt::pow(&BigInt::from(2), L as u32); let lplus_exp = BigInt::pow(&BigInt::from(2), L_PLUS_EPSILON as u32); @@ -139,28 +138,43 @@ impl PaillierDecryptionModQProof { BigInt::sample_range(&BigInt::from(-1).mul(&lplus_exp), &lplus_exp); // mu ← ± 2l · Nˆ let mu = BigInt::sample_range( - &BigInt::from(-1).mul(&l_exp).mul(&statement.N_hat), - &l_exp.mul(&statement.N_hat), + &BigInt::from(-1).mul(&l_exp).mul(&statement.RPParams.N), + &l_exp.mul(&statement.RPParams.N), ); // nu ← 2^{l+ε} · Nˆ let nu = BigInt::sample_range( - &BigInt::from(-1).mul(&lplus_exp).mul(&statement.N_hat), - &lplus_exp.mul(&statement.N_hat), + &BigInt::from(-1).mul(&lplus_exp).mul(&statement.RPParams.N), + &lplus_exp.mul(&statement.RPParams.N), ); // r <- Z*_N let r = sample_relatively_prime_integer(&statement.N0); // big_S = s^y * t^μ mod Nˆ let big_S = { - let s = BigInt::mod_pow(&statement.S, &witness.y, &statement.N_hat); - let t = mod_pow_with_negative(&statement.T, &mu, &statement.N_hat); - BigInt::mod_mul(&s, &t, &statement.N_hat) + let s = BigInt::mod_pow( + &statement.RPParams.s, + &witness.y, + &statement.RPParams.N, + ); + let t = mod_pow_with_negative( + &statement.RPParams.t, + &mu, + &statement.RPParams.N, + ); + BigInt::mod_mul(&s, &t, &statement.RPParams.N) }; // big_T = s^α & t^ν mod Nˆ let big_T = { - let s = - mod_pow_with_negative(&statement.S, &alpha, &statement.N_hat); - let t = mod_pow_with_negative(&statement.T, &nu, &statement.N_hat); - BigInt::mod_mul(&s, &t, &statement.N_hat) + let s = mod_pow_with_negative( + &statement.RPParams.s, + &alpha, + &statement.RPParams.N, + ); + let t = mod_pow_with_negative( + &statement.RPParams.t, + &nu, + &statement.RPParams.N, + ); + BigInt::mod_mul(&s, &t, &statement.RPParams.N) }; // A = (1 + N0)^α * r^N0 mod N0^2 let A = { @@ -188,13 +202,12 @@ impl PaillierDecryptionModQProof { .mul(&BigInt::from(-2)) .add(&BigInt::one()) .mul(&e); - let commitment: PaillierDecryptionModQCommitment = - PaillierDecryptionModQCommitment { - A, - gamma, - big_S, - big_T, - }; + let commitment: PiDecCommitment = PiDecCommitment { + A, + gamma, + big_S, + big_T, + }; // z1 = α + e · y let z1 = BigInt::add(&alpha, &BigInt::mul(&e, &witness.y)); // z2 = ν + e · μ @@ -205,7 +218,7 @@ impl PaillierDecryptionModQProof { BigInt::mod_mul(&r, &rho, &statement.N0) }; // Return the proof - PaillierDecryptionModQProof { + PiDecProof { z1, z2, w, @@ -215,9 +228,9 @@ impl PaillierDecryptionModQProof { } pub fn verify( - proof: &PaillierDecryptionModQProof, - statement: &PaillierDecryptionModQStatement, - ) -> Result<(), Error> { + proof: &PiDecProof, + statement: &PiDecStatement, + ) -> Result<(), PiDecError> { // Compute the challenge let mut e = H::new() .chain_bigint(&proof.commitment.A) @@ -252,7 +265,9 @@ impl PaillierDecryptionModQProof { BigInt::mod_mul(&proof.commitment.A, &C, &statement.NN0) }; // Check the equality - assert!(left_1 == right_1); + if left_1 != right_1 { + return Err(PiDecError::Proof); + } /* SECOND EQUALITY CHECK z1 = γ + e * x mod q @@ -266,7 +281,9 @@ impl PaillierDecryptionModQProof { Scalar::::group_order(), ); // Check the equality - assert!(left_2 == right_2); + if left_2 != right_2 { + return Err(PiDecError::Proof); + } /* THIRD EQUALITY CHECK s^z1 · t^z2 = T · S^e mod Nˆ @@ -274,28 +291,34 @@ impl PaillierDecryptionModQProof { // Compute the left hand side let left_3 = { let s = mod_pow_with_negative( - &statement.S, + &statement.RPParams.s, &proof.z1, - &statement.N_hat, + &statement.RPParams.N, ); let t = mod_pow_with_negative( - &statement.T, + &statement.RPParams.t, &proof.z2, - &statement.N_hat, + &statement.RPParams.N, ); - BigInt::mod_mul(&s, &t, &statement.N_hat) + BigInt::mod_mul(&s, &t, &statement.RPParams.N) }; // Compute the right hand side let right_3 = { let temp = mod_pow_with_negative( &proof.commitment.big_S, &e, - &statement.N_hat, + &statement.RPParams.N, ); - BigInt::mod_mul(&proof.commitment.big_T, &temp, &statement.N_hat) + BigInt::mod_mul( + &proof.commitment.big_T, + &temp, + &statement.RPParams.N, + ) }; // Check the equality - assert!(left_3 == right_3); + if left_3 != right_3 { + return Err(PiDecError::Proof); + } Ok(()) } } @@ -303,36 +326,26 @@ impl PaillierDecryptionModQProof { #[cfg(test)] mod tests { use super::*; - use crate::{ - mpc_ecdsa::utilities::mta::range_proofs::SampleFromMultiplicativeGroup, - utilities::BITS_PAILLIER, - }; + use crate::security_level::BITS_PAILLIER; + use crate::utilities::generate_safe_h1_h2_N_tilde; use curv::elliptic::curves::secp256_k1::Secp256k1; - use fs_dkr::ring_pedersen_proof::RingPedersenStatement; use paillier::{KeyGeneration, Paillier}; use sha2::Sha256; #[test] fn test_paillier_decryption_modulo_q() { - let (ring_pedersen_statement, _witness) = - RingPedersenStatement::::generate(); + let (rpparam, _) = generate_safe_h1_h2_N_tilde(); let (ek_prover, _) = Paillier::keypair_with_modulus_size(BITS_PAILLIER).keys(); - let rho: BigInt = BigInt::from_paillier_key(&ek_prover); + let rho: BigInt = sample_relatively_prime_integer(&ek_prover.n); let (statement, witness) = - PaillierDecryptionModQStatement::::generate( - ring_pedersen_statement.S, - ring_pedersen_statement.T, - ring_pedersen_statement.N, - rho, - ek_prover, + PiDecStatement::::generate( + rpparam, rho, ek_prover, ); - let proof = PaillierDecryptionModQProof::::prove( - &witness, &statement, + let proof = + PiDecProof::::prove(&witness, &statement); + assert!( + PiDecProof::::verify(&proof, &statement).is_ok() ); - assert!(PaillierDecryptionModQProof::::verify( - &proof, &statement - ) - .is_ok()); } } diff --git a/src/utilities/enc/mod.rs b/tss-core/src/zkproof/enc/mod.rs similarity index 64% rename from src/utilities/enc/mod.rs rename to tss-core/src/zkproof/enc/mod.rs index c7100b4c..84bf89b8 100644 --- a/src/utilities/enc/mod.rs +++ b/tss-core/src/zkproof/enc/mod.rs @@ -20,8 +20,10 @@ //! Common input is (N0, K). The Prover has secret input (k, ρ) such that //! k ∈ ± 2l, and K = (1 + N0)^k · ρ^N0 mod N0^2. -use super::sample_relatively_prime_integer; -use crate::utilities::{mod_pow_with_negative, L}; +use crate::security_level::{L, L_PLUS_EPSILON}; +use crate::utilities::mod_pow_with_negative; +use crate::utilities::sample_relatively_prime_integer; +use crate::utilities::RingPedersenParams; use curv::{ arithmetic::{traits::*, Modulo}, cryptographic_primitives::hashing::{Digest, DigestExt}, @@ -34,29 +36,33 @@ use paillier::{ }; use serde::{Deserialize, Serialize}; use std::marker::PhantomData; -use zk_paillier::zkproofs::IncorrectProof; #[derive(Clone, Debug, Serialize, Deserialize)] -pub struct PaillierEncryptionInRangeStatement { +pub struct PiEncStatement { pub N0: BigInt, pub NN0: BigInt, pub K: BigInt, - pub s: BigInt, - pub t: BigInt, - pub N_hat: BigInt, + pub RPParam: RingPedersenParams, pub phantom: PhantomData<(E, H)>, } #[derive(Clone, Debug, Serialize, Deserialize)] -pub struct PaillierEncryptionInRangeWitness { +pub struct PiEncWitness { k: BigInt, rho: BigInt, phantom: PhantomData<(E, H)>, } +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum PiEncError { + Serialization, + Validation, + Challenge, + Proof, +} -impl PaillierEncryptionInRangeWitness { +impl PiEncWitness { pub fn new(k: BigInt, rho: BigInt) -> Self { - PaillierEncryptionInRangeWitness { + PiEncWitness { k, rho, phantom: PhantomData, @@ -64,15 +70,13 @@ impl PaillierEncryptionInRangeWitness { } } -impl PaillierEncryptionInRangeStatement { +impl PiEncStatement { #[allow(clippy::too_many_arguments)] pub fn generate( rho: BigInt, - s: BigInt, - t: BigInt, - N_hat: BigInt, + rpparam: RingPedersenParams, paillier_key: EncryptionKey, - ) -> (Self, PaillierEncryptionInRangeWitness) { + ) -> (Self, PiEncWitness) { // Set up exponents let _l_exp = BigInt::pow(&BigInt::from(2), L as u32); // Set up moduli @@ -91,12 +95,10 @@ impl PaillierEncryptionInRangeStatement { N0, NN0, K, - s, - t, - N_hat, + RPParam: rpparam, phantom: PhantomData, }, - PaillierEncryptionInRangeWitness { + PiEncWitness { k, rho, phantom: PhantomData, @@ -113,7 +115,7 @@ pub struct PaillierEncryptionInRangeCommitment { } #[derive(Clone, Debug, Serialize, Deserialize)] -pub struct PaillierEncryptionInRangeProof { +pub struct PiEncProof { z_1: BigInt, z_2: BigInt, z_3: BigInt, @@ -121,36 +123,29 @@ pub struct PaillierEncryptionInRangeProof { phantom: PhantomData<(E, H)>, } -impl PaillierEncryptionInRangeProof { - #[allow(dead_code)] +impl PiEncProof { pub fn prove( - witness: &PaillierEncryptionInRangeWitness, - statement: &PaillierEncryptionInRangeStatement, + witness: &PiEncWitness, + statement: &PiEncStatement, ) -> Self { // Step 1: Sample alpha between -2^{L+eps} and 2^{L+eps} - let alpha_upper = BigInt::pow( - &BigInt::from(2), - crate::utilities::L_PLUS_EPSILON as u32, - ); + let alpha_upper = BigInt::pow(&BigInt::from(2), L_PLUS_EPSILON as u32); let alpha_lower = BigInt::from(-1).mul(&alpha_upper); let alpha = BigInt::sample_range(&alpha_lower, &alpha_upper); // Step 2: mu, r, gamma // Sample mu between -2^L * N_hat and 2^L * N_hat let mu_upper = BigInt::mul( - &statement.N_hat, - &BigInt::pow(&BigInt::from(2), crate::utilities::L as u32), + &statement.RPParam.N, + &BigInt::pow(&BigInt::from(2), L as u32), ); let mu_lower = BigInt::from(-1).mul(&mu_upper); let mu = BigInt::sample_range(&mu_lower, &mu_upper); // γ ← ± 2^{l+ε} · Nˆ let gamma_upper = BigInt::mul( - &statement.N_hat, - &BigInt::pow( - &BigInt::from(2), - crate::utilities::L_PLUS_EPSILON as u32, - ), + &statement.RPParam.N, + &BigInt::pow(&BigInt::from(2), L_PLUS_EPSILON as u32), ); let gamma_lower = BigInt::from(-1).mul(&gamma_upper); let gamma = BigInt::sample_range(&gamma_lower, &gamma_upper); @@ -160,9 +155,17 @@ impl PaillierEncryptionInRangeProof { // Step 3: S, A, C // S = s^k t^mu mod N_hat let S = BigInt::mod_mul( - &mod_pow_with_negative(&statement.s, &witness.k, &statement.N_hat), - &mod_pow_with_negative(&statement.t, &mu, &statement.N_hat), - &statement.N_hat, + &mod_pow_with_negative( + &statement.RPParam.s, + &witness.k, + &statement.RPParam.N, + ), + &mod_pow_with_negative( + &statement.RPParam.t, + &mu, + &statement.RPParam.N, + ), + &statement.RPParam.N, ); // A = (1+N_0)^{alpha}r^{N_0} mod N_0^2 @@ -178,9 +181,17 @@ impl PaillierEncryptionInRangeProof { // C = s^alpha * t^gamma mod N_hat let C = BigInt::mod_mul( - &mod_pow_with_negative(&statement.s, &alpha, &statement.N_hat), - &mod_pow_with_negative(&statement.t, &gamma, &statement.N_hat), - &statement.N_hat, + &mod_pow_with_negative( + &statement.RPParam.s, + &alpha, + &statement.RPParam.N, + ), + &mod_pow_with_negative( + &statement.RPParam.t, + &gamma, + &statement.RPParam.N, + ), + &statement.RPParam.N, ); let commitment = PaillierEncryptionInRangeCommitment { @@ -217,11 +228,10 @@ impl PaillierEncryptionInRangeProof { } } - #[allow(dead_code)] pub fn verify( - proof: &PaillierEncryptionInRangeProof, - statement: &PaillierEncryptionInRangeStatement, - ) -> Result<(), IncorrectProof> { + proof: &PiEncProof, + statement: &PiEncStatement, + ) -> Result<(), PiEncError> { let e = H::new() .chain_bigint(&proof.commitment.S) .chain_bigint(&proof.commitment.A) @@ -249,36 +259,43 @@ impl PaillierEncryptionInRangeProof { // left_2 = s^z_1 t^z_3 mod N_hat let left_2 = BigInt::mod_mul( - &mod_pow_with_negative(&statement.s, &proof.z_1, &statement.N_hat), - &mod_pow_with_negative(&statement.t, &proof.z_3, &statement.N_hat), - &statement.N_hat, + &mod_pow_with_negative( + &statement.RPParam.s, + &proof.z_1, + &statement.RPParam.N, + ), + &mod_pow_with_negative( + &statement.RPParam.t, + &proof.z_3, + &statement.RPParam.N, + ), + &statement.RPParam.N, ); // right_2 = C * S^e mod N_hat let right_2 = BigInt::mod_mul( &proof.commitment.C, - &mod_pow_with_negative(&proof.commitment.S, &e, &statement.N_hat), - &statement.N_hat, + &mod_pow_with_negative( + &proof.commitment.S, + &e, + &statement.RPParam.N, + ), + &statement.RPParam.N, ); if left_1.mod_floor(&NN0) != right_1 || left_2 != right_2 { - return Err(IncorrectProof); + return Err(PiEncError::Proof); } // Range Check -2^{L + eps} <= z_1 <= 2^{L+eps} let lower_bound_check: bool = proof.z_1 - >= BigInt::from(-1).mul(&BigInt::pow( - &BigInt::from(2), - crate::utilities::L_PLUS_EPSILON as u32, - )); - - let upper_bound_check = proof.z_1 - <= BigInt::pow( - &BigInt::from(2), - crate::utilities::L_PLUS_EPSILON as u32, - ); + >= BigInt::from(-1) + .mul(&BigInt::pow(&BigInt::from(2), L_PLUS_EPSILON as u32)); + + let upper_bound_check = + proof.z_1 <= BigInt::pow(&BigInt::from(2), L_PLUS_EPSILON as u32); if !(lower_bound_check && upper_bound_check) { - return Err(IncorrectProof); + return Err(PiEncError::Proof); } Ok(()) @@ -288,37 +305,30 @@ impl PaillierEncryptionInRangeProof { #[cfg(test)] mod tests { use super::*; - use crate::{ - mpc_ecdsa::utilities::mta::range_proofs::SampleFromMultiplicativeGroup, - utilities::BITS_PAILLIER, - }; + use crate::utilities::generate_safe_h1_h2_N_tilde; use curv::elliptic::curves::secp256_k1::Secp256k1; - use fs_dkr::ring_pedersen_proof::RingPedersenStatement; use paillier::{KeyGeneration, Paillier}; use sha2::Sha256; #[test] fn test_paillier_encryption_in_range_proof() { - let (ring_pedersen_statement, _witness) = - RingPedersenStatement::::generate(); - let (paillier_key, _) = - Paillier::keypair_with_modulus_size(BITS_PAILLIER).keys(); + let (auxRPParam, _) = generate_safe_h1_h2_N_tilde(); + let (paillier_key, _) = Paillier::keypair_with_modulus_size( + crate::security_level::BITS_PAILLIER, + ) + .keys(); - let rho: BigInt = BigInt::from_paillier_key(&paillier_key); + // sample the prover secret inputs + let rho: BigInt = sample_relatively_prime_integer(&paillier_key.n); let (statement, witness) = - PaillierEncryptionInRangeStatement::::generate( + PiEncStatement::::generate( rho, - ring_pedersen_statement.S, - ring_pedersen_statement.T, - ring_pedersen_statement.N, + auxRPParam, paillier_key, ); - let proof = PaillierEncryptionInRangeProof::::prove( - &witness, &statement, - ); - assert!(PaillierEncryptionInRangeProof::::verify( - &proof, &statement, - ) - .is_ok()); + let proof = + PiEncProof::::prove(&witness, &statement); + assert!(PiEncProof::::verify(&proof, &statement,) + .is_ok()); } } diff --git a/tss-core/src/zkproof/fac/mod.rs b/tss-core/src/zkproof/fac/mod.rs new file mode 100644 index 00000000..72a8c390 --- /dev/null +++ b/tss-core/src/zkproof/fac/mod.rs @@ -0,0 +1,356 @@ +#![allow(non_snake_case)] + +use crate::{ + security_level::{L, L_PLUS_EPSILON, SEC_BYTES}, + utilities::{ + mod_pow_with_negative, RingPedersenParams, RingPedersenWitness, + }, +}; + +use curv::{ + arithmetic::{traits::*, Modulo}, + BigInt, +}; + +use merlin::Transcript; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum PiFacError { + Statement, + Serialization, + Proof, +} + +impl From> for PiFacError { + fn from(_: Box) -> Self { + Self::Serialization + } +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct PiFacStatement { + pub RPParam: RingPedersenParams, + pub N0: BigInt, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct PiFacWitness { + pub RPWitness: RingPedersenWitness, + pub p: BigInt, + pub q: BigInt, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct PiFacCommitment { + pub P: BigInt, + pub Q: BigInt, + pub A: BigInt, + pub B: BigInt, + pub T: BigInt, + pub sigma: BigInt, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct PiFacProof { + pub cmt: PiFacCommitment, + pub z1: BigInt, + pub z2: BigInt, + pub w1: BigInt, + pub w2: BigInt, + pub v: BigInt, +} + +impl PiFacProof { + pub fn prove( + statement: &PiFacStatement, + witness: &PiFacWitness, + ) -> Result { + let mone = BigInt::from(-1); + let two = BigInt::from(2); + let l_exp = BigInt::pow(&two, L as u32); + let lplus_exp = BigInt::pow(&two, L_PLUS_EPSILON as u32); + + // TODO: not sure in which domain we're taking sqrt of N0. However, we can still use bound of 1. + + // let mut sqrtN0 = match sqrt_comp( + // &statement.N0, + // &witness.RPWitness.p, + // &witness.RPWitness.q, + // ) { + // Ok(sqrtN0) => sqrtN0, + // Err(_) => return Err(PiFacError::Statement), + // }; + // if &sqrtN0 < &mone { + // sqrtN0 = -&sqrtN0; + // } + let sqrtN0 = BigInt::from(1); // bound + + // 2^{l+epsilon} sqrt(N0) + let lplus_sqrtN0 = lplus_exp.mul(&sqrtN0); + // 2^{l} \hat{N} + let l_N = l_exp.mul(&statement.RPParam.N); + // 2^{l} N0 \hat{N} + let l_N0_N = l_exp.mul(&statement.N0).mul(&statement.RPParam.N); + // 2^{l+epsilon} N0 \hat{N} + let lplus_N0_N = lplus_exp.mul(&statement.N0).mul(&statement.RPParam.N); + // 2^{l+epsilon} \hat{N} + let lplus_N = lplus_exp.mul(&statement.RPParam.N); + + let alpha = + BigInt::sample_range(&mone.mul(&lplus_sqrtN0), &lplus_sqrtN0); + let beta = + BigInt::sample_range(&mone.mul(&lplus_sqrtN0), &lplus_sqrtN0); + let mu = BigInt::sample_range(&mone.mul(&l_N), &l_N); + let nu = BigInt::sample_range(&mone.mul(&l_N), &l_N); + let sigma = BigInt::sample_range(&mone.mul(&l_N0_N), &l_N0_N); + let r = BigInt::sample_range(&mone.mul(&lplus_N0_N), &lplus_N0_N); + let x = BigInt::sample_range(&mone.mul(&lplus_N), &lplus_N); + let y = BigInt::sample_range(&mone.mul(&lplus_N), &lplus_N); + + let P = BigInt::mod_mul( + &BigInt::mod_pow( + &statement.RPParam.s, + &witness.p, + &statement.RPParam.N, + ), + &mod_pow_with_negative( + &statement.RPParam.t, + &mu, + &statement.RPParam.N, + ), + &statement.RPParam.N, + ); + let Q = BigInt::mod_mul( + &BigInt::mod_pow( + &statement.RPParam.s, + &witness.q, + &statement.RPParam.N, + ), + &mod_pow_with_negative( + &statement.RPParam.t, + &nu, + &statement.RPParam.N, + ), + &statement.RPParam.N, + ); + let A = BigInt::mod_mul( + &mod_pow_with_negative( + &statement.RPParam.s, + &alpha, + &statement.RPParam.N, + ), + &mod_pow_with_negative( + &statement.RPParam.t, + &x, + &statement.RPParam.N, + ), + &statement.RPParam.N, + ); + let B = BigInt::mod_mul( + &mod_pow_with_negative( + &statement.RPParam.s, + &beta, + &statement.RPParam.N, + ), + &mod_pow_with_negative( + &statement.RPParam.t, + &y, + &statement.RPParam.N, + ), + &statement.RPParam.N, + ); + let T = BigInt::mod_mul( + &mod_pow_with_negative(&Q, &alpha, &statement.RPParam.N), + &mod_pow_with_negative( + &statement.RPParam.t, + &r, + &statement.RPParam.N, + ), + &statement.RPParam.N, + ); + let cmt = PiFacCommitment { + A, + B, + P, + Q, + T, + sigma: sigma.clone(), + }; + + let mut transcript = Transcript::new(b"PiFacProof"); + transcript.append_message( + b"PiFacStatement", + &bincode::serialize(&statement)?, + ); + transcript + .append_message(b"PiFacCommitment", &bincode::serialize(&cmt)?); + let mut challenge_bytes = [0u8; SEC_BYTES]; + transcript.challenge_bytes(b"PiFacChallenge", &mut challenge_bytes); + let mut e = BigInt::from_bytes(&challenge_bytes); + let mut challenge_sign_byte = [0u8; 1]; + transcript + .challenge_bytes(b"PiFacChallengeSign", &mut challenge_sign_byte); + if challenge_sign_byte[0] % 2 == 0 { + e = -e; + } + + let sigmahat = &sigma.sub(&nu.mul(&witness.p)); + + let z1 = BigInt::add(&alpha, &e.mul(&witness.p)); + let z2 = BigInt::add(&beta, &e.mul(&witness.q)); + let w1 = BigInt::add(&x, &e.mul(&mu)); + let w2 = BigInt::add(&y, &e.mul(&nu)); + let v = BigInt::add(&r, &e.mul(sigmahat)); + + Ok(PiFacProof { + cmt, + v, + w1, + w2, + z1, + z2, + }) + } + + pub fn verify( + statement: &PiFacStatement, + proof: &PiFacProof, + ) -> Result<(), PiFacError> { + let mut transcript = Transcript::new(b"PiFacProof"); + transcript.append_message( + b"PiFacStatement", + &bincode::serialize(&statement)?, + ); + transcript.append_message( + b"PiFacCommitment", + &bincode::serialize(&proof.cmt)?, + ); + let mut challenge_bytes = [0u8; SEC_BYTES]; + transcript.challenge_bytes(b"PiFacChallenge", &mut challenge_bytes); + let mut e = BigInt::from_bytes(&challenge_bytes); + let mut challenge_sign_byte = [0u8; 1]; + transcript + .challenge_bytes(b"PiFacChallengeSign", &mut challenge_sign_byte); + if challenge_sign_byte[0] % 2 == 0 { + e = -e; + } + // TODO: also sample the sign bit? + + let R = BigInt::mod_mul( + &BigInt::mod_pow( + &statement.RPParam.s, + &statement.N0, + &statement.RPParam.N, + ), + &mod_pow_with_negative( + &statement.RPParam.t, + &proof.cmt.sigma, + &statement.RPParam.N, + ), + &statement.RPParam.N, + ); + // first check + let first_ls = BigInt::mod_mul( + &mod_pow_with_negative( + &statement.RPParam.s, + &proof.z1, + &statement.RPParam.N, + ), + &mod_pow_with_negative( + &statement.RPParam.t, + &proof.w1, + &statement.RPParam.N, + ), + &statement.RPParam.N, + ); + let first_rs = BigInt::mod_mul( + &proof.cmt.A, + &mod_pow_with_negative(&proof.cmt.P, &e, &statement.RPParam.N), + &statement.RPParam.N, + ); + if first_ls != first_rs { + return Err(PiFacError::Proof); + } + // second check + let second_ls = BigInt::mod_mul( + &mod_pow_with_negative( + &statement.RPParam.s, + &proof.z2, + &statement.RPParam.N, + ), + &mod_pow_with_negative( + &statement.RPParam.t, + &proof.w2, + &statement.RPParam.N, + ), + &statement.RPParam.N, + ); + let second_rs = BigInt::mod_mul( + &proof.cmt.B, + &mod_pow_with_negative(&proof.cmt.Q, &e, &statement.RPParam.N), + &statement.RPParam.N, + ); + if second_ls != second_rs { + return Err(PiFacError::Proof); + } + // third check + let third_ls = BigInt::mod_mul( + &mod_pow_with_negative( + &proof.cmt.Q, + &proof.z1, + &statement.RPParam.N, + ), + &mod_pow_with_negative( + &statement.RPParam.t, + &proof.v, + &statement.RPParam.N, + ), + &statement.RPParam.N, + ); + let third_rs = BigInt::mod_mul( + &proof.cmt.T, + &mod_pow_with_negative(&R, &e, &statement.RPParam.N), + &statement.RPParam.N, + ); + if third_ls != third_rs { + return Err(PiFacError::Proof); + } + + // range check + // we take sqrt{N0} == 1 + if proof.z1.bit_length() > L_PLUS_EPSILON { + return Err(PiFacError::Proof); + } + if proof.z2.bit_length() > L_PLUS_EPSILON { + return Err(PiFacError::Proof); + } + + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::utilities::generate_safe_h1_h2_N_tilde; + + #[test] + fn test_prove() { + let (rpparams, rpwitnes) = generate_safe_h1_h2_N_tilde(); + let (rpparam2, rpwitness2) = generate_safe_h1_h2_N_tilde(); + let statement = PiFacStatement { + N0: rpparam2.N, + RPParam: rpparams, + }; + let witness = PiFacWitness { + RPWitness: rpwitnes, + p: rpwitness2.p, + q: rpwitness2.q, + }; + let proof = PiFacProof::prove(&statement, &witness); + assert!(proof.is_ok()); + let res = PiFacProof::verify(&statement, &proof.unwrap()); + assert!(res.is_ok()); + } +} diff --git a/src/utilities/log_star/mod.rs b/tss-core/src/zkproof/log_star/mod.rs similarity index 63% rename from src/utilities/log_star/mod.rs rename to tss-core/src/zkproof/log_star/mod.rs index 882a24fc..3a51afb9 100644 --- a/src/utilities/log_star/mod.rs +++ b/tss-core/src/zkproof/log_star/mod.rs @@ -21,8 +21,11 @@ //! The Prover has secret input (x,ρ) such that //! x ∈ ± 2l, and C = (1 + N0)^x · ρ^N0 mod N0^2 and X = g^x ∈ G. -use super::sample_relatively_prime_integer; -use crate::utilities::{mod_pow_with_negative, L}; +use crate::security_level::{L, L_PLUS_EPSILON}; +use crate::utilities::RingPedersenParams; +use crate::utilities::{ + mod_pow_with_negative, sample_relatively_prime_integer, +}; use curv::{ arithmetic::{traits::*, Modulo}, cryptographic_primitives::hashing::{Digest, DigestExt}, @@ -35,13 +38,17 @@ use paillier::{ }; use serde::{Deserialize, Serialize}; use std::marker::PhantomData; -use zk_paillier::zkproofs::IncorrectProof; #[derive(Clone, Debug, Serialize, Deserialize)] -pub struct KnowledgeOfExponentPaillierEncryptionStatement< - E: Curve, - H: Digest + Clone, -> { +pub enum PiLogStarError { + Serialization, + Validation, + Challenge, + Proof, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct PiLogStarStatement { pub N0: BigInt, pub NN0: BigInt, pub C: BigInt, @@ -55,26 +62,19 @@ pub struct KnowledgeOfExponentPaillierEncryptionStatement< // - Delta_i = Gamma^{k_i} // :- g = Gamma pub g: Point, - pub N_hat: BigInt, - pub s: BigInt, - pub t: BigInt, + pub RPParams: RingPedersenParams, pub phantom: PhantomData<(E, H)>, } -pub struct KnowledgeOfExponentPaillierEncryptionWitness< - E: Curve, - H: Digest + Clone, -> { +pub struct PiLogStarWitness { x: BigInt, rho: BigInt, phantom: PhantomData<(E, H)>, } -impl - KnowledgeOfExponentPaillierEncryptionWitness -{ +impl PiLogStarWitness { pub fn new(x: BigInt, rho: BigInt) -> Self { - KnowledgeOfExponentPaillierEncryptionWitness { + PiLogStarWitness { x, rho, phantom: PhantomData, @@ -82,18 +82,14 @@ impl } } -impl - KnowledgeOfExponentPaillierEncryptionStatement -{ +impl PiLogStarStatement { #[allow(clippy::too_many_arguments)] pub fn generate( rho: BigInt, g: Option>, - s: BigInt, - t: BigInt, - N_hat: BigInt, + rpparam: RingPedersenParams, paillier_key: EncryptionKey, - ) -> (Self, KnowledgeOfExponentPaillierEncryptionWitness) { + ) -> (Self, PiLogStarWitness) { // Set up exponents let l_exp = BigInt::pow(&BigInt::from(2), L as u32); // Set up moduli @@ -118,12 +114,10 @@ impl C, X, g, - N_hat, - s, - t, + RPParams: rpparam, phantom: PhantomData, }, - KnowledgeOfExponentPaillierEncryptionWitness { + PiLogStarWitness { x, rho, phantom: PhantomData, @@ -132,7 +126,7 @@ impl } } #[derive(Clone, Debug, Serialize, Deserialize)] -pub struct KnowledgeOfExponentPaillierEncryptionCommitment { +pub struct PiLogStarCommitment { S: BigInt, A: BigInt, Y: Point, @@ -140,60 +134,57 @@ pub struct KnowledgeOfExponentPaillierEncryptionCommitment { } #[derive(Clone, Debug, Serialize, Deserialize)] -pub struct KnowledgeOfExponentPaillierEncryptionProof< - E: Curve, - H: Digest + Clone, -> { +pub struct PiLogStarProof { z_1: BigInt, z_2: BigInt, z_3: BigInt, - commitment: KnowledgeOfExponentPaillierEncryptionCommitment, + commitment: PiLogStarCommitment, phantom: PhantomData<(E, H)>, } // Link to the UC non-interactive threshold ECDSA paper -impl - KnowledgeOfExponentPaillierEncryptionProof -{ +impl PiLogStarProof { pub fn prove( - witness: &KnowledgeOfExponentPaillierEncryptionWitness, - statement: &KnowledgeOfExponentPaillierEncryptionStatement, - ) -> KnowledgeOfExponentPaillierEncryptionProof { + witness: &PiLogStarWitness, + statement: &PiLogStarStatement, + ) -> PiLogStarProof { // Step 1: Sample alpha between -2^{l+ε} and 2^{l+ε} - let alpha_upper = BigInt::pow( - &BigInt::from(2), - crate::utilities::L_PLUS_EPSILON as u32, - ); + let alpha_upper = BigInt::pow(&BigInt::from(2), L_PLUS_EPSILON as u32); let alpha_lower = BigInt::from(-1).mul(&alpha_upper); let alpha = BigInt::sample_range(&alpha_lower, &alpha_upper); // Step 2: mu, r, gamma - // Sample mu between -2^L * N_hat and 2^L * N_hat + // Sample mu between -2^L * RPParams.N and 2^L * RPParams.N let mu_upper = BigInt::mul( - &statement.N_hat, - &BigInt::pow(&BigInt::from(2), crate::utilities::L as u32), + &statement.RPParams.N, + &BigInt::pow(&BigInt::from(2), L as u32), ); let mu_lower = BigInt::from(-1).mul(&mu_upper); let mu = BigInt::sample_range(&mu_lower, &mu_upper); // γ ← ± 2^{l+ε} · Nˆ let gamma_upper = BigInt::mul( - &statement.N_hat, - &BigInt::pow( - &BigInt::from(2), - crate::utilities::L_PLUS_EPSILON as u32, - ), + &statement.RPParams.N, + &BigInt::pow(&BigInt::from(2), L_PLUS_EPSILON as u32), ); let gamma_lower = BigInt::from(-1).mul(&gamma_upper); let gamma = BigInt::sample_range(&gamma_lower, &gamma_upper); // Sample r from Z*_{N_0} let r = sample_relatively_prime_integer(&statement.N0.clone()); - // S = s^x t^mu mod N_hat + // S = s^x t^mu mod RPParams.N let S = BigInt::mod_mul( - &mod_pow_with_negative(&statement.s, &witness.x, &statement.N_hat), - &mod_pow_with_negative(&statement.t, &mu, &statement.N_hat), - &statement.N_hat, + &mod_pow_with_negative( + &statement.RPParams.s, + &witness.x, + &statement.RPParams.N, + ), + &mod_pow_with_negative( + &statement.RPParams.t, + &mu, + &statement.RPParams.N, + ), + &statement.RPParams.N, ); // A = (1+N_0)^{alpha}r^{N_0} mod N_0^2 @@ -209,14 +200,22 @@ impl // Y = g^alpha let Y = &statement.g * Scalar::from_bigint(&alpha); - // D = s^alpha t^gamma mod N_hat + // D = s^alpha t^gamma mod RPParams.N let D = BigInt::mod_mul( - &mod_pow_with_negative(&statement.s, &alpha, &statement.N_hat), - &mod_pow_with_negative(&statement.t, &gamma, &statement.N_hat), - &statement.N_hat, + &mod_pow_with_negative( + &statement.RPParams.s, + &alpha, + &statement.RPParams.N, + ), + &mod_pow_with_negative( + &statement.RPParams.t, + &gamma, + &statement.RPParams.N, + ), + &statement.RPParams.N, ); - let commitment = KnowledgeOfExponentPaillierEncryptionCommitment { + let commitment = PiLogStarCommitment { S: S.clone(), A: A.clone(), Y: Y.clone(), @@ -252,9 +251,9 @@ impl } pub fn verify( - proof: &KnowledgeOfExponentPaillierEncryptionProof, - statement: &KnowledgeOfExponentPaillierEncryptionStatement, - ) -> Result<(), IncorrectProof> { + proof: &PiLogStarProof, + statement: &PiLogStarStatement, + ) -> Result<(), PiLogStarError> { let e = H::new() .chain_bigint(&proof.commitment.S) .chain_bigint(&proof.commitment.A) @@ -286,42 +285,49 @@ impl let right_2 = proof.commitment.Y.clone() + (statement.X.clone() * Scalar::from_bigint(&e)); - // left_3 = s^z_1 t^z_3 mod N_hat + // left_3 = s^z_1 t^z_3 mod RPParams.N let left_3 = BigInt::mod_mul( - &mod_pow_with_negative(&statement.s, &proof.z_1, &statement.N_hat), - &mod_pow_with_negative(&statement.t, &proof.z_3, &statement.N_hat), - &statement.N_hat, + &mod_pow_with_negative( + &statement.RPParams.s, + &proof.z_1, + &statement.RPParams.N, + ), + &mod_pow_with_negative( + &statement.RPParams.t, + &proof.z_3, + &statement.RPParams.N, + ), + &statement.RPParams.N, ); - // right_3 = D * S^e mod N_hat + // right_3 = D * S^e mod RPParams.N let right_3 = BigInt::mod_mul( &proof.commitment.D, - &mod_pow_with_negative(&proof.commitment.S, &e, &statement.N_hat), - &statement.N_hat, + &mod_pow_with_negative( + &proof.commitment.S, + &e, + &statement.RPParams.N, + ), + &statement.RPParams.N, ); if left_1.mod_floor(&statement.NN0) != right_1 || left_2 != right_2 || left_3 != right_3 { - return Err(IncorrectProof); + return Err(PiLogStarError::Proof); } // Range Check -2^{L + eps} <= z_1 <= 2^{L+eps} let lower_bound_check: bool = proof.z_1 - >= BigInt::from(-1).mul(&BigInt::pow( - &BigInt::from(2), - crate::utilities::L_PLUS_EPSILON as u32, - )); - - let upper_bound_check = proof.z_1 - <= BigInt::pow( - &BigInt::from(2), - crate::utilities::L_PLUS_EPSILON as u32, - ); + >= BigInt::from(-1) + .mul(&BigInt::pow(&BigInt::from(2), L_PLUS_EPSILON as u32)); + + let upper_bound_check = + proof.z_1 <= BigInt::pow(&BigInt::from(2), L_PLUS_EPSILON as u32); if !(lower_bound_check && upper_bound_check) { - return Err(IncorrectProof); + return Err(PiLogStarError::Proof); } Ok(()) } @@ -330,39 +336,31 @@ impl #[cfg(test)] mod tests { use super::*; - use crate::{ - mpc_ecdsa::utilities::mta::range_proofs::SampleFromMultiplicativeGroup, - utilities::BITS_PAILLIER, - }; + use crate::security_level::BITS_PAILLIER; + use crate::utilities::generate_safe_h1_h2_N_tilde; use curv::elliptic::curves::secp256_k1::Secp256k1; - use fs_dkr::ring_pedersen_proof::RingPedersenStatement; use paillier::{KeyGeneration, Paillier}; use sha2::Sha256; #[test] fn test_log_star_proof() { - let (ring_pedersen_statement, _witness) = - RingPedersenStatement::::generate(); + let (rpparam, _) = generate_safe_h1_h2_N_tilde(); let (paillier_key, _) = Paillier::keypair_with_modulus_size(BITS_PAILLIER).keys(); - let rho: BigInt = BigInt::from_paillier_key(&paillier_key); + let rho: BigInt = sample_relatively_prime_integer(&paillier_key.n); let (statement, witness) = - KnowledgeOfExponentPaillierEncryptionStatement::::generate( - rho, - Some(Point::::generator().to_point()), - ring_pedersen_statement.S, - ring_pedersen_statement.T, - ring_pedersen_statement.N, - paillier_key, - ); - let proof = KnowledgeOfExponentPaillierEncryptionProof::< - Secp256k1, - Sha256, - >::prove(&witness, &statement); - assert!(KnowledgeOfExponentPaillierEncryptionProof::::verify( - &proof, &statement - ) - .is_ok()); + PiLogStarStatement::::generate( + rho, + Some(Point::::generator().to_point()), + rpparam, + paillier_key, + ); + let proof = + PiLogStarProof::::prove(&witness, &statement); + assert!(PiLogStarProof::::verify( + &proof, &statement + ) + .is_ok()); } } diff --git a/tss-core/src/zkproof/mod.rs b/tss-core/src/zkproof/mod.rs new file mode 100644 index 00000000..abcef9d3 --- /dev/null +++ b/tss-core/src/zkproof/mod.rs @@ -0,0 +1,9 @@ +pub mod aff_g; +pub mod dec; +pub mod enc; +pub mod fac; +pub mod log_star; +pub mod modulus; +pub mod mul; +pub mod mul_star; +pub mod prm; diff --git a/tss-core/src/zkproof/modulus/mod.rs b/tss-core/src/zkproof/modulus/mod.rs new file mode 100644 index 00000000..4eb9fb0b --- /dev/null +++ b/tss-core/src/zkproof/modulus/mod.rs @@ -0,0 +1,224 @@ +#![allow(non_snake_case)] + +use crate::{ + security_level::{SEC_BYTES, STAT_PARAM}, + utilities::{legendre, sqrt_comp}, +}; +use curv::{ + arithmetic::{traits::*, Modulo}, + BigInt, +}; +use merlin::Transcript; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum PiModError { + Statement, + Serialization, + Proof, +} + +impl From> for PiModError { + fn from(_: Box) -> Self { + Self::Serialization + } +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct PiModStatement { + pub N: BigInt, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct PiModWitness { + pub p: BigInt, + pub q: BigInt, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct PiModCommitment { + pub w: BigInt, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct PiModProof { + pub cmt: PiModCommitment, + pub x: Vec, + pub a: Vec, + pub b: Vec, + pub z: Vec, +} + +impl PiModProof { + pub fn prove( + statement: &PiModStatement, + witness: &PiModWitness, + ) -> Result { + let one = BigInt::from(1); + let three = BigInt::from(3); + let four = BigInt::from(4); + if &witness.p % &four != three { + return Err(PiModError::Statement); + } + if &witness.q % &four != three { + return Err(PiModError::Statement); + } + let phi = (&witness.p - &one) * (&witness.q - &one); + let ninv = match BigInt::mod_inv(&statement.N, &phi) { + Some(ninv) => ninv, + None => return Err(PiModError::Statement), + }; + + let mone = BigInt::from(-1); + let mut w = BigInt::sample_below(&statement.N); + while legendre(&w, &witness.p) * legendre(&w, &witness.q) != mone { + w = BigInt::sample_below(&statement.N); + } + let mut y: Vec = Vec::with_capacity(STAT_PARAM); + let commitment = PiModCommitment { w: w.clone() }; + let mut transcript = Transcript::new(b"PiModProof"); + transcript.append_message( + b"PiModStatement", + &bincode::serialize(&statement)?, + ); + transcript.append_message( + b"PiModCommitment", + &bincode::serialize(&commitment)?, + ); + let mut a: Vec = Vec::with_capacity(STAT_PARAM); + let mut b: Vec = Vec::with_capacity(STAT_PARAM); + let mut x: Vec = Vec::with_capacity(STAT_PARAM); + let mut z: Vec = Vec::with_capacity(STAT_PARAM); + 'outer: for i in 0..STAT_PARAM { + transcript.append_message(b"PiModChallengeRound", &i.to_le_bytes()); + let mut challenge_bytes = [0u8; SEC_BYTES]; + transcript.challenge_bytes(b"PiModChallenge", &mut challenge_bytes); + let mut yi = BigInt::from_bytes(&challenge_bytes); + yi %= &statement.N; + y.push(yi.clone()); + let zi = BigInt::mod_pow(&yi, &ninv, &statement.N); + z.push(zi.clone()); + + for (ai, bi) in + [(false, false), (false, true), (true, false), (true, true)] + { + let mut ypi = yi.clone(); + if ai { + ypi = &statement.N - ypi; + } + if bi { + ypi = BigInt::mod_mul(&w, &ypi, &statement.N); + } + let ypi_sqrt = sqrt_comp(&ypi, &witness.p, &witness.q); + if ypi_sqrt.is_err() { + continue; + } + let ypi_fourth_sqrt = + sqrt_comp(&(ypi_sqrt.unwrap()), &witness.p, &witness.q); + if ypi_fourth_sqrt.is_err() { + continue; + } + a.push(ai); + b.push(bi); + x.push(ypi_fourth_sqrt.unwrap()); + continue 'outer; + } + return Err(PiModError::Statement); + } + + Ok(PiModProof { + cmt: commitment, + x, + a, + b, + z, + }) + } + + pub fn verify( + statement: &PiModStatement, + proof: &PiModProof, + ) -> Result<(), PiModError> { + let one = BigInt::from(1); + let two = BigInt::from(2); + let four = BigInt::from(4); + if &statement.N % two != one { + return Err(PiModError::Statement); + } + if BigInt::is_probable_prime( + &statement.N, + (STAT_PARAM / 2).try_into().unwrap(), + ) { + return Err(PiModError::Statement); + } + + let mut transcript = Transcript::new(b"PiModProof"); + transcript.append_message( + b"PiModStatement", + &bincode::serialize(&statement)?, + ); + transcript.append_message( + b"PiModCommitment", + &bincode::serialize(&proof.cmt)?, + ); + for i in 0..STAT_PARAM { + transcript.append_message(b"PiModChallengeRound", &i.to_le_bytes()); + let mut challenge_bytes = [0u8; SEC_BYTES]; + transcript.challenge_bytes(b"PiModChallenge", &mut challenge_bytes); + let mut yi = BigInt::from_bytes(&challenge_bytes); + yi &= &statement.N; + + let zi = match proof.z.get(i) { + Some(zi) => zi, + None => return Err(PiModError::Proof), + }; + let zin = BigInt::mod_pow(zi, &statement.N, &statement.N); + if zin != yi { + return Err(PiModError::Proof); + } + let ai = match proof.a.get(i) { + Some(ai) => *ai, + None => return Err(PiModError::Proof), + }; + let bi = match proof.b.get(i) { + Some(bi) => *bi, + None => return Err(PiModError::Proof), + }; + if ai { + yi = &statement.N - yi; + } + if bi { + yi = BigInt::mod_mul(&proof.cmt.w, &yi, &statement.N); + } + let xi = match proof.x.get(i) { + Some(xi) => xi, + None => return Err(PiModError::Proof), + }; + let xifourth = BigInt::mod_pow(xi, &four, &statement.N); + if xifourth != yi { + return Err(PiModError::Proof); + } + } + + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::utilities::generate_safe_h1_h2_N_tilde; + + #[test] + fn test_prove() { + let (rpparams, rpwitness) = generate_safe_h1_h2_N_tilde(); + let statement = PiModStatement { N: rpparams.N }; + let witness = PiModWitness { + p: rpwitness.p, + q: rpwitness.q, + }; + let proof = PiModProof::prove(&statement, &witness); + assert!(proof.is_ok()); + assert!(PiModProof::verify(&statement, &proof.unwrap()).is_ok()); + } +} diff --git a/src/utilities/mul/mod.rs b/tss-core/src/zkproof/mul/mod.rs similarity index 80% rename from src/utilities/mul/mod.rs rename to tss-core/src/zkproof/mul/mod.rs index 4e4d082e..049185f8 100644 --- a/src/utilities/mul/mod.rs +++ b/tss-core/src/zkproof/mul/mod.rs @@ -15,10 +15,8 @@ @license GPL-3.0+ */ -use super::sample_relatively_prime_integer; -use crate::{ - utilities::{fixed_array, mod_pow_with_negative}, - Error, +use crate::utilities::{ + fixed_array, mod_pow_with_negative, sample_relatively_prime_integer, }; use curv::{ arithmetic::{traits::*, Modulo}, @@ -36,7 +34,15 @@ use serde::{Deserialize, Serialize}; use std::marker::PhantomData; #[derive(Clone, Debug, Serialize, Deserialize)] -pub struct PaillierMulStatement { +pub enum PiMulError { + Serialization, + Validation, + Challenge, + Proof, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct PiMulStatement { pub N: BigInt, pub NN: BigInt, pub C: BigInt, @@ -46,16 +52,16 @@ pub struct PaillierMulStatement { pub phantom: PhantomData<(E, H)>, } -pub struct PaillierMulWitness { +pub struct PiMulWitness { x: BigInt, rho: BigInt, rho_x: BigInt, phantom: PhantomData<(E, H)>, } -impl PaillierMulWitness { +impl PiMulWitness { pub fn new(x: BigInt, rho: BigInt, rho_x: BigInt) -> Self { - PaillierMulWitness { + PiMulWitness { x, rho, rho_x, @@ -64,14 +70,14 @@ impl PaillierMulWitness { } } -impl PaillierMulStatement { +impl PiMulStatement { #[allow(clippy::too_many_arguments)] pub fn generate( rho: BigInt, rho_x: BigInt, prover: EncryptionKey, Y: BigInt, - ) -> (Self, PaillierMulWitness) { + ) -> (Self, PiMulWitness) { let ek_prover = prover.clone(); // x <- Z_N let x = BigInt::sample_below(&prover.n); @@ -98,7 +104,7 @@ impl PaillierMulStatement { ek_prover, phantom: PhantomData, }, - PaillierMulWitness { + PiMulWitness { x, rho, rho_x, @@ -109,26 +115,26 @@ impl PaillierMulStatement { } #[derive(Clone, Debug, Serialize, Deserialize)] -pub struct PaillierMulCommitment { +pub struct PiMulCommitment { A: BigInt, B: BigInt, } #[derive(Clone, Debug, Serialize, Deserialize)] -pub struct PaillierMulProof { +pub struct PiMulProof { z: BigInt, u: BigInt, v: BigInt, - commitment: PaillierMulCommitment, + commitment: PiMulCommitment, phantom: PhantomData<(E, H)>, } // Link to the UC non-interactive threshold ECDSA paper -impl PaillierMulProof { +impl PiMulProof { pub fn prove( - witness: &PaillierMulWitness, - statement: &PaillierMulStatement, - ) -> PaillierMulProof { + witness: &PiMulWitness, + statement: &PiMulStatement, + ) -> PiMulProof { // α,r,s <- Z∗_N let alpha = sample_relatively_prime_integer(&statement.N); let r = sample_relatively_prime_integer(&statement.N); @@ -158,7 +164,7 @@ impl PaillierMulProof { .mul(&BigInt::from(-2)) .add(&BigInt::one()) .mul(&e); - let commitment: PaillierMulCommitment = PaillierMulCommitment { A, B }; + let commitment: PiMulCommitment = PiMulCommitment { A, B }; // z = α + e * x mod N let z = BigInt::add(&alpha, &BigInt::mul(&e, &witness.x)); // u = r * rho^e mod N @@ -174,7 +180,7 @@ impl PaillierMulProof { &statement.N, ); // Return the proof - PaillierMulProof { + PiMulProof { z, u, v, @@ -184,9 +190,9 @@ impl PaillierMulProof { } pub fn verify( - proof: &PaillierMulProof, - statement: &PaillierMulStatement, - ) -> Result<(), Error> { + proof: &PiMulProof, + statement: &PiMulStatement, + ) -> Result<(), PiMulError> { // Compute the challenge let mut e = H::new() .chain_bigint(&proof.commitment.A) @@ -213,7 +219,9 @@ impl PaillierMulProof { &mod_pow_with_negative(&statement.C, &e, &statement.NN), &statement.NN, ); - assert!(left_1 == right_1); + if left_1 != right_1 { + return Err(PiMulError::Proof); + } /* SECOND EQUALITY CHECK (1 + N)^z · v^N = B · X^e mod N^2 === Enc(z,c) = B · X^e mod N^2 @@ -229,7 +237,9 @@ impl PaillierMulProof { &mod_pow_with_negative(&statement.X, &e, &statement.NN), &statement.NN, ); - assert!(left_2.mod_floor(&statement.NN) == right_2); + if left_2.mod_floor(&statement.NN) != right_2 { + return Err(PiMulError::Proof); + } Ok(()) } } @@ -237,10 +247,7 @@ impl PaillierMulProof { #[cfg(test)] mod tests { use super::*; - use crate::{ - mpc_ecdsa::utilities::mta::range_proofs::SampleFromMultiplicativeGroup, - utilities::BITS_PAILLIER, - }; + use crate::security_level::BITS_PAILLIER; use curv::elliptic::curves::secp256_k1::Secp256k1; use paillier::{Encrypt, KeyGeneration, Paillier, RawPlaintext}; use sha2::Sha256; @@ -249,22 +256,21 @@ mod tests { fn test_paillier_mul() { let (ek_prover, _) = Paillier::keypair_with_modulus_size(BITS_PAILLIER).keys(); - let rho: BigInt = BigInt::from_paillier_key(&ek_prover); - let rho_x: BigInt = BigInt::from_paillier_key(&ek_prover); + let rho: BigInt = sample_relatively_prime_integer(&ek_prover.n); + let rho_x: BigInt = sample_relatively_prime_integer(&ek_prover.n); let Y = Paillier::encrypt(&ek_prover, RawPlaintext::from(BigInt::from(12))); let (statement, witness) = - PaillierMulStatement::::generate( + PiMulStatement::::generate( rho, rho_x, ek_prover, Y.0.into_owned(), ); let proof = - PaillierMulProof::::prove(&witness, &statement); - assert!(PaillierMulProof::::verify( - &proof, &statement - ) - .is_ok()); + PiMulProof::::prove(&witness, &statement); + assert!( + PiMulProof::::verify(&proof, &statement).is_ok() + ); } } diff --git a/src/utilities/mul_star/mod.rs b/tss-core/src/zkproof/mul_star/mod.rs similarity index 61% rename from src/utilities/mul_star/mod.rs rename to tss-core/src/zkproof/mul_star/mod.rs index 3de810e4..daf61915 100644 --- a/src/utilities/mul_star/mod.rs +++ b/tss-core/src/zkproof/mul_star/mod.rs @@ -21,8 +21,11 @@ //! The Prover has secret input (x,ρ) such that //! x ∈ ± 2l, and C = (1 + N0)^x · ρ^N0 mod N0^2 and X = g^x ∈ G. -use super::sample_relatively_prime_integer; -use crate::utilities::{mod_pow_with_negative, L}; +use crate::security_level::{L, L_PLUS_EPSILON}; +use crate::utilities::RingPedersenParams; +use crate::utilities::{ + mod_pow_with_negative, sample_relatively_prime_integer, +}; use curv::{ arithmetic::{traits::*, Modulo}, cryptographic_primitives::hashing::{Digest, DigestExt}, @@ -32,36 +35,32 @@ use curv::{ use paillier::EncryptionKey; use serde::{Deserialize, Serialize}; use std::marker::PhantomData; -use zk_paillier::zkproofs::IncorrectProof; #[derive(Clone, Debug, Serialize, Deserialize)] -pub struct PaillierMultiplicationVersusGroupStatement< - E: Curve, - H: Digest + Clone, -> { +pub enum PiMulStarError { + Proof, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct PiMulStarStatement { pub N0: BigInt, pub NN0: BigInt, pub C: BigInt, pub D: BigInt, pub X: Point, - pub N_hat: BigInt, - pub s: BigInt, - pub t: BigInt, + pub RPParams: RingPedersenParams, pub phantom: PhantomData<(E, H)>, } -pub struct PaillierMultiplicationVersusGroupWitness -{ +pub struct PiMulStarWitness { x: BigInt, rho: BigInt, phantom: PhantomData<(E, H)>, } -impl - PaillierMultiplicationVersusGroupWitness -{ +impl PiMulStarWitness { pub fn new(x: BigInt, rho: BigInt) -> Self { - PaillierMultiplicationVersusGroupWitness { + PiMulStarWitness { x, rho, phantom: PhantomData, @@ -69,18 +68,14 @@ impl } } -impl - PaillierMultiplicationVersusGroupStatement -{ +impl PiMulStarStatement { #[allow(clippy::too_many_arguments)] pub fn generate( rho: BigInt, _C: BigInt, - s: BigInt, - t: BigInt, - N_hat: BigInt, + rpparam: RingPedersenParams, paillier_key: EncryptionKey, - ) -> (Self, PaillierMultiplicationVersusGroupWitness) { + ) -> (Self, PiMulStarWitness) { // Set up exponents let l_exp = BigInt::pow(&BigInt::from(2), L as u32); // Set up moduli @@ -102,12 +97,10 @@ impl C, D, X, - N_hat, - s, - t, + RPParams: rpparam, phantom: PhantomData, }, - PaillierMultiplicationVersusGroupWitness { + PiMulStarWitness { x, rho, phantom: PhantomData, @@ -117,7 +110,7 @@ impl } #[derive(Clone, Debug, Serialize, Deserialize)] -pub struct PaillierMultiplicationVersusGroupCommitment { +pub struct PiMulStarCommitment { A: BigInt, B_x: Point, E: BigInt, @@ -125,44 +118,38 @@ pub struct PaillierMultiplicationVersusGroupCommitment { } #[derive(Clone, Debug, Serialize, Deserialize)] -pub struct PaillierMultiplicationVersusGroupProof { +pub struct PiMulStarProof { z_1: BigInt, z_2: BigInt, w: BigInt, - commitment: PaillierMultiplicationVersusGroupCommitment, + commitment: PiMulStarCommitment, phantom: PhantomData<(E, H)>, } // Link to the UC non-interactive threshold ECDSA paper -impl PaillierMultiplicationVersusGroupProof { +impl PiMulStarProof { pub fn prove( - witness: &PaillierMultiplicationVersusGroupWitness, - statement: &PaillierMultiplicationVersusGroupStatement, - ) -> PaillierMultiplicationVersusGroupProof { + witness: &PiMulStarWitness, + statement: &PiMulStarStatement, + ) -> PiMulStarProof { // Step 1: Sample alpha between -2^{l+ε} and 2^{l+ε} - let alpha_upper = BigInt::pow( - &BigInt::from(2), - crate::utilities::L_PLUS_EPSILON as u32, - ); + let alpha_upper = BigInt::pow(&BigInt::from(2), L_PLUS_EPSILON as u32); let alpha_lower = BigInt::from(-1).mul(&alpha_upper); let alpha = BigInt::sample_range(&alpha_lower, &alpha_upper); // Step 2: m, r, r_y gamma - // Sample mu between -2^L * N_hat and 2^L * N_hat + // Sample mu between -2^L * RPParams.N and 2^L * RPParams.N let m_upper = BigInt::mul( - &statement.N_hat, - &BigInt::pow(&BigInt::from(2), crate::utilities::L as u32), + &statement.RPParams.N, + &BigInt::pow(&BigInt::from(2), L as u32), ); let m_lower = BigInt::from(-1).mul(&m_upper); let m = BigInt::sample_range(&m_lower, &m_upper); // γ ← ± 2^{l+ε} · Nˆ let gamma_upper = BigInt::mul( - &statement.N_hat, - &BigInt::pow( - &BigInt::from(2), - crate::utilities::L_PLUS_EPSILON as u32, - ), + &statement.RPParams.N, + &BigInt::pow(&BigInt::from(2), L_PLUS_EPSILON as u32), ); let gamma_lower = BigInt::from(-1).mul(&gamma_upper); let gamma = BigInt::sample_range(&gamma_lower, &gamma_upper); @@ -180,18 +167,34 @@ impl PaillierMultiplicationVersusGroupProof { let B_x: Point = Point::::generator().as_point() * Scalar::from_bigint(&alpha); - // E = s^alpha t^gamma mod N_hat + // E = s^alpha t^gamma mod RPParams.N let E = BigInt::mod_mul( - &mod_pow_with_negative(&statement.s, &alpha, &statement.N_hat), - &mod_pow_with_negative(&statement.t, &gamma, &statement.N_hat), - &statement.N_hat, + &mod_pow_with_negative( + &statement.RPParams.s, + &alpha, + &statement.RPParams.N, + ), + &mod_pow_with_negative( + &statement.RPParams.t, + &gamma, + &statement.RPParams.N, + ), + &statement.RPParams.N, ); - // S = s^x t^m mod N_hat + // S = s^x t^m mod RPParams.N let S = BigInt::mod_mul( - &mod_pow_with_negative(&statement.s, &witness.x, &statement.N_hat), - &mod_pow_with_negative(&statement.t, &m, &statement.N_hat), - &statement.N_hat, + &mod_pow_with_negative( + &statement.RPParams.s, + &witness.x, + &statement.RPParams.N, + ), + &mod_pow_with_negative( + &statement.RPParams.t, + &m, + &statement.RPParams.N, + ), + &statement.RPParams.N, ); let e = H::new() @@ -212,8 +215,7 @@ impl PaillierMultiplicationVersusGroupProof { &mod_pow_with_negative(&witness.rho, &e, &statement.N0), &statement.N0, ); - let commitment = - PaillierMultiplicationVersusGroupCommitment { A, B_x, E, S }; + let commitment = PiMulStarCommitment { A, B_x, E, S }; Self { z_1, z_2, @@ -224,9 +226,9 @@ impl PaillierMultiplicationVersusGroupProof { } pub fn verify( - proof: &PaillierMultiplicationVersusGroupProof, - statement: &PaillierMultiplicationVersusGroupStatement, - ) -> Result<(), IncorrectProof> { + proof: &PiMulStarProof, + statement: &PiMulStarStatement, + ) -> Result<(), PiMulStarError> { let e = H::new() .chain_bigint(&proof.commitment.A) .chain_point(&proof.commitment.B_x) @@ -255,39 +257,46 @@ impl PaillierMultiplicationVersusGroupProof { let right_2 = proof.commitment.B_x.clone() + (statement.X.clone() * Scalar::from_bigint(&e)); - // left_3 = s^z_1 t^z_2 mod N_hat + // left_3 = s^z_1 t^z_2 mod RPParams.N let left_3 = BigInt::mod_mul( - &mod_pow_with_negative(&statement.s, &proof.z_1, &statement.N_hat), - &mod_pow_with_negative(&statement.t, &proof.z_2, &statement.N_hat), - &statement.N_hat, + &mod_pow_with_negative( + &statement.RPParams.s, + &proof.z_1, + &statement.RPParams.N, + ), + &mod_pow_with_negative( + &statement.RPParams.t, + &proof.z_2, + &statement.RPParams.N, + ), + &statement.RPParams.N, ); - // right_3 = E * S^e mod N_hat + // right_3 = E * S^e mod RPParams.N let right_3 = BigInt::mod_mul( &proof.commitment.E, - &mod_pow_with_negative(&proof.commitment.S, &e, &statement.N_hat), - &statement.N_hat, + &mod_pow_with_negative( + &proof.commitment.S, + &e, + &statement.RPParams.N, + ), + &statement.RPParams.N, ); if left_1 != right_1 || left_2 != right_2 || left_3 != right_3 { - return Err(IncorrectProof); + return Err(PiMulStarError::Proof); } // Range Check -2^{L + eps} <= z_1 <= 2^{L+eps} let lower_bound_check: bool = proof.z_1 - >= BigInt::from(-1).mul(&BigInt::pow( - &BigInt::from(2), - crate::utilities::L_PLUS_EPSILON as u32, - )); - - let upper_bound_check = proof.z_1 - <= BigInt::pow( - &BigInt::from(2), - crate::utilities::L_PLUS_EPSILON as u32, - ); + >= BigInt::from(-1) + .mul(&BigInt::pow(&BigInt::from(2), L_PLUS_EPSILON as u32)); + + let upper_bound_check = + proof.z_1 <= BigInt::pow(&BigInt::from(2), L_PLUS_EPSILON as u32); if !(lower_bound_check && upper_bound_check) { - return Err(IncorrectProof); + return Err(PiMulStarError::Proof); } Ok(()) } @@ -296,47 +305,37 @@ impl PaillierMultiplicationVersusGroupProof { #[cfg(test)] mod tests { use super::*; - use crate::{ - mpc_ecdsa::utilities::mta::range_proofs::SampleFromMultiplicativeGroup, - utilities::BITS_PAILLIER, - }; + use crate::security_level::BITS_PAILLIER; + use crate::utilities::generate_safe_h1_h2_N_tilde; use curv::elliptic::curves::secp256_k1::Secp256k1; - use fs_dkr::ring_pedersen_proof::RingPedersenStatement; use paillier::{Encrypt, KeyGeneration, Paillier, RawPlaintext}; use sha2::Sha256; #[test] fn test_mul_star_proof() { - let (ring_pedersen_statement, _witness) = - RingPedersenStatement::::generate(); + let (rpparam, _) = generate_safe_h1_h2_N_tilde(); let (paillier_key, _) = Paillier::keypair_with_modulus_size(BITS_PAILLIER).keys(); - let rho: BigInt = BigInt::from_paillier_key(&paillier_key); + let rho: BigInt = sample_relatively_prime_integer(&paillier_key.n); let C: BigInt = Paillier::encrypt( &paillier_key, RawPlaintext::from(BigInt::from(123)), ) .into(); - let (statement, witness) = PaillierMultiplicationVersusGroupStatement::< - Secp256k1, - Sha256, - >::generate( - rho, - C, - ring_pedersen_statement.S, - ring_pedersen_statement.T, - ring_pedersen_statement.N, - paillier_key, - ); - let proof = - PaillierMultiplicationVersusGroupProof::::prove( - &witness, &statement, + let (statement, witness) = + PiMulStarStatement::::generate( + rho, + C, + rpparam, + paillier_key, ); - assert!(PaillierMultiplicationVersusGroupProof::::verify( - &proof, &statement - ) - .is_ok()); + let proof = + PiMulStarProof::::prove(&witness, &statement); + assert!(PiMulStarProof::::verify( + &proof, &statement + ) + .is_ok()); } } diff --git a/multi-party-ecdsa/src/utilities/zk_composite_dlog.rs b/tss-core/src/zkproof/prm/mod.rs similarity index 66% rename from multi-party-ecdsa/src/utilities/zk_composite_dlog.rs rename to tss-core/src/zkproof/prm/mod.rs index 0edcde0d..1abc2148 100644 --- a/multi-party-ecdsa/src/utilities/zk_composite_dlog.rs +++ b/tss-core/src/zkproof/prm/mod.rs @@ -23,25 +23,27 @@ use serde_repr::{Deserialize_repr, Serialize_repr}; use serde_with::serde_as; use zeroize::ZeroizeOnDrop; +use crate::utilities::{RingPedersenParams, RingPedersenWitness}; + /// Statistical security parameter (i.e. m=80 in CGGMP20). const STAT_SECURITY: usize = 80; #[derive(Debug, Clone, Serialize, Deserialize)] -pub struct CompositeDLogStatement { +pub struct PiPrmStatement { pub modulus: BigInt, pub base: BigInt, pub value: BigInt, } #[derive(Debug, Clone, Serialize, Deserialize, ZeroizeOnDrop)] -pub struct CompositeDLogWitness { +pub struct PiPrmWitness { pub exponent: BigInt, pub totient: BigInt, } #[serde_as] #[derive(Debug, Clone, Serialize, Deserialize)] -pub struct CompositeDLogProof { +pub struct PiPrmProof { pub commitments: Vec, #[serde_as(as = "[_; STAT_SECURITY]")] pub challenges: [ChallengeBit; STAT_SECURITY], @@ -58,14 +60,14 @@ pub enum ChallengeBit { } #[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum CompositeDLogError { +pub enum PiPrmError { Serialization, Validation, Challenge, Proof, } -impl From> for CompositeDLogError { +impl From> for PiPrmError { fn from(_: Box) -> Self { Self::Serialization } @@ -73,23 +75,20 @@ impl From> for CompositeDLogError { /// Computes Fiat-Shamir transform challenges using merlin transcript. fn compute_challenges( - statement: &CompositeDLogStatement, + statement: &PiPrmStatement, commitments: &[BigInt], -) -> Result<[ChallengeBit; STAT_SECURITY], CompositeDLogError> { - let mut transcript = Transcript::new(b"CompositeDLogProof"); - transcript.append_message( - b"CompositeDLogStatement", - &bincode::serialize(&statement)?, - ); +) -> Result<[ChallengeBit; STAT_SECURITY], PiPrmError> { + let mut transcript = Transcript::new(b"PiPrmProof"); + transcript + .append_message(b"PiPrmStatement", &bincode::serialize(&statement)?); transcript.append_message( - b"CompositeDLogCommitments", + b"PiPrmCommitments", &bincode::serialize(&commitments)?, ); // Each challenge is only a bit so we divide 8. let mut challenge_bytes = [0u8; STAT_SECURITY / 8]; - transcript - .challenge_bytes(b"CompositeDLogChallenges", &mut challenge_bytes); + transcript.challenge_bytes(b"PiPrmChallenges", &mut challenge_bytes); // Parses challenge bits. let mut challenge_bits = [ChallengeBit::ZERO; STAT_SECURITY]; @@ -111,11 +110,45 @@ fn compute_challenges( Ok(challenge_bits) } -impl CompositeDLogProof { +impl PiPrmStatement { + pub fn from(rpparams: &RingPedersenParams) -> PiPrmStatement { + PiPrmStatement { + modulus: rpparams.N.clone(), + base: rpparams.s.clone(), + value: rpparams.t.clone(), + } + } + + pub fn inverse_from(rpparams: &RingPedersenParams) -> PiPrmStatement { + PiPrmStatement { + modulus: rpparams.N.clone(), + base: rpparams.t.clone(), + value: rpparams.s.clone(), + } + } +} + +impl PiPrmWitness { + pub fn from(witness: &RingPedersenWitness) -> PiPrmWitness { + PiPrmWitness { + exponent: witness.lambda.clone(), + totient: witness.phi.clone(), + } + } + + pub fn inverse_from(witness: &RingPedersenWitness) -> PiPrmWitness { + PiPrmWitness { + exponent: witness.lambdaInv.clone(), + totient: witness.phi.clone(), + } + } +} + +impl PiPrmProof { pub fn prove( - statement: &CompositeDLogStatement, - witness: &CompositeDLogWitness, - ) -> Result { + statement: &PiPrmStatement, + witness: &PiPrmWitness, + ) -> Result { // a_i ← Z_{φ(N)} in CGGMP20. let mut randomness: Vec = Vec::with_capacity(STAT_SECURITY); // A_i = t^{a_i} mod N in CGGMP20. @@ -148,29 +181,26 @@ impl CompositeDLogProof { }) .collect(); - Ok(CompositeDLogProof { + Ok(PiPrmProof { commitments, challenges, responses, }) } - pub fn verify( - &self, - statement: &CompositeDLogStatement, - ) -> Result<(), CompositeDLogError> { + pub fn verify(&self, statement: &PiPrmStatement) -> Result<(), PiPrmError> { // Validate expected lengths i.e m in CGGMP20. if self.commitments.len() != STAT_SECURITY || self.challenges.len() != STAT_SECURITY || self.responses.len() != STAT_SECURITY { - return Err(CompositeDLogError::Validation); + return Err(PiPrmError::Validation); } // Verify Fiat-Shamir challenges .i.e e_i ← {0, 1} in CGGMP20. let challenges = compute_challenges(statement, &self.commitments)?; if challenges != self.challenges { - return Err(CompositeDLogError::Challenge); + return Err(PiPrmError::Challenge); } // Verify responses i.e t^{z_i} = {A_i} * s^{e_i} mod N in CGGMP20. @@ -190,7 +220,7 @@ impl CompositeDLogProof { ), } { - return Err(CompositeDLogError::Proof); + return Err(PiPrmError::Proof); } } @@ -202,58 +232,42 @@ impl CompositeDLogProof { #[allow(non_snake_case)] mod tests { use super::*; - use crate::gg_2020::party_i::generate_h1_h2_N_tilde; + use crate::utilities::generate_normal_h1_h2_N_tilde; #[test] fn valid_composite_dlog_proof_works() { - let (N_tilde, h1, h2, xhi, xhi_inv, phi) = generate_h1_h2_N_tilde(); - let statement_base_h1 = CompositeDLogStatement { - modulus: N_tilde.clone(), - base: h1.clone(), - value: h2.clone(), - }; - let witness_base_h1 = CompositeDLogWitness { - exponent: xhi, - totient: phi.clone(), - }; + // for testing we use normal primes - it is important in the big + // protocol that N is a product of safe primes, but not for the invidual + // test. + let (rpparams, rpwitness) = generate_normal_h1_h2_N_tilde(); + let statement_base_h1 = PiPrmStatement::from(&rpparams); + let witness_base_h1 = PiPrmWitness::from(&rpwitness); let proof_base_h1 = - CompositeDLogProof::prove(&statement_base_h1, &witness_base_h1) - .unwrap(); + PiPrmProof::prove(&statement_base_h1, &witness_base_h1).unwrap(); let result_base_h1 = proof_base_h1.verify(&statement_base_h1); assert!(result_base_h1.is_ok()); - let statement_base_h2 = CompositeDLogStatement { - modulus: N_tilde, - base: h2, - value: h1, - }; - let witness_base_h2 = CompositeDLogWitness { - exponent: xhi_inv, - totient: phi, - }; + let statement_base_h2 = PiPrmStatement::inverse_from(&rpparams); + let witness_base_h2 = PiPrmWitness::inverse_from(&rpwitness); let proof_base_h2 = - CompositeDLogProof::prove(&statement_base_h2, &witness_base_h2) - .unwrap(); + PiPrmProof::prove(&statement_base_h2, &witness_base_h2).unwrap(); let result_base_h2 = proof_base_h2.verify(&statement_base_h2); assert!(result_base_h2.is_ok()); } #[test] fn invalid_composite_dlog_proof_fails() { - let (N_tilde, h1, h2, _, _, phi) = generate_h1_h2_N_tilde(); + let (rpparams, rpwitness) = generate_normal_h1_h2_N_tilde(); // We use a fake/wrong/guessed exponent. - let xhi = BigInt::sample_below(&phi); - let statement = CompositeDLogStatement { - modulus: N_tilde.clone(), - base: h1.clone(), - value: h2.clone(), - }; - let witness = CompositeDLogWitness { + let xhi = BigInt::sample_below(&rpwitness.phi); + + let statement = PiPrmStatement::from(&rpparams); + let witness = PiPrmWitness { exponent: xhi, - totient: phi.clone(), + totient: rpwitness.phi, }; - let proof = CompositeDLogProof::prove(&statement, &witness).unwrap(); + let proof = PiPrmProof::prove(&statement, &witness).unwrap(); let result = proof.verify(&statement); - assert_eq!(result, Err(CompositeDLogError::Proof)); + assert_eq!(result, Err(PiPrmError::Proof)); } }