From 6f19578dc11291a83534d2e3b6647945d197fc71 Mon Sep 17 00:00:00 2001 From: Mike Rolish Date: Mon, 19 Aug 2024 11:29:14 -0500 Subject: [PATCH 01/14] [WAR-489] DKG test mockup using Fp --- Cargo.toml | 15 ++++- dkg.toml | 1 + src/dkg.rs | 178 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + 4 files changed, 194 insertions(+), 1 deletion(-) create mode 100644 dkg.toml create mode 100644 src/dkg.rs diff --git a/Cargo.toml b/Cargo.toml index 27e19e1..34050cc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,12 +13,21 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[[bin]] +name = "dkg" +path = "src/dkg.rs" + [dependencies] hex-literal = "0.4.1" num-traits = "0.2.19" subtle = "2.6.1" crypto-bigint = "0.6.0-rc.2" sha3 = "0.11.0-pre.4" +tracing-subscriber = "0.3.18" +tracing = "0.1.40" +confy = "0.6.1" +rand = "0.9.0-alpha.2" +serde = { version = "1.0.204", features = ["derive"] } [lib] proc-macro = true @@ -26,4 +35,8 @@ proc-macro = true [dev-dependencies] serde = { version = "1.0.204", features = ["derive"] } serde_json = "1.0.120" -sha2 = "0.11.0-pre.4" \ No newline at end of file +sha2 = "0.11.0-pre.4" +tracing-subscriber = "0.3.18" +tracing = "0.1.40" +confy = "0.6.1" +rand = "0.9.0-alpha.2" \ No newline at end of file diff --git a/dkg.toml b/dkg.toml new file mode 100644 index 0000000..0cc985d --- /dev/null +++ b/dkg.toml @@ -0,0 +1 @@ +quorum = 5 \ No newline at end of file diff --git a/src/dkg.rs b/src/dkg.rs new file mode 100644 index 0000000..80498bc --- /dev/null +++ b/src/dkg.rs @@ -0,0 +1,178 @@ +use crypto_bigint::U256; +use std::collections::HashMap; +use num_traits::{One, Pow, Zero}; +use crate::fields::fp::Fp; +use tracing::{event, Level}; +use serde::{Deserialize, Serialize}; +use std::path::PathBuf; +use rand::Rng; +use std::collections::HashSet; + +const GENERATOR: Fp = Fp::new(U256::from_u64(3u64)); + +// TODO: Bounding coefficients until we address exponent modulo arithmetic +const MIN_COEFFICIENT: u32 = 1; +const MAX_COEFFICIENT: u32 = 1000; + +fn generate_distinct_random_values(count: usize, min: u32, max: u32) -> Vec { + let mut rng = rand::thread_rng(); + let mut values = HashSet::new(); + + while values.len() < count { + let value = rng.gen_range(min..=max); + values.insert(value); + } + + values.into_iter().collect() +} + +fn from_u32(n: u32) -> Fp { + Fp::new(U256::from_u64(n as u64)) +} + +fn from_vec_u32(v: Vec) -> Vec { + v.iter().map(|n| from_u32(*n)).collect() +} + +struct DealerSecret { + quorum: u32, + round_id: u64, + coefficients: Vec, + secret: Fp, + commitments: Vec, +} + +impl DealerSecret { + fn new(quorum: u32, round_id: u64) -> Self { + let coefficients = from_vec_u32(generate_distinct_random_values(quorum as usize, MIN_COEFFICIENT, MAX_COEFFICIENT)); + let secret = coefficients[0].clone(); + let commitments = coefficients + .iter() + .map(|c| GENERATOR.pow(c.value())) + .collect(); + DealerSecret { + quorum, + round_id, + coefficients, + secret, + commitments, + } + } +} +struct DealerShare { + round_id: u64, + dealer_id: u64, + commitments: Vec, + x: Fp, + y: Fp, +} + +struct Participant { + participant_id: u64, + host: String, + dealer_secret: DealerSecret, + dealer_shares: HashMap, +} + +struct Round { + round_id: u64, + quorum: u32, + participants: HashMap, +} + +// The coefficients are [a_0,...,a_n], and so this evaluates sum(a_i x^i). +impl DealerSecret { + fn eval_polynomial(&self, x: Fp) -> Fp { + let mut val = Fp::zero(); + for (i, c) in self.coefficients.iter().enumerate() { + val += *c * x.pow(U256::from_u64(i as u64)); + } + val + } +} + +impl DealerShare { + fn is_valid(&self) -> bool { + let commitments_val = self.eval_commitments(); + let share_val = GENERATOR.pow(self.y.value()); + commitments_val == share_val + } + + fn eval_commitments(&self) -> Fp { + let mut val = Fp::one(); + for (j, cmt_j) in self.commitments.iter().enumerate() { + val *= cmt_j.pow(self.x.pow(U256::from_u64(j as u64)).value()); + } + val + } +} + +#[derive(Debug, Serialize, Deserialize)] +struct MyConfig { + quorum: u32, +} + +impl Default for MyConfig { + fn default() -> Self { + Self { + quorum: 0, + } + } +} + +fn do_round(round_id: u64, quorum: u32) { + let mut round_data = Round { + round_id, + quorum, + participants: HashMap::new(), + }; + + // set up participants + let n_participants: u64 = (quorum + 1) as u64; + for participant_id in 0u64..n_participants { + let participant = Participant { + participant_id, + host: "todo".to_string(), + dealer_secret: DealerSecret::new(quorum, round_id), + dealer_shares: HashMap::new(), + }; + round_data.participants.insert(participant_id, participant); + } + + // iterate through dealers + for (dealer_id, dealer) in round_data.participants.iter() { + let dealer_secret = &dealer.dealer_secret; + let x_shares = from_vec_u32(generate_distinct_random_values(quorum as usize, MIN_COEFFICIENT, MAX_COEFFICIENT)); + let recipient_index = 0; + for (recipient_id, recipient) in round_data.participants.iter() { + let x_share = x_shares[recipient_index]; + let y_share = dealer_secret.eval_polynomial(x_share); + let share = DealerShare { + round_id, + dealer_id: *dealer_id, + commitments: dealer_secret.commitments.clone(), + x: x_share, + y: y_share, + }; + let share_valid = share.is_valid(); + event!(Level::INFO, "round_id: {round_id} dealer_id: {dealer_id} recipient_id: {recipient_id} share_valid: {share_valid}"); + } + } +} + +#[test] +fn main() -> Result<(), confy::ConfyError> { + tracing_subscriber::fmt().init(); + event!(Level::INFO, "Begin dkg::main"); + let config_path = PathBuf::from("dkg.toml"); + let cfg: MyConfig = confy::load_path(&config_path)?; + event!(Level::INFO, "Loaded config: {:?}", cfg); + + const NUMBER_OF_ROUNDS: u64 = 3; + for round_id in 0..NUMBER_OF_ROUNDS { + do_round(round_id, cfg.quorum); + } + + event!(Level::INFO, "End dkg::main"); + Ok(()) +} diff --git a/src/lib.rs b/src/lib.rs index c1d15da..feb9d67 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,3 +16,4 @@ mod fields; mod groups; mod hasher; mod svdw; +mod dkg; From 059c0e05a4182d2f9322ce0eaa2cb6042160be95 Mon Sep 17 00:00:00 2001 From: Mike Rolish Date: Mon, 19 Aug 2024 11:53:41 -0500 Subject: [PATCH 02/14] Example commitment fail/kick --- src/dkg.rs | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/src/dkg.rs b/src/dkg.rs index 80498bc..5a34761 100644 --- a/src/dkg.rs +++ b/src/dkg.rs @@ -58,6 +58,18 @@ impl DealerSecret { commitments, } } + fn new_bad(quorum: u32, round_id: u64) -> Self { + let coefficients = from_vec_u32(vec![42; quorum as usize]); + let secret = coefficients[0].clone(); + let commitments = from_vec_u32(vec![42; quorum as usize]); + DealerSecret { + quorum, + round_id, + coefficients, + secret, + commitments, + } + } } struct DealerShare { round_id: u64, @@ -121,6 +133,7 @@ impl Default for MyConfig { } fn do_round(round_id: u64, quorum: u32) { + event!(Level::INFO, "Begin round {round_id}"); let mut round_data = Round { round_id, quorum, @@ -128,12 +141,16 @@ fn do_round(round_id: u64, quorum: u32) { }; // set up participants - let n_participants: u64 = (quorum + 1) as u64; + let n_participants: u64 = (quorum + 2) as u64; for participant_id in 0u64..n_participants { let participant = Participant { participant_id, host: "todo".to_string(), - dealer_secret: DealerSecret::new(quorum, round_id), + dealer_secret: if participant_id != (quorum + 1) as u64 { + DealerSecret::new(quorum, round_id) + } else { + DealerSecret::new_bad(quorum, round_id) + }, dealer_shares: HashMap::new(), }; round_data.participants.insert(participant_id, participant); @@ -144,6 +161,7 @@ fn do_round(round_id: u64, quorum: u32) { let dealer_secret = &dealer.dealer_secret; let x_shares = from_vec_u32(generate_distinct_random_values(quorum as usize, MIN_COEFFICIENT, MAX_COEFFICIENT)); let recipient_index = 0; + let mut complaint_count = 0; for (recipient_id, recipient) in round_data.participants.iter() { let x_share = x_shares[recipient_index]; let y_share = dealer_secret.eval_polynomial(x_share); @@ -155,9 +173,16 @@ fn do_round(round_id: u64, quorum: u32) { y: y_share, }; let share_valid = share.is_valid(); + if !share_valid { + complaint_count += 1; + } event!(Level::INFO, "round_id: {round_id} dealer_id: {dealer_id} recipient_id: {recipient_id} share_valid: {share_valid}"); } + if complaint_count >= n_participants / 2 { + event!(Level::ERROR, "round_id: {round_id} dealer_id: {dealer_id} kicked for {complaint_count}/{n_participants} complaints"); + } } + event!(Level::INFO, "End round {round_id}"); } #[test] From 54dbfcb7acc212200c44f84e60d5ed7abaae5435 Mon Sep 17 00:00:00 2001 From: Mike Rolish Date: Mon, 19 Aug 2024 21:37:15 -0500 Subject: [PATCH 03/14] Move dkg to examples --- Cargo.toml | 11 +++-------- {src => examples}/dkg.rs | 14 ++++++++------ src/lib.rs | 1 - 3 files changed, 11 insertions(+), 15 deletions(-) rename {src => examples}/dkg.rs (97%) diff --git a/Cargo.toml b/Cargo.toml index 3674dbc..1472723 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,9 +13,9 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html -[[bin]] +[[example]] name = "dkg" -path = "src/dkg.rs" +path = "examples/dkg.rs" [dependencies] hex-literal = "0.4.1" @@ -23,11 +23,6 @@ num-traits = "0.2.19" subtle = "2.6.1" crypto-bigint = "0.6.0-rc.2" sha3 = "0.11.0-pre.4" -tracing-subscriber = "0.3.18" -tracing = "0.1.40" -confy = "0.6.1" -rand = "0.9.0-alpha.2" -serde = { version = "1.0.204", features = ["derive"] } [dev-dependencies] @@ -37,4 +32,4 @@ sha2 = "0.11.0-pre.4" tracing-subscriber = "0.3.18" tracing = "0.1.40" confy = "0.6.1" -rand = "0.9.0-alpha.2" \ No newline at end of file +rand = "0.9.0-alpha.2" diff --git a/src/dkg.rs b/examples/dkg.rs similarity index 97% rename from src/dkg.rs rename to examples/dkg.rs index 36c78ce..99cd60f 100644 --- a/src/dkg.rs +++ b/examples/dkg.rs @@ -1,8 +1,7 @@ -// TODO: to examples dir -use crypto_bigint::U256; use std::collections::HashMap; +use crypto_bigint::U256; use num_traits::{One, Pow, Zero}; -use crate::fields::fp::Fp; +use sylow::Fp; use tracing::{event, Level}; use serde::{Deserialize, Serialize}; use std::path::PathBuf; @@ -164,8 +163,12 @@ fn do_round(round_id: u64, quorum: u32) { let x_shares = from_vec_u32(generate_distinct_random_values(quorum as usize, MIN_COEFFICIENT, MAX_COEFFICIENT)); let recipient_index = 0; let mut complaint_count = 0; - // TODO: exclude self + for (recipient_id, recipient) in round_data.participants.iter() { + if dealer_id == recipient_id { + continue; + } + let x_share = x_shares[recipient_index]; let y_share = dealer_secret.eval_polynomial(x_share); let share = DealerShare { @@ -190,11 +193,10 @@ fn do_round(round_id: u64, quorum: u32) { event!(Level::INFO, "End round {round_id}"); } -#[test] fn main() -> Result<(), confy::ConfyError> { tracing_subscriber::fmt().init(); event!(Level::INFO, "Begin dkg::main"); - let config_path = PathBuf::from("dkg.toml"); + let config_path = PathBuf::from("../dkg.toml"); let cfg: MyConfig = confy::load_path(&config_path)?; event!(Level::INFO, "Loaded config: {:?}", cfg); diff --git a/src/lib.rs b/src/lib.rs index 5bcda4c..4ec84ff 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,7 +19,6 @@ mod groups; mod hasher; mod pairing; mod svdw; -mod dkg; use crate::fields::fp::{FieldExtensionTrait, Fp, Fr}; use crate::groups::g1::G1Projective; From 42e7fc3e27ae40027586e57f27df9004741f1016 Mon Sep 17 00:00:00 2001 From: Mike Rolish Date: Mon, 19 Aug 2024 21:44:32 -0500 Subject: [PATCH 04/14] Fix config --- examples/dkg.rs | 2 +- dkg.toml => examples/dkg.toml | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename dkg.toml => examples/dkg.toml (100%) diff --git a/examples/dkg.rs b/examples/dkg.rs index 99cd60f..bb63229 100644 --- a/examples/dkg.rs +++ b/examples/dkg.rs @@ -196,7 +196,7 @@ fn do_round(round_id: u64, quorum: u32) { fn main() -> Result<(), confy::ConfyError> { tracing_subscriber::fmt().init(); event!(Level::INFO, "Begin dkg::main"); - let config_path = PathBuf::from("../dkg.toml"); + let config_path = PathBuf::from("examples/dkg.toml"); let cfg: MyConfig = confy::load_path(&config_path)?; event!(Level::INFO, "Loaded config: {:?}", cfg); diff --git a/dkg.toml b/examples/dkg.toml similarity index 100% rename from dkg.toml rename to examples/dkg.toml From dd25ede4db43931e90d7699bc3b2d626142b0b35 Mon Sep 17 00:00:00 2001 From: Mike Rolish Date: Mon, 19 Aug 2024 23:22:17 -0500 Subject: [PATCH 05/14] cleanup --- examples/dkg.rs | 71 +++++++++++++++++++++++++++---------------------- 1 file changed, 39 insertions(+), 32 deletions(-) diff --git a/examples/dkg.rs b/examples/dkg.rs index bb63229..51764cb 100644 --- a/examples/dkg.rs +++ b/examples/dkg.rs @@ -1,39 +1,31 @@ -use std::collections::HashMap; +use crypto_bigint::rand_core::OsRng; use crypto_bigint::U256; use num_traits::{One, Pow, Zero}; -use sylow::Fp; -use tracing::{event, Level}; use serde::{Deserialize, Serialize}; -use std::path::PathBuf; -use rand::Rng; +use std::collections::HashMap; use std::collections::HashSet; +use std::path::PathBuf; +use sylow::{FieldExtensionTrait, Fp}; +use tracing::{event, Level}; const GENERATOR: Fp = Fp::new(U256::from_u64(3u64)); // TODO: Bounding coefficients until we address exponent modulo arithmetic -const MIN_COEFFICIENT: u32 = 1; -const MAX_COEFFICIENT: u32 = 1000; +const MIN_COEFFICIENT: u64 = 1; +const MAX_COEFFICIENT: u64 = 1000; -fn generate_distinct_random_values(count: usize, min: u32, max: u32) -> Vec { - let mut rng = rand::thread_rng(); +fn generate_distinct_random_values(count: usize, min: u64, max: u64) -> Vec { let mut values = HashSet::new(); while values.len() < count { - let value = rng.gen_range(min..=max); - values.insert(value); + let value = >::rand(&mut OsRng) % Fp::from(max) + Fp::from(min); + values.insert(value.value()); } - values.into_iter().collect() -} - -fn from_u32(n: u32) -> Fp { - Fp::new(U256::from_u64(n as u64)) -} - -fn from_vec_u32(v: Vec) -> Vec { - v.iter().map(|n| from_u32(*n)).collect() + values.into_iter().map(|n| Fp::new(n)).collect() } +#[allow(dead_code)] struct DealerSecret { quorum: u32, round_id: u64, @@ -42,10 +34,13 @@ struct DealerSecret { commitments: Vec, } -// TODO: random value generation in Fp impl DealerSecret { fn new(quorum: u32, round_id: u64) -> Self { - let coefficients = from_vec_u32(generate_distinct_random_values(quorum as usize, MIN_COEFFICIENT, MAX_COEFFICIENT)); + let coefficients = generate_distinct_random_values( + quorum as usize, + MIN_COEFFICIENT, + MAX_COEFFICIENT, + ); let secret = coefficients[0].clone(); let commitments = coefficients .iter() @@ -60,9 +55,9 @@ impl DealerSecret { } } fn new_bad(quorum: u32, round_id: u64) -> Self { - let coefficients = from_vec_u32(vec![42; quorum as usize]); + let coefficients = vec![Fp::from(42u64); quorum as usize]; let secret = coefficients[0].clone(); - let commitments = from_vec_u32(vec![42; quorum as usize]); + let commitments = vec![Fp::from(42u64); quorum as usize]; DealerSecret { quorum, round_id, @@ -72,6 +67,8 @@ impl DealerSecret { } } } + +#[allow(dead_code)] struct DealerShare { round_id: u64, dealer_id: u64, @@ -80,6 +77,7 @@ struct DealerShare { y: Fp, } +#[allow(dead_code)] struct Participant { participant_id: u64, host: String, @@ -87,6 +85,7 @@ struct Participant { dealer_shares: HashMap, } +#[allow(dead_code)] struct Round { round_id: u64, quorum: u32, @@ -127,9 +126,7 @@ struct MyConfig { impl Default for MyConfig { fn default() -> Self { - Self { - quorum: 0, - } + Self { quorum: 0 } } } @@ -146,7 +143,7 @@ fn do_round(round_id: u64, quorum: u32) { for participant_id in 0u64..n_participants { let participant = Participant { participant_id, - host: "todo".to_string(), + host: "some_host".to_string(), dealer_secret: if participant_id != (quorum + 1) as u64 { DealerSecret::new(quorum, round_id) } else { @@ -157,14 +154,20 @@ fn do_round(round_id: u64, quorum: u32) { round_data.participants.insert(participant_id, participant); } + let mut public_key = Fp::one(); + // iterate through dealers for (dealer_id, dealer) in round_data.participants.iter() { let dealer_secret = &dealer.dealer_secret; - let x_shares = from_vec_u32(generate_distinct_random_values(quorum as usize, MIN_COEFFICIENT, MAX_COEFFICIENT)); + let x_shares = generate_distinct_random_values( + quorum as usize, + MIN_COEFFICIENT, + MAX_COEFFICIENT, + ); let recipient_index = 0; let mut complaint_count = 0; - for (recipient_id, recipient) in round_data.participants.iter() { + for (recipient_id, _recipient) in round_data.participants.iter() { if dealer_id == recipient_id { continue; } @@ -180,16 +183,20 @@ fn do_round(round_id: u64, quorum: u32) { }; let share_valid = share.is_valid(); if !share_valid { + // complaint broadcast and validation would go here complaint_count += 1; } event!(Level::INFO, "round_id: {round_id} dealer_id: {dealer_id} recipient_id: {recipient_id} share_valid: {share_valid}"); } - // TODO: complaint broadcast and validation here + if complaint_count >= n_participants / 2 { event!(Level::ERROR, "round_id: {round_id} dealer_id: {dealer_id} kicked for {complaint_count}/{n_participants} complaints"); + } else { + public_key *= dealer.dealer_secret.commitments[0]; } } - // TODO: print out computed public key + + event!(Level::INFO, "Aggregate public key: {}", public_key.value()); event!(Level::INFO, "End round {round_id}"); } From 539160106ac6d286f4b7f3f5841269293e69f9b9 Mon Sep 17 00:00:00 2001 From: Mike Rolish Date: Mon, 19 Aug 2024 23:24:52 -0500 Subject: [PATCH 06/14] fmt --- examples/dkg.rs | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/examples/dkg.rs b/examples/dkg.rs index 51764cb..3d8ed38 100644 --- a/examples/dkg.rs +++ b/examples/dkg.rs @@ -18,7 +18,8 @@ fn generate_distinct_random_values(count: usize, min: u64, max: u64) -> Vec let mut values = HashSet::new(); while values.len() < count { - let value = >::rand(&mut OsRng) % Fp::from(max) + Fp::from(min); + let value = + >::rand(&mut OsRng) % Fp::from(max) + Fp::from(min); values.insert(value.value()); } @@ -36,11 +37,8 @@ struct DealerSecret { impl DealerSecret { fn new(quorum: u32, round_id: u64) -> Self { - let coefficients = generate_distinct_random_values( - quorum as usize, - MIN_COEFFICIENT, - MAX_COEFFICIENT, - ); + let coefficients = + generate_distinct_random_values(quorum as usize, MIN_COEFFICIENT, MAX_COEFFICIENT); let secret = coefficients[0].clone(); let commitments = coefficients .iter() @@ -159,11 +157,8 @@ fn do_round(round_id: u64, quorum: u32) { // iterate through dealers for (dealer_id, dealer) in round_data.participants.iter() { let dealer_secret = &dealer.dealer_secret; - let x_shares = generate_distinct_random_values( - quorum as usize, - MIN_COEFFICIENT, - MAX_COEFFICIENT, - ); + let x_shares = + generate_distinct_random_values(quorum as usize, MIN_COEFFICIENT, MAX_COEFFICIENT); let recipient_index = 0; let mut complaint_count = 0; From 94d1d9f678fc5c9c03049f7f35cc6279714ec86d Mon Sep 17 00:00:00 2001 From: Mike Rolish Date: Mon, 19 Aug 2024 23:29:23 -0500 Subject: [PATCH 07/14] clippy --- examples/dkg.rs | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/examples/dkg.rs b/examples/dkg.rs index 3d8ed38..d532631 100644 --- a/examples/dkg.rs +++ b/examples/dkg.rs @@ -23,7 +23,7 @@ fn generate_distinct_random_values(count: usize, min: u64, max: u64) -> Vec values.insert(value.value()); } - values.into_iter().map(|n| Fp::new(n)).collect() + values.into_iter().map(Fp::new).collect() } #[allow(dead_code)] @@ -39,7 +39,7 @@ impl DealerSecret { fn new(quorum: u32, round_id: u64) -> Self { let coefficients = generate_distinct_random_values(quorum as usize, MIN_COEFFICIENT, MAX_COEFFICIENT); - let secret = coefficients[0].clone(); + let secret = coefficients[0]; let commitments = coefficients .iter() .map(|c| GENERATOR.pow(c.value())) @@ -54,7 +54,7 @@ impl DealerSecret { } fn new_bad(quorum: u32, round_id: u64) -> Self { let coefficients = vec![Fp::from(42u64); quorum as usize]; - let secret = coefficients[0].clone(); + let secret = coefficients[0]; let commitments = vec![Fp::from(42u64); quorum as usize]; DealerSecret { quorum, @@ -117,17 +117,11 @@ impl DealerShare { } } -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Default, Serialize, Deserialize)] struct MyConfig { quorum: u32, } -impl Default for MyConfig { - fn default() -> Self { - Self { quorum: 0 } - } -} - fn do_round(round_id: u64, quorum: u32) { event!(Level::INFO, "Begin round {round_id}"); let mut round_data = Round { From acd1593e9f6a39eaaea63ccc093d0112ef6b30dc Mon Sep 17 00:00:00 2001 From: Mike Rolish Date: Tue, 20 Aug 2024 15:52:10 -0500 Subject: [PATCH 08/14] Some debug tracing for intermediate operations --- src/fields/fp.rs | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/src/fields/fp.rs b/src/fields/fp.rs index fffeb50..e76c21c 100644 --- a/src/fields/fp.rs +++ b/src/fields/fp.rs @@ -133,7 +133,7 @@ macro_rules! define_finite_prime_field { //special struct for const-time arithmetic on montgomery form integers mod p type $output = crypto_bigint::modular::ConstMontyForm<$mod_struct, { $mod_struct::LIMBS }>; - #[derive(Clone, Debug, Copy)] //to be used in const contexts + #[derive(Clone, Copy)] //to be used in const contexts /// This is the actual struct that serves as our finite field implementation, containing /// the modulus of the field, as well as the output type that contains the internal /// Montgomery arithmetic logic @@ -374,14 +374,14 @@ macro_rules! define_finite_prime_field { if other.is_zero() { return Self::from(0u64); } - let (mut _q, mut _r) = self + let (mut _q, mut _r) = dbg!(self .1 .retrieve() - .div_rem(&NonZero::<$uint_type>::new(other.1.retrieve()).unwrap()); + .div_rem(&NonZero::<$uint_type>::new(other.1.retrieve()).unwrap())); if self.1.retrieve().bit(255).into() { - _q = _q - <$uint_type>::ONE; - _r = other.1.retrieve() - _r; + _q = dbg!(_q - <$uint_type>::ONE); + _r = dbg!(other.1.retrieve() - _r); } Self::new(_q) } @@ -389,18 +389,25 @@ macro_rules! define_finite_prime_field { if other.is_zero() { return Self::from(0u64); } - let (mut _q, mut _r) = self + let (mut _q, mut _r) = dbg!(self .1 .retrieve() - .div_rem(&NonZero::<$uint_type>::new(other.1.retrieve()).unwrap()); + .div_rem(&NonZero::<$uint_type>::new(other.1.retrieve()).unwrap())); if self.1.retrieve().bit(255).into() { // _q = _q - <$uint_type>::ONE; - _r = other.1.retrieve() - _r; + _r = dbg!(other.1.retrieve() - _r); } Self::new(_r) } } + impl std::fmt::Debug for $wrapper_name { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct(stringify!($wrapper_name)) + .field(stringify!($uint_type), &self.value()) + .finish() + } + } }; } @@ -457,8 +464,8 @@ impl Fp { /// possible solution of $\pm pow(n, \frac{p+1}{4})$, which is where this magic /// number below comes from ;) pub fn sqrt(&self) -> CtOption { - let arg = ((Self::new(Self::characteristic()) + Self::one()) / Self::from(4)).value(); - let sqrt = self.pow(arg); + let arg = dbg!((Self::new(Self::characteristic()) + Self::one()) / Self::from(4)).value(); + let sqrt = dbg!(self.pow(arg)); CtOption::new(sqrt, sqrt.square().ct_eq(self)) } /// Returns the square of the element in the base field @@ -468,14 +475,14 @@ impl Fp { /// Determines if the element in the base field is a square of another element pub fn is_square(&self) -> Choice { let p_minus_1_div_2 = - ((Self::new(Self::characteristic()) - Self::from(1)) / Self::from(2)).value(); - let retval = self.pow(p_minus_1_div_2); + dbg!((Self::new(Self::characteristic()) - Self::from(1)) / Self::from(2)).value(); + let retval = dbg!(self.pow(p_minus_1_div_2)); Choice::from((retval == Self::zero() || retval == Self::one()) as u8) } /// Determines the 'sign' of a value in the base field, /// see for more details pub fn sgn0(&self) -> Choice { - let a = *self % Self::from(2u64); + let a = dbg!(*self % Self::from(2u64)); if a.is_zero() { Choice::from(0u8) } else { From 003c8da01ef5a9270f53b228fbb1ed9ef130da3b Mon Sep 17 00:00:00 2001 From: Mike Rolish Date: Tue, 20 Aug 2024 16:11:56 -0500 Subject: [PATCH 09/14] review fixes --- Cargo.toml | 1 - examples/dkg.rs | 4 ++-- examples/dkg.toml | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c31c123..555e21a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,4 +33,3 @@ sha2 = "0.11.0-pre.4" tracing-subscriber = "0.3.18" tracing = "0.1.40" confy = "0.6.1" -rand = "0.9.0-alpha.2" diff --git a/examples/dkg.rs b/examples/dkg.rs index d532631..458b468 100644 --- a/examples/dkg.rs +++ b/examples/dkg.rs @@ -8,7 +8,7 @@ use std::path::PathBuf; use sylow::{FieldExtensionTrait, Fp}; use tracing::{event, Level}; -const GENERATOR: Fp = Fp::new(U256::from_u64(3u64)); +const GENERATOR: Fp = Fp::THREE; // TODO: Bounding coefficients until we address exponent modulo arithmetic const MIN_COEFFICIENT: u64 = 1; @@ -109,7 +109,7 @@ impl DealerShare { } fn eval_commitments(&self) -> Fp { - let mut val = Fp::one(); + let mut val = Fp::ONE; for (j, cmt_j) in self.commitments.iter().enumerate() { val *= cmt_j.pow(self.x.pow(U256::from_u64(j as u64)).value()); } diff --git a/examples/dkg.toml b/examples/dkg.toml index 0cc985d..8e1e631 100644 --- a/examples/dkg.toml +++ b/examples/dkg.toml @@ -1 +1 @@ -quorum = 5 \ No newline at end of file +quorum = 5 From 4d2f53127999fee4521360862edc9e40c552364c Mon Sep 17 00:00:00 2001 From: Mike Rolish Date: Tue, 20 Aug 2024 16:33:36 -0500 Subject: [PATCH 10/14] Add Eq/Hash for Fp to support use as hash key --- examples/dkg.rs | 4 ++-- src/fields/fp.rs | 7 ++++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/examples/dkg.rs b/examples/dkg.rs index 458b468..34f507c 100644 --- a/examples/dkg.rs +++ b/examples/dkg.rs @@ -20,10 +20,10 @@ fn generate_distinct_random_values(count: usize, min: u64, max: u64) -> Vec while values.len() < count { let value = >::rand(&mut OsRng) % Fp::from(max) + Fp::from(min); - values.insert(value.value()); + values.insert(value); } - values.into_iter().map(Fp::new).collect() + values.into_iter().collect() } #[allow(dead_code)] diff --git a/src/fields/fp.rs b/src/fields/fp.rs index e76c21c..2fe7ee4 100644 --- a/src/fields/fp.rs +++ b/src/fields/fp.rs @@ -133,7 +133,7 @@ macro_rules! define_finite_prime_field { //special struct for const-time arithmetic on montgomery form integers mod p type $output = crypto_bigint::modular::ConstMontyForm<$mod_struct, { $mod_struct::LIMBS }>; - #[derive(Clone, Copy)] //to be used in const contexts + #[derive(Clone, Copy, Eq)] //to be used in const contexts /// This is the actual struct that serves as our finite field implementation, containing /// the modulus of the field, as well as the output type that contains the internal /// Montgomery arithmetic logic @@ -408,6 +408,11 @@ macro_rules! define_finite_prime_field { .finish() } } + impl std::hash::Hash for $wrapper_name { + fn hash(&self, state: &mut H) { + self.value().hash(state); + } + } }; } From de8b2b24e6730e67ec58d3597af15f7b47a4a0b7 Mon Sep 17 00:00:00 2001 From: Mike Rolish Date: Wed, 21 Aug 2024 09:54:59 -0500 Subject: [PATCH 11/14] More tracing --- Cargo.toml | 2 +- src/fields/fp.rs | 32 +++++++++++++++++++------------- src/fields/fp12.rs | 19 +++++++++++++++++++ src/fields/fp2.rs | 3 +++ src/fields/fp6.rs | 3 +++ src/groups/g1.rs | 9 +++++++++ src/groups/g2.rs | 5 +++++ src/lib.rs | 2 +- 8 files changed, 60 insertions(+), 15 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 555e21a..dc63840 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ subtle = "2.6.1" crypto-bigint = "0.6.0-rc.2" sha3 = "0.11.0-pre.4" lazy_static = "1.5.0" - +tracing = "0.1.40" [dev-dependencies] hex-literal = "0.4.1" diff --git a/src/fields/fp.rs b/src/fields/fp.rs index 2fe7ee4..e93bcbc 100644 --- a/src/fields/fp.rs +++ b/src/fields/fp.rs @@ -133,7 +133,8 @@ macro_rules! define_finite_prime_field { //special struct for const-time arithmetic on montgomery form integers mod p type $output = crypto_bigint::modular::ConstMontyForm<$mod_struct, { $mod_struct::LIMBS }>; - #[derive(Clone, Copy, Eq)] //to be used in const contexts + #[derive(Clone, Copy)] //to be used in const contexts + #[derive(Eq)] /// This is the actual struct that serves as our finite field implementation, containing /// the modulus of the field, as well as the output type that contains the internal /// Montgomery arithmetic logic @@ -374,14 +375,14 @@ macro_rules! define_finite_prime_field { if other.is_zero() { return Self::from(0u64); } - let (mut _q, mut _r) = dbg!(self + let (mut _q, mut _r) = self .1 .retrieve() - .div_rem(&NonZero::<$uint_type>::new(other.1.retrieve()).unwrap())); + .div_rem(&NonZero::<$uint_type>::new(other.1.retrieve()).unwrap()); if self.1.retrieve().bit(255).into() { - _q = dbg!(_q - <$uint_type>::ONE); - _r = dbg!(other.1.retrieve() - _r); + _q = _q - <$uint_type>::ONE; + _r = other.1.retrieve() - _r; } Self::new(_q) } @@ -389,14 +390,16 @@ macro_rules! define_finite_prime_field { if other.is_zero() { return Self::from(0u64); } - let (mut _q, mut _r) = dbg!(self + let (mut _q, mut _r) = self .1 .retrieve() - .div_rem(&NonZero::<$uint_type>::new(other.1.retrieve()).unwrap())); + .div_rem(&NonZero::<$uint_type>::new(other.1.retrieve()).unwrap()); + tracing::debug!(?_q, ?_r, "finite_prime_field::rem_euclid"); if self.1.retrieve().bit(255).into() { // _q = _q - <$uint_type>::ONE; - _r = dbg!(other.1.retrieve() - _r); + _r = other.1.retrieve() - _r; + tracing::debug!(?_r, "finite_prime_field::rem_euclid high bit"); } Self::new(_r) } @@ -469,8 +472,9 @@ impl Fp { /// possible solution of $\pm pow(n, \frac{p+1}{4})$, which is where this magic /// number below comes from ;) pub fn sqrt(&self) -> CtOption { - let arg = dbg!((Self::new(Self::characteristic()) + Self::one()) / Self::from(4)).value(); - let sqrt = dbg!(self.pow(arg)); + let arg = ((Self::new(Self::characteristic()) + Self::one()) / Self::from(4)).value(); + let sqrt = self.pow(arg); + tracing::debug!(?arg, ?sqrt, "Fp::sqrt"); CtOption::new(sqrt, sqrt.square().ct_eq(self)) } /// Returns the square of the element in the base field @@ -480,14 +484,16 @@ impl Fp { /// Determines if the element in the base field is a square of another element pub fn is_square(&self) -> Choice { let p_minus_1_div_2 = - dbg!((Self::new(Self::characteristic()) - Self::from(1)) / Self::from(2)).value(); - let retval = dbg!(self.pow(p_minus_1_div_2)); + ((Self::new(Self::characteristic()) - Self::from(1)) / Self::from(2)).value(); + let retval = self.pow(p_minus_1_div_2); + tracing::debug!(?p_minus_1_div_2, ?retval, "Fp::is_square"); Choice::from((retval == Self::zero() || retval == Self::one()) as u8) } /// Determines the 'sign' of a value in the base field, /// see for more details pub fn sgn0(&self) -> Choice { - let a = dbg!(*self % Self::from(2u64)); + let a = *self % Self::from(2u64); + tracing::debug!(?a, "Fp::sgn0"); if a.is_zero() { Choice::from(0u8) } else { diff --git a/src/fields/fp12.rs b/src/fields/fp12.rs index c3d42a8..2a4d3b4 100644 --- a/src/fields/fp12.rs +++ b/src/fields/fp12.rs @@ -201,6 +201,7 @@ impl<'a, 'b> Mul<&'b Fp12> for &'a Fp12 { // let t0 = self.0[0] * other.0[0]; let t1 = self.0[1] * other.0[1]; + tracing::debug!(?t0, ?t1, "Fp12::mul"); Self::Output::new(&[ t1.residue_mul() + t0, @@ -224,6 +225,7 @@ impl Inv for Fp12 { fn inv(self) -> Self::Output { // Implements Alg 23 of let tmp = (self.0[0].square() - (self.0[1].square().residue_mul())).inv(); + tracing::debug!(?tmp, "Fp12::inv"); Self([self.0[0] * tmp, -(self.0[1] * tmp)]) } } @@ -304,10 +306,12 @@ impl Fp12 { let z3 = self.0[1].0[0]; let z4 = self.0[1].0[1]; let z5 = self.0[1].0[2]; + tracing::debug!(?z0, ?z1, ?z2, ?z3, ?z4, ?z5, "Fp12::sparse_mul"); let x0 = ell_0; let x2 = ell_vv; let x4 = ell_vw; + tracing::debug!(?x0, ?x2, ?x4, "Fp12::sparse_mul"); let d0 = z0 * x0; let d2 = z2 * x2; @@ -315,49 +319,61 @@ impl Fp12 { let t2 = z0 + z4; let t1 = z0 + z2; let s0 = z1 + z3 + z5; + tracing::debug!(?d0, ?d2, ?d4, ?t2, ?t1, ?s0, "Fp12::sparse_mul"); let s1 = z1 * x2; let t3 = s1 + d4; let t4 = t3.residue_mul() + d0; let z0 = t4; + tracing::debug!(?s1, ?t2, ?t4, ?z0, "Fp12::sparse_mul"); let t3 = z5 * x4; let s1 = s1 + t3; + tracing::debug!(?t3, ?s1, "Fp12::sparse_mul"); let t3 = t3 + d2; let t4 = t3.residue_mul(); + tracing::debug!(?t3, ?t4, "Fp12::sparse_mul"); let t3 = z1 * x0; let s1 = s1 + t3; let t4 = t4 + t3; let z1 = t4; + tracing::debug!(?t3, ?s1, ?t4, ?z1, "Fp12::sparse_mul"); let t0 = x0 + x2; let t3 = t1 * t0 - d0 - d2; let t4 = z3 * x4; let s1 = s1 + t4; let t3 = t3 + t4; + tracing::debug!(?t0, ?t3, ?t4, ?s1, ?t3, "Fp12::sparse_mul"); let t0 = z2 + z4; let z2 = t3; + tracing::debug!(?t0, ?z2, "Fp12::sparse_mul"); let t1 = x2 + x4; let t3 = t0 * t1 - d2 - d4; let t4 = t3.residue_mul(); + tracing::debug!(?t1, ?t3, ?t4, "Fp12::sparse_mul"); let t3 = z3 * x0; let s1 = s1 + t3; let t4 = t4 + t3; let z3 = t4; + tracing::debug!(?t3, ?s1, ?t4, ?z3, "Fp12::sparse_mul"); let t3 = z5 * x2; let s1 = s1 + t3; let t4 = t3.residue_mul(); let t0 = x0 + x4; + tracing::debug!(?t3, ?s1, ?t4, ?t0, "Fp12::sparse_mul"); let t3 = t2 * t0 - d0 - d4; let t4 = t4 + t3; let z4 = t4; + tracing::debug!(?t3, ?t4, ?z4, "Fp12::sparse_mul"); let t0 = x0 + x2 + x4; let t3 = s0 * t0 - s1; let z5 = t3; + tracing::debug!(?t0, ?t3, ?z5, "Fp12::sparse_mul"); Fp12::new(&[Fp6::new(&[z0, z1, z2]), Fp6::new(&[z3, z4, z5])]) } @@ -376,10 +392,13 @@ impl Fp12 { let c0 = self.0[0] - self.0[1]; let c3 = self.0[0] - self.0[1].residue_mul(); let c2 = self.0[0] * self.0[1]; + tracing::debug!(?c0, ?c2, ?c3, "Fp12::square 1"); let c0 = c0 * c3 + c2; let c1 = c2 + c2; let c2 = c2.residue_mul(); + tracing::debug!(?c0, ?c1, ?c2, "Fp12::square 2"); let c0 = c0 + c2; + tracing::debug!(?c0, "Fp12::square 3"); Self::new(&[c0, c1]) } } diff --git a/src/fields/fp2.rs b/src/fields/fp2.rs index d7c1acb..dcb2ba8 100644 --- a/src/fields/fp2.rs +++ b/src/fields/fp2.rs @@ -101,6 +101,7 @@ impl Fp2 { if a0 == -Fp2::one() { return CtOption::new(Fp2::zero(), Choice::from(0u8)); } + tracing::debug!(?alpha, ?a0, "Fp2::sqrt"); if alpha == -Fp2::one() { let i = Fp2::new(&[Fp::ZERO, Fp::ONE]); @@ -114,6 +115,7 @@ impl Fp2 { } pub fn square(&self) -> Self { let t0 = self.0[0] * self.0[1]; + tracing::debug!(?t0, "Fp2::square"); Self([ (self.0[1] * >::quadratic_non_residue() + self.0[0]) * (self.0[0] + self.0[1]) @@ -136,6 +138,7 @@ impl Fp2 { }; let sum = self.0[0].square() + >::quadratic_non_residue() * (-self.0[0]).square(); + tracing::debug!(?sum, "Fp2::is_square"); Choice::from((legendre(&sum) != -1) as u8) } pub fn sgn0(&self) -> Choice { diff --git a/src/fields/fp6.rs b/src/fields/fp6.rs index 7da0f74..ca98fb1 100644 --- a/src/fields/fp6.rs +++ b/src/fields/fp6.rs @@ -199,6 +199,7 @@ impl Fp6 { let s3 = bc + bc; let mut s4 = self.0[2]; s4 = s4.square(); + tracing::debug!(?t0, ?cross, ?t1, ?t2, ?bc, ?s3, ?s4, "Fp6::square"); Self([ t0 + s3.residue_mul(), @@ -231,6 +232,7 @@ impl<'a, 'b> Mul<&'b Fp6> for &'a Fp6 { let t0 = self.0[0] * other.0[0]; let t1 = self.0[1] * other.0[1]; let t2 = self.0[2] * other.0[2]; + tracing::debug!(?t0, ?t1, ?t2, "Fp6::mul"); Self::Output::new(&[ ((self.0[1] + self.0[2]) * (other.0[1] + other.0[2]) - t1 - t2).residue_mul() + t0, @@ -260,6 +262,7 @@ impl Inv for Fp6 { let t2 = self.0[1].square() - self.0[0] * self.0[2]; let inverse = ((self.0[2] * t1 + self.0[1] * t2).residue_mul() + self.0[0] * t0).inv(); + tracing::debug!(?t0, ?t1, ?t2, ?inverse, "Fp6::inv"); Self([inverse * t0, inverse * t1, inverse * t2]) } } diff --git a/src/groups/g1.rs b/src/groups/g1.rs index 77a43ec..39c0390 100644 --- a/src/groups/g1.rs +++ b/src/groups/g1.rs @@ -77,6 +77,7 @@ impl G1Affine { let x2 = x.square(); let lhs = y2 - (x2 * (*x)); let rhs = >::curve_constant(); + tracing::debug!(?y2, ?x2, ?lhs, ?rhs, "G1Affine::new"); lhs.ct_eq(&rhs) | *z }; @@ -85,10 +86,12 @@ impl G1Affine { Choice::from(1u8) }; let is_on_curve: Choice = _g1affine_is_on_curve(&v[0], &v[1], &Choice::from(0u8)); + tracing::debug!(?is_on_curve, "G1Affine::new"); match bool::from(is_on_curve) { true => { let is_in_torsion: Choice = _g1affine_is_torsion_free(&v[0], &v[1], &Choice::from(0u8)); + tracing::debug!(?is_in_torsion, "G1Affine::new"); match bool::from(is_in_torsion) { true => Ok(Self { x: v[0], @@ -123,6 +126,7 @@ impl GroupTrait<1, 1, Fp> for G1Projective { let scalars = exp .hash_to_field(msg, COUNT, L) .expect("Hashing to base field failed"); + tracing::debug!(?scalars, "GroupTrait::hash_to_curve"); match SvdW::precompute_constants(Fp::from(0), Fp::from(3)) { Ok(bn254_g1_svdw) => { let a = G1Projective::from( @@ -135,6 +139,7 @@ impl GroupTrait<1, 1, Fp> for G1Projective { .unchecked_map_to_point(scalars[1]) .expect("Failed to hash"), ); + tracing::debug!(?a, ?b, "GroupTrait::hash_to_curve"); Ok(a + b) } _ => Err(GroupError::CannotHashToGroup), @@ -151,6 +156,7 @@ impl GroupTrait<1, 1, Fp> for G1Projective { .iter() .map(|x| x.frobenius(exponent)) .collect(); + tracing::debug!(?vec, "GroupTrait::frobenius"); Self { x: vec[0], y: vec[1], @@ -171,14 +177,17 @@ impl G1Projective { let z2 = z.square(); let lhs = y2 * (*z); let rhs = x2 * (*x) + z2 * (*z) * >::curve_constant(); + tracing::debug!(?y2, ?x2, ?z2, ?lhs, ?rhs, "G1Projective::new"); lhs.ct_eq(&rhs) | Choice::from(z.is_zero() as u8) }; let _g1projective_is_torsion_free = |_x: &Fp, _y: &Fp, _z: &Fp| -> Choice { Choice::from(1u8) }; let is_on_curve: Choice = _g1projective_is_on_curve(&v[0], &v[1], &v[2]); + tracing::debug!(?is_on_curve, "G1Projective::new"); match bool::from(is_on_curve) { true => { let is_in_torsion: Choice = _g1projective_is_torsion_free(&v[0], &v[1], &v[2]); + tracing::debug!(?is_in_torsion, "G1Projective::new"); match bool::from(is_in_torsion) { true => Ok(Self { x: v[0], diff --git a/src/groups/g2.rs b/src/groups/g2.rs index a833e28..5bfd715 100644 --- a/src/groups/g2.rs +++ b/src/groups/g2.rs @@ -117,6 +117,7 @@ impl GroupTrait<2, 2, Fp2> for G2Affine { let x_endo = EPS_EXP0 * x_frob; let y_endo = EPS_EXP1 * y_frob; + tracing::debug!(?x_frob, ?y_frob, ?x_endo, ?y_endo, "G2Affine::endomorphism"); Self::new_unchecked([x_endo, y_endo]).expect("Endomorphism failed") } @@ -177,6 +178,7 @@ impl GroupTrait<2, 2, Fp2> for G2Projective { ])); let rando = Fp::new(Fr::rand(rng).value()); let mut tmp = Self::generator() * rando; + tracing::debug!(?rando, ?tmp, "G2Projective::rand"); // multiplying an element of the larger base field by the cofactor of a prime-ordered // subgroup will return an element in the prime-order subgroup, see @@ -222,6 +224,7 @@ impl G2Affine { let x2 = x.square(); let lhs = y2 - (x2 * (*x)); let rhs = >::curve_constant(); + tracing::debug!(?y2, ?x2, ?lhs, ?rhs, "G2Affine::new_unchecked"); lhs.ct_eq(&rhs) | *z }; @@ -250,6 +253,7 @@ impl G2Projective { let z2 = z.square(); let lhs = y2 * (*z); let rhs = x2 * (*x) + z2 * (*z) * >::curve_constant(); + tracing::debug!(?y2, ?x2, ?z2, ?lhs, ?rhs, "G2Projective::new"); lhs.ct_eq(&rhs) | Choice::from(z.is_zero() as u8) }; // This method is where the magic happens. In a naïve approach, in order to check for @@ -287,6 +291,7 @@ impl G2Projective { let mut rhs = b.endomorphism(); // ψ^2(xQ) let lhs = rhs + b + a; // ψ^2(xQ) + ψ(xQ) + (x+1)Q rhs = rhs.endomorphism().double() - lhs; // ψ^3(2xQ) - (ψ^2(xQ) + ψ(xQ) + (x+1)Q) + tracing::debug!(?x, ?y, ?z, ?a, ?b, ?lhs, ?rhs, "G2Projective::_g2projective_is_torsion_free"); // we do two checks: one is to verify that the result is indeed a point at infinity, // but we need a second check to verify that it is OUR point at infinity, namely for diff --git a/src/lib.rs b/src/lib.rs index e83b105..03c1689 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -64,7 +64,7 @@ pub fn sign(k: &Fp, msg: &[u8]) -> Result { } } -/// This takes a pub lic key, message, and a signature, and verifies that the signature is valid +/// This takes a public key, message, and a signature, and verifies that the signature is valid pub fn verify(pubkey: &G2Projective, msg: &[u8], sig: &G1Projective) -> Result { let expander = XMDExpander::::new(DST, SECURITY_BITS); match G1Projective::hash_to_curve(&expander, msg) { From 6a87548685d06ced49c8e24f5e33530eafe98094 Mon Sep 17 00:00:00 2001 From: Mike Rolish Date: Wed, 21 Aug 2024 14:07:27 -0500 Subject: [PATCH 12/14] fix, yet more tracing --- src/fields/fp.rs | 3 +-- src/groups/g2.rs | 11 ++++++++++- src/groups/group.rs | 16 ++++++++++++++++ src/hasher.rs | 13 +++++++++++++ src/pairing.rs | 36 ++++++++++++++++++++++++++++++++++++ src/svdw.rs | 18 ++++++++++++++++++ 6 files changed, 94 insertions(+), 3 deletions(-) diff --git a/src/fields/fp.rs b/src/fields/fp.rs index e93bcbc..bfd0794 100644 --- a/src/fields/fp.rs +++ b/src/fields/fp.rs @@ -133,8 +133,7 @@ macro_rules! define_finite_prime_field { //special struct for const-time arithmetic on montgomery form integers mod p type $output = crypto_bigint::modular::ConstMontyForm<$mod_struct, { $mod_struct::LIMBS }>; - #[derive(Clone, Copy)] //to be used in const contexts - #[derive(Eq)] + #[derive(Clone, Copy, Eq)] //Clone and Copy to be used in const contexts /// This is the actual struct that serves as our finite field implementation, containing /// the modulus of the field, as well as the output type that contains the internal /// Montgomery arithmetic logic diff --git a/src/groups/g2.rs b/src/groups/g2.rs index 5bfd715..412b0cb 100644 --- a/src/groups/g2.rs +++ b/src/groups/g2.rs @@ -291,7 +291,16 @@ impl G2Projective { let mut rhs = b.endomorphism(); // ψ^2(xQ) let lhs = rhs + b + a; // ψ^2(xQ) + ψ(xQ) + (x+1)Q rhs = rhs.endomorphism().double() - lhs; // ψ^3(2xQ) - (ψ^2(xQ) + ψ(xQ) + (x+1)Q) - tracing::debug!(?x, ?y, ?z, ?a, ?b, ?lhs, ?rhs, "G2Projective::_g2projective_is_torsion_free"); + tracing::debug!( + ?x, + ?y, + ?z, + ?a, + ?b, + ?lhs, + ?rhs, + "G2Projective::_g2projective_is_torsion_free" + ); // we do two checks: one is to verify that the result is indeed a point at infinity, // but we need a second check to verify that it is OUR point at infinity, namely for diff --git a/src/groups/group.rs b/src/groups/group.rs index 0b61c30..ec04fcd 100644 --- a/src/groups/group.rs +++ b/src/groups/group.rs @@ -250,28 +250,34 @@ impl> GroupProjecti let t0 = self.y * self.y; let z3 = t0 + t0; let z3 = z3 + z3; + tracing::debug!(?t0, ?z3, "GroupProjective::double 1"); let z3 = z3 + z3; let t1 = self.y * self.z; let t2 = self.z * self.z; + tracing::debug!(?z3, ?t1, ?t2, "GroupProjective::double 2"); // the magic 3 below is an artifact directly from the algorithm itself, // see the main text in Ref (1) Alg. (9) let t2 = F::from(3) * F::curve_constant() * t2; let x3 = t2 * z3; let y3 = t0 + t2; + tracing::debug!(?t2, ?x3, ?y3, "GroupProjective::double 3"); let z3 = t1 * z3; let t1 = t2 + t2; let t2 = t1 + t2; + tracing::debug!(?z3, ?t1, ?t2, "GroupProjective::double 3"); let t0 = t0 - t2; let y3 = t0 * y3; let y3 = x3 + y3; + tracing::debug!(?t0, ?y3, "GroupProjective::double 4"); let t1 = self.x * self.y; let x3 = t0 * t1; let x3 = x3 + x3; + tracing::debug!(?t1, ?x3, "GroupProjective::double 5"); Self::conditional_select( &Self { x: x3, @@ -316,6 +322,7 @@ impl> ConstantTimeE let y0 = self.y * other.z; let y1 = other.y * self.z; + tracing::debug!(?x0, ?x1, ?y0, ?y1, "GroupProjective::ct_eq"); let i_am_zero = self.z.is_zero(); let you_are_zero = other.z.is_zero(); @@ -354,6 +361,7 @@ impl<'a, const D: usize, const N: usize, F: FieldExtensionTrait> let inverse = arg.z.inv(); // this is either a good value or zero, see `inv` in `fp.rs` let x = arg.x * inverse; let y = arg.y * inverse; + tracing::debug!(?x, ?y, "GroupAffine::from(GroupProjective)"); GroupAffine::conditional_select( &GroupAffine { @@ -407,26 +415,32 @@ impl<'a, 'b, const D: usize, const N: usize, F: FieldExtensionTrait> let t0 = self.x * other.x; let t1 = self.y * other.y; let t2 = self.z * other.z; + tracing::debug!(?t0, ?t1, ?t1, "GroupProjective::add 1"); let t3 = self.x + self.y; let t4 = other.x + other.y; let t3 = t3 * t4; + tracing::debug!(?t3, ?t4, "GroupProjective::add 2"); let t4 = t0 + t1; let t3 = t3 - t4; let t4 = self.y + self.z; + tracing::debug!(?t3, ?t4, "GroupProjective::add 3"); let x3 = other.y + other.z; let t4 = t4 * x3; let x3 = t1 + t2; + tracing::debug!(?x3, ?t4, "GroupProjective::add 4"); let t4 = t4 - x3; let x3 = self.x + self.z; let y3 = other.x + other.z; + tracing::debug!(?t4, ?x3, ?y3, "GroupProjective::add 5"); let x3 = x3 * y3; let y3 = t0 + t2; let y3 = x3 - y3; + tracing::debug!(?x3, ?y3, "GroupProjective::add 6"); // again, the magic 3 below is an artifact from the algorithm itself, // see the main text of Ref (1) Alg. (7) above @@ -437,6 +451,7 @@ impl<'a, 'b, const D: usize, const N: usize, F: FieldExtensionTrait> let z3 = t1 + t2; let t1 = t1 - t2; let y3 = F::from(3) * F::curve_constant() * y3; + tracing::debug!(?x3, ?t0, ?t2, ?z3, ?t1, ?y3, "GroupProjective::add 7"); let x3 = t4 * y3; let t2 = t3 * t1; @@ -449,6 +464,7 @@ impl<'a, 'b, const D: usize, const N: usize, F: FieldExtensionTrait> let t0 = t0 * t3; let z3 = z3 * t4; let z3 = z3 + t0; + tracing::debug!(?x3, ?t2, ?y3, ?t1, ?t0, ?z3, "GroupProjective::add 8"); Self::Output { x: x3, y: y3, diff --git a/src/hasher.rs b/src/hasher.rs index f892d67..02ff437 100644 --- a/src/hasher.rs +++ b/src/hasher.rs @@ -85,6 +85,16 @@ pub trait Expander { .map_err(|_e: TryFromSliceError| HashError::CastToField)?, ); *f = Fp::new(scalar); + tracing::debug!( + ?i, + ?f, + ?tv, + ?bs, + ?cast_value, + ?modulus, + ?scalar, + "Expander::hash_to_field" + ); } Ok(retval) } @@ -135,6 +145,7 @@ impl Expander for XMDExpander { &i2osp(self.dst_prime.len() as u64, 1)?, ] .concat(); + tracing::debug!(?ell, ?dst_prime, "XMDExpander::expand_message"); if 8 * b_in_bytes < 2 * self.security_param as usize || ell > 255 || dst_prime.len() != self.dst_prime.len() + 1 @@ -155,6 +166,7 @@ impl Expander for XMDExpander { .chain(dst_prime.iter()) .finalize_fixed() .to_vec(); + tracing::debug!(?z_pad, ?l_i_b_str, ?b_vals, "XMDExpander::expand_message"); for i in 1..ell { let xored: Vec = b_0 @@ -169,6 +181,7 @@ impl Expander for XMDExpander { .cloned() .collect(); b_vals[i] = D::default().chain(b_i).finalize_fixed().to_vec(); + tracing::debug!(?xored, b_vals_i = ?b_vals[i], "XMDExpander::expand_message"); } Ok(b_vals.into_iter().flatten().take(len_in_bytes).collect()) diff --git a/src/pairing.rs b/src/pairing.rs index c94a3d7..2c58a10 100644 --- a/src/pairing.rs +++ b/src/pairing.rs @@ -109,6 +109,7 @@ impl MillerLoopResult { let t1 = b.square(); // Line 3 let c0 = t1.residue_mul(); + tracing::debug!(?t0, ?t1, ?c0, "MillerLoopResult::fp4_square"); // Line 4 let c0 = c0 + t0; // Line 5 @@ -130,6 +131,7 @@ impl MillerLoopResult { let mut z5 = f.0[1].0[2]; // Line 9 let (t0, t1) = fp4_square(z0, z1); + tracing::debug!(?t0, ?t1, "MillerLoopResult::cyclotonic_squared"); // Line 13-22 for A z0 = t0 - z0; z0 = z0 + z0 + t0; @@ -139,6 +141,7 @@ impl MillerLoopResult { let (mut t0, t1) = fp4_square(z2, z3); let (t2, t3) = fp4_square(z4, z5); + tracing::debug!(?t0, ?t1, ?t2, ?t3, "MillerLoopResult::cyclotonic_squared"); // Lines 25-31, for C z4 = t0 - z4; @@ -220,6 +223,30 @@ impl MillerLoopResult { let s = input.unitary_inverse(); let t = s * l; let u = t.frobenius(3); + tracing::debug!( + ?a, + ?b, + ?c, + ?d, + ?e, + ?f, + ?g, + ?h, + ?i, + ?j, + ?k, + ?l, + ?m, + ?n, + ?o, + ?p, + ?q, + ?r, + ?s, + ?t, + ?u, + "MillerLoopResult::hard_part" + ); u * r } @@ -265,20 +292,24 @@ impl G2PreComputed { let c = &self.coeffs[idx]; idx += 1; f = f.square().sparse_mul(c.0, c.1.scale(g1.y), c.2.scale(g1.x)); + tracing::debug!(?idx, ?f, "G2PreComputed::miller_loop"); if *i != 0 { let c = &self.coeffs[idx]; idx += 1; f = f.sparse_mul(c.0, c.1.scale(g1.y), c.2.scale(g1.x)); + tracing::debug!(?idx, ?f, "G2PreComputed::miller_loop"); } } let c = &self.coeffs[idx]; idx += 1; f = f.sparse_mul(c.0, c.1.scale(g1.y), c.2.scale(g1.x)); + tracing::debug!(?idx, ?f, "G2PreComputed::miller_loop"); let c = &self.coeffs[idx]; f = f.sparse_mul(c.0, c.1.scale(g1.y), c.2.scale(g1.x)); + tracing::debug!(?idx, ?f, "G2PreComputed::miller_loop"); MillerLoopResult(f) } @@ -343,6 +374,7 @@ impl G2Projective { let h = d * f; let i = self.x * f; let j = self.z * g + h - (i + i); + tracing::debug!(?d, ?e, ?f, ?g, ?h, ?i, ?j, "G2Projective::addition_step"); self.x = d * j; self.y = e * (i - j) - h * self.y; @@ -366,6 +398,7 @@ impl G2Projective { let i = e - b; let j = self.x.square(); let e_sq = e.square(); + tracing::debug!(?f, ?g, ?h, ?i, ?j, ?e_sq, "G2Projective::doubling_step"); self.x = a * (b - f); self.y = g.square() - (e_sq + e_sq + e_sq); @@ -394,6 +427,7 @@ pub fn pairing(p: &G1Projective, q: &G2Projective) -> Gt { let q = G2Affine::conditional_select(q, &G2Affine::generator(), either_zero); let tmp = q.precompute().miller_loop(&p).0; let tmp = MillerLoopResult(Fp12::conditional_select(&tmp, &Fp12::one(), either_zero)); + tracing::debug!(?p, ?q, ?tmp, "pairing"); tmp.final_exponentiation() } @@ -423,11 +457,13 @@ pub fn glued_miller_loop(g2_precomps: &[G2PreComputed], g1s: &[G1Affine]) -> Mil idx += 1; } } + tracing::debug!(?f, "glued_miller_loop 1"); for (g2_precompute, g1) in g2_precomps.iter().zip(g1s.iter()) { let c = &g2_precompute.coeffs[idx]; f = f.sparse_mul(c.0, c.1.scale(g1.y), c.2.scale(g1.x)); } + tracing::debug!(?f, "glued_miller_loop 2"); idx += 1; for (g2_precompute, g1) in g2_precomps.iter().zip(g1s.iter()) { let c = &g2_precompute.coeffs[idx]; diff --git a/src/svdw.rs b/src/svdw.rs index 66d1d86..4f22e5c 100644 --- a/src/svdw.rs +++ b/src/svdw.rs @@ -161,6 +161,24 @@ impl SvdWTrait for SvdW { }; let e3 = Choice::from((bool::from(u.sgn0()) == bool::from(y.sgn0())) as u8); let y = cmov(&(-y), &y, &e3); // Select correct sign of y; + tracing::debug!( + ?tv1, + ?tv2, + ?tv3, + ?tv4, + ?x1, + ?gx1, + ?e1, + ?x2, + ?gx2, + ?e2, + ?x3, + ?x, + ?gx, + ?y, + ?e3, + "SvdW::unchecked_map_to_point" + ); Ok([x, y]) } } From 82426c69975abfd4046f908d52275a5b4aca6c23 Mon Sep 17 00:00:00 2001 From: Mike Rolish Date: Wed, 21 Aug 2024 15:08:57 -0500 Subject: [PATCH 13/14] typo fix --- src/pairing.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pairing.rs b/src/pairing.rs index 2c58a10..f80a30c 100644 --- a/src/pairing.rs +++ b/src/pairing.rs @@ -131,7 +131,7 @@ impl MillerLoopResult { let mut z5 = f.0[1].0[2]; // Line 9 let (t0, t1) = fp4_square(z0, z1); - tracing::debug!(?t0, ?t1, "MillerLoopResult::cyclotonic_squared"); + tracing::debug!(?t0, ?t1, "MillerLoopResult::cyclotomic_squared"); // Line 13-22 for A z0 = t0 - z0; z0 = z0 + z0 + t0; @@ -141,7 +141,7 @@ impl MillerLoopResult { let (mut t0, t1) = fp4_square(z2, z3); let (t2, t3) = fp4_square(z4, z5); - tracing::debug!(?t0, ?t1, ?t2, ?t3, "MillerLoopResult::cyclotonic_squared"); + tracing::debug!(?t0, ?t1, ?t2, ?t3, "MillerLoopResult::cyclotomic_squared"); // Lines 25-31, for C z4 = t0 - z4; From d303b0b64ba4cc0be1ec242150254bfe6eda12fb Mon Sep 17 00:00:00 2001 From: Mike Rolish Date: Wed, 21 Aug 2024 16:04:00 -0500 Subject: [PATCH 14/14] Remove unused fields from example --- examples/dkg.rs | 38 +++++--------------------------------- 1 file changed, 5 insertions(+), 33 deletions(-) diff --git a/examples/dkg.rs b/examples/dkg.rs index 34f507c..ed80e0b 100644 --- a/examples/dkg.rs +++ b/examples/dkg.rs @@ -26,67 +26,46 @@ fn generate_distinct_random_values(count: usize, min: u64, max: u64) -> Vec values.into_iter().collect() } -#[allow(dead_code)] struct DealerSecret { - quorum: u32, - round_id: u64, + // polynomial coefficients; coefficients[0] is the secret a_0 coefficients: Vec, - secret: Fp, commitments: Vec, } impl DealerSecret { - fn new(quorum: u32, round_id: u64) -> Self { + fn new(quorum: u32) -> Self { let coefficients = generate_distinct_random_values(quorum as usize, MIN_COEFFICIENT, MAX_COEFFICIENT); - let secret = coefficients[0]; let commitments = coefficients .iter() .map(|c| GENERATOR.pow(c.value())) .collect(); DealerSecret { - quorum, - round_id, coefficients, - secret, commitments, } } - fn new_bad(quorum: u32, round_id: u64) -> Self { + fn new_bad(quorum: u32) -> Self { let coefficients = vec![Fp::from(42u64); quorum as usize]; - let secret = coefficients[0]; let commitments = vec![Fp::from(42u64); quorum as usize]; DealerSecret { - quorum, - round_id, coefficients, - secret, commitments, } } } -#[allow(dead_code)] struct DealerShare { - round_id: u64, - dealer_id: u64, commitments: Vec, x: Fp, y: Fp, } -#[allow(dead_code)] struct Participant { - participant_id: u64, - host: String, dealer_secret: DealerSecret, - dealer_shares: HashMap, } -#[allow(dead_code)] struct Round { - round_id: u64, - quorum: u32, participants: HashMap, } @@ -125,8 +104,6 @@ struct MyConfig { fn do_round(round_id: u64, quorum: u32) { event!(Level::INFO, "Begin round {round_id}"); let mut round_data = Round { - round_id, - quorum, participants: HashMap::new(), }; @@ -134,14 +111,11 @@ fn do_round(round_id: u64, quorum: u32) { let n_participants: u64 = (quorum + 2) as u64; for participant_id in 0u64..n_participants { let participant = Participant { - participant_id, - host: "some_host".to_string(), dealer_secret: if participant_id != (quorum + 1) as u64 { - DealerSecret::new(quorum, round_id) + DealerSecret::new(quorum) } else { - DealerSecret::new_bad(quorum, round_id) + DealerSecret::new_bad(quorum) }, - dealer_shares: HashMap::new(), }; round_data.participants.insert(participant_id, participant); } @@ -164,8 +138,6 @@ fn do_round(round_id: u64, quorum: u32) { let x_share = x_shares[recipient_index]; let y_share = dealer_secret.eval_polynomial(x_share); let share = DealerShare { - round_id, - dealer_id: *dealer_id, commitments: dealer_secret.commitments.clone(), x: x_share, y: y_share,