diff --git a/frost-core/CHANGELOG.md b/frost-core/CHANGELOG.md index 838ff4f7..49bbd0fd 100644 --- a/frost-core/CHANGELOG.md +++ b/frost-core/CHANGELOG.md @@ -13,6 +13,7 @@ Entries are listed in reverse chronological order. struct, which affects self-describing formats like JSON. The ciphersuite ID string was also changed for all ciphersuites: it is now equal to the `contextString` of each ciphersuite per the FROST spec. +* An option to disable cheater detection during aggregation of signatures has been added. ## Released diff --git a/frost-core/Cargo.toml b/frost-core/Cargo.toml index 472c9f6e..8b5831ba 100644 --- a/frost-core/Cargo.toml +++ b/frost-core/Cargo.toml @@ -50,7 +50,7 @@ rand_chacha = "0.3" serde_json = "1.0" [features] -default = ["serialization"] +default = ["serialization", "cheater-detection"] #! ## Features ## Expose internal types, which do not have SemVer guarantees. This is an advanced ## feature which can be useful if you need to build a modified version of FROST. @@ -63,6 +63,8 @@ serde = ["dep:serde", "dep:serdect"] serialization = ["serde", "dep:postcard"] # Exposes ciphersuite-generic tests for other crates to use test-impl = ["proptest", "serde_json", "criterion"] +# Enable cheater detection +cheater-detection = [] [lib] bench = false diff --git a/frost-core/src/frost.rs b/frost-core/src/frost.rs index 0e3d3910..2093e17e 100644 --- a/frost-core/src/frost.rs +++ b/frost-core/src/frost.rs @@ -406,6 +406,7 @@ where /// signature, if the coordinator themselves is a signer and misbehaves, they /// can avoid that step. However, at worst, this results in a denial of /// service attack due to publishing an invalid signature. + pub fn aggregate( signing_package: &SigningPackage, signature_shares: &BTreeMap, round2::SignatureShare>, @@ -419,11 +420,12 @@ where if signing_package.signing_commitments().len() != signature_shares.len() { return Err(Error::UnknownIdentifier); } - if !signing_package - .signing_commitments() - .keys() - .all(|id| signature_shares.contains_key(id) && pubkeys.verifying_shares().contains_key(id)) - { + if !signing_package.signing_commitments().keys().all(|id| { + #[cfg(feature = "cheater-detection")] + return signature_shares.contains_key(id) && pubkeys.verifying_shares().contains_key(id); + #[cfg(not(feature = "cheater-detection"))] + return signature_shares.contains_key(id); + }) { return Err(Error::UnknownIdentifier); } @@ -460,6 +462,7 @@ where // Only if the verification of the aggregate signature failed; verify each share to find the cheater. // This approach is more efficient since we don't need to verify all shares // if the aggregate signature is valid (which should be the common case). + #[cfg(feature = "cheater-detection")] if let Err(err) = verification_result { // Compute the per-message challenge. let challenge = crate::challenge::( @@ -504,5 +507,8 @@ where return Err(err); } + #[cfg(not(feature = "cheater-detection"))] + verification_result?; + Ok(signature) } diff --git a/frost-core/src/frost/round2.rs b/frost-core/src/frost/round2.rs index 019530a7..89a2e40b 100644 --- a/frost-core/src/frost/round2.rs +++ b/frost-core/src/frost/round2.rs @@ -88,12 +88,12 @@ where &self, identifier: Identifier, group_commitment_share: &round1::GroupCommitmentShare, - public_key: &frost::keys::VerifyingShare, + verifying_share: &frost::keys::VerifyingShare, lambda_i: Scalar, challenge: &Challenge, ) -> Result<(), Error> { if (::generator() * self.share) - != (group_commitment_share.0 + (public_key.0 * challenge.0 * lambda_i)) + != (group_commitment_share.0 + (verifying_share.0 * challenge.0 * lambda_i)) { return Err(Error::InvalidSignatureShare { culprit: identifier, diff --git a/frost-core/src/tests/ciphersuite_generic.rs b/frost-core/src/tests/ciphersuite_generic.rs index 6dff6fe0..eb644486 100644 --- a/frost-core/src/tests/ciphersuite_generic.rs +++ b/frost-core/src/tests/ciphersuite_generic.rs @@ -4,7 +4,7 @@ use std::{collections::BTreeMap, convert::TryFrom}; use crate::{ - frost::{self, Identifier}, + frost::{self, keys::PublicKeyPackage, Identifier}, Error, Field, Group, Signature, SigningKey, VerifyingKey, }; use rand_core::{CryptoRng, RngCore}; @@ -191,7 +191,7 @@ pub fn check_sign( min_signers: u16, key_packages: BTreeMap, frost::keys::KeyPackage>, mut rng: R, - pubkey_package: frost::keys::PublicKeyPackage, + pubkey_package: PublicKeyPackage, ) -> Result<(Vec, Signature, VerifyingKey), Error> { let mut nonces_map: BTreeMap, frost::round1::SigningNonces> = BTreeMap::new(); @@ -248,6 +248,13 @@ pub fn check_sign( // generates the final signature. //////////////////////////////////////////////////////////////////////////// + #[cfg(not(feature = "cheater-detection"))] + let pubkey_package = PublicKeyPackage { + header: pubkey_package.header, + verifying_shares: BTreeMap::new(), + verifying_key: pubkey_package.verifying_key, + }; + check_aggregate_errors( signing_package.clone(), signature_shares.clone(), @@ -305,11 +312,13 @@ fn check_aggregate_errors( signature_shares: BTreeMap, frost::round2::SignatureShare>, pubkey_package: frost::keys::PublicKeyPackage, ) { + #[cfg(feature = "cheater-detection")] check_aggregate_corrupted_share( signing_package.clone(), signature_shares.clone(), pubkey_package.clone(), ); + check_aggregate_invalid_share_identifier_for_verifying_shares( signing_package, signature_shares, diff --git a/frost-ed25519/Cargo.toml b/frost-ed25519/Cargo.toml index 9ca194d2..2574af4e 100644 --- a/frost-ed25519/Cargo.toml +++ b/frost-ed25519/Cargo.toml @@ -45,13 +45,15 @@ serde_json = "1.0" [features] nightly = [] -default = ["serialization"] +default = ["serialization", "cheater-detection"] serialization = ["serde", "frost-core/serialization"] #! ## Features ## 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`). serde = ["frost-core/serde"] +## Enable cheater detection +cheater-detection = ["frost-core/cheater-detection"] [lib] # Disables non-criterion benchmark which is not used; prevents errors diff --git a/frost-ed448/Cargo.toml b/frost-ed448/Cargo.toml index 0b524c8e..c80bcfd5 100644 --- a/frost-ed448/Cargo.toml +++ b/frost-ed448/Cargo.toml @@ -43,13 +43,15 @@ serde_json = "1.0" [features] nightly = [] -default = ["serialization"] +default = ["serialization", "cheater-detection"] serialization = ["serde", "frost-core/serialization"] #! ## Features ## 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`). serde = ["frost-core/serde"] +## Enable cheater detection +cheater-detection = ["frost-core/cheater-detection"] [lib] # Disables non-criterion benchmark which is not used; prevents errors diff --git a/frost-p256/Cargo.toml b/frost-p256/Cargo.toml index 5f50f91d..903e3b95 100644 --- a/frost-p256/Cargo.toml +++ b/frost-p256/Cargo.toml @@ -44,13 +44,15 @@ serde_json = "1.0" [features] nightly = [] -default = ["serialization"] +default = ["serialization", "cheater-detection"] serialization = ["serde", "frost-core/serialization"] #! ## Features ## 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`). serde = ["frost-core/serde"] +## Enable cheater detection +cheater-detection = ["frost-core/cheater-detection"] [lib] # Disables non-criterion benchmark which is not used; prevents errors diff --git a/frost-rerandomized/Cargo.toml b/frost-rerandomized/Cargo.toml index d9a8918a..5735f6a7 100644 --- a/frost-rerandomized/Cargo.toml +++ b/frost-rerandomized/Cargo.toml @@ -29,7 +29,7 @@ rand_core = "0.6" [features] nightly = [] -default = ["serialization"] +default = ["serialization", "cheater-detection"] serialization = ["serde", "frost-core/serialization"] #! ## Features ## Enable `serde` support for types that need to be communicated. You @@ -38,3 +38,5 @@ serialization = ["serde", "frost-core/serialization"] serde = ["frost-core/serde"] # Exposes ciphersuite-generic tests for other crates to use test-impl = ["frost-core/test-impl"] +## Enable cheater detection +cheater-detection = ["frost-core/cheater-detection"] diff --git a/frost-ristretto255/Cargo.toml b/frost-ristretto255/Cargo.toml index 49830e74..6780bca1 100644 --- a/frost-ristretto255/Cargo.toml +++ b/frost-ristretto255/Cargo.toml @@ -41,13 +41,15 @@ serde_json = "1.0" [features] nightly = [] -default = ["serialization"] +default = ["serialization", "cheater-detection"] serialization = ["serde", "frost-core/serialization"] #! ## Features ## 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`). serde = ["frost-core/serde"] +## Enable cheater detection +cheater-detection = ["frost-core/cheater-detection"] [lib] # Disables non-criterion benchmark which is not used; prevents errors diff --git a/frost-secp256k1/Cargo.toml b/frost-secp256k1/Cargo.toml index 068cfe2d..b22ef862 100644 --- a/frost-secp256k1/Cargo.toml +++ b/frost-secp256k1/Cargo.toml @@ -43,13 +43,15 @@ serde_json = "1.0" [features] nightly = [] -default = ["serialization"] +default = ["serialization", "cheater-detection"] serialization = ["serde", "frost-core/serialization"] #! ## Features ## 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`). serde = ["frost-core/serde"] +## Enable cheater detection +cheater-detection = ["frost-core/cheater-detection"] [lib] # Disables non-criterion benchmark which is not used; prevents errors