diff --git a/multi-party-ecdsa/src/protocols/mod.rs b/multi-party-ecdsa/src/protocols/mod.rs index 373276d..4037de7 100644 --- a/multi-party-ecdsa/src/protocols/mod.rs +++ b/multi-party-ecdsa/src/protocols/mod.rs @@ -14,4 +14,5 @@ @license GPL-3.0+ */ +#[deprecated(note = "Use top level modules instead (eg: gg_2020).")] pub mod multi_party_ecdsa; diff --git a/src/party_i.rs b/src/party_i.rs index deac4aa..4324460 100644 --- a/src/party_i.rs +++ b/src/party_i.rs @@ -43,19 +43,19 @@ use paillier::{ use serde::{Deserialize, Serialize}; use zk_paillier::zkproofs::{DLogStatement, NiCorrectKeyProof}; -use crate::{ - utilities::zk_pdl_with_slack::{ - PDLwSlackProof, PDLwSlackStatement, PDLwSlackWitness, - }, - ErrorType, -}; +use crate::ErrorType; use curv::cryptographic_primitives::proofs::sigma_valid_pedersen::PedersenProof; use std::convert::TryInto; -pub use crate::mpc_ecdsa::gg_2020::party_i::{ - KeyGenBroadcastMessage1, KeyGenDecommitMessage1, Parameters, SharedKeys, - SignBroadcastPhase1, SignDecommitPhase1, SignatureRecid, +pub use crate::mpc_ecdsa::{ + gg_2020::party_i::{ + KeyGenBroadcastMessage1, KeyGenDecommitMessage1, Parameters, + SharedKeys, SignBroadcastPhase1, SignDecommitPhase1, SignatureRecid, + }, + utilities::zk_pdl_with_slack::{ + PDLwSlackProof, PDLwSlackStatement, PDLwSlackWitness, + }, }; use multi_party_ecdsa::gg_2020::party_i::generate_h1_h2_N_tilde; use multi_party_ecdsa::utilities::zk_composite_dlog::{ diff --git a/src/utilities/aff_g/mod.rs b/src/utilities/aff_g/mod.rs index ed09561..1ddeedf 100644 --- a/src/utilities/aff_g/mod.rs +++ b/src/utilities/aff_g/mod.rs @@ -518,8 +518,9 @@ impl #[cfg(test)] mod tests { use super::*; - use crate::utilities::{ - mta::range_proofs::SampleFromMultiplicativeGroup, BITS_PAILLIER, + use crate::{ + mpc_ecdsa::utilities::mta::range_proofs::SampleFromMultiplicativeGroup, + utilities::BITS_PAILLIER, }; use curv::elliptic::curves::secp256_k1::Secp256k1; use fs_dkr::ring_pedersen_proof::RingPedersenStatement; diff --git a/src/utilities/dec_q/mod.rs b/src/utilities/dec_q/mod.rs index 707f093..e9ea563 100644 --- a/src/utilities/dec_q/mod.rs +++ b/src/utilities/dec_q/mod.rs @@ -303,8 +303,9 @@ impl PaillierDecryptionModQProof { #[cfg(test)] mod tests { use super::*; - use crate::utilities::{ - mta::range_proofs::SampleFromMultiplicativeGroup, BITS_PAILLIER, + use crate::{ + mpc_ecdsa::utilities::mta::range_proofs::SampleFromMultiplicativeGroup, + utilities::BITS_PAILLIER, }; use curv::elliptic::curves::secp256_k1::Secp256k1; use fs_dkr::ring_pedersen_proof::RingPedersenStatement; diff --git a/src/utilities/enc/mod.rs b/src/utilities/enc/mod.rs index b1d909d..c7100b4 100644 --- a/src/utilities/enc/mod.rs +++ b/src/utilities/enc/mod.rs @@ -288,8 +288,9 @@ impl PaillierEncryptionInRangeProof { #[cfg(test)] mod tests { use super::*; - use crate::utilities::{ - mta::range_proofs::SampleFromMultiplicativeGroup, BITS_PAILLIER, + use crate::{ + mpc_ecdsa::utilities::mta::range_proofs::SampleFromMultiplicativeGroup, + utilities::BITS_PAILLIER, }; use curv::elliptic::curves::secp256_k1::Secp256k1; use fs_dkr::ring_pedersen_proof::RingPedersenStatement; diff --git a/src/utilities/log_star/mod.rs b/src/utilities/log_star/mod.rs index 8189f61..882a24f 100644 --- a/src/utilities/log_star/mod.rs +++ b/src/utilities/log_star/mod.rs @@ -330,8 +330,9 @@ impl #[cfg(test)] mod tests { use super::*; - use crate::utilities::{ - mta::range_proofs::SampleFromMultiplicativeGroup, BITS_PAILLIER, + use crate::{ + mpc_ecdsa::utilities::mta::range_proofs::SampleFromMultiplicativeGroup, + utilities::BITS_PAILLIER, }; use curv::elliptic::curves::secp256_k1::Secp256k1; use fs_dkr::ring_pedersen_proof::RingPedersenStatement; diff --git a/src/utilities/mod.rs b/src/utilities/mod.rs index ec500c2..d320c00 100644 --- a/src/utilities/mod.rs +++ b/src/utilities/mod.rs @@ -7,12 +7,9 @@ pub mod aff_g; pub mod dec_q; pub mod enc; pub mod log_star; -pub mod mta; pub mod mul; pub mod mul_star; pub mod sha2; -pub mod zk_pdl; -pub mod zk_pdl_with_slack; /// Extend or truncate a vector of bytes to a fixed length array. /// diff --git a/src/utilities/mta/mod.rs b/src/utilities/mta/mod.rs deleted file mode 100644 index bd24ada..0000000 --- a/src/utilities/mta/mod.rs +++ /dev/null @@ -1,237 +0,0 @@ -/* - Multi-party ECDSA - - Copyright 2018 by Kzen Networks - - This file is part of Multi-party ECDSA library - (https://github.com/KZen-networks/multi-party-ecdsa) - - Multi-party ECDSA 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+ -*/ - -/// MtA is described in https://eprint.iacr.org/2019/114.pdf section 3 -use curv::arithmetic::traits::Samplable; -use curv::{ - cryptographic_primitives::proofs::sigma_dlog::DLogProof, - elliptic::curves::{secp256_k1::Secp256k1, Point, Scalar}, - BigInt, -}; -use paillier::{ - traits::EncryptWithChosenRandomness, Add, Decrypt, DecryptionKey, - EncryptionKey, Mul, Paillier, Randomness, RawCiphertext, RawPlaintext, -}; -use zk_paillier::zkproofs::DLogStatement; - -use serde::{Deserialize, Serialize}; -use sha2::Sha256; - -use crate::{ - party_i::PartyPrivate, - utilities::mta::range_proofs::AliceProof, - Error::{self, InvalidKey}, -}; - -pub mod range_proofs; -#[cfg(test)] -mod test; - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct MessageA { - pub c: BigInt, // paillier encryption - pub range_proofs: Vec, /* proofs (using other parties' - * h1,h2,N_tilde) that the - * plaintext is small */ -} - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct MessageB { - pub c: BigInt, // paillier encryption - pub b_proof: DLogProof, - pub beta_tag_proof: DLogProof, -} - -impl MessageA { - /// Creates a new `messageA` using Alice's Paillier encryption key and - /// `dlog_statements` - /// - other parties' `h1,h2,N_tilde`s for range proofs. - /// If range proofs are not needed (one example is identification of aborts - /// where we only want to reconstruct a ciphertext), `dlog_statements` - /// can be an empty slice. - pub fn a( - a: &Scalar, - alice_ek: &EncryptionKey, - dlog_statements: &[DLogStatement], - ) -> (Self, BigInt) { - let randomness = BigInt::sample_below(&alice_ek.n); - let m_a = MessageA::a_with_predefined_randomness( - a, - alice_ek, - &randomness, - dlog_statements, - ); - (m_a, randomness) - } - - pub fn a_with_predefined_randomness( - a: &Scalar, - alice_ek: &EncryptionKey, - randomness: &BigInt, - dlog_statements: &[DLogStatement], - ) -> Self { - let c_a = Paillier::encrypt_with_chosen_randomness( - alice_ek, - RawPlaintext::from(a.to_bigint()), - &Randomness::from(randomness.clone()), - ) - .0 - .clone() - .into_owned(); - let alice_range_proofs = dlog_statements - .iter() - .map(|dlog_statement| { - AliceProof::generate( - &a.to_bigint(), - &c_a, - alice_ek, - dlog_statement, - randomness, - ) - }) - .collect::>(); - - Self { - c: c_a, - range_proofs: alice_range_proofs, - } - } -} - -impl MessageB { - pub fn b( - b: &Scalar, - alice_ek: &EncryptionKey, - m_a: MessageA, - dlog_statements: &[DLogStatement], - ) -> Result<(Self, Scalar, BigInt, BigInt), Error> { - let beta_tag = BigInt::sample_below(&alice_ek.n); - let randomness = BigInt::sample_below(&alice_ek.n); - let (m_b, beta) = MessageB::b_with_predefined_randomness( - b, - alice_ek, - m_a, - &randomness, - &beta_tag, - dlog_statements, - )?; - - Ok((m_b, beta, randomness, beta_tag)) - } - - pub fn b_with_predefined_randomness( - b: &Scalar, - alice_ek: &EncryptionKey, - m_a: MessageA, - randomness: &BigInt, - beta_tag: &BigInt, - dlog_statements: &[DLogStatement], - ) -> Result<(Self, Scalar), Error> { - if m_a.range_proofs.len() != dlog_statements.len() { - return Err(InvalidKey); - } - // verify proofs - if !m_a - .range_proofs - .iter() - .zip(dlog_statements) - .map(|(proof, dlog_statement)| { - proof.verify(&m_a.c, alice_ek, dlog_statement) - }) - .all(|x| x) - { - return Err(InvalidKey); - }; - let beta_tag_fe = Scalar::::from(beta_tag); - let c_beta_tag = Paillier::encrypt_with_chosen_randomness( - alice_ek, - RawPlaintext::from(beta_tag), - &Randomness::from(randomness.clone()), - ); - - let b_bn = b.to_bigint(); - let b_c_a = Paillier::mul( - alice_ek, - RawCiphertext::from(m_a.c), - RawPlaintext::from(b_bn), - ); - let c_b = Paillier::add(alice_ek, b_c_a, c_beta_tag); - let beta = Scalar::::zero() - &beta_tag_fe; - let dlog_proof_b = DLogProof::prove(b); - let dlog_proof_beta_tag = DLogProof::prove(&beta_tag_fe); - - Ok(( - Self { - c: c_b.0.clone().into_owned(), - b_proof: dlog_proof_b, - beta_tag_proof: dlog_proof_beta_tag, - }, - beta, - )) - } - - pub fn verify_proofs_get_alpha( - &self, - dk: &DecryptionKey, - a: &Scalar, - ) -> Result<(Scalar, BigInt), Error> { - let alice_share = - Paillier::decrypt(dk, &RawCiphertext::from(self.c.clone())); - let g = Point::generator(); - let alpha = Scalar::::from(alice_share.0.as_ref()); - let g_alpha = g * α - let ba_btag = &self.b_proof.pk * a + &self.beta_tag_proof.pk; - if DLogProof::verify(&self.b_proof).is_ok() - && DLogProof::verify(&self.beta_tag_proof).is_ok() - // we prove the correctness of the ciphertext using this check and the proof of knowledge of dlog of beta_tag - && ba_btag == g_alpha - { - Ok((alpha, alice_share.0.into_owned())) - } else { - Err(InvalidKey) - } - } - - // another version, supporting PartyPrivate therefore binding mta to gg18. - // with the regular version mta can be used in general - pub fn verify_proofs_get_alpha_gg18( - &self, - private: &PartyPrivate, - a: &Scalar, - ) -> Result, Error> { - let alice_share = private.decrypt(self.c.clone()); - let g = Point::generator(); - let alpha = Scalar::::from(alice_share.0.as_ref()); - let g_alpha = g * α - let ba_btag = &self.b_proof.pk * a + &self.beta_tag_proof.pk; - - if DLogProof::verify(&self.b_proof).is_ok() - && DLogProof::verify(&self.beta_tag_proof).is_ok() - && ba_btag == g_alpha - { - Ok(alpha) - } else { - Err(InvalidKey) - } - } - - pub fn verify_b_against_public( - public_gb: &Point, - mta_gb: &Point, - ) -> bool { - public_gb == mta_gb - } -} diff --git a/src/utilities/mta/range_proofs.rs b/src/utilities/mta/range_proofs.rs deleted file mode 100644 index 97c417b..0000000 --- a/src/utilities/mta/range_proofs.rs +++ /dev/null @@ -1,745 +0,0 @@ -#![allow(non_snake_case)] - -//! This file is a modified version of ING bank's range proofs implementation: -//! https://github.com/ing-bank/threshold-signatures/blob/master/src/algorithms/zkp.rs -//! -//! Zero knowledge range proofs for MtA protocol are implemented here. -//! Formal description can be found in Appendix A of https://eprint.iacr.org/2019/114.pdf -//! There are some deviations from the original specification: -//! 1) In Bob's proofs `gamma` is sampled from `[0;q^2 * N]` and `tau` from -//! `[0;q^3 * N_tilde]`. -//! 2) A non-interactive version is implemented, with challenge `e` computed via -//! Fiat-Shamir. - -use curv::{ - arithmetic::traits::*, - cryptographic_primitives::hashing::{Digest, DigestExt}, - elliptic::curves::{secp256_k1::Secp256k1, Point, Scalar}, - BigInt, -}; -use sha2::Sha256; - -use paillier::{EncryptionKey, Randomness}; -use zk_paillier::zkproofs::DLogStatement; - -use serde::{Deserialize, Serialize}; -use std::borrow::Borrow; -use zeroize::Zeroize; - -/// Represents the first round of the interactive version of the proof -#[derive(Zeroize)] -#[zeroize(drop)] -struct AliceZkpRound1 { - alpha: BigInt, - beta: BigInt, - gamma: BigInt, - ro: BigInt, - z: BigInt, - u: BigInt, - w: BigInt, -} - -impl AliceZkpRound1 { - fn from( - alice_ek: &EncryptionKey, - dlog_statement: &DLogStatement, - a: &BigInt, - q: &BigInt, - ) -> Self { - let h1 = &dlog_statement.g; - let h2 = &dlog_statement.ni; - let N_tilde = &dlog_statement.N; - let alpha = BigInt::sample_below(&q.pow(3)); - let beta = BigInt::from_paillier_key(alice_ek); - let gamma = BigInt::sample_below(&(q.pow(3) * N_tilde)); - let ro = BigInt::sample_below(&(q * N_tilde)); - let z = (BigInt::mod_pow(h1, a, N_tilde) - * BigInt::mod_pow(h2, &ro, N_tilde)) - % N_tilde; - let u = ((alpha.borrow() * &alice_ek.n + 1) - * BigInt::mod_pow(&beta, &alice_ek.n, &alice_ek.nn)) - % &alice_ek.nn; - let w = (BigInt::mod_pow(h1, &alpha, N_tilde) - * BigInt::mod_pow(h2, &gamma, N_tilde)) - % N_tilde; - Self { - alpha, - beta, - gamma, - ro, - z, - u, - w, - } - } -} - -/// Represents the second round of the interactive version of the proof -struct AliceZkpRound2 { - s: BigInt, - s1: BigInt, - s2: BigInt, -} - -impl AliceZkpRound2 { - fn from( - alice_ek: &EncryptionKey, - round1: &AliceZkpRound1, - e: &BigInt, - a: &BigInt, - r: &BigInt, - ) -> Self { - Self { - s: (BigInt::mod_pow(r, e, &alice_ek.n) * round1.beta.borrow()) - % &alice_ek.n, - s1: (e * a) + round1.alpha.borrow(), - s2: (e * round1.ro.borrow()) + round1.gamma.borrow(), - } - } -} - -/// Alice's proof -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct AliceProof { - z: BigInt, - e: BigInt, - s: BigInt, - s1: BigInt, - s2: BigInt, -} - -impl AliceProof { - /// verify Alice's proof using the proof and public keys - pub fn verify( - &self, - cipher: &BigInt, - alice_ek: &EncryptionKey, - dlog_statement: &DLogStatement, - ) -> bool { - let N = &alice_ek.n; - let NN = &alice_ek.nn; - let N_tilde = &dlog_statement.N; - let h1 = &dlog_statement.g; - let h2 = &dlog_statement.ni; - let Gen = alice_ek.n.borrow() + 1; - - if self.s1 > Scalar::::group_order().pow(3) { - return false; - } - - let z_e_inv = BigInt::mod_inv( - &BigInt::mod_pow(&self.z, &self.e, N_tilde), - N_tilde, - ); - let z_e_inv = match z_e_inv { - // z must be invertible, yet the check is done here - None => return false, - Some(c) => c, - }; - - let w = (BigInt::mod_pow(h1, &self.s1, N_tilde) - * BigInt::mod_pow(h2, &self.s2, N_tilde) - * z_e_inv) - % N_tilde; - - let gs1 = (self.s1.borrow() * N + 1) % NN; - let cipher_e_inv = - BigInt::mod_inv(&BigInt::mod_pow(cipher, &self.e, NN), NN); - let cipher_e_inv = match cipher_e_inv { - None => return false, - Some(c) => c, - }; - - let u = (gs1 * BigInt::mod_pow(&self.s, N, NN) * cipher_e_inv) % NN; - - let e = Sha256::new() - .chain_bigint(N) - .chain_bigint(&Gen) - .chain_bigint(cipher) - .chain_bigint(&self.z) - .chain_bigint(&u) - .chain_bigint(&w) - .result_bigint(); - if e != self.e { - return false; - } - - true - } - /// Create the proof using Alice's Paillier private keys and public ZKP - /// setup. Requires randomness used for encrypting Alice's secret a. - /// It is assumed that secp256k1 curve is used. - pub fn generate( - a: &BigInt, - cipher: &BigInt, - alice_ek: &EncryptionKey, - dlog_statement: &DLogStatement, - r: &BigInt, - ) -> Self { - let round1 = AliceZkpRound1::from( - alice_ek, - dlog_statement, - a, - Scalar::::group_order(), - ); - - let Gen = alice_ek.n.borrow() + 1; - let e = Sha256::new() - .chain_bigint(&alice_ek.n) - .chain_bigint(&Gen) - .chain_bigint(cipher) - .chain_bigint(&round1.z) - .chain_bigint(&round1.u) - .chain_bigint(&round1.w) - .result_bigint(); - - let round2 = AliceZkpRound2::from(alice_ek, &round1, &e, a, r); - - Self { - z: round1.z.clone(), - e, - s: round2.s, - s1: round2.s1, - s2: round2.s2, - } - } -} - -/// Represents first round of the interactive version of the proof -#[derive(Zeroize)] -#[zeroize(drop)] -struct BobZkpRound1 { - pub alpha: BigInt, - pub beta: BigInt, - pub gamma: BigInt, - pub ro: BigInt, - pub ro_prim: BigInt, - pub sigma: BigInt, - pub tau: BigInt, - pub z: BigInt, - pub z_prim: BigInt, - pub t: BigInt, - pub w: BigInt, - pub v: BigInt, -} - -impl BobZkpRound1 { - /// `b` - Bob's secret - /// `beta_prim` - randomly chosen in `MtA` by Bob - /// `a_encrypted` - Alice's secret encrypted by Alice - fn from( - alice_ek: &EncryptionKey, - dlog_statement: &DLogStatement, - b: &Scalar, - beta_prim: &BigInt, - a_encrypted: &BigInt, - q: &BigInt, - ) -> Self { - let h1 = &dlog_statement.g; - let h2 = &dlog_statement.ni; - let N_tilde = &dlog_statement.N; - let b_bn = b.to_bigint(); - - let alpha = BigInt::sample_below(&q.pow(3)); - let beta = BigInt::from_paillier_key(alice_ek); - let gamma = BigInt::sample_below(&(q.pow(2) * &alice_ek.n)); - let ro = BigInt::sample_below(&(q * N_tilde)); - let ro_prim = BigInt::sample_below(&(q.pow(3) * N_tilde)); - let sigma = BigInt::sample_below(&(q * N_tilde)); - let tau = BigInt::sample_below(&(q.pow(3) * N_tilde)); - let z = (BigInt::mod_pow(h1, &b_bn, N_tilde) - * BigInt::mod_pow(h2, &ro, N_tilde)) - % N_tilde; - let z_prim = (BigInt::mod_pow(h1, &alpha, N_tilde) - * BigInt::mod_pow(h2, &ro_prim, N_tilde)) - % N_tilde; - let t = (BigInt::mod_pow(h1, beta_prim, N_tilde) - * BigInt::mod_pow(h2, &sigma, N_tilde)) - % N_tilde; - let w = (BigInt::mod_pow(h1, &gamma, N_tilde) - * BigInt::mod_pow(h2, &tau, N_tilde)) - % N_tilde; - let v = (BigInt::mod_pow(a_encrypted, &alpha, &alice_ek.nn) - * (gamma.borrow() * &alice_ek.n + 1) - * BigInt::mod_pow(&beta, &alice_ek.n, &alice_ek.nn)) - % &alice_ek.nn; - Self { - alpha, - beta, - gamma, - ro, - ro_prim, - sigma, - tau, - z, - z_prim, - t, - w, - v, - } - } -} - -/// represents second round of the interactive version of the proof -struct BobZkpRound2 { - pub s: BigInt, - pub s1: BigInt, - pub s2: BigInt, - pub t1: BigInt, - pub t2: BigInt, -} - -impl BobZkpRound2 { - /// `e` - the challenge in interactive ZKP, the hash in non-interactive ZKP - /// `b` - Bob's secret - /// `beta_prim` - randomly chosen in `MtA` by Bob - /// `r` - randomness used by Bob on Alice's public Paillier key to encrypt - /// `beta_prim` in `MtA` - fn from( - alice_ek: &EncryptionKey, - round1: &BobZkpRound1, - e: &BigInt, - b: &Scalar, - beta_prim: &BigInt, - r: &Randomness, - ) -> Self { - let b_bn = b.to_bigint(); - Self { - s: (BigInt::mod_pow(r.0.borrow(), e, &alice_ek.n) - * round1.beta.borrow()) - % &alice_ek.n, - s1: (e * b_bn) + round1.alpha.borrow(), - s2: (e * round1.ro.borrow()) + round1.ro_prim.borrow(), - t1: (e * beta_prim) + round1.gamma.borrow(), - t2: (e * round1.sigma.borrow()) + round1.tau.borrow(), - } - } -} - -/// Additional fields in Bob's proof if MtA is run with check -pub struct BobCheck { - u: Point, - X: Point, -} - -/// Bob's regular proof -#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] -pub struct BobProof { - t: BigInt, - z: BigInt, - e: BigInt, - s: BigInt, - s1: BigInt, - s2: BigInt, - t1: BigInt, - t2: BigInt, -} - -#[allow(clippy::too_many_arguments)] -impl BobProof { - pub fn verify( - &self, - a_enc: &BigInt, - mta_avc_out: &BigInt, - alice_ek: &EncryptionKey, - dlog_statement: &DLogStatement, - check: Option<&BobCheck>, - ) -> bool { - let N = &alice_ek.n; - let NN = &alice_ek.nn; - let N_tilde = &dlog_statement.N; - let h1 = &dlog_statement.g; - let h2 = &dlog_statement.ni; - - if self.s1 > Scalar::::group_order().pow(3) { - return false; - } - - let z_e_inv = BigInt::mod_inv( - &BigInt::mod_pow(&self.z, &self.e, N_tilde), - N_tilde, - ); - let z_e_inv = match z_e_inv { - // z must be invertible, yet the check is done here - None => return false, - Some(c) => c, - }; - - let z_prim = (BigInt::mod_pow(h1, &self.s1, N_tilde) - * BigInt::mod_pow(h2, &self.s2, N_tilde) - * z_e_inv) - % N_tilde; - - let mta_e_inv = - BigInt::mod_inv(&BigInt::mod_pow(mta_avc_out, &self.e, NN), NN); - let mta_e_inv = match mta_e_inv { - None => return false, - Some(c) => c, - }; - - let v = (BigInt::mod_pow(a_enc, &self.s1, NN) - * BigInt::mod_pow(&self.s, N, NN) - * (self.t1.borrow() * N + 1) - * mta_e_inv) - % NN; - - let t_e_inv = BigInt::mod_inv( - &BigInt::mod_pow(&self.t, &self.e, N_tilde), - N_tilde, - ); - let t_e_inv = match t_e_inv { - None => return false, - Some(c) => c, - }; - - let w = (BigInt::mod_pow(h1, &self.t1, N_tilde) - * BigInt::mod_pow(h2, &self.t2, N_tilde) - * t_e_inv) - % N_tilde; - - let Gen = alice_ek.n.borrow() + 1; - let mut values_to_hash = vec![ - &alice_ek.n, - &Gen, - a_enc, - mta_avc_out, - &self.z, - &z_prim, - &self.t, - &v, - &w, - ]; - let e = match check { - Some(_) => { - let X_x_coor = check.unwrap().X.x_coord().unwrap(); - values_to_hash.push(&X_x_coor); - let X_y_coor = check.unwrap().X.y_coord().unwrap(); - values_to_hash.push(&X_y_coor); - let u_x_coor = check.unwrap().u.x_coord().unwrap(); - values_to_hash.push(&u_x_coor); - let u_y_coor = check.unwrap().u.y_coord().unwrap(); - values_to_hash.push(&u_y_coor); - values_to_hash - .into_iter() - .fold(Sha256::new(), |acc, b| acc.chain_bigint(b)) - .result_bigint() - } - None => values_to_hash - .into_iter() - .fold(Sha256::new(), |acc, b| acc.chain_bigint(b)) - .result_bigint(), - }; - - if e != self.e { - return false; - } - - true - } - - pub fn generate( - a_encrypted: &BigInt, - mta_encrypted: &BigInt, - b: &Scalar, - beta_prim: &BigInt, - alice_ek: &EncryptionKey, - dlog_statement: &DLogStatement, - r: &Randomness, - check: bool, - ) -> (BobProof, Option>) { - let round1 = BobZkpRound1::from( - alice_ek, - dlog_statement, - b, - beta_prim, - a_encrypted, - Scalar::::group_order(), - ); - - let Gen = alice_ek.n.borrow() + 1; - let mut values_to_hash = vec![ - &alice_ek.n, - &Gen, - a_encrypted, - mta_encrypted, - &round1.z, - &round1.z_prim, - &round1.t, - &round1.v, - &round1.w, - ]; - let mut check_u = None; - let e = if check { - let (X, u) = { - let ec_gen = Point::generator(); - let alpha = Scalar::::from(&round1.alpha); - (ec_gen * b, ec_gen * alpha) - }; - check_u = Some(u.clone()); - let X_x_coor = X.x_coord().unwrap(); - values_to_hash.push(&X_x_coor); - let X_y_coor = X.y_coord().unwrap(); - values_to_hash.push(&X_y_coor); - let u_x_coor = u.x_coord().unwrap(); - values_to_hash.push(&u_x_coor); - let u_y_coor = u.y_coord().unwrap(); - values_to_hash.push(&u_y_coor); - values_to_hash - .into_iter() - .fold(Sha256::new(), |acc, b| acc.chain_bigint(b)) - .result_bigint() - } else { - values_to_hash - .into_iter() - .fold(Sha256::new(), |acc, b| acc.chain_bigint(b)) - .result_bigint() - }; - - let round2 = BobZkpRound2::from(alice_ek, &round1, &e, b, beta_prim, r); - - ( - BobProof { - t: round1.t.clone(), - z: round1.z.clone(), - e, - s: round2.s, - s1: round2.s1, - s2: round2.s2, - t1: round2.t1, - t2: round2.t2, - }, - check_u, - ) - } -} - -/// Bob's extended proof, adds the knowledge of $`B = g^b \in \mathcal{G}`$ -#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] -pub struct BobProofExt { - proof: BobProof, - u: Point, -} - -#[allow(clippy::too_many_arguments)] -impl BobProofExt { - pub fn verify( - &self, - a_enc: &BigInt, - mta_avc_out: &BigInt, - alice_ek: &EncryptionKey, - dlog_statement: &DLogStatement, - X: &Point, - ) -> bool { - // check basic proof first - if !self.proof.verify( - a_enc, - mta_avc_out, - alice_ek, - dlog_statement, - Some(&BobCheck { - u: self.u.clone(), - X: X.clone(), - }), - ) { - return false; - } - - // fiddle with EC points - let (x1, x2) = { - let ec_gen = Point::generator(); - let s1 = Scalar::::from(&self.proof.s1); - let e = Scalar::::from(&self.proof.e); - (ec_gen * s1, (X * &e) + &self.u) - }; - - if x1 != x2 { - return false; - } - - true - } -} - -/// sample random value of an element of a multiplicative group -pub trait SampleFromMultiplicativeGroup { - fn from_modulo(N: &BigInt) -> BigInt; - fn from_paillier_key(ek: &EncryptionKey) -> BigInt; -} - -impl SampleFromMultiplicativeGroup for BigInt { - fn from_modulo(N: &BigInt) -> BigInt { - let One = BigInt::one(); - loop { - let r = Self::sample_below(N); - if r.gcd(N) == One { - return r; - } - } - } - - fn from_paillier_key(ek: &EncryptionKey) -> BigInt { - Self::from_modulo(ek.n.borrow()) - } -} - -#[cfg(test)] -pub(crate) mod tests { - use super::*; - use paillier::{ - traits::{Encrypt, EncryptWithChosenRandomness, KeyGeneration}, - Add, DecryptionKey, Mul, Paillier, RawCiphertext, RawPlaintext, - }; - - fn generate( - a_encrypted: &BigInt, - mta_encrypted: &BigInt, - b: &Scalar, - beta_prim: &BigInt, - alice_ek: &EncryptionKey, - dlog_statement: &DLogStatement, - r: &Randomness, - ) -> BobProofExt { - // proving a basic proof (with modified hash) - let (bob_proof, u) = BobProof::generate( - a_encrypted, - mta_encrypted, - b, - beta_prim, - alice_ek, - dlog_statement, - r, - true, - ); - - BobProofExt { - proof: bob_proof, - u: u.unwrap(), - } - } - - pub(crate) fn generate_init( - ) -> (DLogStatement, EncryptionKey, DecryptionKey) { - let (ek_tilde, dk_tilde) = Paillier::keypair().keys(); - let one = BigInt::one(); - let phi = (&dk_tilde.p - &one) * (&dk_tilde.q - &one); - let h1 = BigInt::sample_below(&ek_tilde.n); - let (xhi, _) = loop { - let xhi_ = BigInt::sample_below(&phi); - match BigInt::mod_inv(&xhi_, &phi) { - Some(inv) => break (xhi_, inv), - None => continue, - } - }; - let h2 = BigInt::mod_pow(&h1, &xhi, &ek_tilde.n); - - let (ek, dk) = Paillier::keypair().keys(); - let dlog_statement = DLogStatement { - g: h1, - ni: h2, - N: ek_tilde.n, - }; - (dlog_statement, ek, dk) - } - - #[test] - fn alice_zkp() { - let (dlog_statement, ek, _) = generate_init(); - - // Alice's secret value - let a = Scalar::::random().to_bigint(); - let r = BigInt::from_paillier_key(&ek); - let cipher = Paillier::encrypt_with_chosen_randomness( - &ek, - RawPlaintext::from(a.clone()), - &Randomness::from(&r), - ) - .0 - .clone() - .into_owned(); - - let alice_proof = - AliceProof::generate(&a, &cipher, &ek, &dlog_statement, &r); - - assert!(alice_proof.verify(&cipher, &ek, &dlog_statement)); - } - - #[test] - fn bob_zkp() { - let (dlog_statement, ek, _) = generate_init(); - - (0..5).for_each(|_| { - let alice_public_key = &ek; - - // run MtA protocol with different inputs - (0..5).for_each(|_| { - // Simulate Alice - let a = Scalar::::random().to_bigint(); - let encrypted_a = - Paillier::encrypt(alice_public_key, RawPlaintext::from(a)) - .0 - .clone() - .into_owned(); - - // Bob follows MtA - let b = Scalar::::random(); - // E(a) * b - let b_times_enc_a = Paillier::mul( - alice_public_key, - RawCiphertext::from(encrypted_a.clone()), - RawPlaintext::from(&b.to_bigint()), - ); - let beta_prim = BigInt::sample_below(&alice_public_key.n); - let r = Randomness::sample(alice_public_key); - let enc_beta_prim = Paillier::encrypt_with_chosen_randomness( - alice_public_key, - RawPlaintext::from(&beta_prim), - &r, - ); - - let mta_out = Paillier::add( - alice_public_key, - b_times_enc_a, - enc_beta_prim, - ); - - let (bob_proof, _) = BobProof::generate( - &encrypted_a, - &mta_out.0.clone(), - &b, - &beta_prim, - alice_public_key, - &dlog_statement, - &r, - false, - ); - assert!(bob_proof.verify( - &encrypted_a, - &mta_out.0.clone(), - alice_public_key, - &dlog_statement, - None - )); - - // Bob follows MtAwc - let ec_gen = Point::generator(); - let X = ec_gen * &b; - let bob_proof = generate( - &encrypted_a, - &mta_out.0.clone(), - &b, - &beta_prim, - alice_public_key, - &dlog_statement, - &r, - ); - assert!(bob_proof.verify( - &encrypted_a, - &mta_out.0.clone(), - alice_public_key, - &dlog_statement, - &X - )); - }); - }); - } -} diff --git a/src/utilities/mta/test.rs b/src/utilities/mta/test.rs deleted file mode 100644 index c2e6d63..0000000 --- a/src/utilities/mta/test.rs +++ /dev/null @@ -1,22 +0,0 @@ -use crate::utilities::mta::{ - range_proofs::tests::generate_init, MessageA, MessageB, -}; -use curv::elliptic::curves::{secp256_k1::Secp256k1, Scalar}; - -#[test] -fn test_mta() { - let alice_input = Scalar::::random(); - let (dlog_statement, ek_alice, dk_alice) = generate_init(); - let bob_input = Scalar::::random(); - let (m_a, _) = - MessageA::a(&alice_input, &ek_alice, &[dlog_statement.clone()]); - let (m_b, beta, _, _) = - MessageB::b(&bob_input, &ek_alice, m_a, &[dlog_statement]).unwrap(); - let alpha = m_b - .verify_proofs_get_alpha(&dk_alice, &alice_input) - .expect("wrong dlog or m_b"); - - let left = alpha.0 + beta; - let right = alice_input * bob_input; - assert_eq!(left, right); -} diff --git a/src/utilities/mul/mod.rs b/src/utilities/mul/mod.rs index 26eeecc..4e4d082 100644 --- a/src/utilities/mul/mod.rs +++ b/src/utilities/mul/mod.rs @@ -237,8 +237,9 @@ impl PaillierMulProof { #[cfg(test)] mod tests { use super::*; - use crate::utilities::{ - mta::range_proofs::SampleFromMultiplicativeGroup, BITS_PAILLIER, + use crate::{ + mpc_ecdsa::utilities::mta::range_proofs::SampleFromMultiplicativeGroup, + utilities::BITS_PAILLIER, }; use curv::elliptic::curves::secp256_k1::Secp256k1; use paillier::{Encrypt, KeyGeneration, Paillier, RawPlaintext}; diff --git a/src/utilities/mul_star/mod.rs b/src/utilities/mul_star/mod.rs index 25a1e78..3de810e 100644 --- a/src/utilities/mul_star/mod.rs +++ b/src/utilities/mul_star/mod.rs @@ -296,8 +296,9 @@ impl PaillierMultiplicationVersusGroupProof { #[cfg(test)] mod tests { use super::*; - use crate::utilities::{ - mta::range_proofs::SampleFromMultiplicativeGroup, BITS_PAILLIER, + use crate::{ + mpc_ecdsa::utilities::mta::range_proofs::SampleFromMultiplicativeGroup, + utilities::BITS_PAILLIER, }; use curv::elliptic::curves::secp256_k1::Secp256k1; use fs_dkr::ring_pedersen_proof::RingPedersenStatement; diff --git a/src/utilities/zk_pdl/mod.rs b/src/utilities/zk_pdl/mod.rs deleted file mode 100644 index cfe8529..0000000 --- a/src/utilities/zk_pdl/mod.rs +++ /dev/null @@ -1,275 +0,0 @@ -#![allow(non_snake_case)] -/* - Multi-party ECDSA - - Copyright 2018 by Kzen Networks - - This file is part of Multi-party ECDSA library - (https://github.com/KZen-networks/multi-party-ecdsa) - - Multi-party ECDSA 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+ -*/ - -//! We use the proof as given in protocol 6.1 in https://eprint.iacr.org/2017/552.pdf -//! Statement: (c, pk, Q, G) -//! witness (x, r, sk) such that Q = xG, c = Enc(pk, x, r) and Dec(sk, c) = x. -//! note that because of the range proof, the proof is sound only for x < q/3 - -use std::ops::Shl; - -use curv::{ - arithmetic::traits::*, - cryptographic_primitives::commitments::{ - hash_commitment::HashCommitment, traits::Commitment, - }, - elliptic::curves::{secp256_k1::Secp256k1, Point, Scalar}, - BigInt, -}; -use paillier::{ - Add, Decrypt, DecryptionKey, Encrypt, EncryptionKey, Mul, Paillier, - RawCiphertext, RawPlaintext, -}; -use serde::{Deserialize, Serialize}; -use sha2::Sha256; -use thiserror::Error; -use zk_paillier::zkproofs::{IncorrectProof, RangeProofNi}; - -#[derive(Error, Debug)] -pub enum ZkPdlError { - #[error("zk pdl message2 failed")] - Message2, - #[error("zk pdl finalize failed")] - Finalize, -} - -#[derive(Clone)] -pub struct PDLStatement { - pub ciphertext: BigInt, - pub ek: EncryptionKey, - pub Q: Point, - pub G: Point, -} -#[derive(Clone)] -pub struct PDLWitness { - pub x: Scalar, - pub r: BigInt, - pub dk: DecryptionKey, -} - -#[derive(Debug, Clone)] -pub struct PDLVerifierState { - pub c_tag: BigInt, - pub c_tag_tag: BigInt, - a: BigInt, - b: BigInt, - blindness: BigInt, - q_tag: Point, - c_hat: BigInt, -} - -#[derive(Debug, Clone)] -pub struct PDLProverState { - pub decommit: PDLProverDecommit, - pub alpha: BigInt, -} - -#[derive(Debug, Serialize, Deserialize, Clone)] -pub struct PDLVerifierFirstMessage { - pub c_tag: BigInt, - pub c_tag_tag: BigInt, -} - -#[derive(Debug, Serialize, Deserialize, Clone)] -pub struct PDLProverFirstMessage { - pub c_hat: BigInt, - pub range_proof: RangeProofNi, -} - -#[derive(Debug, Serialize, Deserialize, Clone)] -pub struct PDLVerifierSecondMessage { - pub a: BigInt, - pub b: BigInt, - pub blindness: BigInt, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct PDLProverDecommit { - pub q_hat: Point, - pub blindness: BigInt, -} - -#[derive(Debug, Serialize, Deserialize, Clone)] -pub struct PDLProverSecondMessage { - pub decommit: PDLProverDecommit, -} - -pub struct Prover {} -pub struct Verifier {} - -impl Verifier { - pub fn message1( - statement: &PDLStatement, - ) -> (PDLVerifierFirstMessage, PDLVerifierState) { - let a_fe = Scalar::::random(); - let a = a_fe.to_bigint(); - let q = Scalar::::group_order(); - let q_sq = q.pow(2); - let b = BigInt::sample_below(&q_sq); - let b_fe = Scalar::::from(&b); - let b_enc = - Paillier::encrypt(&statement.ek, RawPlaintext::from(b.clone())); - let ac = Paillier::mul( - &statement.ek, - RawCiphertext::from(statement.ciphertext.clone()), - RawPlaintext::from(a.clone()), - ); - let c_tag = Paillier::add(&statement.ek, ac, b_enc).0.into_owned(); - let ab_concat = a.clone() + b.clone().shl(a.bit_length()); - let blindness = BigInt::sample_below(q); - let c_tag_tag = HashCommitment::::create_commitment_with_user_defined_randomness( - &ab_concat, &blindness, - ); - let q_tag = &statement.Q * &a_fe + &statement.G * b_fe; - - ( - PDLVerifierFirstMessage { - c_tag: c_tag.clone(), - c_tag_tag: c_tag_tag.clone(), - }, - PDLVerifierState { - c_tag, - c_tag_tag, - a, - b, - blindness, - q_tag, - c_hat: BigInt::zero(), - }, - ) - } - - pub fn message2( - prover_first_messasge: &PDLProverFirstMessage, - statement: &PDLStatement, - state: &mut PDLVerifierState, - ) -> Result { - let decommit_message = PDLVerifierSecondMessage { - a: state.a.clone(), - b: state.b.clone(), - blindness: state.blindness.clone(), - }; - let range_proof_is_ok = - verify_range_proof(statement, &prover_first_messasge.range_proof) - .is_ok(); - state.c_hat = prover_first_messasge.c_hat.clone(); - if range_proof_is_ok { - Ok(decommit_message) - } else { - Err(ZkPdlError::Message2) - } - } - - pub fn finalize( - prover_first_message: &PDLProverFirstMessage, - prover_second_message: &PDLProverSecondMessage, - state: &PDLVerifierState, - ) -> Result<(), ZkPdlError> { - let c_hat_test = HashCommitment::::create_commitment_with_user_defined_randomness( - &BigInt::from_bytes(prover_second_message.decommit.q_hat.to_bytes(true).as_ref()), - &prover_second_message.decommit.blindness, - ); - - if prover_first_message.c_hat == c_hat_test - && prover_second_message.decommit.q_hat == state.q_tag - { - Ok(()) - } else { - Err(ZkPdlError::Finalize) - } - } -} - -impl Prover { - pub fn message1( - witness: &PDLWitness, - statement: &PDLStatement, - verifier_first_message: &PDLVerifierFirstMessage, - ) -> (PDLProverFirstMessage, PDLProverState) { - let c_tag = verifier_first_message.c_tag.clone(); - let alpha = Paillier::decrypt(&witness.dk, &RawCiphertext::from(c_tag)); - let alpha_fe = Scalar::::from(alpha.0.as_ref()); - let q_hat = &statement.G * alpha_fe; - let blindness = - BigInt::sample_below(Scalar::::group_order()); - let c_hat = HashCommitment::::create_commitment_with_user_defined_randomness( - &BigInt::from_bytes(q_hat.to_bytes(true).as_ref()), - &blindness, - ); - // in parallel generate range proof: - let range_proof = generate_range_proof(statement, witness); - ( - PDLProverFirstMessage { c_hat, range_proof }, - PDLProverState { - decommit: PDLProverDecommit { blindness, q_hat }, - alpha: alpha.0.into_owned(), - }, - ) - } - - pub fn message2( - verifier_first_message: &PDLVerifierFirstMessage, - verifier_second_message: &PDLVerifierSecondMessage, - witness: &PDLWitness, - state: &PDLProverState, - ) -> Result { - let ab_concat = &verifier_second_message.a - + verifier_second_message - .b - .clone() - .shl(verifier_second_message.a.bit_length()); // b|a (in the paper it is a|b) - let c_tag_tag_test = - HashCommitment::::create_commitment_with_user_defined_randomness( - &ab_concat, - &verifier_second_message.blindness, - ); - let ax1 = &verifier_second_message.a * witness.x.to_bigint(); - let alpha_test = ax1 + &verifier_second_message.b; - if alpha_test == state.alpha - && verifier_first_message.c_tag_tag == c_tag_tag_test - { - Ok(PDLProverSecondMessage { - decommit: state.decommit.clone(), - }) - } else { - Err(ZkPdlError::Message2) - } - } -} - -fn generate_range_proof( - statement: &PDLStatement, - witness: &PDLWitness, -) -> RangeProofNi { - RangeProofNi::prove( - &statement.ek, - Scalar::::group_order(), - &statement.ciphertext, - &witness.x.to_bigint(), - &witness.r, - ) -} - -fn verify_range_proof( - statement: &PDLStatement, - range_proof: &RangeProofNi, -) -> Result<(), IncorrectProof> { - range_proof.verify(&statement.ek, &statement.ciphertext) -} - -#[cfg(test)] -mod test; diff --git a/src/utilities/zk_pdl/test.rs b/src/utilities/zk_pdl/test.rs deleted file mode 100644 index 3e5a223..0000000 --- a/src/utilities/zk_pdl/test.rs +++ /dev/null @@ -1,64 +0,0 @@ -#![allow(non_snake_case)] - -use curv::{ - arithmetic::traits::*, - elliptic::curves::{secp256_k1::Secp256k1, Point, Scalar}, - BigInt, -}; -use paillier::{ - core::Randomness, - traits::{EncryptWithChosenRandomness, KeyGeneration}, - Paillier, RawPlaintext, -}; - -use crate::utilities::zk_pdl::{PDLStatement, PDLWitness, Prover, Verifier}; - -#[test] -fn test_zk_pdl() { - // pre-test: - - let (ek, dk) = Paillier::keypair().keys(); - let randomness = Randomness::sample(&ek); - let x = Scalar::::random(); - let x: Scalar = - Scalar::::from(&x.to_bigint().div_floor(&BigInt::from(3))); - - let Q = Point::generator() * &x; - - let c = Paillier::encrypt_with_chosen_randomness( - &ek, - RawPlaintext::from(x.to_bigint()), - &randomness, - ) - .0 - .into_owned(); - let statement = PDLStatement { - ciphertext: c, - ek, - Q, - G: Point::generator().to_point(), - }; - let witness = PDLWitness { - x, - r: randomness.0, - dk, - }; - // - let (verifier_message1, mut verifier_state) = - Verifier::message1(&statement); - let (prover_message1, prover_state) = - Prover::message1(&witness, &statement, &verifier_message1); - let verifier_message2 = - Verifier::message2(&prover_message1, &statement, &mut verifier_state) - .expect(""); - let prover_message2 = Prover::message2( - &verifier_message1, - &verifier_message2, - &witness, - &prover_state, - ) - .expect(""); - let result = - Verifier::finalize(&prover_message1, &prover_message2, &verifier_state); - assert!(result.is_ok()); -} diff --git a/src/utilities/zk_pdl_with_slack/mod.rs b/src/utilities/zk_pdl_with_slack/mod.rs deleted file mode 100644 index dfa737e..0000000 --- a/src/utilities/zk_pdl_with_slack/mod.rs +++ /dev/null @@ -1,226 +0,0 @@ -#![allow(non_snake_case)] -/* - Multi-party ECDSA - - Copyright 2018 by Kzen Networks - - This file is part of Multi-party ECDSA library - (https://github.com/KZen-networks/multi-party-ecdsa) - - Multi-party ECDSA 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+ -*/ - -//! We use the proof as given in proof PIi in https://eprint.iacr.org/2016/013.pdf. -//! This proof ws taken from the proof 6.3 (left side ) in https://www.cs.unc.edu/~reiter/papers/2004/IJIS.pdf -//! -//! Statement: (c, pk, Q, G) -//! witness (x, r) such that Q = xG, c = Enc(pk, x, r) -//! note that because of the range proof, the proof has a slack in the range: x -//! in [-q^3, q^3] - -use curv::{ - arithmetic::traits::*, - cryptographic_primitives::hashing::{Digest, DigestExt}, - elliptic::curves::{secp256_k1::Secp256k1, Point, Scalar}, - BigInt, -}; -use paillier::EncryptionKey; -use serde::{Deserialize, Serialize}; -use sha2::Sha256; -use thiserror::Error; - -#[derive(Error, Debug)] -pub enum ZkPdlWithSlackError { - #[error("zk pdl with slack verification failed")] - Verify, -} - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct PDLwSlackStatement { - pub ciphertext: BigInt, - pub ek: EncryptionKey, - pub Q: Point, - pub G: Point, - pub h1: BigInt, - pub h2: BigInt, - pub N_tilde: BigInt, -} -#[derive(Clone)] -pub struct PDLwSlackWitness { - pub x: Scalar, - pub r: BigInt, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct PDLwSlackProof { - z: BigInt, - u1: Point, - u2: BigInt, - u3: BigInt, - s1: BigInt, - s2: BigInt, - s3: BigInt, -} - -impl PDLwSlackProof { - pub fn prove( - witness: &PDLwSlackWitness, - statement: &PDLwSlackStatement, - ) -> Self { - let q3 = Scalar::::group_order().pow(3); - let q_N_tilde = Scalar::::group_order() * &statement.N_tilde; - let q3_N_tilde = &q3 * &statement.N_tilde; - - let alpha = BigInt::sample_below(&q3); - let one = BigInt::one(); - let beta = BigInt::sample_range(&one, &(&statement.ek.n - &one)); - let rho = BigInt::sample_below(&q_N_tilde); - let gamma = BigInt::sample_below(&q3_N_tilde); - - let z = commitment_unknown_order( - &statement.h1, - &statement.h2, - &statement.N_tilde, - &witness.x.to_bigint(), - &rho, - ); - let u1 = &statement.G * &Scalar::::from(&alpha); - let u2 = commitment_unknown_order( - &(&statement.ek.n + BigInt::one()), - &beta, - &statement.ek.nn, - &alpha, - &statement.ek.n, - ); - let u3 = commitment_unknown_order( - &statement.h1, - &statement.h2, - &statement.N_tilde, - &alpha, - &gamma, - ); - - let e = Sha256::new() - .chain_bigint(&BigInt::from_bytes( - statement.G.to_bytes(true).as_ref(), - )) - .chain_bigint(&BigInt::from_bytes( - statement.Q.to_bytes(true).as_ref(), - )) - .chain_bigint(&statement.ciphertext) - .chain_bigint(&z) - .chain_bigint(&BigInt::from_bytes(u1.to_bytes(true).as_ref())) - .chain_bigint(&u2) - .chain_bigint(&u3) - .result_bigint(); - - let s1 = &e * witness.x.to_bigint() + alpha; - let s2 = commitment_unknown_order( - &witness.r, - &beta, - &statement.ek.n, - &e, - &BigInt::one(), - ); - let s3 = &e * rho + gamma; - - PDLwSlackProof { - z, - u1, - u2, - u3, - s1, - s2, - s3, - } - } - - pub fn verify( - &self, - statement: &PDLwSlackStatement, - ) -> Result<(), ZkPdlWithSlackError> { - let e = Sha256::new() - .chain_bigint(&BigInt::from_bytes( - statement.G.to_bytes(true).as_ref(), - )) - .chain_bigint(&BigInt::from_bytes( - statement.Q.to_bytes(true).as_ref(), - )) - .chain_bigint(&statement.ciphertext) - .chain_bigint(&self.z) - .chain_bigint(&BigInt::from_bytes(self.u1.to_bytes(true).as_ref())) - .chain_bigint(&self.u2) - .chain_bigint(&self.u3) - .result_bigint(); - - let g_s1 = statement.G.clone() * &Scalar::::from(&self.s1); - let e_fe_neg: Scalar = Scalar::::from( - &(Scalar::::group_order() - &e), - ); - let y_minus_e = &statement.Q * &e_fe_neg; - let u1_test = g_s1 + y_minus_e; - - let u2_test_tmp = commitment_unknown_order( - &(&statement.ek.n + BigInt::one()), - &self.s2, - &statement.ek.nn, - &self.s1, - &statement.ek.n, - ); - let u2_test = commitment_unknown_order( - &u2_test_tmp, - &statement.ciphertext, - &statement.ek.nn, - &BigInt::one(), - &(-&e), - ); - - let u3_test_tmp = commitment_unknown_order( - &statement.h1, - &statement.h2, - &statement.N_tilde, - &self.s1, - &self.s3, - ); - let u3_test = commitment_unknown_order( - &u3_test_tmp, - &self.z, - &statement.N_tilde, - &BigInt::one(), - &(-&e), - ); - - if self.u1 == u1_test && self.u2 == u2_test && self.u3 == u3_test { - Ok(()) - } else { - Err(ZkPdlWithSlackError::Verify) - } - } -} - -pub fn commitment_unknown_order( - h1: &BigInt, - h2: &BigInt, - N_tilde: &BigInt, - x: &BigInt, - r: &BigInt, -) -> BigInt { - let h1_x = BigInt::mod_pow(h1, x, N_tilde); - let h2_r = { - if r < &BigInt::zero() { - let h2_inv = BigInt::mod_inv(h2, N_tilde).unwrap(); - BigInt::mod_pow(&h2_inv, &(-r), N_tilde) - } else { - BigInt::mod_pow(h2, r, N_tilde) - } - }; - BigInt::mod_mul(&h1_x, &h2_r, N_tilde) -} - -#[cfg(test)] -mod test; diff --git a/src/utilities/zk_pdl_with_slack/test.rs b/src/utilities/zk_pdl_with_slack/test.rs deleted file mode 100644 index 227bb4f..0000000 --- a/src/utilities/zk_pdl_with_slack/test.rs +++ /dev/null @@ -1,134 +0,0 @@ -#![allow(non_snake_case)] -use crate::utilities::zk_pdl_with_slack::*; -use curv::{ - elliptic::curves::{secp256_k1::Secp256k1, Point, Scalar}, - BigInt, -}; -use paillier::{ - core::Randomness, - traits::{EncryptWithChosenRandomness, KeyGeneration}, - Paillier, RawPlaintext, -}; -use zk_paillier::zkproofs::{CompositeDLogProof, DLogStatement}; - -#[test] -fn test_zk_pdl_with_slack() { - // N_tilde, h1, h2 generation - let (ek_tilde, dk_tilde) = Paillier::keypair().keys(); - // note: safe primes should be used: - // let (ek_tilde, dk_tilde) = Paillier::keypair_safe_primes().keys(); - let one = BigInt::one(); - let phi = (&dk_tilde.p - &one) * (&dk_tilde.q - &one); - let h1 = BigInt::sample_below(&phi); - let S = BigInt::from(2).pow(256_u32); - let xhi = BigInt::sample_below(&S); - let h1_inv = BigInt::mod_inv(&h1, &ek_tilde.n).unwrap(); - let h2 = BigInt::mod_pow(&h1_inv, &xhi, &ek_tilde.n); - let statement = DLogStatement { - N: ek_tilde.n.clone(), - g: h1.clone(), - ni: h2.clone(), - }; - - let composite_dlog_proof = CompositeDLogProof::prove(&statement, &xhi); - - // generate the scalar secret and Paillier encrypt it - let (ek, _dk) = Paillier::keypair().keys(); - // note: safe primes should be used here as well: - // let (ek_tilde, dk_tilde) = Paillier::keypair_safe_primes().keys(); - let randomness = Randomness::sample(&ek); - let x = Scalar::::random(); - - let Q = Point::generator() * &x; - - let c = Paillier::encrypt_with_chosen_randomness( - &ek, - RawPlaintext::from(x.to_bigint()), - &randomness, - ) - .0 - .into_owned(); - - // Generate PDL with slack statement, witness and proof - let pdl_w_slack_statement = PDLwSlackStatement { - ciphertext: c, - ek, - Q, - G: Point::generator().to_point(), - h1, - h2, - N_tilde: ek_tilde.n, - }; - - let pdl_w_slack_witness = PDLwSlackWitness { x, r: randomness.0 }; - - let proof = - PDLwSlackProof::prove(&pdl_w_slack_witness, &pdl_w_slack_statement); - // verify h1,h2, N_tilde - let setup_result = composite_dlog_proof.verify(&statement); - assert!(setup_result.is_ok()); - let result = proof.verify(&pdl_w_slack_statement); - assert!(result.is_ok()); -} - -#[test] -#[should_panic] -fn test_zk_pdl_with_slack_soundness() { - // N_tilde, h1, h2 generation - let (ek_tilde, dk_tilde) = Paillier::keypair().keys(); - // note: safe primes should be used: - // let (ek_tilde, dk_tilde) = Paillier::keypair_safe_primes().keys(); - let one = BigInt::one(); - let phi = (&dk_tilde.p - &one) * (&dk_tilde.q - &one); - let h1 = BigInt::sample_below(&phi); - let S = BigInt::from(2).pow(256_u32); - let xhi = BigInt::sample_below(&S); - let h1_inv = BigInt::mod_inv(&h1, &ek_tilde.n).unwrap(); - let h2 = BigInt::mod_pow(&h1_inv, &xhi, &ek_tilde.n); - let statement = DLogStatement { - N: ek_tilde.n.clone(), - g: h1.clone(), - ni: h2.clone(), - }; - - let composite_dlog_proof = CompositeDLogProof::prove(&statement, &xhi); - - // generate the scalar secret and Paillier encrypt it - let (ek, _dk) = Paillier::keypair().keys(); - // note: safe primes should be used here as well: - // let (ek_tilde, dk_tilde) = Paillier::keypair_safe_primes().keys(); - let randomness = Randomness::sample(&ek); - let x = Scalar::::random(); - - let Q = Point::generator() * &x; - - // here we encrypt x + 1 instead of x: - let c = Paillier::encrypt_with_chosen_randomness( - &ek, - RawPlaintext::from(x.to_bigint() + BigInt::one()), - &randomness, - ) - .0 - .into_owned(); - - // Generate PDL with slack statement, witness and proof - let pdl_w_slack_statement = PDLwSlackStatement { - ciphertext: c, - ek, - Q, - G: Point::generator().to_point(), - h1, - h2, - N_tilde: ek_tilde.n, - }; - - let pdl_w_slack_witness = PDLwSlackWitness { x, r: randomness.0 }; - - let proof = - PDLwSlackProof::prove(&pdl_w_slack_witness, &pdl_w_slack_statement); - // verify h1,h2, N_tilde - let setup_result = composite_dlog_proof.verify(&statement); - assert!(setup_result.is_ok()); - let result = proof.verify(&pdl_w_slack_statement); - assert!(result.is_ok()); -}