Skip to content

Commit

Permalink
feat: switch to frost fork with no_std support and additional trait b…
Browse files Browse the repository at this point in the history
…ounds
  • Loading branch information
StackOverflowExcept1on committed Jan 21, 2025
1 parent 50e9b1b commit 0fd3f03
Show file tree
Hide file tree
Showing 26 changed files with 74 additions and 112 deletions.
19 changes: 9 additions & 10 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,20 @@ aes = { version = "0.8", features = ["zeroize"], default-features = false }
ctr = { version = "0.9", features = ["zeroize"], default-features = false }
digest = { version = "0.10", default-features = false }
document-features = "0.2"
frost-core = { version = "2.1", features = ["internals"], default-features = false }
frost-ed25519 = { version = "2.1", default-features = false }
frost-ed448 = { version = "2.1", default-features = false }
frost-p256 = { version = "2.1", default-features = false }
frost-ristretto255 = { version = "2.1", default-features = false }
frost-secp256k1 = { version = "2.1", default-features = false }
frost-secp256k1-evm = { version = "2.1", default-features = false }
frost-secp256k1-tr = { version = "2.1", default-features = false }
frost-core = { version = "2.1", git = "https://github.com/StackOverflowExcept1on/frost", branch = "frost-secp256k1-evm-crates-io-no-std", features = ["internals"], default-features = false }
frost-ed25519 = { version = "2.1", git = "https://github.com/StackOverflowExcept1on/frost", branch = "frost-secp256k1-evm-crates-io-no-std", default-features = false }
frost-ed448 = { version = "2.1", git = "https://github.com/StackOverflowExcept1on/frost", branch = "frost-secp256k1-evm-crates-io-no-std", default-features = false }
frost-p256 = { version = "2.1", git = "https://github.com/StackOverflowExcept1on/frost", branch = "frost-secp256k1-evm-crates-io-no-std", default-features = false }
frost-ristretto255 = { version = "2.1", git = "https://github.com/StackOverflowExcept1on/frost", branch = "frost-secp256k1-evm-crates-io-no-std", default-features = false }
frost-secp256k1 = { version = "2.1", git = "https://github.com/StackOverflowExcept1on/frost", branch = "frost-secp256k1-evm-crates-io-no-std", default-features = false }
frost-secp256k1-evm = { version = "2.1", git = "https://github.com/StackOverflowExcept1on/frost", branch = "frost-secp256k1-evm-crates-io-no-std", default-features = false }
frost-secp256k1-tr = { version = "2.1", git = "https://github.com/StackOverflowExcept1on/frost", branch = "frost-secp256k1-evm-crates-io-no-std", default-features = false }
hkdf = { version = "0.12", default-features = false }
rand = { version = "0.8", default-features = false }
rand_core = { version = "0.6", default-features = false }
sha2 = { version = "0.10", default-features = false }
sha3 = { version = "0.10", default-features = false }
thiserror-nostd-notrait = { version = "1.0", default-features = false }
thiserror = { version = "1.0", default-features = false } # TODO: https://github.com/ZcashFoundation/frost/issues/768
thiserror = { version = "2.0", default-features = false }

roast-core = { path = "roast-core", default-features = false }
roast-ed25519 = { path = "roast-ed25519", default-features = false }
Expand Down
7 changes: 2 additions & 5 deletions roast-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,11 @@ frost-core.workspace = true
hkdf.workspace = true
rand = { workspace = true, optional = true }
rand_core.workspace = true
thiserror-nostd-notrait.workspace = true
thiserror = { workspace = true, optional = true }
thiserror.workspace = true

[features]
default = ["serialization", "cheater-detection", "std"]
default = ["serialization", "cheater-detection"]
#! ## Features
## Enable standard library support.
std = ["dep:thiserror"]
## Enable `serde` support for types that need to be communicated. You
## can use `serde` to serialize structs with any encoder that supports
## `serde` (e.g. JSON with `serde_json`).
Expand Down
51 changes: 20 additions & 31 deletions roast-core/src/dkg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,37 +54,38 @@ fn try_apply_keystream(key: [u8; 16], iv: [u8; 16], buffer: &mut [u8]) -> Option
.ok()
}

