From b183a8c7e127dcb381f2efb6c96cdd54ad7bfe41 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Tue, 24 Oct 2023 12:49:16 +0200 Subject: [PATCH 01/26] refactor: add tss-core package --- Cargo.toml | 3 +++ tss-core/Cargo.toml | 29 +++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 tss-core/Cargo.toml diff --git a/Cargo.toml b/Cargo.toml index b7bd8ec..89e00e6 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,7 @@ 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" } [workspace.dependencies.multi-party-ecdsa] version = "0.8" @@ -51,6 +53,7 @@ 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/tss-core/Cargo.toml b/tss-core/Cargo.toml new file mode 100644 index 0000000..9fe6f53 --- /dev/null +++ b/tss-core/Cargo.toml @@ -0,0 +1,29 @@ +[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 + +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 From 745e512b4f7b8b0d4e5dababf4c4611491520633 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Tue, 24 Oct 2023 12:51:02 +0200 Subject: [PATCH 02/26] refactor: move composite dlog proof to tss-core --- tss-core/src/lib.rs | 2 ++ tss-core/src/zkproof/mod.rs | 1 + .../zk_composite_dlog.rs => tss-core/src/zkproof/prm/mod.rs | 2 +- 3 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 tss-core/src/lib.rs create mode 100644 tss-core/src/zkproof/mod.rs rename multi-party-ecdsa/src/utilities/zk_composite_dlog.rs => tss-core/src/zkproof/prm/mod.rs (99%) diff --git a/tss-core/src/lib.rs b/tss-core/src/lib.rs new file mode 100644 index 0000000..83f5b16 --- /dev/null +++ b/tss-core/src/lib.rs @@ -0,0 +1,2 @@ +pub mod utilities; +pub mod zkproof; diff --git a/tss-core/src/zkproof/mod.rs b/tss-core/src/zkproof/mod.rs new file mode 100644 index 0000000..612b3ad --- /dev/null +++ b/tss-core/src/zkproof/mod.rs @@ -0,0 +1 @@ +pub mod prm; diff --git a/multi-party-ecdsa/src/utilities/zk_composite_dlog.rs b/tss-core/src/zkproof/prm/mod.rs similarity index 99% rename from multi-party-ecdsa/src/utilities/zk_composite_dlog.rs rename to tss-core/src/zkproof/prm/mod.rs index 0edcde0..3570fa0 100644 --- a/multi-party-ecdsa/src/utilities/zk_composite_dlog.rs +++ b/tss-core/src/zkproof/prm/mod.rs @@ -202,7 +202,7 @@ 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_h1_h2_N_tilde; #[test] fn valid_composite_dlog_proof_works() { From 6836ad3da48524c59e9c61891a052ba6b32a9dbb Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Tue, 24 Oct 2023 12:54:31 +0200 Subject: [PATCH 03/26] refactor: use tss-core composite dlog proof --- Cargo.lock | 17 +++++++++++++++++ fs-dkr/Cargo.toml | 1 + fs-dkr/src/add_party_message.rs | 7 +++---- fs-dkr/src/range_proofs.rs | 2 +- fs-dkr/src/refresh_message.rs | 2 +- multi-party-ecdsa/Cargo.toml | 1 + multi-party-ecdsa/src/gg_2020/party_i.rs | 10 ++++++---- .../src/gg_2020/state_machine/keygen/rounds.rs | 2 +- multi-party-ecdsa/src/gg_2020/test.rs | 2 +- multi-party-ecdsa/src/utilities/mod.rs | 1 - multi-party-ecdsa/src/utilities/mta/mod.rs | 2 +- .../src/utilities/mta/range_proofs.rs | 2 +- src/party_i.rs | 6 ++++-- 13 files changed, 38 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 405da44..ac743f3 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,20 @@ dependencies = [ "cfg-if 0.1.10", ] +[[package]] +name = "tss-core" +version = "0.1.0" +dependencies = [ + "bincode", + "curv-kzen", + "kzen-paillier", + "merlin", + "serde", + "serde_repr", + "serde_with", + "zeroize", +] + [[package]] name = "typenum" version = "1.17.0" diff --git a/fs-dkr/Cargo.toml b/fs-dkr/Cargo.toml index 708da36..8f14074 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 9737969..ce80f6e 100644 --- a/fs-dkr/src/add_party_message.rs +++ b/fs-dkr/src/add_party_message.rs @@ -29,20 +29,19 @@ 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 zk_paillier::zkproofs::NiCorrectKeyProof; use crate::ring_pedersen_proof::{RingPedersenProof, RingPedersenStatement}; +use tss_core::zkproof::prm::{ + CompositeDLogProof, CompositeDLogStatement, CompositeDLogWitness, +}; /// Message used by new parties to join the protocol. #[derive(Clone, Deserialize, Serialize, Debug)] diff --git a/fs-dkr/src/range_proofs.rs b/fs-dkr/src/range_proofs.rs index 30c5b0c..b3df634 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::CompositeDLogStatement; use zeroize::Zeroize; /// Represents the first round of the interactive version of the proof diff --git a/fs-dkr/src/refresh_message.rs b/fs-dkr/src/refresh_message.rs index c6e21ad..34456e9 100644 --- a/fs-dkr/src/refresh_message.rs +++ b/fs-dkr/src/refresh_message.rs @@ -23,7 +23,7 @@ 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 tss_core::zkproof::prm::CompositeDLogStatement; use crate::ring_pedersen_proof::{RingPedersenProof, RingPedersenStatement}; diff --git a/multi-party-ecdsa/Cargo.toml b/multi-party-ecdsa/Cargo.toml index 00befa2..918af85 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 ce1e94c..b4bc9f4 100644 --- a/multi-party-ecdsa/src/gg_2020/party_i.rs +++ b/multi-party-ecdsa/src/gg_2020/party_i.rs @@ -47,18 +47,20 @@ 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::{ + zkproof::prm::{ + CompositeDLogProof, CompositeDLogStatement, CompositeDLogWitness, + }, +}; + const SECURITY: usize = 256; const PAILLIER_MIN_BIT_LENGTH: usize = 2047; const PAILLIER_MAX_BIT_LENGTH: usize = 2048; 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 d7470ea..b932292 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::CompositeDLogStatement; pub struct Round0 { pub party_i: u16, diff --git a/multi-party-ecdsa/src/gg_2020/test.rs b/multi-party-ecdsa/src/gg_2020/test.rs index 059a118..b8ad2b9 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::CompositeDLogStatement; #[test] fn test_keygen_t1_n2() { diff --git a/multi-party-ecdsa/src/utilities/mod.rs b/multi-party-ecdsa/src/utilities/mod.rs index 40fe8bc..867fce3 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 1edf067..0ec6657 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::CompositeDLogStatement; #[derive(Clone, Debug, Serialize, Deserialize)] pub struct MessageA { diff --git a/multi-party-ecdsa/src/utilities/mta/range_proofs.rs b/multi-party-ecdsa/src/utilities/mta/range_proofs.rs index e96508c..60d34ad 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::CompositeDLogStatement; /// Represents the first round of the interactive version of the proof #[derive(Zeroize)] diff --git a/src/party_i.rs b/src/party_i.rs index 4324460..bb11372 100644 --- a/src/party_i.rs +++ b/src/party_i.rs @@ -58,8 +58,10 @@ pub use crate::mpc_ecdsa::{ }, }; 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::{ + zkproof::prm::{ + CompositeDLogProof, CompositeDLogStatement, CompositeDLogWitness, + }, }; const SECURITY: usize = 256; From e5770ba822a39f48f92d8db765f600082a402a92 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Tue, 24 Oct 2023 12:56:24 +0200 Subject: [PATCH 04/26] refactor: move generate_h1_h2_N_tilde to tss-core --- fs-dkr/src/add_party_message.rs | 1 + multi-party-ecdsa/src/gg_2020/party_i.rs | 29 +--------------------- src/party_i.rs | 2 +- tss-core/src/utilities/mod.rs | 31 ++++++++++++++++++++++++ 4 files changed, 34 insertions(+), 29 deletions(-) create mode 100644 tss-core/src/utilities/mod.rs diff --git a/fs-dkr/src/add_party_message.rs b/fs-dkr/src/add_party_message.rs index ce80f6e..e72f9c5 100644 --- a/fs-dkr/src/add_party_message.rs +++ b/fs-dkr/src/add_party_message.rs @@ -39,6 +39,7 @@ use std::{collections::HashMap, fmt::Debug}; use zk_paillier::zkproofs::NiCorrectKeyProof; use crate::ring_pedersen_proof::{RingPedersenProof, RingPedersenStatement}; +use tss_core::utilities::generate_h1_h2_N_tilde; use tss_core::zkproof::prm::{ CompositeDLogProof, CompositeDLogStatement, CompositeDLogWitness, }; diff --git a/multi-party-ecdsa/src/gg_2020/party_i.rs b/multi-party-ecdsa/src/gg_2020/party_i.rs index b4bc9f4..8ba873d 100644 --- a/multi-party-ecdsa/src/gg_2020/party_i.rs +++ b/multi-party-ecdsa/src/gg_2020/party_i.rs @@ -56,6 +56,7 @@ use curv::cryptographic_primitives::proofs::sigma_valid_pedersen::PedersenProof; use std::convert::TryInto; use tss_core::{ + utilities::generate_h1_h2_N_tilde, zkproof::prm::{ CompositeDLogProof, CompositeDLogStatement, CompositeDLogWitness, }, @@ -151,34 +152,6 @@ 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(); diff --git a/src/party_i.rs b/src/party_i.rs index bb11372..392d941 100644 --- a/src/party_i.rs +++ b/src/party_i.rs @@ -57,8 +57,8 @@ pub use crate::mpc_ecdsa::{ PDLwSlackProof, PDLwSlackStatement, PDLwSlackWitness, }, }; -use multi_party_ecdsa::gg_2020::party_i::generate_h1_h2_N_tilde; use tss_core::{ + utilities::generate_h1_h2_N_tilde, zkproof::prm::{ CompositeDLogProof, CompositeDLogStatement, CompositeDLogWitness, }, diff --git a/tss-core/src/utilities/mod.rs b/tss-core/src/utilities/mod.rs new file mode 100644 index 0000000..c3a64fa --- /dev/null +++ b/tss-core/src/utilities/mod.rs @@ -0,0 +1,31 @@ +use curv::arithmetic::traits::*; +use curv::BigInt; +use paillier::{KeyGeneration, Paillier}; + +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) +} From e87ff902d32c19573731221e1b918dd673025123 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Fri, 27 Oct 2023 14:37:58 +0200 Subject: [PATCH 05/26] refactor: allow non-snake-case --- tss-core/src/utilities/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tss-core/src/utilities/mod.rs b/tss-core/src/utilities/mod.rs index c3a64fa..e5090ed 100644 --- a/tss-core/src/utilities/mod.rs +++ b/tss-core/src/utilities/mod.rs @@ -1,3 +1,5 @@ +#![allow(non_snake_case)] + use curv::arithmetic::traits::*; use curv::BigInt; use paillier::{KeyGeneration, Paillier}; From 86ddbc54b0fa954c9da56f3a10efc0a603ecab2e Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Mon, 6 Nov 2023 21:49:13 +0100 Subject: [PATCH 06/26] refactor: rename to PiPrm and use instead of existing Ring-Pedersen --- fs-dkr/src/add_party_message.rs | 49 +++++------- fs-dkr/src/range_proofs.rs | 22 ++--- fs-dkr/src/refresh_message.rs | 8 +- multi-party-ecdsa/src/gg_2020/party_i.rs | 57 +++++++------ .../gg_2020/state_machine/keygen/rounds.rs | 6 +- multi-party-ecdsa/src/gg_2020/test.rs | 8 +- multi-party-ecdsa/src/utilities/mta/mod.rs | 10 +-- .../src/utilities/mta/range_proofs.rs | 22 ++--- src/party_i.rs | 47 ++++++----- src/presign/state_machine.rs | 11 ++- src/utilities/aff_g/mod.rs | 11 ++- src/utilities/dec_q/mod.rs | 11 +-- src/utilities/enc/mod.rs | 19 ++--- src/utilities/log_star/mod.rs | 11 ++- src/utilities/mul_star/mod.rs | 12 +-- tss-core/src/utilities/mod.rs | 48 +++++++---- tss-core/src/zkproof/prm/mod.rs | 80 +++++++++---------- 17 files changed, 210 insertions(+), 222 deletions(-) diff --git a/fs-dkr/src/add_party_message.rs b/fs-dkr/src/add_party_message.rs index e72f9c5..be488ed 100644 --- a/fs-dkr/src/add_party_message.rs +++ b/fs-dkr/src/add_party_message.rs @@ -39,10 +39,8 @@ use std::{collections::HashMap, fmt::Debug}; use zk_paillier::zkproofs::NiCorrectKeyProof; use crate::ring_pedersen_proof::{RingPedersenProof, RingPedersenStatement}; -use tss_core::utilities::generate_h1_h2_N_tilde; -use tss_core::zkproof::prm::{ - CompositeDLogProof, CompositeDLogStatement, CompositeDLogWitness, -}; +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)] @@ -51,52 +49,45 @@ 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) dlog_statement: PiPrmStatement, + pub(crate) composite_dlog_proof_base_h1: PiPrmProof, + pub(crate) composite_dlog_proof_base_h2: PiPrmProof, pub(crate) ring_pedersen_statement: RingPedersenStatement, pub(crate) ring_pedersen_proof: RingPedersenProof, } /// 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 (n_tilde, h1, h2, xhi, xhi_inv, phi) = generate_safe_h1_h2_N_tilde(); - let dlog_statement_base_h1 = CompositeDLogStatement { + let dlog_statement_base_h1 = PiPrmStatement { modulus: n_tilde.clone(), base: h1.clone(), value: h2.clone(), }; - let dlog_witness_base_h1 = CompositeDLogWitness { + let dlog_witness_base_h1 = PiPrmWitness { exponent: xhi, totient: phi.clone(), }; - let dlog_statement_base_h2 = CompositeDLogStatement { + let dlog_statement_base_h2 = PiPrmStatement { modulus: n_tilde, base: h2, value: h1, }; - let dlog_witness_base_h2 = CompositeDLogWitness { + let dlog_witness_base_h2 = PiPrmWitness { exponent: xhi_inv, totient: phi.clone(), }; - 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, @@ -261,7 +252,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 +280,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/range_proofs.rs b/fs-dkr/src/range_proofs.rs index b3df634..175b7ff 100644 --- a/fs-dkr/src/range_proofs.rs +++ b/fs-dkr/src/range_proofs.rs @@ -22,7 +22,7 @@ use curv::{ use paillier::{EncryptionKey, Randomness}; use serde::{Deserialize, Serialize}; use std::{borrow::Borrow, marker::PhantomData}; -use tss_core::zkproof::prm::CompositeDLogStatement; +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 34456e9..16e8831 100644 --- a/fs-dkr/src/refresh_message.rs +++ b/fs-dkr/src/refresh_message.rs @@ -23,7 +23,7 @@ use serde::{Deserialize, Serialize}; use std::{borrow::Borrow, collections::HashMap, fmt::Debug}; use zeroize::Zeroize; use zk_paillier::zkproofs::{NiCorrectKeyProof, SALT_STRING}; -use tss_core::zkproof::prm::CompositeDLogStatement; +use tss_core::zkproof::prm::PiPrmStatement; use crate::ring_pedersen_proof::{RingPedersenProof, RingPedersenStatement}; @@ -39,7 +39,7 @@ 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, @@ -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 @@ -452,7 +452,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/multi-party-ecdsa/src/gg_2020/party_i.rs b/multi-party-ecdsa/src/gg_2020/party_i.rs index 8ba873d..8211982 100644 --- a/multi-party-ecdsa/src/gg_2020/party_i.rs +++ b/multi-party-ecdsa/src/gg_2020/party_i.rs @@ -56,10 +56,8 @@ use curv::cryptographic_primitives::proofs::sigma_valid_pedersen::PedersenProof; use std::convert::TryInto; use tss_core::{ - utilities::generate_h1_h2_N_tilde, - zkproof::prm::{ - CompositeDLogProof, CompositeDLogStatement, CompositeDLogWitness, - }, + utilities::generate_safe_h1_h2_N_tilde, + zkproof::prm::{PiPrmProof, PiPrmStatement, PiPrmWitness}, }; const SECURITY: usize = 256; @@ -97,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)] @@ -157,7 +155,8 @@ 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 (N_tilde, h1, h2, xhi, xhi_inv, phi) = + generate_safe_h1_h2_N_tilde(); Self { u_i: u, @@ -180,7 +179,8 @@ 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 (N_tilde, h1, h2, xhi, xhi_inv, phi) = + generate_safe_h1_h2_N_tilde(); Self { u_i: u, @@ -199,7 +199,8 @@ impl Keys { 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 (N_tilde, h1, h2, xhi, xhi_inv, phi) = + generate_safe_h1_h2_N_tilde(); Self { u_i: u, @@ -223,22 +224,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(), }; @@ -248,16 +249,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()), @@ -295,7 +292,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(), @@ -553,7 +550,8 @@ 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 (N_tilde, h1, h2, xhi, xhi_inv, phi) = + generate_safe_h1_h2_N_tilde(); Keys { u_i: u, @@ -580,7 +578,8 @@ 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 (N_tilde, h1, h2, xhi, xhi_inv, phi) = + generate_safe_h1_h2_N_tilde(); Keys { u_i: u, @@ -805,7 +804,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 { @@ -832,7 +831,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 b932292..f4283da 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 tss_core::zkproof::prm::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 b8ad2b9..a6aa317 100644 --- a/multi-party-ecdsa/src/gg_2020/test.rs +++ b/multi-party-ecdsa/src/gg_2020/test.rs @@ -44,7 +44,7 @@ use curv::{ }; use paillier::*; use sha2::Sha256; -use tss_core::zkproof::prm::CompositeDLogStatement; +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/mta/mod.rs b/multi-party-ecdsa/src/utilities/mta/mod.rs index 0ec6657..d6d2252 100644 --- a/multi-party-ecdsa/src/utilities/mta/mod.rs +++ b/multi-party-ecdsa/src/utilities/mta/mod.rs @@ -34,7 +34,7 @@ use crate::{ utilities::mta::range_proofs::AliceProof, Error::{self, InvalidKey}, }; -use tss_core::zkproof::prm::CompositeDLogStatement; +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 60d34ad..ab87ce8 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 tss_core::zkproof::prm::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 392d941..3d34a6f 100644 --- a/src/party_i.rs +++ b/src/party_i.rs @@ -58,10 +58,8 @@ pub use crate::mpc_ecdsa::{ }, }; use tss_core::{ - utilities::generate_h1_h2_N_tilde, - zkproof::prm::{ - CompositeDLogProof, CompositeDLogStatement, CompositeDLogWitness, - }, + utilities::generate_safe_h1_h2_N_tilde, + zkproof::prm::{PiPrmProof, PiPrmStatement, PiPrmWitness}, }; const SECURITY: usize = 256; @@ -138,7 +136,8 @@ 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 (N_tilde, h1, h2, xhi, xhi_inv, phi) = + generate_safe_h1_h2_N_tilde(); Self { u_i: u, @@ -161,7 +160,8 @@ 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 (N_tilde, h1, h2, xhi, xhi_inv, phi) = + generate_safe_h1_h2_N_tilde(); Self { u_i: u, @@ -180,7 +180,8 @@ impl Keys { 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 (N_tilde, h1, h2, xhi, xhi_inv, phi) = + generate_safe_h1_h2_N_tilde(); Self { u_i: u, @@ -204,22 +205,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(), }; @@ -229,16 +230,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()), @@ -281,7 +278,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(), @@ -489,7 +486,8 @@ 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 (N_tilde, h1, h2, xhi, xhi_inv, phi) = + generate_safe_h1_h2_N_tilde(); Keys { u_i: u, @@ -516,7 +514,8 @@ 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 (N_tilde, h1, h2, xhi, xhi_inv, phi) = + generate_safe_h1_h2_N_tilde(); Keys { u_i: u, diff --git a/src/presign/state_machine.rs b/src/presign/state_machine.rs index 31db8b0..1333fb4 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 (N_hat, S, T, _, _, _) = generate_safe_h1_h2_N_tilde(); + aux_ring_pedersen_n_hat_values.insert(idx, N_hat); + aux_ring_pedersen_s_values.insert(idx, S); + aux_ring_pedersen_t_values.insert(idx, T); } // Creates pre-signing inputs and auxiliary parameters for ZK proofs. diff --git a/src/utilities/aff_g/mod.rs b/src/utilities/aff_g/mod.rs index 1ddeedf..352e2db 100644 --- a/src/utilities/aff_g/mod.rs +++ b/src/utilities/aff_g/mod.rs @@ -523,14 +523,13 @@ mod tests { utilities::BITS_PAILLIER, }; use curv::elliptic::curves::secp256_k1::Secp256k1; - use fs_dkr::ring_pedersen_proof::RingPedersenStatement; use paillier::{Encrypt, KeyGeneration, Paillier, RawPlaintext}; use sha2::Sha256; + use tss_core::utilities::generate_safe_h1_h2_N_tilde; #[test] fn test_affine_g_proof() { - let (ring_pedersen_statement, _witness) = - RingPedersenStatement::::generate(); + let (N_hat, S, T, _, _, _) = generate_safe_h1_h2_N_tilde(); let (ek_prover, _) = Paillier::keypair_with_modulus_size(BITS_PAILLIER).keys(); let (ek_verifier, _) = @@ -546,9 +545,9 @@ mod tests { Secp256k1, Sha256, >::generate( - ring_pedersen_statement.S, - ring_pedersen_statement.T, - ring_pedersen_statement.N, + S, + T, + N_hat, rho, rho_y, ek_prover, diff --git a/src/utilities/dec_q/mod.rs b/src/utilities/dec_q/mod.rs index e9ea563..8d29ccb 100644 --- a/src/utilities/dec_q/mod.rs +++ b/src/utilities/dec_q/mod.rs @@ -308,24 +308,19 @@ mod tests { utilities::BITS_PAILLIER, }; use curv::elliptic::curves::secp256_k1::Secp256k1; - use fs_dkr::ring_pedersen_proof::RingPedersenStatement; use paillier::{KeyGeneration, Paillier}; use sha2::Sha256; + use tss_core::utilities::generate_safe_h1_h2_N_tilde; #[test] fn test_paillier_decryption_modulo_q() { - let (ring_pedersen_statement, _witness) = - RingPedersenStatement::::generate(); + let (N_hat, S, T, _, _, _) = 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 (statement, witness) = PaillierDecryptionModQStatement::::generate( - ring_pedersen_statement.S, - ring_pedersen_statement.T, - ring_pedersen_statement.N, - rho, - ek_prover, + S, T, N_hat, rho, ek_prover, ); let proof = PaillierDecryptionModQProof::::prove( &witness, &statement, diff --git a/src/utilities/enc/mod.rs b/src/utilities/enc/mod.rs index c7100b4..aa52766 100644 --- a/src/utilities/enc/mod.rs +++ b/src/utilities/enc/mod.rs @@ -293,26 +293,23 @@ mod tests { utilities::BITS_PAILLIER, }; use curv::elliptic::curves::secp256_k1::Secp256k1; - use fs_dkr::ring_pedersen_proof::RingPedersenStatement; use paillier::{KeyGeneration, Paillier}; use sha2::Sha256; + use tss_core::utilities::generate_safe_h1_h2_N_tilde; #[test] fn test_paillier_encryption_in_range_proof() { - let (ring_pedersen_statement, _witness) = - RingPedersenStatement::::generate(); + let (N_hat, S, T, _, _, _) = 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 (statement, witness) = - PaillierEncryptionInRangeStatement::::generate( - rho, - ring_pedersen_statement.S, - ring_pedersen_statement.T, - ring_pedersen_statement.N, - paillier_key, - ); + let (statement, witness) = PaillierEncryptionInRangeStatement::< + Secp256k1, + Sha256, + >::generate( + rho, S, T, N_hat, paillier_key + ); let proof = PaillierEncryptionInRangeProof::::prove( &witness, &statement, ); diff --git a/src/utilities/log_star/mod.rs b/src/utilities/log_star/mod.rs index 882a24f..3dcfba2 100644 --- a/src/utilities/log_star/mod.rs +++ b/src/utilities/log_star/mod.rs @@ -335,14 +335,13 @@ mod tests { utilities::BITS_PAILLIER, }; use curv::elliptic::curves::secp256_k1::Secp256k1; - use fs_dkr::ring_pedersen_proof::RingPedersenStatement; use paillier::{KeyGeneration, Paillier}; use sha2::Sha256; + use tss_core::utilities::generate_safe_h1_h2_N_tilde; #[test] fn test_log_star_proof() { - let (ring_pedersen_statement, _witness) = - RingPedersenStatement::::generate(); + let (N_hat, S, T, _, _, _) = generate_safe_h1_h2_N_tilde(); let (paillier_key, _) = Paillier::keypair_with_modulus_size(BITS_PAILLIER).keys(); @@ -351,9 +350,9 @@ mod tests { KnowledgeOfExponentPaillierEncryptionStatement::::generate( rho, Some(Point::::generator().to_point()), - ring_pedersen_statement.S, - ring_pedersen_statement.T, - ring_pedersen_statement.N, + S, + T, + N_hat, paillier_key, ); let proof = KnowledgeOfExponentPaillierEncryptionProof::< diff --git a/src/utilities/mul_star/mod.rs b/src/utilities/mul_star/mod.rs index 3de810e..cea91b2 100644 --- a/src/utilities/mul_star/mod.rs +++ b/src/utilities/mul_star/mod.rs @@ -301,14 +301,13 @@ mod tests { utilities::BITS_PAILLIER, }; use curv::elliptic::curves::secp256_k1::Secp256k1; - use fs_dkr::ring_pedersen_proof::RingPedersenStatement; use paillier::{Encrypt, KeyGeneration, Paillier, RawPlaintext}; use sha2::Sha256; + use tss_core::utilities::generate_safe_h1_h2_N_tilde; #[test] fn test_mul_star_proof() { - let (ring_pedersen_statement, _witness) = - RingPedersenStatement::::generate(); + let (N_hat, S, T, _, _, _) = generate_safe_h1_h2_N_tilde(); let (paillier_key, _) = Paillier::keypair_with_modulus_size(BITS_PAILLIER).keys(); @@ -323,12 +322,7 @@ mod tests { Secp256k1, Sha256, >::generate( - rho, - C, - ring_pedersen_statement.S, - ring_pedersen_statement.T, - ring_pedersen_statement.N, - paillier_key, + rho, C, S, T, N_hat, paillier_key ); let proof = PaillierMultiplicationVersusGroupProof::::prove( diff --git a/tss-core/src/utilities/mod.rs b/tss-core/src/utilities/mod.rs index e5090ed..36c6c00 100644 --- a/tss-core/src/utilities/mod.rs +++ b/tss-core/src/utilities/mod.rs @@ -2,23 +2,44 @@ use curv::arithmetic::traits::*; use curv::BigInt; -use paillier::{KeyGeneration, Paillier}; +use paillier::{DecryptionKey, EncryptionKey, KeyGeneration, Paillier}; -pub fn generate_h1_h2_N_tilde( +use crate::security_level::DEFAULT_LEVEL; + +pub fn generate_safe_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(); + let (ek_tilde, dk_tilde) = Paillier::keypair_safe_primes_with_modulus_size( + DEFAULT_LEVEL.paillier_key_size, + ) + .keys(); + let (h1, h2, lambda, lambda_inv, phi) = + get_related_values(&ek_tilde, &dk_tilde); + (ek_tilde.n, h1, h2, lambda, lambda_inv, phi) +} + +// 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( +) -> (BigInt, BigInt, BigInt, BigInt, BigInt, BigInt) { + let (ek_tilde, dk_tilde) = + Paillier::keypair_with_modulus_size(DEFAULT_LEVEL.paillier_key_size) + .keys(); + let (h1, h2, lambda, lambda_inv, phi) = + get_related_values(&ek_tilde, &dk_tilde); + return (ek_tilde.n, h1, h2, lambda, lambda_inv, phi); +} + +fn get_related_values( + ek: &EncryptionKey, + dk: &DecryptionKey, +) -> (BigInt, BigInt, BigInt, BigInt, BigInt) { // 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); + 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, lambda_inv) = loop { let lambda_ = BigInt::sample_below(&phi); @@ -27,7 +48,6 @@ pub fn generate_h1_h2_N_tilde( None => continue, } }; - let h2 = BigInt::mod_pow(&h1, &lambda, &ek_tilde.n); - - (ek_tilde.n, h1, h2, lambda, lambda_inv, phi) + let h2 = BigInt::mod_pow(&h1, &lambda, &ek.n); + return (h1, h2, lambda, lambda_inv, phi); } diff --git a/tss-core/src/zkproof/prm/mod.rs b/tss-core/src/zkproof/prm/mod.rs index 3570fa0..2a1fb65 100644 --- a/tss-core/src/zkproof/prm/mod.rs +++ b/tss-core/src/zkproof/prm/mod.rs @@ -27,21 +27,21 @@ use zeroize::ZeroizeOnDrop; 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 +58,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 +73,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 +108,11 @@ fn compute_challenges( Ok(challenge_bits) } -impl CompositeDLogProof { +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 +145,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 +184,7 @@ impl CompositeDLogProof { ), } { - return Err(CompositeDLogError::Proof); + return Err(PiPrmError::Proof); } } @@ -202,58 +196,60 @@ impl CompositeDLogProof { #[allow(non_snake_case)] mod tests { use super::*; - use crate::utilities::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 { + // 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 (N_tilde, h1, h2, xhi, xhi_inv, phi) = + generate_normal_h1_h2_N_tilde(); + let statement_base_h1 = PiPrmStatement { modulus: N_tilde.clone(), base: h1.clone(), value: h2.clone(), }; - let witness_base_h1 = CompositeDLogWitness { + let witness_base_h1 = PiPrmWitness { exponent: xhi, totient: phi.clone(), }; 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 { + let statement_base_h2 = PiPrmStatement { modulus: N_tilde, base: h2, value: h1, }; - let witness_base_h2 = CompositeDLogWitness { + let witness_base_h2 = PiPrmWitness { exponent: xhi_inv, totient: phi, }; 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 (N_tilde, h1, h2, _, _, phi) = generate_normal_h1_h2_N_tilde(); // We use a fake/wrong/guessed exponent. let xhi = BigInt::sample_below(&phi); - let statement = CompositeDLogStatement { + let statement = PiPrmStatement { modulus: N_tilde.clone(), base: h1.clone(), value: h2.clone(), }; - let witness = CompositeDLogWitness { + let witness = PiPrmWitness { exponent: xhi, totient: phi.clone(), }; - 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)); } } From 70309b2609fcb8eec3dd970b6a5e07bcdd9af38c Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Tue, 7 Nov 2023 00:29:04 +0100 Subject: [PATCH 07/26] refactor: define RingPedersenParams structure --- fs-dkr/src/add_party_message.rs | 24 ++----- multi-party-ecdsa/src/gg_2020/party_i.rs | 81 +++++++++++------------- src/party_i.rs | 77 +++++++++++----------- src/presign/state_machine.rs | 8 +-- src/utilities/aff_g/mod.rs | 17 ++--- src/utilities/dec_q/mod.rs | 21 +++--- src/utilities/enc/mod.rs | 15 ++--- src/utilities/log_star/mod.rs | 17 ++--- src/utilities/mul_star/mod.rs | 15 ++--- tss-core/src/utilities/mod.rs | 55 ++++++++++------ tss-core/src/zkproof/prm/mod.rs | 74 ++++++++++++++-------- 11 files changed, 203 insertions(+), 201 deletions(-) diff --git a/fs-dkr/src/add_party_message.rs b/fs-dkr/src/add_party_message.rs index be488ed..1212d47 100644 --- a/fs-dkr/src/add_party_message.rs +++ b/fs-dkr/src/add_party_message.rs @@ -60,27 +60,13 @@ pub struct JoinMessage { /// generated by [generate_h1_h2_n_tilde] fn generate_dlog_statement_proofs( ) -> FsDkrResult<(PiPrmStatement, PiPrmProof, PiPrmProof)> { - let (n_tilde, h1, h2, xhi, xhi_inv, phi) = generate_safe_h1_h2_N_tilde(); + let (rpparam, rpwitness) = generate_safe_h1_h2_N_tilde(); - let dlog_statement_base_h1 = PiPrmStatement { - modulus: n_tilde.clone(), - base: h1.clone(), - value: h2.clone(), - }; - let dlog_witness_base_h1 = PiPrmWitness { - 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 = PiPrmStatement { - modulus: n_tilde, - base: h2, - value: h1, - }; - let dlog_witness_base_h2 = PiPrmWitness { - 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 = PiPrmProof::prove(&dlog_statement_base_h1, &dlog_witness_base_h1) diff --git a/multi-party-ecdsa/src/gg_2020/party_i.rs b/multi-party-ecdsa/src/gg_2020/party_i.rs index 8211982..c8bf013 100644 --- a/multi-party-ecdsa/src/gg_2020/party_i.rs +++ b/multi-party-ecdsa/src/gg_2020/party_i.rs @@ -56,7 +56,7 @@ use curv::cryptographic_primitives::proofs::sigma_valid_pedersen::PedersenProof; use std::convert::TryInto; use tss_core::{ - utilities::generate_safe_h1_h2_N_tilde, + utilities::{generate_normal_h1_h2_N_tilde, generate_safe_h1_h2_N_tilde}, zkproof::prm::{PiPrmProof, PiPrmStatement, PiPrmWitness}, }; @@ -155,21 +155,20 @@ 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_safe_h1_h2_N_tilde(); + let (rpparam, rpwitness) = generate_safe_h1_h2_N_tilde(); Self { u_i: u, y_i: y, - dk, - ek, + dk: dk, + ek: 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, } } @@ -179,8 +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_safe_h1_h2_N_tilde(); + let (rpparam, rpwitness) = generate_safe_h1_h2_N_tilde(); Self { u_i: u, @@ -188,19 +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_safe_h1_h2_N_tilde(); + let (rpparam, rpwitness) = generate_normal_h1_h2_N_tilde(); Self { u_i: u, @@ -208,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, } } @@ -550,8 +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_safe_h1_h2_N_tilde(); + let (rpparam, rpwitness) = generate_normal_h1_h2_N_tilde(); Keys { u_i: u, @@ -559,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, } } @@ -578,8 +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_safe_h1_h2_N_tilde(); + let (rpparam, rpwitness) = generate_safe_h1_h2_N_tilde(); Keys { u_i: u, @@ -587,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, } } diff --git a/src/party_i.rs b/src/party_i.rs index 3d34a6f..33358e5 100644 --- a/src/party_i.rs +++ b/src/party_i.rs @@ -58,7 +58,7 @@ pub use crate::mpc_ecdsa::{ }, }; use tss_core::{ - utilities::generate_safe_h1_h2_N_tilde, + utilities::{generate_normal_h1_h2_N_tilde, generate_safe_h1_h2_N_tilde}, zkproof::prm::{PiPrmProof, PiPrmStatement, PiPrmWitness}, }; @@ -136,8 +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_safe_h1_h2_N_tilde(); + let (rpparam, rpwitness) = generate_safe_h1_h2_N_tilde(); Self { u_i: u, @@ -145,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, } } @@ -160,8 +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_safe_h1_h2_N_tilde(); + let (rpparam, rpwitness) = generate_safe_h1_h2_N_tilde(); Self { u_i: u, @@ -169,19 +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_safe_h1_h2_N_tilde(); + let (rpparam, rpwitness) = generate_normal_h1_h2_N_tilde(); Self { u_i: u, @@ -189,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, } } @@ -486,8 +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_safe_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,8 +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_safe_h1_h2_N_tilde(); + let (rpparam, rpwitness) = generate_safe_h1_h2_N_tilde(); Keys { u_i: u, @@ -523,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/state_machine.rs b/src/presign/state_machine.rs index 1333fb4..fa1ba11 100644 --- a/src/presign/state_machine.rs +++ b/src/presign/state_machine.rs @@ -736,10 +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 (N_hat, S, T, _, _, _) = generate_safe_h1_h2_N_tilde(); - aux_ring_pedersen_n_hat_values.insert(idx, N_hat); - aux_ring_pedersen_s_values.insert(idx, S); - aux_ring_pedersen_t_values.insert(idx, 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/utilities/aff_g/mod.rs b/src/utilities/aff_g/mod.rs index 352e2db..0131086 100644 --- a/src/utilities/aff_g/mod.rs +++ b/src/utilities/aff_g/mod.rs @@ -55,6 +55,7 @@ use rand::Rng; use rand_chacha::{rand_core::SeedableRng, ChaChaRng}; use serde::{Deserialize, Serialize}; use std::marker::PhantomData; +use tss_core::utilities::RingPedersenParams; #[derive(Clone, Debug, Serialize, Deserialize)] pub struct PaillierAffineOpWithGroupComInRangeStatement< @@ -107,9 +108,7 @@ impl { #[allow(clippy::too_many_arguments)] pub fn generate( - S: BigInt, - T: BigInt, - N_hat: BigInt, + rpparam: RingPedersenParams, rho: BigInt, rho_y: BigInt, prover: EncryptionKey, @@ -156,9 +155,9 @@ impl ( Self { - S, - T, - N_hat, + S: rpparam.s, + T: rpparam.t, + N_hat: rpparam.N, N0, N1, NN0, @@ -529,7 +528,7 @@ mod tests { #[test] fn test_affine_g_proof() { - let (N_hat, S, T, _, _, _) = generate_safe_h1_h2_N_tilde(); + let (rpparam, _) = generate_safe_h1_h2_N_tilde(); let (ek_prover, _) = Paillier::keypair_with_modulus_size(BITS_PAILLIER).keys(); let (ek_verifier, _) = @@ -545,9 +544,7 @@ mod tests { Secp256k1, Sha256, >::generate( - S, - T, - N_hat, + rpparam, rho, rho_y, ek_prover, diff --git a/src/utilities/dec_q/mod.rs b/src/utilities/dec_q/mod.rs index 8d29ccb..03af84d 100644 --- a/src/utilities/dec_q/mod.rs +++ b/src/utilities/dec_q/mod.rs @@ -34,6 +34,7 @@ use rand::Rng; use rand_chacha::{rand_core::SeedableRng, ChaChaRng}; use serde::{Deserialize, Serialize}; use std::marker::PhantomData; +use tss_core::utilities::RingPedersenParams; #[derive(Clone, Debug, Serialize, Deserialize)] pub struct PaillierDecryptionModQStatement { @@ -67,9 +68,7 @@ impl PaillierDecryptionModQWitness { impl PaillierDecryptionModQStatement { #[allow(clippy::too_many_arguments)] pub fn generate( - S: BigInt, - T: BigInt, - N_hat: BigInt, + rpparams: RingPedersenParams, rho: BigInt, prover: EncryptionKey, ) -> (Self, PaillierDecryptionModQWitness) { @@ -89,9 +88,9 @@ impl PaillierDecryptionModQStatement { let x = BigInt::mod_floor(&y, Scalar::::group_order()); ( Self { - S, - T, - N_hat, + S: rpparams.s, + T: rpparams.t, + N_hat: rpparams.N, N0: prover.n, NN0: prover.nn, C, @@ -314,14 +313,14 @@ mod tests { #[test] fn test_paillier_decryption_modulo_q() { - let (N_hat, S, T, _, _, _) = generate_safe_h1_h2_N_tilde(); + 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 (statement, witness) = - PaillierDecryptionModQStatement::::generate( - S, T, N_hat, rho, ek_prover, - ); + let (statement, witness) = PaillierDecryptionModQStatement::< + Secp256k1, + Sha256, + >::generate(rpparam, rho, ek_prover); let proof = PaillierDecryptionModQProof::::prove( &witness, &statement, ); diff --git a/src/utilities/enc/mod.rs b/src/utilities/enc/mod.rs index aa52766..2defd26 100644 --- a/src/utilities/enc/mod.rs +++ b/src/utilities/enc/mod.rs @@ -34,6 +34,7 @@ use paillier::{ }; use serde::{Deserialize, Serialize}; use std::marker::PhantomData; +use tss_core::utilities::RingPedersenParams; use zk_paillier::zkproofs::IncorrectProof; #[derive(Clone, Debug, Serialize, Deserialize)] @@ -68,9 +69,7 @@ impl PaillierEncryptionInRangeStatement { #[allow(clippy::too_many_arguments)] pub fn generate( rho: BigInt, - s: BigInt, - t: BigInt, - N_hat: BigInt, + rpparam: RingPedersenParams, paillier_key: EncryptionKey, ) -> (Self, PaillierEncryptionInRangeWitness) { // Set up exponents @@ -91,9 +90,9 @@ impl PaillierEncryptionInRangeStatement { N0, NN0, K, - s, - t, - N_hat, + s: rpparam.s, + t: rpparam.t, + N_hat: rpparam.N, phantom: PhantomData, }, PaillierEncryptionInRangeWitness { @@ -299,7 +298,7 @@ mod tests { #[test] fn test_paillier_encryption_in_range_proof() { - let (N_hat, S, T, _, _, _) = generate_safe_h1_h2_N_tilde(); + let (rpparam, _) = generate_safe_h1_h2_N_tilde(); let (paillier_key, _) = Paillier::keypair_with_modulus_size(BITS_PAILLIER).keys(); @@ -308,7 +307,7 @@ mod tests { Secp256k1, Sha256, >::generate( - rho, S, T, N_hat, paillier_key + rho, rpparam, paillier_key ); let proof = PaillierEncryptionInRangeProof::::prove( &witness, &statement, diff --git a/src/utilities/log_star/mod.rs b/src/utilities/log_star/mod.rs index 3dcfba2..48dab99 100644 --- a/src/utilities/log_star/mod.rs +++ b/src/utilities/log_star/mod.rs @@ -35,6 +35,7 @@ use paillier::{ }; use serde::{Deserialize, Serialize}; use std::marker::PhantomData; +use tss_core::utilities::RingPedersenParams; use zk_paillier::zkproofs::IncorrectProof; #[derive(Clone, Debug, Serialize, Deserialize)] @@ -89,9 +90,7 @@ impl pub fn generate( rho: BigInt, g: Option>, - s: BigInt, - t: BigInt, - N_hat: BigInt, + rpparam: RingPedersenParams, paillier_key: EncryptionKey, ) -> (Self, KnowledgeOfExponentPaillierEncryptionWitness) { // Set up exponents @@ -118,9 +117,9 @@ impl C, X, g, - N_hat, - s, - t, + N_hat: rpparam.N, + s: rpparam.s, + t: rpparam.t, phantom: PhantomData, }, KnowledgeOfExponentPaillierEncryptionWitness { @@ -341,7 +340,7 @@ mod tests { #[test] fn test_log_star_proof() { - let (N_hat, S, T, _, _, _) = generate_safe_h1_h2_N_tilde(); + let (rpparam, _) = generate_safe_h1_h2_N_tilde(); let (paillier_key, _) = Paillier::keypair_with_modulus_size(BITS_PAILLIER).keys(); @@ -350,9 +349,7 @@ mod tests { KnowledgeOfExponentPaillierEncryptionStatement::::generate( rho, Some(Point::::generator().to_point()), - S, - T, - N_hat, + rpparam, paillier_key, ); let proof = KnowledgeOfExponentPaillierEncryptionProof::< diff --git a/src/utilities/mul_star/mod.rs b/src/utilities/mul_star/mod.rs index cea91b2..9a1eeee 100644 --- a/src/utilities/mul_star/mod.rs +++ b/src/utilities/mul_star/mod.rs @@ -32,6 +32,7 @@ use curv::{ use paillier::EncryptionKey; use serde::{Deserialize, Serialize}; use std::marker::PhantomData; +use tss_core::utilities::RingPedersenParams; use zk_paillier::zkproofs::IncorrectProof; #[derive(Clone, Debug, Serialize, Deserialize)] @@ -76,9 +77,7 @@ impl pub fn generate( rho: BigInt, _C: BigInt, - s: BigInt, - t: BigInt, - N_hat: BigInt, + rpparam: RingPedersenParams, paillier_key: EncryptionKey, ) -> (Self, PaillierMultiplicationVersusGroupWitness) { // Set up exponents @@ -102,9 +101,9 @@ impl C, D, X, - N_hat, - s, - t, + N_hat: rpparam.N, + s: rpparam.s, + t: rpparam.t, phantom: PhantomData, }, PaillierMultiplicationVersusGroupWitness { @@ -307,7 +306,7 @@ mod tests { #[test] fn test_mul_star_proof() { - let (N_hat, S, T, _, _, _) = generate_safe_h1_h2_N_tilde(); + let (rpparam, _) = generate_safe_h1_h2_N_tilde(); let (paillier_key, _) = Paillier::keypair_with_modulus_size(BITS_PAILLIER).keys(); @@ -322,7 +321,7 @@ mod tests { Secp256k1, Sha256, >::generate( - rho, C, S, T, N_hat, paillier_key + rho, C, rpparam, paillier_key ); let proof = PaillierMultiplicationVersusGroupProof::::prove( diff --git a/tss-core/src/utilities/mod.rs b/tss-core/src/utilities/mod.rs index 36c6c00..2b26baf 100644 --- a/tss-core/src/utilities/mod.rs +++ b/tss-core/src/utilities/mod.rs @@ -3,37 +3,43 @@ 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, +} -pub fn generate_safe_h1_h2_N_tilde( -) -> (BigInt, BigInt, BigInt, BigInt, BigInt, BigInt) { - let (ek_tilde, dk_tilde) = Paillier::keypair_safe_primes_with_modulus_size( - DEFAULT_LEVEL.paillier_key_size, - ) - .keys(); - let (h1, h2, lambda, lambda_inv, phi) = - get_related_values(&ek_tilde, &dk_tilde); +// 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, +} - (ek_tilde.n, h1, h2, lambda, lambda_inv, phi) +pub fn generate_safe_h1_h2_N_tilde() -> (RingPedersenParams, RingPedersenWitness) +{ + let (ek_tilde, dk_tilde) = Paillier::keypair_safe_primes().keys(); + return 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( -) -> (BigInt, BigInt, BigInt, BigInt, BigInt, BigInt) { - let (ek_tilde, dk_tilde) = - Paillier::keypair_with_modulus_size(DEFAULT_LEVEL.paillier_key_size) - .keys(); - let (h1, h2, lambda, lambda_inv, phi) = - get_related_values(&ek_tilde, &dk_tilde); - return (ek_tilde.n, h1, h2, lambda, lambda_inv, phi); +) -> (RingPedersenParams, RingPedersenWitness) { + let (ek_tilde, dk_tilde) = Paillier::keypair().keys(); + return get_related_values(&ek_tilde, &dk_tilde); } fn get_related_values( ek: &EncryptionKey, dk: &DecryptionKey, -) -> (BigInt, BigInt, BigInt, BigInt, BigInt) { +) -> (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(); @@ -49,5 +55,16 @@ fn get_related_values( } }; let h2 = BigInt::mod_pow(&h1, &lambda, &ek.n); - return (h1, h2, lambda, lambda_inv, phi); + return ( + RingPedersenParams { + N: ek.n.clone(), + s: h1, + t: h2, + }, + RingPedersenWitness { + lambda: lambda, + lambdaInv: lambda_inv, + phi: phi, + }, + ); } diff --git a/tss-core/src/zkproof/prm/mod.rs b/tss-core/src/zkproof/prm/mod.rs index 2a1fb65..1abc214 100644 --- a/tss-core/src/zkproof/prm/mod.rs +++ b/tss-core/src/zkproof/prm/mod.rs @@ -23,6 +23,8 @@ 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; @@ -108,6 +110,40 @@ fn compute_challenges( Ok(challenge_bits) } +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: &PiPrmStatement, @@ -203,31 +239,16 @@ mod tests { // 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 (N_tilde, h1, h2, xhi, xhi_inv, phi) = - generate_normal_h1_h2_N_tilde(); - let statement_base_h1 = PiPrmStatement { - modulus: N_tilde.clone(), - base: h1.clone(), - value: h2.clone(), - }; - let witness_base_h1 = PiPrmWitness { - exponent: xhi, - totient: phi.clone(), - }; + 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 = 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 = PiPrmStatement { - modulus: N_tilde, - base: h2, - value: h1, - }; - let witness_base_h2 = PiPrmWitness { - 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 = PiPrmProof::prove(&statement_base_h2, &witness_base_h2).unwrap(); let result_base_h2 = proof_base_h2.verify(&statement_base_h2); @@ -236,17 +257,14 @@ mod tests { #[test] fn invalid_composite_dlog_proof_fails() { - let (N_tilde, h1, h2, _, _, phi) = generate_normal_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 = PiPrmStatement { - modulus: N_tilde.clone(), - base: h1.clone(), - value: h2.clone(), - }; + 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 = PiPrmProof::prove(&statement, &witness).unwrap(); let result = proof.verify(&statement); From b70b7894005ae66b302cc24ebadfcb45edc124c4 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Tue, 7 Nov 2023 01:54:00 +0100 Subject: [PATCH 08/26] refactor: use pi-prm proof in fs-dkr --- fs-dkr/src/add_party_message.rs | 56 ++++----- fs-dkr/src/lib.rs | 1 - fs-dkr/src/refresh_message.rs | 48 ++++---- fs-dkr/src/ring_pedersen_proof.rs | 186 ------------------------------ 4 files changed, 50 insertions(+), 241 deletions(-) delete mode 100644 fs-dkr/src/ring_pedersen_proof.rs diff --git a/fs-dkr/src/add_party_message.rs b/fs-dkr/src/add_party_message.rs index 1212d47..8388bd4 100644 --- a/fs-dkr/src/add_party_message.rs +++ b/fs-dkr/src/add_party_message.rs @@ -35,10 +35,9 @@ use multi_party_ecdsa::protocols::multi_party_ecdsa::gg_2020::{ }; 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}; @@ -52,8 +51,9 @@ pub struct JoinMessage { 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_statement: RingPedersenStatement, - pub(crate) ring_pedersen_proof: RingPedersenProof, + 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 @@ -98,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 @@ -117,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)) @@ -149,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 diff --git a/fs-dkr/src/lib.rs b/fs-dkr/src/lib.rs index f98b985..1215a16 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/refresh_message.rs b/fs-dkr/src/refresh_message.rs index 16e8831..1cbdc55 100644 --- a/fs-dkr/src/refresh_message.rs +++ b/fs-dkr/src/refresh_message.rs @@ -23,9 +23,10 @@ use serde::{Deserialize, Serialize}; use std::{borrow::Borrow, collections::HashMap, fmt::Debug}; use zeroize::Zeroize; use zk_paillier::zkproofs::{NiCorrectKeyProof, SALT_STRING}; -use tss_core::zkproof::prm::PiPrmStatement; - -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)] @@ -43,8 +44,8 @@ pub struct RefreshMessage { 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, } @@ -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, @@ -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 = diff --git a/fs-dkr/src/ring_pedersen_proof.rs b/fs-dkr/src/ring_pedersen_proof.rs deleted file mode 100644 index ccb81fd..0000000 --- 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()); - } -} From dfe9d9fc9d67149c083aa8eb8f202c0b982a14c6 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Thu, 30 Nov 2023 10:22:11 +0100 Subject: [PATCH 09/26] refactor: move Pi-PRM and utilities to tss-core --- Cargo.lock | 1 + src/presign/mod.rs | 4 +- src/presign/rounds.rs | 38 ++--- src/sign/rounds.rs | 2 +- src/utilities/aff_g/mod.rs | 15 +- src/utilities/dec_q/mod.rs | 10 +- src/utilities/enc/test.rs | 0 src/utilities/log_star/mod.rs | 6 +- src/utilities/mod.rs | 27 ---- src/utilities/mul/mod.rs | 10 +- src/utilities/mul_star/mod.rs | 6 +- tss-core/Cargo.toml | 1 + tss-core/src/lib.rs | 1 + tss-core/src/security_level/mod.rs | 72 ++++++++++ tss-core/src/utilities/mod.rs | 32 ++++- .../src/zkproof}/enc/mod.rs | 133 ++++++++++-------- tss-core/src/zkproof/mod.rs | 1 + 17 files changed, 230 insertions(+), 129 deletions(-) delete mode 100644 src/utilities/enc/test.rs create mode 100644 tss-core/src/security_level/mod.rs rename {src/utilities => tss-core/src/zkproof}/enc/mod.rs (74%) diff --git a/Cargo.lock b/Cargo.lock index ac743f3..ec9a46a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4482,6 +4482,7 @@ dependencies = [ "serde", "serde_repr", "serde_with", + "sha2 0.9.9", "zeroize", ] diff --git a/src/presign/mod.rs b/src/presign/mod.rs index beb3237..1f4457f 100644 --- a/src/presign/mod.rs +++ b/src/presign/mod.rs @@ -31,13 +31,15 @@ use crate::utilities::{ PaillierAffineOpWithGroupComInRangeStatement, }, dec_q::{PaillierDecryptionModQProof, PaillierDecryptionModQStatement}, - enc::{PaillierEncryptionInRangeProof, PaillierEncryptionInRangeStatement}, log_star::{ KnowledgeOfExponentPaillierEncryptionProof, KnowledgeOfExponentPaillierEncryptionStatement, }, mul::{PaillierMulProof, PaillierMulStatement}, }; +use tss_core::zkproof::enc::{ + PaillierEncryptionInRangeProof, PaillierEncryptionInRangeStatement, +}; use serde::{Deserialize, Serialize}; use zeroize::Zeroize; diff --git a/src/presign/rounds.rs b/src/presign/rounds.rs index ecf7515..df87a09 100644 --- a/src/presign/rounds.rs +++ b/src/presign/rounds.rs @@ -16,6 +16,11 @@ use std::{collections::HashMap, marker::PhantomData}; +use super::{ + IdentifiableAbortBroadcastMessage, PreSigningP2PMessage1, + PreSigningP2PMessage2, PreSigningP2PMessage3, PreSigningSecrets, + PresigningOutput, PresigningTranscript, DEFAULT_ENCRYPTION_KEY, SSID, +}; use crate::{ utilities::{ aff_g::{ @@ -27,32 +32,27 @@ use crate::{ 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 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::zkproof::enc::{ + PaillierEncryptionInRangeProof, PaillierEncryptionInRangeStatement, + PaillierEncryptionInRangeWitness, +}; use paillier::{ Add, Decrypt, EncryptWithChosenRandomness, EncryptionKey, Mul, Paillier, @@ -117,13 +117,15 @@ impl Round0 { 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 = diff --git a/src/sign/rounds.rs b/src/sign/rounds.rs index 69b6505..9fdf1d3 100644 --- a/src/sign/rounds.rs +++ b/src/sign/rounds.rs @@ -45,11 +45,11 @@ use crate::{ PaillierMultiplicationVersusGroupStatement, PaillierMultiplicationVersusGroupWitness, }, - sample_relatively_prime_integer, }, ErrorType, NoOfflineStageErrorData, ProofVerificationErrorData, }; use thiserror::Error; +use tss_core::utilities::sample_relatively_prime_integer; use zeroize::Zeroize; diff --git a/src/utilities/aff_g/mod.rs b/src/utilities/aff_g/mod.rs index 0131086..0173356 100644 --- a/src/utilities/aff_g/mod.rs +++ b/src/utilities/aff_g/mod.rs @@ -33,14 +33,7 @@ //! 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::{utilities::fixed_array, Error}; use curv::{ arithmetic::{traits::*, Modulo}, cryptographic_primitives::hashing::{Digest, DigestExt}, @@ -55,7 +48,13 @@ use rand::Rng; use rand_chacha::{rand_core::SeedableRng, ChaChaRng}; use serde::{Deserialize, Serialize}; use std::marker::PhantomData; +use tss_core::security_level::{ + L, L_PLUS_EPSILON, L_PRIME, L_PRIME_PLUS_EPSILON, +}; use tss_core::utilities::RingPedersenParams; +use tss_core::utilities::{ + mod_pow_with_negative, sample_relatively_prime_integer, +}; #[derive(Clone, Debug, Serialize, Deserialize)] pub struct PaillierAffineOpWithGroupComInRangeStatement< diff --git a/src/utilities/dec_q/mod.rs b/src/utilities/dec_q/mod.rs index 03af84d..5adbf32 100644 --- a/src/utilities/dec_q/mod.rs +++ b/src/utilities/dec_q/mod.rs @@ -15,11 +15,7 @@ @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::{utilities::fixed_array, Error}; use curv::{ arithmetic::{traits::*, Modulo}, cryptographic_primitives::hashing::{Digest, DigestExt}, @@ -34,7 +30,11 @@ use rand::Rng; use rand_chacha::{rand_core::SeedableRng, ChaChaRng}; use serde::{Deserialize, Serialize}; use std::marker::PhantomData; +use tss_core::security_level::{L, L_PLUS_EPSILON}; use tss_core::utilities::RingPedersenParams; +use tss_core::utilities::{ + mod_pow_with_negative, sample_relatively_prime_integer, +}; #[derive(Clone, Debug, Serialize, Deserialize)] pub struct PaillierDecryptionModQStatement { diff --git a/src/utilities/enc/test.rs b/src/utilities/enc/test.rs deleted file mode 100644 index e69de29..0000000 diff --git a/src/utilities/log_star/mod.rs b/src/utilities/log_star/mod.rs index 48dab99..e072554 100644 --- a/src/utilities/log_star/mod.rs +++ b/src/utilities/log_star/mod.rs @@ -21,8 +21,6 @@ //! 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 curv::{ arithmetic::{traits::*, Modulo}, cryptographic_primitives::hashing::{Digest, DigestExt}, @@ -35,7 +33,11 @@ use paillier::{ }; use serde::{Deserialize, Serialize}; use std::marker::PhantomData; +use tss_core::security_level::L; use tss_core::utilities::RingPedersenParams; +use tss_core::utilities::{ + mod_pow_with_negative, sample_relatively_prime_integer, +}; use zk_paillier::zkproofs::IncorrectProof; #[derive(Clone, Debug, Serialize, Deserialize)] diff --git a/src/utilities/mod.rs b/src/utilities/mod.rs index d320c00..e349209 100644 --- a/src/utilities/mod.rs +++ b/src/utilities/mod.rs @@ -1,11 +1,5 @@ -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; @@ -37,27 +31,6 @@ pub fn fixed_array( 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; diff --git a/src/utilities/mul/mod.rs b/src/utilities/mul/mod.rs index 4e4d082..f903851 100644 --- a/src/utilities/mul/mod.rs +++ b/src/utilities/mul/mod.rs @@ -15,11 +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; +use crate::Error; use curv::{ arithmetic::{traits::*, Modulo}, cryptographic_primitives::hashing::{Digest, DigestExt}, @@ -34,6 +31,9 @@ use rand::Rng; use rand_chacha::{rand_core::SeedableRng, ChaChaRng}; use serde::{Deserialize, Serialize}; use std::marker::PhantomData; +use tss_core::utilities::{ + mod_pow_with_negative, sample_relatively_prime_integer, +}; #[derive(Clone, Debug, Serialize, Deserialize)] pub struct PaillierMulStatement { diff --git a/src/utilities/mul_star/mod.rs b/src/utilities/mul_star/mod.rs index 9a1eeee..e3d1720 100644 --- a/src/utilities/mul_star/mod.rs +++ b/src/utilities/mul_star/mod.rs @@ -21,8 +21,6 @@ //! 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 curv::{ arithmetic::{traits::*, Modulo}, cryptographic_primitives::hashing::{Digest, DigestExt}, @@ -32,7 +30,11 @@ use curv::{ use paillier::EncryptionKey; use serde::{Deserialize, Serialize}; use std::marker::PhantomData; +use tss_core::security_level::L; use tss_core::utilities::RingPedersenParams; +use tss_core::utilities::{ + mod_pow_with_negative, sample_relatively_prime_integer, +}; use zk_paillier::zkproofs::IncorrectProof; #[derive(Clone, Debug, Serialize, Deserialize)] diff --git a/tss-core/Cargo.toml b/tss-core/Cargo.toml index 9fe6f53..8dd6ae6 100644 --- a/tss-core/Cargo.toml +++ b/tss-core/Cargo.toml @@ -10,6 +10,7 @@ curv-kzen.workspace = true serde.workspace = true zeroize.workspace = true paillier.workspace = true +sha2.workspace = true bincode = "1.3.3" merlin = "3.0.0" diff --git a/tss-core/src/lib.rs b/tss-core/src/lib.rs index 83f5b16..be248a6 100644 --- a/tss-core/src/lib.rs +++ b/tss-core/src/lib.rs @@ -1,2 +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 0000000..cc9a71e --- /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 index 2b26baf..43f9d5b 100644 --- a/tss-core/src/utilities/mod.rs +++ b/tss-core/src/utilities/mod.rs @@ -5,6 +5,8 @@ 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 @@ -24,7 +26,10 @@ pub struct RingPedersenWitness { pub fn generate_safe_h1_h2_N_tilde() -> (RingPedersenParams, RingPedersenWitness) { - let (ek_tilde, dk_tilde) = Paillier::keypair_safe_primes().keys(); + let (ek_tilde, dk_tilde) = Paillier::keypair_safe_primes_with_modulus_size( + DEFAULT_LEVEL.paillier_key_size, + ) + .keys(); return get_related_values(&ek_tilde, &dk_tilde); } @@ -32,7 +37,9 @@ pub fn generate_safe_h1_h2_N_tilde() -> (RingPedersenParams, RingPedersenWitness // 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().keys(); + let (ek_tilde, dk_tilde) = + Paillier::keypair_with_modulus_size(DEFAULT_LEVEL.paillier_key_size) + .keys(); return get_related_values(&ek_tilde, &dk_tilde); } @@ -68,3 +75,24 @@ fn get_related_values( }, ); } + +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) + } +} diff --git a/src/utilities/enc/mod.rs b/tss-core/src/zkproof/enc/mod.rs similarity index 74% rename from src/utilities/enc/mod.rs rename to tss-core/src/zkproof/enc/mod.rs index 2defd26..87daf33 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,17 +36,13 @@ use paillier::{ }; use serde::{Deserialize, Serialize}; use std::marker::PhantomData; -use tss_core::utilities::RingPedersenParams; -use zk_paillier::zkproofs::IncorrectProof; #[derive(Clone, Debug, Serialize, Deserialize)] pub struct PaillierEncryptionInRangeStatement { 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)>, } @@ -55,6 +53,14 @@ pub struct PaillierEncryptionInRangeWitness { phantom: PhantomData<(E, H)>, } +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum PiEncError { + Serialization, + Validation, + Challenge, + Proof, +} + impl PaillierEncryptionInRangeWitness { pub fn new(k: BigInt, rho: BigInt) -> Self { PaillierEncryptionInRangeWitness { @@ -68,16 +74,17 @@ impl PaillierEncryptionInRangeWitness { impl PaillierEncryptionInRangeStatement { #[allow(clippy::too_many_arguments)] pub fn generate( - rho: BigInt, rpparam: RingPedersenParams, paillier_key: EncryptionKey, ) -> (Self, PaillierEncryptionInRangeWitness) { + // sample the prover secret inputs + let rho: BigInt = sample_relatively_prime_integer(&paillier_key.n); + let k = BigInt::sample_below(Scalar::::group_order()); // Set up exponents let _l_exp = BigInt::pow(&BigInt::from(2), L as u32); // Set up moduli let N0 = paillier_key.clone().n; let NN0 = paillier_key.clone().nn; - let k = BigInt::sample_below(Scalar::::group_order()); let K: BigInt = Paillier::encrypt_with_chosen_randomness( &paillier_key, RawPlaintext::from(&k), @@ -90,9 +97,7 @@ impl PaillierEncryptionInRangeStatement { N0, NN0, K, - s: rpparam.s, - t: rpparam.t, - N_hat: rpparam.N, + RPParam: rpparam, phantom: PhantomData, }, PaillierEncryptionInRangeWitness { @@ -127,29 +132,23 @@ impl PaillierEncryptionInRangeProof { statement: &PaillierEncryptionInRangeStatement, ) -> 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); @@ -159,9 +158,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 @@ -177,9 +184,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 { @@ -220,7 +235,7 @@ impl PaillierEncryptionInRangeProof { pub fn verify( proof: &PaillierEncryptionInRangeProof, statement: &PaillierEncryptionInRangeStatement, - ) -> Result<(), IncorrectProof> { + ) -> Result<(), PiEncError> { let e = H::new() .chain_bigint(&proof.commitment.S) .chain_bigint(&proof.commitment.A) @@ -248,36 +263,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, - )); + >= 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), - crate::utilities::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(()) @@ -287,28 +309,23 @@ 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 paillier::{KeyGeneration, Paillier}; use sha2::Sha256; - use tss_core::utilities::generate_safe_h1_h2_N_tilde; #[test] fn test_paillier_encryption_in_range_proof() { - let (rpparam, _) = generate_safe_h1_h2_N_tilde(); - 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); let (statement, witness) = PaillierEncryptionInRangeStatement::< Secp256k1, Sha256, - >::generate( - rho, rpparam, paillier_key - ); + >::generate(auxRPParam, paillier_key); let proof = PaillierEncryptionInRangeProof::::prove( &witness, &statement, ); diff --git a/tss-core/src/zkproof/mod.rs b/tss-core/src/zkproof/mod.rs index 612b3ad..ec8539b 100644 --- a/tss-core/src/zkproof/mod.rs +++ b/tss-core/src/zkproof/mod.rs @@ -1 +1,2 @@ +pub mod enc; pub mod prm; From c9e1e64b67495804b842178ad869105d9a6b38d9 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Thu, 30 Nov 2023 10:34:14 +0100 Subject: [PATCH 10/26] refactor: rename to PiEnc to correspond with paper --- src/presign/mod.rs | 8 +++--- src/presign/rounds.rs | 21 ++++++--------- tss-core/src/zkproof/enc/mod.rs | 48 +++++++++++++++------------------ 3 files changed, 33 insertions(+), 44 deletions(-) diff --git a/src/presign/mod.rs b/src/presign/mod.rs index 1f4457f..7ecd43f 100644 --- a/src/presign/mod.rs +++ b/src/presign/mod.rs @@ -37,9 +37,7 @@ use crate::utilities::{ }, mul::{PaillierMulProof, PaillierMulStatement}, }; -use tss_core::zkproof::enc::{ - PaillierEncryptionInRangeProof, PaillierEncryptionInRangeStatement, -}; +use tss_core::zkproof::enc::{PiEncProof, PiEncStatement}; use serde::{Deserialize, Serialize}; use zeroize::Zeroize; @@ -125,8 +123,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)] diff --git a/src/presign/rounds.rs b/src/presign/rounds.rs index df87a09..ccbf2c4 100644 --- a/src/presign/rounds.rs +++ b/src/presign/rounds.rs @@ -49,10 +49,7 @@ use curv::{ }; use tss_core::security_level::L_PRIME; use tss_core::utilities::sample_relatively_prime_integer; -use tss_core::zkproof::enc::{ - PaillierEncryptionInRangeProof, PaillierEncryptionInRangeStatement, - PaillierEncryptionInRangeWitness, -}; +use tss_core::zkproof::enc::{PiEncProof, PiEncStatement, PiEncWitness}; use paillier::{ Add, Decrypt, EncryptWithChosenRandomness, EncryptionKey, Mul, Paillier, @@ -108,12 +105,11 @@ 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(), @@ -128,11 +124,10 @@ impl Round0 { }, 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(), @@ -226,7 +221,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, ) diff --git a/tss-core/src/zkproof/enc/mod.rs b/tss-core/src/zkproof/enc/mod.rs index 87daf33..014177c 100644 --- a/tss-core/src/zkproof/enc/mod.rs +++ b/tss-core/src/zkproof/enc/mod.rs @@ -38,7 +38,7 @@ use serde::{Deserialize, Serialize}; use std::marker::PhantomData; #[derive(Clone, Debug, Serialize, Deserialize)] -pub struct PaillierEncryptionInRangeStatement { +pub struct PiEncStatement { pub N0: BigInt, pub NN0: BigInt, pub K: BigInt, @@ -47,7 +47,7 @@ pub struct PaillierEncryptionInRangeStatement { } #[derive(Clone, Debug, Serialize, Deserialize)] -pub struct PaillierEncryptionInRangeWitness { +pub struct PiEncWitness { k: BigInt, rho: BigInt, phantom: PhantomData<(E, H)>, @@ -61,9 +61,9 @@ pub enum PiEncError { Proof, } -impl PaillierEncryptionInRangeWitness { +impl PiEncWitness { pub fn new(k: BigInt, rho: BigInt) -> Self { - PaillierEncryptionInRangeWitness { + PiEncWitness { k, rho, phantom: PhantomData, @@ -71,12 +71,12 @@ impl PaillierEncryptionInRangeWitness { } } -impl PaillierEncryptionInRangeStatement { +impl PiEncStatement { #[allow(clippy::too_many_arguments)] pub fn generate( rpparam: RingPedersenParams, paillier_key: EncryptionKey, - ) -> (Self, PaillierEncryptionInRangeWitness) { + ) -> (Self, PiEncWitness) { // sample the prover secret inputs let rho: BigInt = sample_relatively_prime_integer(&paillier_key.n); let k = BigInt::sample_below(Scalar::::group_order()); @@ -100,7 +100,7 @@ impl PaillierEncryptionInRangeStatement { RPParam: rpparam, phantom: PhantomData, }, - PaillierEncryptionInRangeWitness { + PiEncWitness { k, rho, phantom: PhantomData, @@ -117,7 +117,7 @@ pub struct PaillierEncryptionInRangeCommitment { } #[derive(Clone, Debug, Serialize, Deserialize)] -pub struct PaillierEncryptionInRangeProof { +pub struct PiEncProof { z_1: BigInt, z_2: BigInt, z_3: BigInt, @@ -125,11 +125,10 @@ 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), L_PLUS_EPSILON as u32); @@ -231,10 +230,9 @@ impl PaillierEncryptionInRangeProof { } } - #[allow(dead_code)] pub fn verify( - proof: &PaillierEncryptionInRangeProof, - statement: &PaillierEncryptionInRangeStatement, + proof: &PiEncProof, + statement: &PiEncStatement, ) -> Result<(), PiEncError> { let e = H::new() .chain_bigint(&proof.commitment.S) @@ -322,16 +320,14 @@ mod tests { ) .keys(); - let (statement, witness) = PaillierEncryptionInRangeStatement::< - Secp256k1, - Sha256, - >::generate(auxRPParam, paillier_key); - let proof = PaillierEncryptionInRangeProof::::prove( - &witness, &statement, - ); - assert!(PaillierEncryptionInRangeProof::::verify( - &proof, &statement, - ) - .is_ok()); + let (statement, witness) = + PiEncStatement::::generate( + auxRPParam, + paillier_key, + ); + let proof = + PiEncProof::::prove(&witness, &statement); + assert!(PiEncProof::::verify(&proof, &statement,) + .is_ok()); } } From 695b52835f4c03c159722bff0ea9485d7cd64ce5 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Tue, 12 Dec 2023 00:46:11 +0100 Subject: [PATCH 11/26] refactor: move pi-aff-g proof --- Cargo.lock | 2 + Cargo.toml | 6 +- src/presign/mod.rs | 25 +- src/presign/rounds.rs | 359 ++++++++---------- src/sign/mod.rs | 15 +- src/sign/rounds.rs | 178 ++++----- src/utilities/aff_g/test.rs | 0 src/utilities/dec_q/mod.rs | 4 +- src/utilities/mod.rs | 27 -- src/utilities/mul/mod.rs | 2 +- tss-core/Cargo.toml | 2 + tss-core/src/utilities/mod.rs | 26 ++ .../src/zkproof}/aff_g/mod.rs | 286 +++++++------- tss-core/src/zkproof/mod.rs | 1 + 14 files changed, 465 insertions(+), 468 deletions(-) delete mode 100644 src/utilities/aff_g/test.rs rename {src/utilities => tss-core/src/zkproof}/aff_g/mod.rs (70%) diff --git a/Cargo.lock b/Cargo.lock index ec9a46a..c7d507b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4479,6 +4479,8 @@ dependencies = [ "curv-kzen", "kzen-paillier", "merlin", + "rand 0.8.5", + "rand_chacha 0.3.1", "serde", "serde_repr", "serde_with", diff --git a/Cargo.toml b/Cargo.toml index 89e00e6..b9eab12 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,8 @@ 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" @@ -46,12 +48,12 @@ 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 diff --git a/src/presign/mod.rs b/src/presign/mod.rs index 7ecd43f..05d67a4 100644 --- a/src/presign/mod.rs +++ b/src/presign/mod.rs @@ -26,10 +26,6 @@ use paillier::{DecryptionKey, EncryptionKey}; use sha2::Sha256; use crate::utilities::{ - aff_g::{ - PaillierAffineOpWithGroupComInRangeProof, - PaillierAffineOpWithGroupComInRangeStatement, - }, dec_q::{PaillierDecryptionModQProof, PaillierDecryptionModQStatement}, log_star::{ KnowledgeOfExponentPaillierEncryptionProof, @@ -37,6 +33,7 @@ use crate::utilities::{ }, mul::{PaillierMulProof, PaillierMulStatement}, }; +use tss_core::zkproof::aff_g::{PiAffGProof, PiAffGStatement}; use tss_core::zkproof::enc::{PiEncProof, PiEncStatement}; use serde::{Deserialize, Serialize}; @@ -136,12 +133,10 @@ 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_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: KnowledgeOfExponentPaillierEncryptionProof, pub statement_psi_prime_j_i: KnowledgeOfExponentPaillierEncryptionStatement, @@ -225,14 +220,8 @@ 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 statements_D_j_i: HashMap<(u16, u16), PiAffGStatement>, + pub proofs_D_j_i: HashMap<(u16, u16), PiAffGProof>, pub statement_H_i: PaillierMulStatement, pub proof_H_i: PaillierMulProof, pub statement_delta_i: diff --git a/src/presign/rounds.rs b/src/presign/rounds.rs index ccbf2c4..c3c7cb2 100644 --- a/src/presign/rounds.rs +++ b/src/presign/rounds.rs @@ -23,11 +23,6 @@ use super::{ }; use crate::{ utilities::{ - aff_g::{ - PaillierAffineOpWithGroupComInRangeProof, - PaillierAffineOpWithGroupComInRangeStatement, - PaillierAffineOpWithGroupComInRangeWitness, - }, dec_q::{ PaillierDecryptionModQProof, PaillierDecryptionModQStatement, PaillierDecryptionModQWitness, @@ -47,9 +42,10 @@ use curv::{ elliptic::curves::{Point, Scalar, Secp256k1}, BigInt, }; -use tss_core::security_level::L_PRIME; use tss_core::utilities::sample_relatively_prime_integer; +use tss_core::zkproof::aff_g::{PiAffGProof, PiAffGStatement, PiAffGWitness}; use tss_core::zkproof::enc::{PiEncProof, PiEncStatement, PiEncWitness}; +use tss_core::{security_level::L_PRIME, utilities::RingPedersenParams}; use paillier::{ Add, Decrypt, EncryptWithChosenRandomness, EncryptionKey, Mul, Paillier, @@ -406,105 +402,100 @@ 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, ); @@ -676,42 +667,42 @@ 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; @@ -1086,13 +1077,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 @@ -1107,75 +1098,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); @@ -1348,11 +1327,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() { diff --git a/src/sign/mod.rs b/src/sign/mod.rs index 79bcd48..5ed0abe 100644 --- a/src/sign/mod.rs +++ b/src/sign/mod.rs @@ -21,16 +21,13 @@ 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 crate::presign::SSID; pub mod rounds; @@ -54,14 +51,8 @@ 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 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: diff --git a/src/sign/rounds.rs b/src/sign/rounds.rs index 9fdf1d3..b834e0e 100644 --- a/src/sign/rounds.rs +++ b/src/sign/rounds.rs @@ -31,11 +31,6 @@ use paillier::*; use crate::{ presign::{PresigningOutput, PresigningTranscript, DEFAULT_ENCRYPTION_KEY}, utilities::{ - aff_g::{ - PaillierAffineOpWithGroupComInRangeProof, - PaillierAffineOpWithGroupComInRangeStatement, - PaillierAffineOpWithGroupComInRangeWitness, - }, dec_q::{ PaillierDecryptionModQProof, PaillierDecryptionModQStatement, PaillierDecryptionModQWitness, @@ -49,7 +44,10 @@ use crate::{ ErrorType, NoOfflineStageErrorData, ProofVerificationErrorData, }; use thiserror::Error; -use tss_core::utilities::sample_relatively_prime_integer; +use tss_core::utilities::{ + sample_relatively_prime_integer, RingPedersenParams, +}; +use tss_core::zkproof::aff_g::{PiAffGProof, PiAffGStatement, PiAffGWitness}; use zeroize::Zeroize; @@ -183,13 +181,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 +211,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); @@ -556,11 +564,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() { diff --git a/src/utilities/aff_g/test.rs b/src/utilities/aff_g/test.rs deleted file mode 100644 index e69de29..0000000 diff --git a/src/utilities/dec_q/mod.rs b/src/utilities/dec_q/mod.rs index 5adbf32..8de582d 100644 --- a/src/utilities/dec_q/mod.rs +++ b/src/utilities/dec_q/mod.rs @@ -15,7 +15,7 @@ @license GPL-3.0+ */ -use crate::{utilities::fixed_array, Error}; +use crate::Error; use curv::{ arithmetic::{traits::*, Modulo}, cryptographic_primitives::hashing::{Digest, DigestExt}, @@ -33,7 +33,7 @@ use std::marker::PhantomData; use tss_core::security_level::{L, L_PLUS_EPSILON}; use tss_core::utilities::RingPedersenParams; use tss_core::utilities::{ - mod_pow_with_negative, sample_relatively_prime_integer, + fixed_array, mod_pow_with_negative, sample_relatively_prime_integer, }; #[derive(Clone, Debug, Serialize, Deserialize)] diff --git a/src/utilities/mod.rs b/src/utilities/mod.rs index e349209..ef427a9 100644 --- a/src/utilities/mod.rs +++ b/src/utilities/mod.rs @@ -1,36 +1,9 @@ -pub mod aff_g; pub mod dec_q; 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 const SEC_PARAM: usize = 256; pub const SEC_BYTES: usize = SEC_PARAM / 8; pub const OT_PARAM: usize = 128; diff --git a/src/utilities/mul/mod.rs b/src/utilities/mul/mod.rs index f903851..ba43e43 100644 --- a/src/utilities/mul/mod.rs +++ b/src/utilities/mul/mod.rs @@ -15,7 +15,6 @@ @license GPL-3.0+ */ -use crate::utilities::fixed_array; use crate::Error; use curv::{ arithmetic::{traits::*, Modulo}, @@ -31,6 +30,7 @@ use rand::Rng; use rand_chacha::{rand_core::SeedableRng, ChaChaRng}; use serde::{Deserialize, Serialize}; use std::marker::PhantomData; +use tss_core::utilities::fixed_array; use tss_core::utilities::{ mod_pow_with_negative, sample_relatively_prime_integer, }; diff --git a/tss-core/Cargo.toml b/tss-core/Cargo.toml index 8dd6ae6..260bc22 100644 --- a/tss-core/Cargo.toml +++ b/tss-core/Cargo.toml @@ -11,6 +11,8 @@ 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" diff --git a/tss-core/src/utilities/mod.rs b/tss-core/src/utilities/mod.rs index 43f9d5b..1950e7a 100644 --- a/tss-core/src/utilities/mod.rs +++ b/tss-core/src/utilities/mod.rs @@ -96,3 +96,29 @@ pub fn mod_pow_with_negative( BigInt::mod_pow(v, pow, modulus) } } + +/// 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() +} diff --git a/src/utilities/aff_g/mod.rs b/tss-core/src/zkproof/aff_g/mod.rs similarity index 70% rename from src/utilities/aff_g/mod.rs rename to tss-core/src/zkproof/aff_g/mod.rs index 0173356..c0568d9 100644 --- a/src/utilities/aff_g/mod.rs +++ b/tss-core/src/zkproof/aff_g/mod.rs @@ -33,7 +33,12 @@ //! and //! D = C^{x} · (1+N0)^{y} · ρ^{N0} mod N0^{2}. -use crate::{utilities::fixed_array, 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}, cryptographic_primitives::hashing::{Digest, DigestExt}, @@ -48,22 +53,10 @@ use rand::Rng; use rand_chacha::{rand_core::SeedableRng, ChaChaRng}; use serde::{Deserialize, Serialize}; use std::marker::PhantomData; -use tss_core::security_level::{ - L, L_PLUS_EPSILON, L_PRIME, L_PRIME_PLUS_EPSILON, -}; -use tss_core::utilities::RingPedersenParams; -use tss_core::utilities::{ - mod_pow_with_negative, sample_relatively_prime_integer, -}; #[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,9 +99,7 @@ impl } } -impl - PaillierAffineOpWithGroupComInRangeStatement -{ +impl PiAffGStatement { #[allow(clippy::too_many_arguments)] pub fn generate( rpparam: RingPedersenParams, @@ -113,7 +108,7 @@ impl 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); @@ -154,9 +149,7 @@ impl ( Self { - S: rpparam.s, - T: rpparam.t, - N_hat: rpparam.N, + RPParam: rpparam, N0, N1, NN0, @@ -169,7 +162,7 @@ impl ek_verifier, phantom: PhantomData, }, - PaillierAffineOpWithGroupComInRangeWitness { + PiAffGWitness { x, y, rho, @@ -181,7 +174,7 @@ impl } #[derive(Clone, Debug, Serialize, Deserialize)] -pub struct PaillierAffineOpWithGroupComInRangeCommitment { +pub struct PiAffGCommitment { A: BigInt, B_x: Point, B_y: BigInt, @@ -192,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); @@ -231,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 = { @@ -273,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() @@ -313,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(), @@ -356,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()) @@ -381,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 @@ -416,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 */ @@ -426,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 */ @@ -444,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(()) } } @@ -516,14 +552,11 @@ 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 paillier::{Encrypt, KeyGeneration, Paillier, RawPlaintext}; use sha2::Sha256; - use tss_core::utilities::generate_safe_h1_h2_N_tilde; #[test] fn test_affine_g_proof() { @@ -533,29 +566,24 @@ mod tests { 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( - rpparam, - 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/tss-core/src/zkproof/mod.rs b/tss-core/src/zkproof/mod.rs index ec8539b..ce9c0a7 100644 --- a/tss-core/src/zkproof/mod.rs +++ b/tss-core/src/zkproof/mod.rs @@ -1,2 +1,3 @@ +pub mod aff_g; pub mod enc; pub mod prm; From 34b7d2b846c9861fc09209ff807882d1cd04f839 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Tue, 12 Dec 2023 00:46:33 +0100 Subject: [PATCH 12/26] feat: use externally generated rho in pi-enc --- tss-core/src/zkproof/enc/mod.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tss-core/src/zkproof/enc/mod.rs b/tss-core/src/zkproof/enc/mod.rs index 014177c..a2e8579 100644 --- a/tss-core/src/zkproof/enc/mod.rs +++ b/tss-core/src/zkproof/enc/mod.rs @@ -74,17 +74,16 @@ impl PiEncWitness { impl PiEncStatement { #[allow(clippy::too_many_arguments)] pub fn generate( + rho: BigInt, rpparam: RingPedersenParams, paillier_key: EncryptionKey, ) -> (Self, PiEncWitness) { - // sample the prover secret inputs - let rho: BigInt = sample_relatively_prime_integer(&paillier_key.n); - let k = BigInt::sample_below(Scalar::::group_order()); // Set up exponents let _l_exp = BigInt::pow(&BigInt::from(2), L as u32); // Set up moduli let N0 = paillier_key.clone().n; let NN0 = paillier_key.clone().nn; + let k = BigInt::sample_below(Scalar::::group_order()); let K: BigInt = Paillier::encrypt_with_chosen_randomness( &paillier_key, RawPlaintext::from(&k), @@ -320,8 +319,11 @@ mod tests { ) .keys(); + // sample the prover secret inputs + let rho: BigInt = sample_relatively_prime_integer(&paillier_key.n); let (statement, witness) = PiEncStatement::::generate( + rho, auxRPParam, paillier_key, ); From e194cb76baff6229e0209d19b51d23121ef5dc79 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Tue, 12 Dec 2023 13:25:59 +0100 Subject: [PATCH 13/26] refactor: move pi-log-star proof --- src/presign/mod.rs | 16 +- src/presign/rounds.rs | 165 +++++++------- src/utilities/mod.rs | 1 - .../src/zkproof}/log_star/mod.rs | 208 +++++++++--------- tss-core/src/zkproof/mod.rs | 1 + 5 files changed, 188 insertions(+), 203 deletions(-) rename {src/utilities => tss-core/src/zkproof}/log_star/mod.rs (64%) diff --git a/src/presign/mod.rs b/src/presign/mod.rs index 05d67a4..72a81b2 100644 --- a/src/presign/mod.rs +++ b/src/presign/mod.rs @@ -27,14 +27,11 @@ use sha2::Sha256; use crate::utilities::{ dec_q::{PaillierDecryptionModQProof, PaillierDecryptionModQStatement}, - log_star::{ - KnowledgeOfExponentPaillierEncryptionProof, - KnowledgeOfExponentPaillierEncryptionStatement, - }, mul::{PaillierMulProof, PaillierMulStatement}, }; use tss_core::zkproof::aff_g::{PiAffGProof, PiAffGStatement}; use tss_core::zkproof::enc::{PiEncProof, PiEncStatement}; +use tss_core::zkproof::log_star::{PiLogStarProof, PiLogStarStatement}; use serde::{Deserialize, Serialize}; use zeroize::Zeroize; @@ -137,9 +134,8 @@ pub struct PreSigningP2PMessage2 { pub statement_psi_j_i: PiAffGStatement, pub psi_hat_j_i: PiAffGProof, pub statement_psi_hat_j_i: PiAffGStatement, - pub psi_prime_j_i: KnowledgeOfExponentPaillierEncryptionProof, - pub statement_psi_prime_j_i: - KnowledgeOfExponentPaillierEncryptionStatement, + pub psi_prime_j_i: PiLogStarProof, + pub statement_psi_prime_j_i: PiLogStarStatement, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -148,10 +144,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)] diff --git a/src/presign/rounds.rs b/src/presign/rounds.rs index c3c7cb2..da667ec 100644 --- a/src/presign/rounds.rs +++ b/src/presign/rounds.rs @@ -27,11 +27,6 @@ use crate::{ PaillierDecryptionModQProof, PaillierDecryptionModQStatement, PaillierDecryptionModQWitness, }, - log_star::{ - KnowledgeOfExponentPaillierEncryptionProof, - KnowledgeOfExponentPaillierEncryptionStatement, - KnowledgeOfExponentPaillierEncryptionWitness, - }, mul::{PaillierMulProof, PaillierMulStatement, PaillierMulWitness}, }, ErrorType, ProofVerificationErrorData, @@ -42,10 +37,14 @@ use curv::{ 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::enc::{PiEncProof, PiEncStatement, PiEncWitness}; -use tss_core::{security_level::L_PRIME, utilities::RingPedersenParams}; +use tss_core::zkproof::log_star::{ + PiLogStarProof, PiLogStarStatement, PiLogStarWitness, +}; use paillier::{ Add, Decrypt, EncryptWithChosenRandomness, EncryptionKey, Mul, Paillier, @@ -501,35 +500,32 @@ impl Round1 { ); // 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, ); @@ -707,22 +703,22 @@ impl Round2 { // 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) @@ -813,36 +809,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, ); @@ -972,22 +963,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); diff --git a/src/utilities/mod.rs b/src/utilities/mod.rs index ef427a9..81a39d1 100644 --- a/src/utilities/mod.rs +++ b/src/utilities/mod.rs @@ -1,5 +1,4 @@ pub mod dec_q; -pub mod log_star; pub mod mul; pub mod mul_star; pub mod sha2; diff --git a/src/utilities/log_star/mod.rs b/tss-core/src/zkproof/log_star/mod.rs similarity index 64% rename from src/utilities/log_star/mod.rs rename to tss-core/src/zkproof/log_star/mod.rs index e072554..3a51afb 100644 --- a/src/utilities/log_star/mod.rs +++ b/tss-core/src/zkproof/log_star/mod.rs @@ -21,6 +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 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}, @@ -33,18 +38,17 @@ use paillier::{ }; use serde::{Deserialize, Serialize}; use std::marker::PhantomData; -use tss_core::security_level::L; -use tss_core::utilities::RingPedersenParams; -use tss_core::utilities::{ - mod_pow_with_negative, sample_relatively_prime_integer, -}; -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, @@ -58,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, @@ -85,16 +82,14 @@ impl } } -impl - KnowledgeOfExponentPaillierEncryptionStatement -{ +impl PiLogStarStatement { #[allow(clippy::too_many_arguments)] pub fn generate( rho: BigInt, g: Option>, 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 @@ -119,12 +114,10 @@ impl C, X, g, - N_hat: rpparam.N, - s: rpparam.s, - t: rpparam.t, + RPParams: rpparam, phantom: PhantomData, }, - KnowledgeOfExponentPaillierEncryptionWitness { + PiLogStarWitness { x, rho, phantom: PhantomData, @@ -133,7 +126,7 @@ impl } } #[derive(Clone, Debug, Serialize, Deserialize)] -pub struct KnowledgeOfExponentPaillierEncryptionCommitment { +pub struct PiLogStarCommitment { S: BigInt, A: BigInt, Y: Point, @@ -141,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 @@ -210,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(), @@ -253,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) @@ -287,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(()) } @@ -331,14 +336,11 @@ 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 paillier::{KeyGeneration, Paillier}; use sha2::Sha256; - use tss_core::utilities::generate_safe_h1_h2_N_tilde; #[test] fn test_log_star_proof() { @@ -346,21 +348,19 @@ mod tests { 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()), - rpparam, - 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 index ce9c0a7..a346d6e 100644 --- a/tss-core/src/zkproof/mod.rs +++ b/tss-core/src/zkproof/mod.rs @@ -1,3 +1,4 @@ pub mod aff_g; pub mod enc; +pub mod log_star; pub mod prm; From 23e2b9b7117815a42f45b64ddeb419242f245ea5 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Tue, 12 Dec 2023 13:38:11 +0100 Subject: [PATCH 14/26] refactor: move pi-mul --- src/presign/mod.rs | 10 +-- src/presign/rounds.rs | 20 ++--- src/utilities/mod.rs | 1 - tss-core/src/zkproof/enc/mod.rs | 3 +- tss-core/src/zkproof/mod.rs | 1 + .../src/zkproof}/mul/mod.rs | 82 ++++++++++--------- 6 files changed, 59 insertions(+), 58 deletions(-) rename {src/utilities => tss-core/src/zkproof}/mul/mod.rs (80%) diff --git a/src/presign/mod.rs b/src/presign/mod.rs index 72a81b2..11db04c 100644 --- a/src/presign/mod.rs +++ b/src/presign/mod.rs @@ -25,13 +25,13 @@ use multi_party_ecdsa::protocols::multi_party_ecdsa::gg_2020::state_machine::key use paillier::{DecryptionKey, EncryptionKey}; use sha2::Sha256; -use crate::utilities::{ - dec_q::{PaillierDecryptionModQProof, PaillierDecryptionModQStatement}, - mul::{PaillierMulProof, PaillierMulStatement}, +use crate::utilities::dec_q::{ + PaillierDecryptionModQProof, PaillierDecryptionModQStatement, }; use tss_core::zkproof::aff_g::{PiAffGProof, PiAffGStatement}; 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; @@ -216,8 +216,8 @@ pub struct IdentifiableAbortBroadcastMessage { pub i: u16, pub statements_D_j_i: HashMap<(u16, u16), PiAffGStatement>, pub proofs_D_j_i: HashMap<(u16, u16), PiAffGProof>, - pub statement_H_i: PaillierMulStatement, - pub proof_H_i: PaillierMulProof, + 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 da667ec..ab1bfb4 100644 --- a/src/presign/rounds.rs +++ b/src/presign/rounds.rs @@ -22,12 +22,9 @@ use super::{ PresigningOutput, PresigningTranscript, DEFAULT_ENCRYPTION_KEY, SSID, }; use crate::{ - utilities::{ - dec_q::{ - PaillierDecryptionModQProof, PaillierDecryptionModQStatement, - PaillierDecryptionModQWitness, - }, - mul::{PaillierMulProof, PaillierMulStatement, PaillierMulWitness}, + utilities::dec_q::{ + PaillierDecryptionModQProof, PaillierDecryptionModQStatement, + PaillierDecryptionModQWitness, }, ErrorType, ProofVerificationErrorData, }; @@ -45,6 +42,7 @@ 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, @@ -1162,12 +1160,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, @@ -1177,7 +1175,7 @@ impl Round3 { phantom: PhantomData, }; - let proof_H_i = PaillierMulProof::::prove( + let proof_H_i = PiMulProof::::prove( &witness_H_i, &statement_H_i, ); @@ -1346,9 +1344,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, diff --git a/src/utilities/mod.rs b/src/utilities/mod.rs index 81a39d1..8d5e08a 100644 --- a/src/utilities/mod.rs +++ b/src/utilities/mod.rs @@ -1,5 +1,4 @@ pub mod dec_q; -pub mod mul; pub mod mul_star; pub mod sha2; diff --git a/tss-core/src/zkproof/enc/mod.rs b/tss-core/src/zkproof/enc/mod.rs index a2e8579..84bf89b 100644 --- a/tss-core/src/zkproof/enc/mod.rs +++ b/tss-core/src/zkproof/enc/mod.rs @@ -52,8 +52,7 @@ pub struct PiEncWitness { rho: BigInt, phantom: PhantomData<(E, H)>, } - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub enum PiEncError { Serialization, Validation, diff --git a/tss-core/src/zkproof/mod.rs b/tss-core/src/zkproof/mod.rs index a346d6e..79d0594 100644 --- a/tss-core/src/zkproof/mod.rs +++ b/tss-core/src/zkproof/mod.rs @@ -1,4 +1,5 @@ pub mod aff_g; pub mod enc; pub mod log_star; +pub mod mul; pub mod prm; 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 ba43e43..049185f 100644 --- a/src/utilities/mul/mod.rs +++ b/tss-core/src/zkproof/mul/mod.rs @@ -15,7 +15,9 @@ @license GPL-3.0+ */ -use crate::Error; +use crate::utilities::{ + fixed_array, mod_pow_with_negative, sample_relatively_prime_integer, +}; use curv::{ arithmetic::{traits::*, Modulo}, cryptographic_primitives::hashing::{Digest, DigestExt}, @@ -30,13 +32,17 @@ use rand::Rng; use rand_chacha::{rand_core::SeedableRng, ChaChaRng}; use serde::{Deserialize, Serialize}; use std::marker::PhantomData; -use tss_core::utilities::fixed_array; -use tss_core::utilities::{ - mod_pow_with_negative, sample_relatively_prime_integer, -}; #[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() + ); } } From 3b7f73d2e79bfdb140257a9ba33d5b1d1576c5b3 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Tue, 12 Dec 2023 13:58:31 +0100 Subject: [PATCH 15/26] refactor: move pi-mul-star --- src/sign/mod.rs | 15 +- src/sign/rounds.rs | 63 +++--- src/utilities/mod.rs | 1 - tss-core/src/zkproof/mod.rs | 1 + .../src/zkproof}/mul_star/mod.rs | 198 +++++++++--------- 5 files changed, 132 insertions(+), 146 deletions(-) rename {src/utilities => tss-core/src/zkproof}/mul_star/mod.rs (63%) diff --git a/src/sign/mod.rs b/src/sign/mod.rs index 5ed0abe..7938351 100644 --- a/src/sign/mod.rs +++ b/src/sign/mod.rs @@ -20,14 +20,11 @@ use serde::{Deserialize, Serialize}; use sha2::Sha256; -use crate::utilities::{ - dec_q::{PaillierDecryptionModQProof, PaillierDecryptionModQStatement}, - mul_star::{ - PaillierMultiplicationVersusGroupProof, - PaillierMultiplicationVersusGroupStatement, - }, +use crate::utilities::dec_q::{ + PaillierDecryptionModQProof, PaillierDecryptionModQStatement, }; use tss_core::zkproof::aff_g::{PiAffGProof, PiAffGStatement}; +use tss_core::zkproof::mul_star::{PiMulStarProof, PiMulStarStatement}; use crate::presign::SSID; pub mod rounds; @@ -53,10 +50,8 @@ pub struct SigningIdentifiableAbortMessage { pub i: u16, 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_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 b834e0e..f76b133 100644 --- a/src/sign/rounds.rs +++ b/src/sign/rounds.rs @@ -30,16 +30,9 @@ use paillier::*; use crate::{ presign::{PresigningOutput, PresigningTranscript, DEFAULT_ENCRYPTION_KEY}, - utilities::{ - dec_q::{ - PaillierDecryptionModQProof, PaillierDecryptionModQStatement, - PaillierDecryptionModQWitness, - }, - mul_star::{ - PaillierMultiplicationVersusGroupProof, - PaillierMultiplicationVersusGroupStatement, - PaillierMultiplicationVersusGroupWitness, - }, + utilities::dec_q::{ + PaillierDecryptionModQProof, PaillierDecryptionModQStatement, + PaillierDecryptionModQWitness, }, ErrorType, NoOfflineStageErrorData, ProofVerificationErrorData, }; @@ -48,6 +41,9 @@ use tss_core::utilities::{ sample_relatively_prime_integer, RingPedersenParams, }; use tss_core::zkproof::aff_g::{PiAffGProof, PiAffGStatement, PiAffGWitness}; +use tss_core::zkproof::mul_star::{ + PiMulStarProof, PiMulStarStatement, PiMulStarWitness, +}; use zeroize::Zeroize; @@ -320,7 +316,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), ); @@ -330,28 +326,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) @@ -369,18 +360,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, ), ); } @@ -592,11 +582,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(), diff --git a/src/utilities/mod.rs b/src/utilities/mod.rs index 8d5e08a..3f868ac 100644 --- a/src/utilities/mod.rs +++ b/src/utilities/mod.rs @@ -1,5 +1,4 @@ pub mod dec_q; -pub mod mul_star; pub mod sha2; pub const SEC_PARAM: usize = 256; diff --git a/tss-core/src/zkproof/mod.rs b/tss-core/src/zkproof/mod.rs index 79d0594..04c67b7 100644 --- a/tss-core/src/zkproof/mod.rs +++ b/tss-core/src/zkproof/mod.rs @@ -2,4 +2,5 @@ pub mod aff_g; pub mod enc; pub mod log_star; pub mod mul; +pub mod mul_star; pub mod prm; diff --git a/src/utilities/mul_star/mod.rs b/tss-core/src/zkproof/mul_star/mod.rs similarity index 63% rename from src/utilities/mul_star/mod.rs rename to tss-core/src/zkproof/mul_star/mod.rs index e3d1720..daf6191 100644 --- a/src/utilities/mul_star/mod.rs +++ b/tss-core/src/zkproof/mul_star/mod.rs @@ -21,6 +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 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}, @@ -30,41 +35,32 @@ use curv::{ use paillier::EncryptionKey; use serde::{Deserialize, Serialize}; use std::marker::PhantomData; -use tss_core::security_level::L; -use tss_core::utilities::RingPedersenParams; -use tss_core::utilities::{ - mod_pow_with_negative, sample_relatively_prime_integer, -}; -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, @@ -72,16 +68,14 @@ impl } } -impl - PaillierMultiplicationVersusGroupStatement -{ +impl PiMulStarStatement { #[allow(clippy::too_many_arguments)] pub fn generate( rho: BigInt, _C: 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 @@ -103,12 +97,10 @@ impl C, D, X, - N_hat: rpparam.N, - s: rpparam.s, - t: rpparam.t, + RPParams: rpparam, phantom: PhantomData, }, - PaillierMultiplicationVersusGroupWitness { + PiMulStarWitness { x, rho, phantom: PhantomData, @@ -118,7 +110,7 @@ impl } #[derive(Clone, Debug, Serialize, Deserialize)] -pub struct PaillierMultiplicationVersusGroupCommitment { +pub struct PiMulStarCommitment { A: BigInt, B_x: Point, E: BigInt, @@ -126,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); @@ -181,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() @@ -213,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, @@ -225,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) @@ -256,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(()) } @@ -297,14 +305,11 @@ 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 paillier::{Encrypt, KeyGeneration, Paillier, RawPlaintext}; use sha2::Sha256; - use tss_core::utilities::generate_safe_h1_h2_N_tilde; #[test] fn test_mul_star_proof() { @@ -312,26 +317,25 @@ mod tests { 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, rpparam, 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()); } } From f2aec9383c80f86a9b681c76af8ed605da3fda3e Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Tue, 12 Dec 2023 14:17:01 +0100 Subject: [PATCH 16/26] refactor: move pi-dec --- src/presign/mod.rs | 9 +- src/presign/rounds.rs | 46 ++--- src/sign/mod.rs | 9 +- src/sign/rounds.rs | 64 +++---- src/utilities/mod.rs | 1 - .../dec_q => tss-core/src/zkproof/dec}/mod.rs | 167 ++++++++++-------- tss-core/src/zkproof/mod.rs | 1 + 7 files changed, 148 insertions(+), 149 deletions(-) rename {src/utilities/dec_q => tss-core/src/zkproof/dec}/mod.rs (70%) diff --git a/src/presign/mod.rs b/src/presign/mod.rs index 11db04c..614d45c 100644 --- a/src/presign/mod.rs +++ b/src/presign/mod.rs @@ -25,10 +25,8 @@ use multi_party_ecdsa::protocols::multi_party_ecdsa::gg_2020::state_machine::key use paillier::{DecryptionKey, EncryptionKey}; use sha2::Sha256; -use crate::utilities::dec_q::{ - PaillierDecryptionModQProof, PaillierDecryptionModQStatement, -}; 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}; @@ -218,7 +216,6 @@ pub struct IdentifiableAbortBroadcastMessage { 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>, + pub statement_delta_i: HashMap>, + pub proof_delta_i: HashMap>, } diff --git a/src/presign/rounds.rs b/src/presign/rounds.rs index ab1bfb4..3b993b6 100644 --- a/src/presign/rounds.rs +++ b/src/presign/rounds.rs @@ -21,13 +21,7 @@ use super::{ PreSigningP2PMessage2, PreSigningP2PMessage3, PreSigningSecrets, PresigningOutput, PresigningTranscript, DEFAULT_ENCRYPTION_KEY, SSID, }; -use crate::{ - utilities::dec_q::{ - PaillierDecryptionModQProof, PaillierDecryptionModQStatement, - PaillierDecryptionModQWitness, - }, - ErrorType, ProofVerificationErrorData, -}; +use crate::{ErrorType, ProofVerificationErrorData}; use curv::{ arithmetic::{traits::*, Modulo, Samplable}, cryptographic_primitives::secret_sharing::feldman_vss::VerifiableSS, @@ -38,6 +32,7 @@ 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, @@ -1200,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()), @@ -1212,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(), @@ -1243,7 +1238,7 @@ impl Round3 { proof_delta_i.insert( *l, - PaillierDecryptionModQProof::::prove( + PiDecProof::::prove( &witness_delta_i, &statement_delta_l_i, ), @@ -1363,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/sign/mod.rs b/src/sign/mod.rs index 7938351..2fd8400 100644 --- a/src/sign/mod.rs +++ b/src/sign/mod.rs @@ -20,10 +20,8 @@ use serde::{Deserialize, Serialize}; use sha2::Sha256; -use crate::utilities::dec_q::{ - PaillierDecryptionModQProof, PaillierDecryptionModQStatement, -}; 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; @@ -52,7 +50,6 @@ pub struct SigningIdentifiableAbortMessage { 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>, + pub proof_sigma_i: HashMap>, + pub statement_sigma_i: HashMap>, } diff --git a/src/sign/rounds.rs b/src/sign/rounds.rs index f76b133..ae08b32 100644 --- a/src/sign/rounds.rs +++ b/src/sign/rounds.rs @@ -30,10 +30,6 @@ use paillier::*; use crate::{ presign::{PresigningOutput, PresigningTranscript, DEFAULT_ENCRYPTION_KEY}, - utilities::dec_q::{ - PaillierDecryptionModQProof, PaillierDecryptionModQStatement, - PaillierDecryptionModQWitness, - }, ErrorType, NoOfflineStageErrorData, ProofVerificationErrorData, }; use thiserror::Error; @@ -41,6 +37,7 @@ 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, }; @@ -425,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()), @@ -437,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(), @@ -483,7 +480,7 @@ impl Round1 { proof_sigma_i.insert( *l, - PaillierDecryptionModQProof::::prove( + PiDecProof::::prove( &witness_sigma_i, &statement_sigma_l_i, ), @@ -601,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/mod.rs b/src/utilities/mod.rs index 3f868ac..cc5d9c7 100644 --- a/src/utilities/mod.rs +++ b/src/utilities/mod.rs @@ -1,4 +1,3 @@ -pub mod dec_q; pub mod sha2; pub const SEC_PARAM: usize = 256; diff --git a/src/utilities/dec_q/mod.rs b/tss-core/src/zkproof/dec/mod.rs similarity index 70% rename from src/utilities/dec_q/mod.rs rename to tss-core/src/zkproof/dec/mod.rs index 8de582d..d8af4f8 100644 --- a/src/utilities/dec_q/mod.rs +++ b/tss-core/src/zkproof/dec/mod.rs @@ -15,7 +15,11 @@ @license GPL-3.0+ */ -use crate::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}, cryptographic_primitives::hashing::{Digest, DigestExt}, @@ -30,17 +34,15 @@ use rand::Rng; use rand_chacha::{rand_core::SeedableRng, ChaChaRng}; use serde::{Deserialize, Serialize}; use std::marker::PhantomData; -use tss_core::security_level::{L, L_PLUS_EPSILON}; -use tss_core::utilities::RingPedersenParams; -use tss_core::utilities::{ - fixed_array, mod_pow_with_negative, sample_relatively_prime_integer, -}; #[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, @@ -49,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, @@ -65,13 +67,13 @@ impl PaillierDecryptionModQWitness { } } -impl PaillierDecryptionModQStatement { +impl PiDecStatement { #[allow(clippy::too_many_arguments)] pub fn generate( 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); @@ -88,9 +90,7 @@ impl PaillierDecryptionModQStatement { let x = BigInt::mod_floor(&y, Scalar::::group_order()); ( Self { - S: rpparams.s, - T: rpparams.t, - N_hat: rpparams.N, + RPParams: rpparams, N0: prover.n, NN0: prover.nn, C, @@ -98,7 +98,7 @@ impl PaillierDecryptionModQStatement { ek_prover, phantom: PhantomData, }, - PaillierDecryptionModQWitness { + PiDecWitness { y, rho, phantom: PhantomData, @@ -108,7 +108,7 @@ impl PaillierDecryptionModQStatement { } #[derive(Clone, Debug, Serialize, Deserialize)] -pub struct PaillierDecryptionModQCommitment { +pub struct PiDecCommitment { A: BigInt, gamma: BigInt, big_S: BigInt, @@ -116,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); @@ -138,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 = { @@ -187,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 · μ @@ -204,7 +218,7 @@ impl PaillierDecryptionModQProof { BigInt::mod_mul(&r, &rho, &statement.N0) }; // Return the proof - PaillierDecryptionModQProof { + PiDecProof { z1, z2, w, @@ -214,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) @@ -251,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 @@ -265,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ˆ @@ -273,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(()) } } @@ -302,31 +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 paillier::{KeyGeneration, Paillier}; use sha2::Sha256; - use tss_core::utilities::generate_safe_h1_h2_N_tilde; #[test] fn test_paillier_decryption_modulo_q() { 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 (statement, witness) = PaillierDecryptionModQStatement::< - Secp256k1, - Sha256, - >::generate(rpparam, rho, ek_prover); - let proof = PaillierDecryptionModQProof::::prove( - &witness, &statement, + let rho: BigInt = sample_relatively_prime_integer(&ek_prover.n); + let (statement, witness) = + PiDecStatement::::generate( + rpparam, rho, ek_prover, + ); + let proof = + PiDecProof::::prove(&witness, &statement); + assert!( + PiDecProof::::verify(&proof, &statement).is_ok() ); - assert!(PaillierDecryptionModQProof::::verify( - &proof, &statement - ) - .is_ok()); } } diff --git a/tss-core/src/zkproof/mod.rs b/tss-core/src/zkproof/mod.rs index 04c67b7..edc6859 100644 --- a/tss-core/src/zkproof/mod.rs +++ b/tss-core/src/zkproof/mod.rs @@ -1,4 +1,5 @@ pub mod aff_g; +pub mod dec; pub mod enc; pub mod log_star; pub mod mul; From 9c013541d0cb8f936809f90999c5db00ccd45078 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Tue, 12 Dec 2023 14:37:11 +0100 Subject: [PATCH 17/26] refactor: use constant security parameters --- fs-dkr/src/add_party_message.rs | 8 ++-- fs-dkr/src/refresh_message.rs | 10 ++--- fs-dkr/src/test.rs | 67 +++++++++++--------------------- src/refresh/rounds.rs | 69 ++++++--------------------------- src/refresh/state_machine.rs | 30 +++----------- src/utilities/mod.rs | 32 --------------- 6 files changed, 48 insertions(+), 168 deletions(-) diff --git a/fs-dkr/src/add_party_message.rs b/fs-dkr/src/add_party_message.rs index 8388bd4..1aeaf51 100644 --- a/fs-dkr/src/add_party_message.rs +++ b/fs-dkr/src/add_party_message.rs @@ -44,7 +44,7 @@ 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, @@ -82,7 +82,7 @@ fn generate_dlog_statement_proofs( )) } -impl JoinMessage { +impl JoinMessage { pub fn set_party_index(&mut self, new_party_index: u16) { self.party_index = Some(new_party_index); } @@ -139,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, diff --git a/fs-dkr/src/refresh_message.rs b/fs-dkr/src/refresh_message.rs index 1cbdc55..1985c83 100644 --- a/fs-dkr/src/refresh_message.rs +++ b/fs-dkr/src/refresh_message.rs @@ -31,7 +31,7 @@ use tss_core::{ // 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>, @@ -50,13 +50,13 @@ pub struct RefreshMessage { 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 @@ -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, @@ -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(); diff --git a/fs-dkr/src/test.rs b/fs-dkr/src/test.rs index 0e74403..2cf2899 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/src/refresh/rounds.rs b/src/refresh/rounds.rs index c9f3894..f29d7f8 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 e4bccf0..1d23c51 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/utilities/mod.rs b/src/utilities/mod.rs index cc5d9c7..62488e3 100644 --- a/src/utilities/mod.rs +++ b/src/utilities/mod.rs @@ -1,33 +1 @@ pub mod sha2; - -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 From e6c0385c50bf9963c9ee0df6d08ad58c687dbac7 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Tue, 12 Dec 2023 14:45:19 +0100 Subject: [PATCH 18/26] chore: clippy --- tss-core/src/utilities/mod.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tss-core/src/utilities/mod.rs b/tss-core/src/utilities/mod.rs index 1950e7a..146c36b 100644 --- a/tss-core/src/utilities/mod.rs +++ b/tss-core/src/utilities/mod.rs @@ -30,7 +30,7 @@ pub fn generate_safe_h1_h2_N_tilde() -> (RingPedersenParams, RingPedersenWitness DEFAULT_LEVEL.paillier_key_size, ) .keys(); - return get_related_values(&ek_tilde, &dk_tilde); + get_related_values(&ek_tilde, &dk_tilde) } // generate_normal_h1_h2_N_tilde generates Paillier modulus N = p*q and related @@ -40,7 +40,7 @@ pub fn generate_normal_h1_h2_N_tilde( let (ek_tilde, dk_tilde) = Paillier::keypair_with_modulus_size(DEFAULT_LEVEL.paillier_key_size) .keys(); - return get_related_values(&ek_tilde, &dk_tilde); + get_related_values(&ek_tilde, &dk_tilde) } fn get_related_values( @@ -54,7 +54,7 @@ fn get_related_values( 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, lambda_inv) = loop { + let (lambda, lambdaInv) = loop { let lambda_ = BigInt::sample_below(&phi); match BigInt::mod_inv(&lambda_, &phi) { Some(inv) => break (lambda_, inv), @@ -62,18 +62,18 @@ fn get_related_values( } }; let h2 = BigInt::mod_pow(&h1, &lambda, &ek.n); - return ( + ( RingPedersenParams { N: ek.n.clone(), s: h1, t: h2, }, RingPedersenWitness { - lambda: lambda, - lambdaInv: lambda_inv, - phi: phi, + lambda, + lambdaInv, + phi, }, - ); + ) } pub fn sample_relatively_prime_integer(n: &BigInt) -> BigInt { From edcf7c482fda8ea4dbc81386a5acc486fe114a81 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Wed, 10 Jan 2024 15:35:53 +0100 Subject: [PATCH 19/26] feat: add sqrt for ring pedersen params --- tss-core/src/utilities/mod.rs | 72 +++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/tss-core/src/utilities/mod.rs b/tss-core/src/utilities/mod.rs index 146c36b..ee15c5e 100644 --- a/tss-core/src/utilities/mod.rs +++ b/tss-core/src/utilities/mod.rs @@ -22,6 +22,14 @@ 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) @@ -72,6 +80,8 @@ fn get_related_values( lambda, lambdaInv, phi, + p: dk.p.clone(), + q: dk.q.clone(), }, ) } @@ -97,6 +107,14 @@ pub fn mod_pow_with_negative( } } +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); + return 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 @@ -122,3 +140,57 @@ pub fn fixed_array( } seed.try_into() } + +pub fn sqrt( + x: &BigInt, + rpw: &RingPedersenWitness, +) -> Result { + let one = BigInt::from(1); + let two = BigInt::from(2); + let three = BigInt::from(3); + let four = BigInt::from(4); + if &rpw.p % &four != three { + return Err(RingPedersenError::NoSqrt); + } + if &rpw.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 = x % &rpw.p; + let x_mod_q = x % &rpw.q; + let p_exp = (&rpw.p + &one) / &four; + let q_exp = (&rpw.q + &one) / &four; + let lpart = BigInt::mod_pow(&x_mod_p, &p_exp, &rpw.p); + let rpart = BigInt::mod_pow(&x_mod_q, &q_exp, &rpw.q); + if BigInt::mod_pow(&lpart, &two, &rpw.p) != x_mod_p { + return Err(RingPedersenError::NoSqrt); + } + if BigInt::mod_pow(&rpart, &two, &rpw.q) != x_mod_q { + return Err(RingPedersenError::NoSqrt); + } + let pinv = BigInt::mod_inv(&rpw.p, &rpw.q).unwrap(); + let xsqrt = &lpart + &rpw.p * ((&rpart - &lpart) * &pinv); + return 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(&x, &rpwitness); + assert!(xsqrtres.is_ok()); + let xsqrt = xsqrtres.unwrap(); + let xx = BigInt::mod_pow(&xsqrt, &BigInt::from(2), &rpparams.N); + assert_eq!(x, xx); + + // assert_eq!() + } +} From e6bec9c0fe1f013e7d13baccfbdac494f9bb5e96 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Wed, 17 Jan 2024 02:11:47 +0100 Subject: [PATCH 20/26] fix: convert Legendre to -1 --- tss-core/src/utilities/mod.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tss-core/src/utilities/mod.rs b/tss-core/src/utilities/mod.rs index ee15c5e..124a157 100644 --- a/tss-core/src/utilities/mod.rs +++ b/tss-core/src/utilities/mod.rs @@ -112,6 +112,9 @@ pub fn legendre(a: &BigInt, modulus: &BigInt) -> BigInt { 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); + } return l; } From e64071b7c7becf3a71b9471f3f4c5f2055b243a5 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Wed, 17 Jan 2024 02:12:13 +0100 Subject: [PATCH 21/26] fix: use p,q directly in sqrt --- tss-core/src/utilities/mod.rs | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/tss-core/src/utilities/mod.rs b/tss-core/src/utilities/mod.rs index 124a157..995669b 100644 --- a/tss-core/src/utilities/mod.rs +++ b/tss-core/src/utilities/mod.rs @@ -144,35 +144,36 @@ pub fn fixed_array( seed.try_into() } -pub fn sqrt( +pub fn sqrt_comp( x: &BigInt, - rpw: &RingPedersenWitness, + 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 &rpw.p % &four != three { + if p % &four != three { return Err(RingPedersenError::NoSqrt); } - if &rpw.q % &four != three { + 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 = x % &rpw.p; - let x_mod_q = x % &rpw.q; - let p_exp = (&rpw.p + &one) / &four; - let q_exp = (&rpw.q + &one) / &four; - let lpart = BigInt::mod_pow(&x_mod_p, &p_exp, &rpw.p); - let rpart = BigInt::mod_pow(&x_mod_q, &q_exp, &rpw.q); - if BigInt::mod_pow(&lpart, &two, &rpw.p) != x_mod_p { + 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, &rpw.q) != x_mod_q { + if BigInt::mod_pow(&rpart, &two, q) != x_mod_q { return Err(RingPedersenError::NoSqrt); } - let pinv = BigInt::mod_inv(&rpw.p, &rpw.q).unwrap(); - let xsqrt = &lpart + &rpw.p * ((&rpart - &lpart) * &pinv); + let pinv = BigInt::mod_inv(p, q).unwrap(); + let xsqrt = &lpart + p * ((&rpart - &lpart) * &pinv); return Ok(xsqrt); } @@ -188,12 +189,10 @@ mod tests { { x = BigInt::sample_below(&rpparams.N); } - let xsqrtres = sqrt(&x, &rpwitness); + 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); - - // assert_eq!() } } From 24bfd1e505f1aa5e667d8ffe410ac7db6a877936 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Wed, 17 Jan 2024 02:12:34 +0100 Subject: [PATCH 22/26] feat: add pi-mod proof --- tss-core/src/zkproof/mod.rs | 1 + tss-core/src/zkproof/modulus/mod.rs | 224 ++++++++++++++++++++++++++++ 2 files changed, 225 insertions(+) create mode 100644 tss-core/src/zkproof/modulus/mod.rs diff --git a/tss-core/src/zkproof/mod.rs b/tss-core/src/zkproof/mod.rs index edc6859..d19ad61 100644 --- a/tss-core/src/zkproof/mod.rs +++ b/tss-core/src/zkproof/mod.rs @@ -2,6 +2,7 @@ pub mod aff_g; pub mod dec; pub mod enc; 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 0000000..e67cc25 --- /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 = 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 = 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); + } + } + + return 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()); + } +} From 2ea3df3a3e2dda983445aa168971afe596ae726f Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Wed, 24 Jan 2024 00:33:41 +0100 Subject: [PATCH 23/26] feat: add Pi-Fac proof --- tss-core/src/zkproof/fac/mod.rs | 293 ++++++++++++++++++++++++++++++++ tss-core/src/zkproof/mod.rs | 1 + 2 files changed, 294 insertions(+) create mode 100644 tss-core/src/zkproof/fac/mod.rs diff --git a/tss-core/src/zkproof/fac/mod.rs b/tss-core/src/zkproof/fac/mod.rs new file mode 100644 index 0000000..0f03bb0 --- /dev/null +++ b/tss-core/src/zkproof/fac/mod.rs @@ -0,0 +1,293 @@ +#![allow(non_snake_case)] + +use crate::{ + security_level::{L, L_PLUS_EPSILON, SEC_BYTES}, + utilities::{sqrt_comp, 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); + + let sqrtN0 = match sqrt_comp(&statement.N0, &witness.p, &witness.q) { + Ok(sqrtN0) => sqrtN0, + Err(_) => return Err(PiFacError::Statement), + }; + // 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, + ), + &BigInt::mod_pow(&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, + ), + &BigInt::mod_pow(&statement.RPParam.t, &nu, &statement.RPParam.N), + &statement.RPParam.N, + ); + let A = BigInt::mod_mul( + &BigInt::mod_pow( + &statement.RPParam.s, + &alpha, + &statement.RPParam.N, + ), + &BigInt::mod_pow(&statement.RPParam.t, &x, &statement.RPParam.N), + &statement.RPParam.N, + ); + let B = BigInt::mod_mul( + &BigInt::mod_pow(&statement.RPParam.s, &beta, &statement.RPParam.N), + &BigInt::mod_pow(&statement.RPParam.t, &y, &statement.RPParam.N), + &statement.RPParam.N, + ); + let T = BigInt::mod_mul( + &BigInt::mod_pow(&Q, &alpha, &statement.RPParam.N), + &BigInt::mod_pow(&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 e = BigInt::from_bytes(&challenge_bytes); + // TODO: also sample the sign bit? + + 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 e = BigInt::from_bytes(&challenge_bytes); + // TODO: also sample the sign bit? + + let R = BigInt::mod_mul( + &BigInt::mod_pow( + &statement.RPParam.s, + &statement.N0, + &statement.RPParam.N, + ), + &BigInt::mod_pow( + &statement.RPParam.t, + &proof.cmt.sigma, + &statement.RPParam.N, + ), + &statement.RPParam.N, + ); + // first check + let first_ls = BigInt::mod_mul( + &BigInt::mod_pow( + &statement.RPParam.s, + &proof.z1, + &statement.RPParam.N, + ), + &BigInt::mod_pow( + &statement.RPParam.t, + &proof.w1, + &statement.RPParam.N, + ), + &statement.RPParam.N, + ); + let first_rs = BigInt::mod_mul( + &proof.cmt.A, + &BigInt::mod_pow(&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( + &BigInt::mod_pow( + &statement.RPParam.s, + &proof.z2, + &statement.RPParam.N, + ), + &BigInt::mod_pow( + &statement.RPParam.t, + &proof.w2, + &statement.RPParam.N, + ), + &statement.RPParam.N, + ); + let second_rs = BigInt::mod_mul( + &proof.cmt.B, + &BigInt::mod_pow(&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( + &BigInt::mod_pow(&proof.cmt.Q, &proof.z1, &statement.RPParam.N), + &BigInt::mod_pow( + &statement.RPParam.t, + &proof.v, + &statement.RPParam.N, + ), + &statement.RPParam.N, + ); + let third_rs = BigInt::mod_mul( + &proof.cmt.T, + &BigInt::mod_pow(&R, &e, &statement.RPParam.N), + &statement.RPParam.N, + ); + if third_ls != third_rs { + 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()); + } +} diff --git a/tss-core/src/zkproof/mod.rs b/tss-core/src/zkproof/mod.rs index d19ad61..abcef9d 100644 --- a/tss-core/src/zkproof/mod.rs +++ b/tss-core/src/zkproof/mod.rs @@ -1,6 +1,7 @@ pub mod aff_g; pub mod dec; pub mod enc; +pub mod fac; pub mod log_star; pub mod modulus; pub mod mul; From b4a3c6664dda6577da2ca654bf026f5c5891162a Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Mon, 29 Jan 2024 14:24:57 +0100 Subject: [PATCH 24/26] fix: Pi-fac proof --- tss-core/src/zkproof/fac/mod.rs | 98 +++++++++++++++++++++++++-------- 1 file changed, 75 insertions(+), 23 deletions(-) diff --git a/tss-core/src/zkproof/fac/mod.rs b/tss-core/src/zkproof/fac/mod.rs index 0f03bb0..1c62a25 100644 --- a/tss-core/src/zkproof/fac/mod.rs +++ b/tss-core/src/zkproof/fac/mod.rs @@ -2,7 +2,9 @@ use crate::{ security_level::{L, L_PLUS_EPSILON, SEC_BYTES}, - utilities::{sqrt_comp, RingPedersenParams, RingPedersenWitness}, + utilities::{ + mod_pow_with_negative, RingPedersenParams, RingPedersenWitness, + }, }; use curv::{ @@ -69,10 +71,21 @@ impl PiFacProof { let l_exp = BigInt::pow(&two, L as u32); let lplus_exp = BigInt::pow(&two, L_PLUS_EPSILON as u32); - let sqrtN0 = match sqrt_comp(&statement.N0, &witness.p, &witness.q) { - Ok(sqrtN0) => sqrtN0, - Err(_) => return Err(PiFacError::Statement), - }; + // 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} @@ -101,7 +114,11 @@ impl PiFacProof { &witness.p, &statement.RPParam.N, ), - &BigInt::mod_pow(&statement.RPParam.t, &mu, &statement.RPParam.N), + &mod_pow_with_negative( + &statement.RPParam.t, + &mu, + &statement.RPParam.N, + ), &statement.RPParam.N, ); let Q = BigInt::mod_mul( @@ -110,26 +127,46 @@ impl PiFacProof { &witness.q, &statement.RPParam.N, ), - &BigInt::mod_pow(&statement.RPParam.t, &nu, &statement.RPParam.N), + &mod_pow_with_negative( + &statement.RPParam.t, + &nu, + &statement.RPParam.N, + ), &statement.RPParam.N, ); let A = BigInt::mod_mul( - &BigInt::mod_pow( + &mod_pow_with_negative( &statement.RPParam.s, &alpha, &statement.RPParam.N, ), - &BigInt::mod_pow(&statement.RPParam.t, &x, &statement.RPParam.N), + &mod_pow_with_negative( + &statement.RPParam.t, + &x, + &statement.RPParam.N, + ), &statement.RPParam.N, ); let B = BigInt::mod_mul( - &BigInt::mod_pow(&statement.RPParam.s, &beta, &statement.RPParam.N), - &BigInt::mod_pow(&statement.RPParam.t, &y, &statement.RPParam.N), + &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( - &BigInt::mod_pow(&Q, &alpha, &statement.RPParam.N), - &BigInt::mod_pow(&statement.RPParam.t, &r, &statement.RPParam.N), + &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 { @@ -195,7 +232,7 @@ impl PiFacProof { &statement.N0, &statement.RPParam.N, ), - &BigInt::mod_pow( + &mod_pow_with_negative( &statement.RPParam.t, &proof.cmt.sigma, &statement.RPParam.N, @@ -204,12 +241,12 @@ impl PiFacProof { ); // first check let first_ls = BigInt::mod_mul( - &BigInt::mod_pow( + &mod_pow_with_negative( &statement.RPParam.s, &proof.z1, &statement.RPParam.N, ), - &BigInt::mod_pow( + &mod_pow_with_negative( &statement.RPParam.t, &proof.w1, &statement.RPParam.N, @@ -218,7 +255,7 @@ impl PiFacProof { ); let first_rs = BigInt::mod_mul( &proof.cmt.A, - &BigInt::mod_pow(&proof.cmt.P, &e, &statement.RPParam.N), + &mod_pow_with_negative(&proof.cmt.P, &e, &statement.RPParam.N), &statement.RPParam.N, ); if first_ls != first_rs { @@ -226,12 +263,12 @@ impl PiFacProof { } // second check let second_ls = BigInt::mod_mul( - &BigInt::mod_pow( + &mod_pow_with_negative( &statement.RPParam.s, &proof.z2, &statement.RPParam.N, ), - &BigInt::mod_pow( + &mod_pow_with_negative( &statement.RPParam.t, &proof.w2, &statement.RPParam.N, @@ -240,7 +277,7 @@ impl PiFacProof { ); let second_rs = BigInt::mod_mul( &proof.cmt.B, - &BigInt::mod_pow(&proof.cmt.Q, &e, &statement.RPParam.N), + &mod_pow_with_negative(&proof.cmt.Q, &e, &statement.RPParam.N), &statement.RPParam.N, ); if second_ls != second_rs { @@ -248,8 +285,12 @@ impl PiFacProof { } // third check let third_ls = BigInt::mod_mul( - &BigInt::mod_pow(&proof.cmt.Q, &proof.z1, &statement.RPParam.N), - &BigInt::mod_pow( + &mod_pow_with_negative( + &proof.cmt.Q, + &proof.z1, + &statement.RPParam.N, + ), + &mod_pow_with_negative( &statement.RPParam.t, &proof.v, &statement.RPParam.N, @@ -258,13 +299,22 @@ impl PiFacProof { ); let third_rs = BigInt::mod_mul( &proof.cmt.T, - &BigInt::mod_pow(&R, &e, &statement.RPParam.N), + &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(()) } } @@ -289,5 +339,7 @@ mod tests { }; let proof = PiFacProof::prove(&statement, &witness); assert!(proof.is_ok()); + let res = PiFacProof::verify(&statement, &proof.unwrap()); + assert!(res.is_ok()); } } From cd89fc2cc0588472750e90c326193d2e71410fbf Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Wed, 31 Jan 2024 10:46:51 +0100 Subject: [PATCH 25/26] fix: sample sign bit for Pi-Fac challenge --- tss-core/src/zkproof/fac/mod.rs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/tss-core/src/zkproof/fac/mod.rs b/tss-core/src/zkproof/fac/mod.rs index 1c62a25..cc978b6 100644 --- a/tss-core/src/zkproof/fac/mod.rs +++ b/tss-core/src/zkproof/fac/mod.rs @@ -187,8 +187,13 @@ impl PiFacProof { .append_message(b"PiFacCommitment", &bincode::serialize(&cmt)?); let mut challenge_bytes = [0u8; SEC_BYTES]; transcript.challenge_bytes(b"PiFacChallenge", &mut challenge_bytes); - let e = BigInt::from_bytes(&challenge_bytes); - // TODO: also sample the sign bit? + 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)); @@ -223,7 +228,13 @@ impl PiFacProof { ); let mut challenge_bytes = [0u8; SEC_BYTES]; transcript.challenge_bytes(b"PiFacChallenge", &mut challenge_bytes); - let e = BigInt::from_bytes(&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( From 418eefeaae09dfb4ada5ea283802731417773d4a Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Wed, 31 Jan 2024 11:06:05 +0100 Subject: [PATCH 26/26] refactor: clippy suggestions --- multi-party-ecdsa/src/gg_2020/party_i.rs | 4 ++-- tss-core/src/utilities/mod.rs | 4 ++-- tss-core/src/zkproof/fac/mod.rs | 2 +- tss-core/src/zkproof/modulus/mod.rs | 6 +++--- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/multi-party-ecdsa/src/gg_2020/party_i.rs b/multi-party-ecdsa/src/gg_2020/party_i.rs index c8bf013..ce143c5 100644 --- a/multi-party-ecdsa/src/gg_2020/party_i.rs +++ b/multi-party-ecdsa/src/gg_2020/party_i.rs @@ -160,8 +160,8 @@ impl Keys { Self { u_i: u, y_i: y, - dk: dk, - ek: ek, + dk, + ek, party_index: index, N_tilde: rpparam.N, h1: rpparam.s, diff --git a/tss-core/src/utilities/mod.rs b/tss-core/src/utilities/mod.rs index 995669b..84e5508 100644 --- a/tss-core/src/utilities/mod.rs +++ b/tss-core/src/utilities/mod.rs @@ -115,7 +115,7 @@ pub fn legendre(a: &BigInt, modulus: &BigInt) -> BigInt { if &l + &one == *modulus { return BigInt::from(-1); } - return l; + l } /// Extend or truncate a vector of bytes to a fixed length array. @@ -174,7 +174,7 @@ pub fn sqrt_comp( } let pinv = BigInt::mod_inv(p, q).unwrap(); let xsqrt = &lpart + p * ((&rpart - &lpart) * &pinv); - return Ok(xsqrt); + Ok(xsqrt) } #[cfg(test)] diff --git a/tss-core/src/zkproof/fac/mod.rs b/tss-core/src/zkproof/fac/mod.rs index cc978b6..72a8c39 100644 --- a/tss-core/src/zkproof/fac/mod.rs +++ b/tss-core/src/zkproof/fac/mod.rs @@ -201,7 +201,7 @@ impl PiFacProof { 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)); + let v = BigInt::add(&r, &e.mul(sigmahat)); Ok(PiFacProof { cmt, diff --git a/tss-core/src/zkproof/modulus/mod.rs b/tss-core/src/zkproof/modulus/mod.rs index e67cc25..4eb9fb0 100644 --- a/tss-core/src/zkproof/modulus/mod.rs +++ b/tss-core/src/zkproof/modulus/mod.rs @@ -94,7 +94,7 @@ impl PiModProof { let mut challenge_bytes = [0u8; SEC_BYTES]; transcript.challenge_bytes(b"PiModChallenge", &mut challenge_bytes); let mut yi = BigInt::from_bytes(&challenge_bytes); - yi = yi % &statement.N; + yi %= &statement.N; y.push(yi.clone()); let zi = BigInt::mod_pow(&yi, &ninv, &statement.N); z.push(zi.clone()); @@ -166,7 +166,7 @@ impl PiModProof { let mut challenge_bytes = [0u8; SEC_BYTES]; transcript.challenge_bytes(b"PiModChallenge", &mut challenge_bytes); let mut yi = BigInt::from_bytes(&challenge_bytes); - yi = yi % &statement.N; + yi &= &statement.N; let zi = match proof.z.get(i) { Some(zi) => zi, @@ -200,7 +200,7 @@ impl PiModProof { } } - return Ok(()); + Ok(()) } }