diff --git a/Cargo.lock b/Cargo.lock index 9c86cc9..21174db 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -416,7 +416,7 @@ dependencies = [ "itertools", "message-io", "rand", - "reddsa", + "reddsa 0.5.1 (git+https://github.com/ZcashFoundation/reddsa.git?rev=4d8c4bb337231e6e89117334d7c61dada589a953)", "reqwest", "serde_json", "server", @@ -579,7 +579,7 @@ dependencies = [ "itertools", "pipe", "rand", - "reddsa", + "reddsa 0.5.1 (git+https://github.com/ZcashFoundation/reddsa.git?rev=4d8c4bb337231e6e89117334d7c61dada589a953)", "serde_json", "thiserror", ] @@ -1415,7 +1415,7 @@ dependencies = [ "hex", "message-io", "rand", - "reddsa", + "reddsa 0.5.1 (git+https://github.com/ZcashFoundation/reddsa.git?rev=4d8c4bb337231e6e89117334d7c61dada589a953)", "reqwest", "serde_json", "server", @@ -1597,6 +1597,24 @@ dependencies = [ "zeroize", ] +[[package]] +name = "reddsa" +version = "0.5.1" +source = "git+https://github.com/ZcashFoundation/reddsa.git?rev=56a31af7099b95737031ef6cf251939ed99627c0#56a31af7099b95737031ef6cf251939ed99627c0" +dependencies = [ + "blake2b_simd", + "byteorder", + "frost-rerandomized", + "group", + "hex", + "jubjub", + "pasta_curves", + "rand_core", + "serde", + "thiserror", + "zeroize", +] + [[package]] name = "redox_syscall" version = "0.5.3" @@ -1935,7 +1953,7 @@ dependencies = [ "frost-ed25519", "frost-rerandomized", "rand", - "reddsa", + "reddsa 0.5.1 (git+https://github.com/ZcashFoundation/reddsa.git?rev=4d8c4bb337231e6e89117334d7c61dada589a953)", "regex", "reqwest", "serde", @@ -2152,7 +2170,7 @@ dependencies = [ "hex", "participant", "rand", - "reddsa", + "reddsa 0.5.1 (git+https://github.com/ZcashFoundation/reddsa.git?rev=4d8c4bb337231e6e89117334d7c61dada589a953)", "serde_json", "server", "tokio", @@ -2433,10 +2451,11 @@ dependencies = [ "exitcode", "frost-core", "frost-ed25519", + "frost-rerandomized", "hex", "itertools", "rand", - "reddsa", + "reddsa 0.5.1 (git+https://github.com/ZcashFoundation/reddsa.git?rev=56a31af7099b95737031ef6cf251939ed99627c0)", "serde_json", "thiserror", ] diff --git a/dkg/src/cli.rs b/dkg/src/cli.rs index 72b7d66..88e3ddb 100644 --- a/dkg/src/cli.rs +++ b/dkg/src/cli.rs @@ -1,12 +1,45 @@ +use frost_core::keys::{KeyPackage, PublicKeyPackage}; use frost_core::{self as frost, Ciphersuite}; use rand::thread_rng; +use reddsa::frost::redpallas::keys::EvenY; use std::collections::BTreeMap; use std::io::{BufRead, Write}; use crate::inputs::{read_round1_package, read_round2_package, request_inputs}; -pub fn cli( +// The redpallas ciphersuite, when used for generating Orchard spending key +// signatures, requires ensuring public key have an even Y coordinate. Since the +// code uses generics, this trait is used to convert if needed depending on the +// ciphersuite. +// +// If you are adding a new ciphersuite to this tool which does note require +// this, just implement it and the default implementation (which does nothing) +// will suffice. See below. +pub trait MaybeIntoEvenY: Ciphersuite { + fn into_even_y( + key_packages: (KeyPackage, PublicKeyPackage), + ) -> (KeyPackage, PublicKeyPackage) { + key_packages + } +} + +// A ciphersuite that does not need the conversion. +impl MaybeIntoEvenY for frost_ed25519::Ed25519Sha512 {} + +impl MaybeIntoEvenY for reddsa::frost::redpallas::PallasBlake2b512 { + fn into_even_y( + (key_package, public_key_package): (KeyPackage, PublicKeyPackage), + ) -> (KeyPackage, PublicKeyPackage) { + let is_even = public_key_package.has_even_y(); + ( + key_package.into_even_y(Some(is_even)), + public_key_package.into_even_y(Some(is_even)), + ) + } +} + +pub fn cli( reader: &mut impl BufRead, logger: &mut impl Write, ) -> Result<(), Box> { @@ -75,11 +108,11 @@ pub fn cli( writeln!(logger, "=== DKG FINISHED ===")?; - let (key_package, public_key_package) = frost::keys::dkg::part3( + let (key_package, public_key_package) = MaybeIntoEvenY::into_even_y(frost::keys::dkg::part3( &round2_secret_package, &received_round1_packages, &received_round2_packages, - )?; + )?); writeln!( logger, diff --git a/dkg/tests/integration_tests.rs b/dkg/tests/integration_tests.rs index 61cfd68..3d47487 100644 --- a/dkg/tests/integration_tests.rs +++ b/dkg/tests/integration_tests.rs @@ -1,6 +1,6 @@ use frost_core::{self as frost, Ciphersuite}; -use dkg::cli::cli; +use dkg::cli::{cli, MaybeIntoEvenY}; use std::collections::HashMap; use std::io::{BufRead, Write}; @@ -35,7 +35,7 @@ fn check_dkg() { } #[allow(clippy::needless_range_loop)] -fn check_dkg_for_ciphersuite() { +fn check_dkg_for_ciphersuite() { let mut input_writers = Vec::new(); let mut output_readers = Vec::new(); let mut join_handles = Vec::new(); diff --git a/trusted-dealer/Cargo.toml b/trusted-dealer/Cargo.toml index 082121b..841dd6d 100644 --- a/trusted-dealer/Cargo.toml +++ b/trusted-dealer/Cargo.toml @@ -7,8 +7,9 @@ edition = "2021" [dependencies] frost-core = { version = "2.0.0-rc.0", features = ["serde"] } +frost-rerandomized = { version = "2.0.0-rc.0", features = ["serde"] } frost-ed25519 = { version = "2.0.0-rc.0", features = ["serde"] } -reddsa = { git = "https://github.com/ZcashFoundation/reddsa.git", rev = "4d8c4bb337231e6e89117334d7c61dada589a953", features = ["frost"] } +reddsa = { git = "https://github.com/ZcashFoundation/reddsa.git", rev = "56a31af7099b95737031ef6cf251939ed99627c0", features = ["frost"] } clap = { version = "4.5.13", features = ["derive"] } thiserror = "1.0" rand = "0.8" diff --git a/trusted-dealer/src/cli.rs b/trusted-dealer/src/cli.rs index edae584..b424beb 100644 --- a/trusted-dealer/src/cli.rs +++ b/trusted-dealer/src/cli.rs @@ -1,14 +1,61 @@ -use frost_core::keys::IdentifierList; -use frost_core::Ciphersuite; use rand::thread_rng; +use std::collections::BTreeMap; use std::io::{BufRead, Write}; +use frost_core::keys::{IdentifierList, PublicKeyPackage, SecretShare}; +use frost_core::{Ciphersuite, Identifier}; +use reddsa::frost::redpallas::keys::EvenY; + use crate::args::Args; use crate::inputs::{print_values, request_inputs}; use crate::trusted_dealer_keygen::{split_secret, trusted_dealer_keygen}; -// Currently this uses the Default Identifiers -pub fn cli( +// The redpallas ciphersuite, when used for generating Orchard spending key +// signatures, requires ensuring public key have an even Y coordinate. Since the +// code uses generics, this trait is used to convert if needed depending on the +// ciphersuite. +// +// If you are adding a new ciphersuite to this tool which does note require +// this, just implement it and the default implementation (which does nothing) +// will suffice. See below. +pub trait MaybeIntoEvenY: Ciphersuite { + fn into_even_y( + secret_shares_and_public_key_package: ( + BTreeMap, SecretShare>, + PublicKeyPackage, + ), + ) -> ( + BTreeMap, SecretShare>, + PublicKeyPackage, + ) { + secret_shares_and_public_key_package + } +} + +// A ciphersuite that does not need the conversion. +impl MaybeIntoEvenY for frost_ed25519::Ed25519Sha512 {} + +impl MaybeIntoEvenY for reddsa::frost::redpallas::PallasBlake2b512 { + fn into_even_y( + (secret_shares, public_key_package): ( + BTreeMap, SecretShare>, + PublicKeyPackage, + ), + ) -> ( + BTreeMap, SecretShare>, + PublicKeyPackage, + ) { + let is_even = public_key_package.has_even_y(); + let public_key_package = public_key_package.into_even_y(Some(is_even)); + let secret_shares = secret_shares + .iter() + .map(|(i, s)| (*i, s.clone().into_even_y(Some(is_even)))) + .collect(); + (secret_shares, public_key_package) + } +} + +pub fn cli( args: &Args, input: &mut impl BufRead, logger: &mut impl Write, @@ -17,13 +64,13 @@ pub fn cli( let mut rng = thread_rng(); - let keygen = if config.secret.is_empty() { - trusted_dealer_keygen(&config, IdentifierList::::Default, &mut rng) + let shares_and_package = if config.secret.is_empty() { + trusted_dealer_keygen(&config, IdentifierList::::Default, &mut rng)? } else { - split_secret(&config, IdentifierList::::Default, &mut rng) + split_secret(&config, IdentifierList::::Default, &mut rng)? }; - let (shares, pubkeys) = keygen?; + let (shares, pubkeys) = MaybeIntoEvenY::into_even_y(shares_and_package); print_values(args, &shares, &pubkeys, logger)?;