type Round2PackageSerialization<C> =
<<<C as Ciphersuite>::Group as Group>::Field as Field>::Serialization;

fn encrypt_round2_package<C: Ciphersuite, H: Clone + BlockSizeUser + Digest>(
round2_package: round2::Package<C>,
receiver_temp_public_key: &VerifyingKey<C>,
sender_temp_secret_key: &SigningKey<C>,
) -> Option<Vec<u8>> {
) -> Option<Round2PackageSerialization<C>> {
let shared_secret_bytes = diffie_hellman(sender_temp_secret_key, receiver_temp_public_key)?;
let (key, iv) = hkdf::<C, H>(shared_secret_bytes)?;

let signing_share = round2_package.signing_share().to_scalar();
let singing_share_bytes = <<C::Group as Group>::Field as Field>::serialize(&signing_share);
let mut singing_share_bytes = <<C::Group as Group>::Field as Field>::serialize(&signing_share);

let mut buffer = singing_share_bytes.as_ref().to_vec();
try_apply_keystream(key, iv, &mut buffer)?;
try_apply_keystream(key, iv, singing_share_bytes.as_mut())?;

Some(buffer)
Some(singing_share_bytes)
}

fn decrypt_round2_package<C: Ciphersuite, H: Clone + BlockSizeUser + Digest>(
round2_package_encrypted: Vec<u8>,
mut round2_package_encrypted: Round2PackageSerialization<C>,
sender_temp_public_key: &VerifyingKey<C>,
receiver_temp_secret_key: &SigningKey<C>,
) -> Option<round2::Package<C>> {
let shared_secret_bytes = diffie_hellman(receiver_temp_secret_key, sender_temp_public_key)?;
let (key, iv) = hkdf::<C, H>(shared_secret_bytes)?;

let mut buffer = round2_package_encrypted;
try_apply_keystream(key, iv, &mut buffer)?;
try_apply_keystream(key, iv, round2_package_encrypted.as_mut())?;

let buffer_serialized = buffer.try_into().ok()?;
let signing_share =
SigningShare::new(<<C::Group as Group>::Field>::deserialize(&buffer_serialized).ok()?);
let signing_share = SigningShare::new(
<<C::Group as Group>::Field>::deserialize(&round2_package_encrypted).ok()?,
);

Some(round2::Package::new(signing_share))
}
Expand Down Expand Up @@ -112,7 +113,8 @@ pub struct Dealer<C: Ciphersuite, H: Clone + BlockSizeUser + Digest> {
participants: Vec<Identifier<C>>,
participants_set: BTreeSet<Identifier<C>>,
round1_packages: BTreeMap<Identifier<C>, Round1Package<C>>,
round2_packages_encrypted: BTreeMap<Identifier<C>, BTreeMap<Identifier<C>, Vec<u8>>>,
round2_packages_encrypted:
BTreeMap<Identifier<C>, BTreeMap<Identifier<C>, Round2PackageSerialization<C>>>,
round2_participants_set: BTreeSet<Identifier<C>>,
round2_culprits_set: BTreeSet<Identifier<C>>,
phantom: PhantomData<H>,
Expand Down Expand Up @@ -169,7 +171,7 @@ impl<C: Ciphersuite, H: Clone + BlockSizeUser + Digest> Dealer<C, H> {
pub fn round2_packages_encrypted(
&self,
receiver_identifier: Identifier<C>,
) -> Option<&BTreeMap<Identifier<C>, Vec<u8>>> {
) -> Option<&BTreeMap<Identifier<C>, Round2PackageSerialization<C>>> {
self.round2_packages_encrypted.get(&receiver_identifier)
}

Expand Down Expand Up @@ -220,7 +222,7 @@ impl<C: Ciphersuite, H: Clone + BlockSizeUser + Digest> Dealer<C, H> {
pub fn receive_round2_packages_encrypted(
&mut self,
identifier: Identifier<C>,
round2_packages_encrypted: BTreeMap<Identifier<C>, Vec<u8>>,
round2_packages_encrypted: BTreeMap<Identifier<C>, Round2PackageSerialization<C>>,
) -> Result<DkgStatus, DkgDealerError<C>> {
if !self.participants_set.contains(&identifier) {
return Err(DkgDealerError::UnknownParticipant);
Expand All @@ -230,25 +232,11 @@ impl<C: Ciphersuite, H: Clone + BlockSizeUser + Digest> Dealer<C, H> {
return Err(DkgDealerError::Frost(FrostError::IncorrectNumberOfPackages));
}

let zero = <<C::Group as Group>::Field>::zero();
let serialization = <<C::Group as Group>::Field>::serialize(&zero);
let expected_len = serialization.as_ref().len();

// check that `round2_packages_encrypted` keys contain all identifiers except
// sender identifier
if self
.participants
.iter()
.filter(|id| identifier.ne(id))
.any(|id| {
// value must be `Some(_)` and must also have length of `expected_len`
round2_packages_encrypted
.get(id)
.filter(|round2_package_encrypted| {
round2_package_encrypted.len() == expected_len
})
.is_none()
})
.any(|id| !round2_packages_encrypted.contains_key(id))
{
return Err(DkgDealerError::Frost(FrostError::IncorrectPackage));
}
Expand Down Expand Up @@ -461,7 +449,8 @@ impl<C: Ciphersuite, H: Clone + BlockSizeUser + Digest> Participant<C, H> {
pub fn receive_round1_packages(
&mut self,
mut round1_packages: BTreeMap<Identifier<C>, Round1Package<C>>,
) -> Result<BTreeMap<Identifier<C>, Vec<u8>>, DkgParticipantError<C>> {
) -> Result<BTreeMap<Identifier<C>, Round2PackageSerialization<C>>, DkgParticipantError<C>>
{
let round1_secret_package = self
.round1_secret_package
.take()
Expand Down Expand Up @@ -501,7 +490,7 @@ impl<C: Ciphersuite, H: Clone + BlockSizeUser + Digest> Participant<C, H> {
/// Receives `round2_packages_encrypted` from the dealer.
pub fn receive_round2_packages_encrypted(
&mut self,
round2_packages_encrypted: BTreeMap<Identifier<C>, Vec<u8>>,
round2_packages_encrypted: BTreeMap<Identifier<C>, Round2PackageSerialization<C>>,
) -> Result<(KeyPackage<C>, PublicKeyPackage<C>), DkgParticipantError<C>> {
let round2_secret_package = self
.round2_secret_package
Expand Down
16 changes: 0 additions & 16 deletions roast-core/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
//! Error types.
use frost_core::{Ciphersuite, Error as FrostErrorType};
#[cfg(feature = "std")]
use thiserror::Error;
#[cfg(not(feature = "std"))]
use thiserror_nostd_notrait::Error;

/// Represents all possible errors that can occur in FROST protocol.
pub type FrostError<C> = FrostErrorType<C>;
Expand Down Expand Up @@ -48,19 +45,6 @@ pub enum DkgParticipantError<C: Ciphersuite> {
InvalidSecretShares,
}

/// Represents all possible errors that can occur in Distributed Key Generation
/// protocol.
#[cfg(any(test, feature = "test-impl"))]
#[derive(Error, Debug, Copy, Clone, Eq, PartialEq)]
pub enum DkgError<C: Ciphersuite> {
/// Error in Distributed Key Generation protocol on dealer side.
#[error("DKG dealer error: {0}")]
DkgDealer(#[from] DkgDealerError<C>),
/// Error in Distributed Key Generation protocol on participant side.
#[error("DKG participant error: {0}")]
DkgParticipant(#[from] DkgParticipantError<C>),
}

/// Represents all possible errors for which signer can be marked as malicious.
#[derive(Error, Debug, Copy, Clone, Eq, PartialEq)]
pub enum MaliciousSignerError {
Expand Down
2 changes: 1 addition & 1 deletion roast-core/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![cfg_attr(not(feature = "std"), no_std)]
#![no_std]
#![deny(missing_docs)]
#![doc = include_str!("../README.md")]
#![doc = document_features::document_features!()]
Expand Down
7 changes: 4 additions & 3 deletions roast-core/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@
use crate::{
dkg::{Dealer, Participant},
error::{DkgError, DkgParticipantError, RoastError},
error::{DkgParticipantError, RoastError},
Coordinator, SessionStatus, Signer,
};
use aes::cipher::crypto_common::BlockSizeUser;
use alloc::collections::BTreeMap;
use alloc::{boxed::Box, collections::BTreeMap};
use core::error::Error;
use digest::Digest;
use frost_core::{
keys::{self, IdentifierList, KeyPackage},
Expand All @@ -25,7 +26,7 @@ pub fn test_dkg_basic<
min_signers: u16,
max_signers: u16,
rng: &mut RNG,
) -> Result<(), DkgError<C>> {
) -> Result<(), Box<dyn Error>> {
let mut identifiers = vec![];
let mut participants = vec![];

Expand Down
4 changes: 1 addition & 3 deletions roast-ed25519/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,8 @@ roast-core = { workspace = true, features = ["test-impl"] }
rand_core = { workspace = true, features = ["getrandom"] }

[features]
default = ["serialization", "cheater-detection", "std"]
default = ["serialization", "cheater-detection"]
#! ## Features
## Enable standard library support.
std = ["roast-core/std"]
## Enable `serde` support for types that need to be communicated. You
## can use `serde` to serialize structs with any encoder that supports
## `serde` (e.g. JSON with `serde_json`).
Expand Down
2 changes: 1 addition & 1 deletion roast-ed25519/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![cfg_attr(not(feature = "std"), no_std)]
#![no_std]
#![deny(missing_docs)]
#![doc = include_str!("../README.md")]
#![doc = document_features::document_features!()]
Expand Down
6 changes: 3 additions & 3 deletions roast-ed25519/tests/integration_tests.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use roast_core::{error::DkgError, tests};
use roast_core::tests;
use roast_ed25519::{error::RoastError, frost::rand_core::OsRng};

#[test]
fn test_dkg_basic() -> Result<(), DkgError<frost_ed25519::Ed25519Sha512>> {
fn test_dkg_basic() -> Result<(), Box<dyn std::error::Error>> {
let mut rng = OsRng;
tests::test_dkg_basic::<_, sha2::Sha512, _>(2, 3, &mut rng)?;
tests::test_dkg_basic::<frost_ed25519::Ed25519Sha512, sha2::Sha512, _>(2, 3, &mut rng)?;
Ok(())
}

Expand Down
4 changes: 1 addition & 3 deletions roast-ed448/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,8 @@ roast-core = { workspace = true, features = ["test-impl"] }
rand_core = { workspace = true, features = ["getrandom"] }

[features]
default = ["serialization", "cheater-detection", "std"]
default = ["serialization", "cheater-detection"]
#! ## Features
## Enable standard library support.
std = ["roast-core/std"]
## Enable `serde` support for types that need to be communicated. You
## can use `serde` to serialize structs with any encoder that supports
## `serde` (e.g. JSON with `serde_json`).
Expand Down
2 changes: 1 addition & 1 deletion roast-ed448/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// TODO: #![cfg_attr(not(feature = "std"), no_std)] (https://github.com/ZcashFoundation/frost/issues/769)
#![no_std]
#![deny(missing_docs)]
#![doc = include_str!("../README.md")]
#![doc = document_features::document_features!()]
Expand Down
4 changes: 1 addition & 3 deletions roast-p256/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,8 @@ roast-core = { workspace = true, features = ["test-impl"] }
rand_core = { workspace = true, features = ["getrandom"] }

[features]
default = ["serialization", "cheater-detection", "std"]
default = ["serialization", "cheater-detection"]
#! ## Features
## Enable standard library support.
std = ["roast-core/std"]
## Enable `serde` support for types that need to be communicated. You
## can use `serde` to serialize structs with any encoder that supports
## `serde` (e.g. JSON with `serde_json`).
Expand Down
2 changes: 1 addition & 1 deletion roast-p256/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![cfg_attr(not(feature = "std"), no_std)]
#![no_std]
#![deny(missing_docs)]
#![doc = include_str!("../README.md")]
#![doc = document_features::document_features!()]
Expand Down
6 changes: 3 additions & 3 deletions roast-p256/tests/integration_tests.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use roast_core::{error::DkgError, tests};
use roast_core::tests;
use roast_p256::{error::RoastError, frost::rand_core::OsRng};

#[test]
fn test_dkg_basic() -> Result<(), DkgError<frost_p256::P256Sha256>> {
fn test_dkg_basic() -> Result<(), Box<dyn std::error::Error>> {
let mut rng = OsRng;
tests::test_dkg_basic::<_, sha2::Sha256, _>(2, 3, &mut rng)?;
tests::test_dkg_basic::<frost_p256::P256Sha256, sha2::Sha256, _>(2, 3, &mut rng)?;
Ok(())
}

Expand Down
4 changes: 1 addition & 3 deletions roast-ristretto255/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,8 @@ roast-core = { workspace = true, features = ["test-impl"] }
rand_core = { workspace = true, features = ["getrandom"] }

[features]
default = ["serialization", "cheater-detection", "std"]
default = ["serialization", "cheater-detection"]
#! ## Features
## Enable standard library support.
std = ["roast-core/std"]
## Enable `serde` support for types that need to be communicated. You
## can use `serde` to serialize structs with any encoder that supports
## `serde` (e.g. JSON with `serde_json`).
Expand Down
2 changes: 1 addition & 1 deletion roast-ristretto255/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![cfg_attr(not(feature = "std"), no_std)]
#![no_std]
#![deny(missing_docs)]
#![doc = include_str!("../README.md")]
#![doc = document_features::document_features!()]
Expand Down
8 changes: 5 additions & 3 deletions roast-ristretto255/tests/integration_tests.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use roast_core::{error::DkgError, tests};
use roast_core::tests;
use roast_ristretto255::{error::RoastError, frost::rand_core::OsRng};

#[test]
fn test_dkg_basic() -> Result<(), DkgError<frost_ristretto255::Ristretto255Sha512>> {
fn test_dkg_basic() -> Result<(), Box<dyn std::error::Error>> {
let mut rng = OsRng;
tests::test_dkg_basic::<_, sha2::Sha512, _>(2, 3, &mut rng)?;
tests::test_dkg_basic::<frost_ristretto255::Ristretto255Sha512, sha2::Sha512, _>(
2, 3, &mut rng,
)?;
Ok(())
}

Expand Down
4 changes: 1 addition & 3 deletions roast-secp256k1-evm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,8 @@ roast-core = { workspace = true, features = ["test-impl"] }
rand_core = { workspace = true, features = ["getrandom"] }

[features]
default = ["serialization", "cheater-detection", "std"]
default = ["serialization", "cheater-detection"]
#! ## Features
## Enable standard library support.
std = ["roast-core/std"]
## Enable `serde` support for types that need to be communicated. You
## can use `serde` to serialize structs with any encoder that supports
## `serde` (e.g. JSON with `serde_json`).
Expand Down
2 changes: 1 addition & 1 deletion roast-secp256k1-evm/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![cfg_attr(not(feature = "std"), no_std)]
#![no_std]
#![deny(missing_docs)]
#![doc = include_str!("../README.md")]
#![doc = document_features::document_features!()]
Expand Down
8 changes: 5 additions & 3 deletions roast-secp256k1-evm/tests/integration_tests.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use roast_core::{error::DkgError, tests};
use roast_core::tests;
use roast_secp256k1_evm::{error::RoastError, frost::rand_core::OsRng};

#[test]
fn test_dkg_basic() -> Result<(), DkgError<frost_secp256k1_evm::Secp256K1Keccak256>> {
fn test_dkg_basic() -> Result<(), Box<dyn std::error::Error>> {
let mut rng = OsRng;
tests::test_dkg_basic::<_, sha3::Keccak256, _>(2, 3, &mut rng)?;
tests::test_dkg_basic::<frost_secp256k1_evm::Secp256K1Keccak256, sha3::Keccak256, _>(
2, 3, &mut rng,
)?;
Ok(())
}

Expand Down
4 changes: 1 addition & 3 deletions roast-secp256k1-tr/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,8 @@ roast-core = { workspace = true, features = ["test-impl"] }
rand_core = { workspace = true, features = ["getrandom"] }

[features]
default = ["serialization", "cheater-detection", "std"]
default = ["serialization", "cheater-detection"]
#! ## Features
## Enable standard library support.
std = ["roast-core/std"]
## Enable `serde` support for types that need to be communicated. You
## can use `serde` to serialize structs with any encoder that supports
## `serde` (e.g. JSON with `serde_json`).
Expand Down
Loading

0 comments on commit 0fd3f03

Please sign in to comment.