diff --git a/Cargo.lock b/Cargo.lock index 8d4effd..73a415b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -391,9 +391,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "frost-core" -version = "0.7.0" +version = "1.0.0-rc.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3b61d737e19bea0cedda9a11dab96ab1fd1e4016f707e8ee9018d8f17d2cd18" +checksum = "eae732628620e7e52b3146df2eef3636f321b63dfba6e92b3b67147e0c5b2bb2" dependencies = [ "byteorder", "const-crc32", @@ -402,7 +402,7 @@ dependencies = [ "derive-getters", "document-features", "hex", - "itertools 0.11.0", + "itertools 0.12.0", "postcard", "proptest", "rand_core", @@ -416,9 +416,9 @@ dependencies = [ [[package]] name = "frost-rerandomized" -version = "0.7.0" +version = "1.0.0-rc.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b45409d93cf5000f52ae64847a8a270a4562f1a035e74c3fae0e2462adb97ae" +checksum = "abc9f0445f27262bd1e1d4754ad8ce7ac03c8d079704e6c696f5e40bab85d1e2" dependencies = [ "derive-getters", "document-features", @@ -517,9 +517,9 @@ dependencies = [ [[package]] name = "itertools" -version = "0.11.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0" dependencies = [ "either", ] diff --git a/Cargo.toml b/Cargo.toml index 916cef6..3351a44 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,7 +31,7 @@ pasta_curves = { version = "0.5", default-features = false } rand_core = { version = "0.6", default-features = false } serde = { version = "1", optional = true, features = ["derive"] } thiserror = { version = "1.0", optional = true } -frost-rerandomized = { version = "0.7.0", optional = true } +frost-rerandomized = { version = "1.0.0-rc.0", optional = true } [dependencies.zeroize] version = "1" @@ -50,7 +50,7 @@ rand_chacha = "0.3" serde_json = "1.0" num-bigint = "0.4.3" num-traits = "0.2.17" -frost-rerandomized = { version = "0.7.0", features = ["test-impl"] } +frost-rerandomized = { version = "1.0.0-rc.0", features = ["test-impl"] } # `alloc` is only used in test code [dev-dependencies.pasta_curves] diff --git a/src/frost/redjubjub.rs b/src/frost/redjubjub.rs index cf97e41..104d75a 100644 --- a/src/frost/redjubjub.rs +++ b/src/frost/redjubjub.rs @@ -2,7 +2,7 @@ #![allow(non_snake_case)] #![deny(missing_docs)] -use std::collections::HashMap; +use alloc::collections::BTreeMap; use group::GroupEncoding; #[cfg(feature = "alloc")] @@ -12,8 +12,9 @@ use group::{ff::Field as FFField, ff::PrimeField}; #[cfg(feature = "serde")] pub use frost_rerandomized::frost_core::serde; pub use frost_rerandomized::frost_core::{ - frost, Ciphersuite, Field, FieldError, Group, GroupError, + self as frost, Ciphersuite, Field, FieldError, Group, GroupError, }; +use frost_rerandomized::RandomizedCiphersuite; pub use rand_core; use rand_core::{CryptoRng, RngCore}; @@ -184,6 +185,16 @@ impl Ciphersuite for JubjubBlake2b512 { } } +impl RandomizedCiphersuite for JubjubBlake2b512 { + fn hash_randomizer(m: &[u8]) -> Option<<::Field as Field>::Scalar> { + Some( + HStar::::new(b"FROST_RedJubjubA") + .update(m) + .finalize(), + ) + } +} + // Shorthand alias for the ciphersuite type J = JubjubBlake2b512; @@ -192,7 +203,7 @@ pub type Identifier = frost::Identifier; /// FROST(Jubjub, BLAKE2b-512) keys, key generation, key shares. pub mod keys { - use std::collections::HashMap; + use alloc::collections::BTreeMap; use super::*; @@ -206,7 +217,7 @@ pub mod keys { min_signers: u16, identifiers: IdentifierList, mut rng: RNG, - ) -> Result<(HashMap, PublicKeyPackage), Error> { + ) -> Result<(BTreeMap, PublicKeyPackage), Error> { frost::keys::generate_with_dealer(max_signers, min_signers, identifiers, &mut rng) } @@ -222,7 +233,7 @@ pub mod keys { min_signers: u16, identifiers: IdentifierList, rng: &mut R, - ) -> Result<(HashMap, PublicKeyPackage), Error> { + ) -> Result<(BTreeMap, PublicKeyPackage), Error> { frost::keys::split(key, max_signers, min_signers, identifiers, rng) } @@ -275,7 +286,7 @@ pub mod keys { /// FROST(Jubjub, BLAKE2b-512) Round 1 functionality and types. pub mod round1 { - use frost_rerandomized::frost_core::frost::keys::SigningShare; + use frost_rerandomized::frost_core::keys::SigningShare; use super::*; /// Comprised of FROST(Jubjub, BLAKE2b-512) hiding and binding nonces. @@ -365,7 +376,7 @@ pub type RandomizedParams = frost_rerandomized::RandomizedParams; /// service attack due to publishing an invalid signature. pub fn aggregate( signing_package: &SigningPackage, - signature_shares: &HashMap, + signature_shares: &BTreeMap, pubkeys: &keys::PublicKeyPackage, randomized_params: &RandomizedParams, ) -> Result { diff --git a/src/frost/redjubjub/dkg.md b/src/frost/redjubjub/dkg.md index 93cd0c8..9dba6a1 100644 --- a/src/frost/redjubjub/dkg.md +++ b/src/frost/redjubjub/dkg.md @@ -27,7 +27,7 @@ they can proceed to sign messages with FROST. ```rust # // ANCHOR: dkg_import use rand::thread_rng; -use std::collections::HashMap; +use std::collections::BTreeMap; use reddsa::frost::redjubjub as frost; @@ -44,12 +44,12 @@ let min_signers = 3; // Keep track of each participant's round 1 secret package. // In practice each participant will keep its copy; no one // will have all the participant's packages. -let mut round1_secret_packages = HashMap::new(); +let mut round1_secret_packages = BTreeMap::new(); // Keep track of all round 1 packages sent to the given participant. // This is used to simulate the broadcast; in practice the packages // will be sent through some communication channel. -let mut received_round1_packages = HashMap::new(); +let mut received_round1_packages = BTreeMap::new(); // For each participant, perform the first part of the DKG protocol. // In practice, each participant will perform this on their own environments. @@ -69,7 +69,7 @@ for participant_index in 1..=max_signers { round1_secret_packages.insert(participant_identifier, round1_secret_package); // "Send" the round 1 package to all other participants. In this - // test this is simulated using a HashMap; in practice this will be + // test this is simulated using a BTreeMap; in practice this will be // sent through some communication channel. for receiver_participant_index in 1..=max_signers { if receiver_participant_index == participant_index { @@ -80,7 +80,7 @@ for participant_index in 1..=max_signers { .expect("should be nonzero"); received_round1_packages .entry(receiver_participant_identifier) - .or_insert_with(HashMap::new) + .or_insert_with(BTreeMap::new) .insert(participant_identifier, round1_package.clone()); } } @@ -92,12 +92,12 @@ for participant_index in 1..=max_signers { // Keep track of each participant's round 2 secret package. // In practice each participant will keep its copy; no one // will have all the participant's packages. -let mut round2_secret_packages = HashMap::new(); +let mut round2_secret_packages = BTreeMap::new(); // Keep track of all round 2 packages sent to the given participant. // This is used to simulate the broadcast; in practice the packages // will be sent through some communication channel. -let mut received_round2_packages = HashMap::new(); +let mut received_round2_packages = BTreeMap::new(); // For each participant, perform the second part of the DKG protocol. // In practice, each participant will perform this on their own environments. @@ -117,14 +117,14 @@ for participant_index in 1..=max_signers { round2_secret_packages.insert(participant_identifier, round2_secret_package); // "Send" the round 2 package to all other participants. In this - // test this is simulated using a HashMap; in practice this will be + // test this is simulated using a BTreeMap; in practice this will be // sent through some communication channel. // Note that, in contrast to the previous part, here each other participant // gets its own specific package. for (receiver_identifier, round2_package) in round2_packages { received_round2_packages .entry(receiver_identifier) - .or_insert_with(HashMap::new) + .or_insert_with(BTreeMap::new) .insert(participant_identifier, round2_package); } } @@ -136,13 +136,13 @@ for participant_index in 1..=max_signers { // Keep track of each participant's long-lived key package. // In practice each participant will keep its copy; no one // will have all the participant's packages. -let mut key_packages = HashMap::new(); +let mut key_packages = BTreeMap::new(); // Keep track of each participant's public key package. // In practice, if there is a Coordinator, only they need to store the set. // If there is not, then all candidates must store their own sets. // All participants will have the same exact public key package. -let mut pubkey_packages = HashMap::new(); +let mut pubkey_packages = BTreeMap::new(); // For each participant, perform the third part of the DKG protocol. // In practice, each participant will perform this on their own environments. diff --git a/src/frost/redjubjub/keys/dkg.rs b/src/frost/redjubjub/keys/dkg.rs index bf25e22..47a8003 100644 --- a/src/frost/redjubjub/keys/dkg.rs +++ b/src/frost/redjubjub/keys/dkg.rs @@ -64,8 +64,8 @@ pub fn part1( /// must be sent to other participants. pub fn part2( secret_package: round1::SecretPackage, - round1_packages: &HashMap, -) -> Result<(round2::SecretPackage, HashMap), Error> { + round1_packages: &BTreeMap, +) -> Result<(round2::SecretPackage, BTreeMap), Error> { frost::keys::dkg::part2(secret_package, round1_packages) } @@ -80,8 +80,8 @@ pub fn part2( /// signatures. pub fn part3( round2_secret_package: &round2::SecretPackage, - round1_packages: &HashMap, - round2_packages: &HashMap, + round1_packages: &BTreeMap, + round2_packages: &BTreeMap, ) -> Result<(KeyPackage, PublicKeyPackage), Error> { frost::keys::dkg::part3(round2_secret_package, round1_packages, round2_packages) } diff --git a/src/frost/redjubjub/keys/repairable.rs b/src/frost/redjubjub/keys/repairable.rs index bd92a7a..57b01b4 100644 --- a/src/frost/redjubjub/keys/repairable.rs +++ b/src/frost/redjubjub/keys/repairable.rs @@ -4,7 +4,7 @@ //! The RTS is used to help a signer (participant) repair their lost share. This is achieved //! using a subset of the other signers know here as `helpers`. -use std::collections::HashMap; +use alloc::collections::BTreeMap; use jubjub::Scalar; @@ -26,7 +26,7 @@ pub fn repair_share_step_1( share_i: &SecretShare, rng: &mut R, participant: Identifier, -) -> Result, Error> { +) -> Result, Error> { frost::keys::repairable::repair_share_step_1(helpers, share_i, rng, participant) } diff --git a/src/frost/redpallas.rs b/src/frost/redpallas.rs index 4a705ac..5248271 100644 --- a/src/frost/redpallas.rs +++ b/src/frost/redpallas.rs @@ -2,8 +2,9 @@ #![allow(non_snake_case)] #![deny(missing_docs)] -use std::collections::HashMap; +use alloc::collections::BTreeMap; +use frost_rerandomized::RandomizedCiphersuite; use group::GroupEncoding; #[cfg(feature = "alloc")] use group::{ff::Field as FFField, ff::PrimeField, Group as FFGroup}; @@ -13,7 +14,7 @@ use pasta_curves::pallas; #[cfg(feature = "serde")] pub use frost_rerandomized::frost_core::serde; pub use frost_rerandomized::frost_core::{ - frost, Ciphersuite, Field, FieldError, Group, GroupError, + self as frost, Ciphersuite, Field, FieldError, Group, GroupError, }; pub use rand_core; @@ -188,6 +189,16 @@ impl Ciphersuite for PallasBlake2b512 { } } +impl RandomizedCiphersuite for PallasBlake2b512 { + fn hash_randomizer(m: &[u8]) -> Option<<::Field as Field>::Scalar> { + Some( + HStar::::new(b"FROST_RedPallasA") + .update(m) + .finalize(), + ) + } +} + // Shorthand alias for the ciphersuite type P = PallasBlake2b512; @@ -196,7 +207,7 @@ pub type Identifier = frost::Identifier

; /// FROST(Pallas, BLAKE2b-512) keys, key generation, key shares. pub mod keys { - use std::collections::HashMap; + use alloc::collections::BTreeMap; use super::*; @@ -210,7 +221,7 @@ pub mod keys { min_signers: u16, identifiers: IdentifierList, mut rng: RNG, - ) -> Result<(HashMap, PublicKeyPackage), Error> { + ) -> Result<(BTreeMap, PublicKeyPackage), Error> { frost::keys::generate_with_dealer(max_signers, min_signers, identifiers, &mut rng) } @@ -226,7 +237,7 @@ pub mod keys { min_signers: u16, identifiers: IdentifierList, rng: &mut R, - ) -> Result<(HashMap, PublicKeyPackage), Error> { + ) -> Result<(BTreeMap, PublicKeyPackage), Error> { frost::keys::split(key, max_signers, min_signers, identifiers, rng) } @@ -282,19 +293,19 @@ pub mod keys { impl PositiveY for PublicKeyPackage { fn into_positive_y(self) -> Self { - let pubkey = self.group_public(); + let pubkey = self.verifying_key(); let pubkey_serialized = pubkey.serialize(); if pubkey_serialized[31] & 0x80 != 0 { let pubkey = VerifyingKey::new(-pubkey.to_element()); - let signer_pubkeys: HashMap<_, _> = self - .signer_pubkeys() + let verifying_shares: BTreeMap<_, _> = self + .verifying_shares() .iter() .map(|(i, vs)| { let vs = VerifyingShare::new(-vs.to_element()); (*i, vs) }) .collect(); - PublicKeyPackage::new(signer_pubkeys, pubkey) + PublicKeyPackage::new(verifying_shares, pubkey) } else { self } @@ -303,12 +314,12 @@ pub mod keys { impl PositiveY for KeyPackage { fn into_positive_y(self) -> Self { - let pubkey = self.group_public(); + let pubkey = self.verifying_key(); let pubkey_serialized = pubkey.serialize(); if pubkey_serialized[31] & 0x80 != 0 { let pubkey = VerifyingKey::new(-pubkey.to_element()); - let signing_share = SigningShare::new(-self.secret_share().to_scalar()); - let verifying_share = VerifyingShare::new(-self.public().to_element()); + let signing_share = SigningShare::new(-self.signing_share().to_scalar()); + let verifying_share = VerifyingShare::new(-self.verifying_share().to_element()); KeyPackage::new( *self.identifier(), signing_share, @@ -328,7 +339,7 @@ pub mod keys { /// FROST(Pallas, BLAKE2b-512) Round 1 functionality and types. pub mod round1 { - use frost_rerandomized::frost_core::frost::keys::SigningShare; + use frost_rerandomized::frost_core::keys::SigningShare; use super::*; /// Comprised of FROST(Pallas, BLAKE2b-512) hiding and binding nonces. @@ -418,7 +429,7 @@ pub type RandomizedParams = frost_rerandomized::RandomizedParams

; /// service attack due to publishing an invalid signature. pub fn aggregate( signing_package: &SigningPackage, - signature_shares: &HashMap, + signature_shares: &BTreeMap, pubkeys: &keys::PublicKeyPackage, randomized_params: &RandomizedParams, ) -> Result { diff --git a/src/frost/redpallas/dkg.md b/src/frost/redpallas/dkg.md index 93abd4d..858ea71 100644 --- a/src/frost/redpallas/dkg.md +++ b/src/frost/redpallas/dkg.md @@ -27,7 +27,7 @@ they can proceed to sign messages with FROST. ```rust # // ANCHOR: dkg_import use rand::thread_rng; -use std::collections::HashMap; +use std::collections::BTreeMap; use reddsa::frost::redpallas as frost; @@ -44,12 +44,12 @@ let min_signers = 3; // Keep track of each participant's round 1 secret package. // In practice each participant will keep its copy; no one // will have all the participant's packages. -let mut round1_secret_packages = HashMap::new(); +let mut round1_secret_packages = BTreeMap::new(); // Keep track of all round 1 packages sent to the given participant. // This is used to simulate the broadcast; in practice the packages // will be sent through some communication channel. -let mut received_round1_packages = HashMap::new(); +let mut received_round1_packages = BTreeMap::new(); // For each participant, perform the first part of the DKG protocol. // In practice, each participant will perform this on their own environments. @@ -69,7 +69,7 @@ for participant_index in 1..=max_signers { round1_secret_packages.insert(participant_identifier, round1_secret_package); // "Send" the round 1 package to all other participants. In this - // test this is simulated using a HashMap; in practice this will be + // test this is simulated using a BTreeMap; in practice this will be // sent through some communication channel. for receiver_participant_index in 1..=max_signers { if receiver_participant_index == participant_index { @@ -80,7 +80,7 @@ for participant_index in 1..=max_signers { .expect("should be nonzero"); received_round1_packages .entry(receiver_participant_identifier) - .or_insert_with(HashMap::new) + .or_insert_with(BTreeMap::new) .insert(participant_identifier, round1_package.clone()); } } @@ -92,12 +92,12 @@ for participant_index in 1..=max_signers { // Keep track of each participant's round 2 secret package. // In practice each participant will keep its copy; no one // will have all the participant's packages. -let mut round2_secret_packages = HashMap::new(); +let mut round2_secret_packages = BTreeMap::new(); // Keep track of all round 2 packages sent to the given participant. // This is used to simulate the broadcast; in practice the packages // will be sent through some communication channel. -let mut received_round2_packages = HashMap::new(); +let mut received_round2_packages = BTreeMap::new(); // For each participant, perform the second part of the DKG protocol. // In practice, each participant will perform this on their own environments. @@ -117,14 +117,14 @@ for participant_index in 1..=max_signers { round2_secret_packages.insert(participant_identifier, round2_secret_package); // "Send" the round 2 package to all other participants. In this - // test this is simulated using a HashMap; in practice this will be + // test this is simulated using a BTreeMap; in practice this will be // sent through some communication channel. // Note that, in contrast to the previous part, here each other participant // gets its own specific package. for (receiver_identifier, round2_package) in round2_packages { received_round2_packages .entry(receiver_identifier) - .or_insert_with(HashMap::new) + .or_insert_with(BTreeMap::new) .insert(participant_identifier, round2_package); } } @@ -136,13 +136,13 @@ for participant_index in 1..=max_signers { // Keep track of each participant's long-lived key package. // In practice each participant will keep its copy; no one // will have all the participant's packages. -let mut key_packages = HashMap::new(); +let mut key_packages = BTreeMap::new(); // Keep track of each participant's public key package. // In practice, if there is a Coordinator, only they need to store the set. // If there is not, then all candidates must store their own sets. // All participants will have the same exact public key package. -let mut pubkey_packages = HashMap::new(); +let mut pubkey_packages = BTreeMap::new(); // For each participant, perform the third part of the DKG protocol. // In practice, each participant will perform this on their own environments. diff --git a/src/frost/redpallas/keys/dkg.rs b/src/frost/redpallas/keys/dkg.rs index cb638f3..a141b5a 100644 --- a/src/frost/redpallas/keys/dkg.rs +++ b/src/frost/redpallas/keys/dkg.rs @@ -64,8 +64,8 @@ pub fn part1( /// must be sent to other participants. pub fn part2( secret_package: round1::SecretPackage, - round1_packages: &HashMap, -) -> Result<(round2::SecretPackage, HashMap), Error> { + round1_packages: &BTreeMap, +) -> Result<(round2::SecretPackage, BTreeMap), Error> { frost::keys::dkg::part2(secret_package, round1_packages) } @@ -80,8 +80,8 @@ pub fn part2( /// signatures. pub fn part3( round2_secret_package: &round2::SecretPackage, - round1_packages: &HashMap, - round2_packages: &HashMap, + round1_packages: &BTreeMap, + round2_packages: &BTreeMap, ) -> Result<(KeyPackage, PublicKeyPackage), Error> { frost::keys::dkg::part3(round2_secret_package, round1_packages, round2_packages) } diff --git a/src/frost/redpallas/keys/repairable.rs b/src/frost/redpallas/keys/repairable.rs index 15d05db..54dcdd8 100644 --- a/src/frost/redpallas/keys/repairable.rs +++ b/src/frost/redpallas/keys/repairable.rs @@ -4,7 +4,7 @@ //! The RTS is used to help a signer (participant) repair their lost share. This is achieved //! using a subset of the other signers know here as `helpers`. -use std::collections::HashMap; +use alloc::collections::BTreeMap; use pasta_curves::pallas::Scalar; @@ -20,13 +20,13 @@ use super::{SecretShare, VerifiableSecretSharingCommitment}; /// where `helpers` contains the identifiers of all the helpers (including `helper_i`), and `share_i` /// is the share of `helper_i`. /// -/// Returns a HashMap mapping which value should be sent to which participant. +/// Returns a BTreeMap mapping which value should be sent to which participant. pub fn repair_share_step_1( helpers: &[Identifier], share_i: &SecretShare, rng: &mut R, participant: Identifier, -) -> Result, Error> { +) -> Result, Error> { frost::keys::repairable::repair_share_step_1(helpers, share_i, rng, participant) }