From 62c60793d6513d9b9c1d9e30550fa08aa13696e3 Mon Sep 17 00:00:00 2001 From: Francisco Gindre Date: Fri, 21 Jun 2024 19:46:10 -0300 Subject: [PATCH] Fix Randomized tests Closes #45 cargo fmt add redpallas to CI --- .github/workflows/ci.yml | 18 +- frost-uniffi-sdk/src/lib.rs | 4 +- .../src/randomized/coordinator.rs | 39 ++++- frost-uniffi-sdk/src/randomized/randomizer.rs | 2 +- .../src/randomized/tests/helpers.rs | 43 +++-- frost-uniffi-sdk/src/trusted_dealer.rs | 29 ++-- .../tests/dkg_integration_tests.rs | 52 ++++-- frost-uniffi-sdk/tests/integration_tests.rs | 61 ++----- .../tests/randomized_integration_tests.rs | 162 ++++++++++++++++++ 9 files changed, 307 insertions(+), 103 deletions(-) create mode 100644 frost-uniffi-sdk/tests/randomized_integration_tests.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8dc42fd..4d9e7d0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,4 +33,20 @@ jobs: - uses: actions/checkout@v4 - run: rustup update ${{ matrix.toolchain }} && rustup default ${{ matrix.toolchain }} - run: cargo build --verbose --all-features - - run: cargo test --verbose \ No newline at end of file + - run: cargo test --verbose + + build_and_test_redpallas: + if: ${{ ! startsWith(github.event.pull_request.head.ref, 'release-') }} + name: Rust project - latest + runs-on: ubuntu-latest + strategy: + matrix: + toolchain: + - stable + - beta + - nightly + steps: + - uses: actions/checkout@v4 + - run: rustup update ${{ matrix.toolchain }} && rustup default ${{ matrix.toolchain }} + - run: cargo build --verbose --features redpallas + - run: cargo test --verbose --features redpallas \ No newline at end of file diff --git a/frost-uniffi-sdk/src/lib.rs b/frost-uniffi-sdk/src/lib.rs index 1c93bc0..7114ef6 100644 --- a/frost-uniffi-sdk/src/lib.rs +++ b/frost-uniffi-sdk/src/lib.rs @@ -265,8 +265,8 @@ pub fn trusted_dealer_keygen_with_identifiers( let trust_dealt_keys = trusted_dealer_keygen(&configuration, list, &mut rng).map_err(FrostError::map_err)?; - let pubkey = - FrostPublicKeyPackage::from_public_key_package::(trust_dealt_keys.public_keys).map_err(FrostError::map_err)?; + let pubkey = FrostPublicKeyPackage::from_public_key_package::(trust_dealt_keys.public_keys) + .map_err(FrostError::map_err)?; let mut hash_map: HashMap = HashMap::new(); diff --git a/frost-uniffi-sdk/src/randomized/coordinator.rs b/frost-uniffi-sdk/src/randomized/coordinator.rs index 2dc51b0..d599119 100644 --- a/frost-uniffi-sdk/src/randomized/coordinator.rs +++ b/frost-uniffi-sdk/src/randomized/coordinator.rs @@ -1,5 +1,6 @@ #[cfg(feature = "redpallas")] use reddsa::frost::redpallas as frost; +use reddsa::frost::redpallas::RandomizedParams; #[cfg(feature = "redpallas")] use crate::randomized::randomizer::FrostRandomizer; @@ -10,7 +11,10 @@ type E = reddsa::frost::redpallas::PallasBlake2b512; type E = frost_ed25519::Ed25519Sha512; use crate::{ - coordinator::{CoordinationError, FrostSignature, FrostSigningPackage}, + coordinator::{ + CoordinationError, FrostSignature, FrostSignatureVerificationError, FrostSigningPackage, + Message, + }, participant::FrostSignatureShare, FrostPublicKeyPackage, }; @@ -66,3 +70,36 @@ pub fn aggregate( }) .map(FrostSignature::from_signature) } + +#[uniffi::export] +pub fn verify_randomized_signature( + randomizer: FrostRandomizer, + message: Message, + signature: FrostSignature, + pubkey: FrostPublicKeyPackage, +) -> Result<(), FrostSignatureVerificationError> { + let randomizer = randomizer + .into_randomizer::() + .map_err(|_| FrostSignatureVerificationError::InvalidPublicKeyPackage)?; + + let signature = signature.to_signature::().map_err(|e| { + FrostSignatureVerificationError::ValidationFailed { + reason: e.to_string(), + } + })?; + + let pubkey = pubkey + .into_public_key_package() + .map_err(|_| FrostSignatureVerificationError::InvalidPublicKeyPackage)?; + + let verifying_key = pubkey.verifying_key(); + + let randomizer_params = RandomizedParams::from_randomizer(verifying_key, randomizer); + + randomizer_params + .randomized_verifying_key() + .verify(&message.data, &signature) + .map_err(|e| FrostSignatureVerificationError::ValidationFailed { + reason: e.to_string(), + }) +} diff --git a/frost-uniffi-sdk/src/randomized/randomizer.rs b/frost-uniffi-sdk/src/randomized/randomizer.rs index 500248b..eecf981 100644 --- a/frost-uniffi-sdk/src/randomized/randomizer.rs +++ b/frost-uniffi-sdk/src/randomized/randomizer.rs @@ -9,7 +9,7 @@ use uniffi; type E = reddsa::frost::redpallas::PallasBlake2b512; #[cfg(feature = "redpallas")] -#[derive(uniffi::Record)] +#[derive(uniffi::Record, Clone)] pub struct FrostRandomizer { data: Vec, } diff --git a/frost-uniffi-sdk/src/randomized/tests/helpers.rs b/frost-uniffi-sdk/src/randomized/tests/helpers.rs index c272f99..c1bbad9 100644 --- a/frost-uniffi-sdk/src/randomized/tests/helpers.rs +++ b/frost-uniffi-sdk/src/randomized/tests/helpers.rs @@ -1,54 +1,61 @@ -use std::collections::HashMap; - -use rand::rngs::ThreadRng; -use reddsa::frost::redpallas as frost; +#[cfg(feature = "redpallas")] +type E = reddsa::frost::redpallas::PallasBlake2b512; +#[cfg(not(feature = "redpallas"))] +type E = frost_ed25519::Ed25519Sha512; use crate::coordinator::new_signing_package; use crate::randomized::participant::sign; use crate::randomized::randomizer::FrostRandomizer; +use crate::FrostPublicKeyPackage; use crate::{ coordinator::{FrostSigningPackage, Message}, participant::{FrostSignatureShare, FrostSigningCommitments, FrostSigningNonces}, FrostKeyPackage, ParticipantIdentifier, }; +use frost::RandomizedParams; +use rand::rngs::ThreadRng; +use reddsa::frost::redpallas as frost; +use std::collections::HashMap; pub fn round_2( rng: &mut ThreadRng, nonces_map: &HashMap, key_packages: &HashMap, commitments_map: HashMap, + pub_key: FrostPublicKeyPackage, message: Message, - randomizer: Option, ) -> ( FrostSigningPackage, HashMap, - Option, + RandomizedParams, ) { let commitments = commitments_map.into_iter().map(|c| c.1).collect(); let signing_package = new_signing_package(message, commitments).unwrap(); let mut signature_shares = HashMap::new(); - let randomizer = match randomizer { - Some(r) => r, - None => { - let randomizer = - frost::round2::Randomizer::new(rng, &signing_package.to_signing_package().unwrap()) - .unwrap(); + let pub_keys = pub_key.into_public_key_package().unwrap(); + let pallas_signing_package = signing_package.to_signing_package().unwrap(); + let randomized_params = + RandomizedParams::new(pub_keys.verifying_key(), &pallas_signing_package, rng).unwrap(); + let randomizer = randomized_params.randomizer(); - FrostRandomizer::from_randomizer::(randomizer).unwrap() - } - }; + let frost_randomizer = FrostRandomizer::from_randomizer::(*randomizer).unwrap(); for participant_identifier in nonces_map.keys() { let key_package = key_packages[participant_identifier].clone(); let nonces = nonces_map[participant_identifier].clone(); - let signature_share = - sign(signing_package.clone(), nonces, key_package, &randomizer).unwrap(); + let signature_share = sign( + signing_package.clone(), + nonces, + key_package, + &frost_randomizer, + ) + .unwrap(); signature_shares.insert(participant_identifier.clone(), signature_share); } - (signing_package, signature_shares, Some(randomizer)) + (signing_package, signature_shares, randomized_params) } diff --git a/frost-uniffi-sdk/src/trusted_dealer.rs b/frost-uniffi-sdk/src/trusted_dealer.rs index ecb228d..0543294 100644 --- a/frost-uniffi-sdk/src/trusted_dealer.rs +++ b/frost-uniffi-sdk/src/trusted_dealer.rs @@ -28,9 +28,8 @@ pub fn trusted_dealer_keygen_from_configuration( let trusted_dealt_keys = keygen?; - - - let pubkey = FrostPublicKeyPackage::from_public_key_package::(trusted_dealt_keys.public_keys)?; + let pubkey = + FrostPublicKeyPackage::from_public_key_package::(trusted_dealt_keys.public_keys)?; let mut hash_map: HashMap = HashMap::new(); @@ -45,8 +44,8 @@ pub fn trusted_dealer_keygen_from_configuration( } pub struct TrustDealtKeys { - pub secret_shares: BTreeMap,SecretShare>, - pub public_keys: PublicKeyPackage + pub secret_shares: BTreeMap, SecretShare>, + pub public_keys: PublicKeyPackage, } pub fn trusted_dealer_keygen( @@ -65,12 +64,10 @@ pub fn trusted_dealer_keygen( frost::keys::KeyPackage::try_from(v)?; } - Ok( - TrustDealtKeys { - secret_shares: shares, - public_keys: pubkeys - } - ) + Ok(TrustDealtKeys { + secret_shares: shares, + public_keys: pubkeys, + }) } fn split_secret( @@ -97,12 +94,10 @@ fn split_secret( frost::keys::KeyPackage::try_from(v)?; } - Ok( - TrustDealtKeys { - secret_shares: shares, - public_keys: pubkeys - } - ) + Ok(TrustDealtKeys { + secret_shares: shares, + public_keys: pubkeys, + }) } #[cfg(test)] mod tests { diff --git a/frost-uniffi-sdk/tests/dkg_integration_tests.rs b/frost-uniffi-sdk/tests/dkg_integration_tests.rs index 26c54cd..4810414 100644 --- a/frost-uniffi-sdk/tests/dkg_integration_tests.rs +++ b/frost-uniffi-sdk/tests/dkg_integration_tests.rs @@ -8,11 +8,15 @@ use frost_core::Identifier; use frost_uniffi_sdk::coordinator::{aggregate, verify_signature}; #[cfg(feature = "redpallas")] -use frost_uniffi_sdk::{ - coordinator::verify_signature, - randomized::{coordinator::aggregate, tests::helpers::round_2}, +use frost_uniffi_sdk::randomized::{ + coordinator::{aggregate, verify_randomized_signature}, + randomizer::FrostRandomizer, + tests::helpers::round_2, }; +mod helpers; +use helpers::round_1; + use rand::thread_rng; use std::{collections::HashMap, sync::Arc}; @@ -24,8 +28,6 @@ use frost_uniffi_sdk::dkg::lib::{ part_1, part_2, part_3, DKGRound1Package, DKGRound1SecretPackage, DKGRound2Package, DKGRound2SecretPackage, }; -mod helpers; -use helpers::round_1; #[cfg(not(feature = "redpallas"))] use helpers::round_2; @@ -198,19 +200,26 @@ fn test_dkg_from_3_participants() { }; #[cfg(feature = "redpallas")] - let (signing_package, signature_shares, randomizer) = round_2( + let pubkey = pubkeys.get(&p1_identifier).unwrap(); + + #[cfg(feature = "redpallas")] + let (signing_package, signature_shares, randomized_params) = round_2( &mut rng, &nonces, &key_packages, commitments, + pubkey.clone(), message.clone(), - None, ); #[cfg(not(feature = "redpallas"))] let (signing_package, signature_shares) = round_2(&nonces, &key_packages, commitments, message.clone()); + #[cfg(feature = "redpallas")] + let randomizer = + FrostRandomizer::from_randomizer::(*randomized_params.randomizer()).unwrap(); + let p1identifier = p1_identifier.clone(); let pubkey = pubkeys.get(&p1identifier).unwrap().clone(); let group_signature = aggregate( @@ -218,16 +227,31 @@ fn test_dkg_from_3_participants() { signature_shares.into_iter().map(|s| s.1).collect(), pubkey.clone(), #[cfg(feature = "redpallas")] - randomizer.unwrap(), + randomizer.clone(), ) .unwrap(); - let verify_signature = verify_signature(message, group_signature, pubkey.clone()); - - match verify_signature { - Ok(()) => assert!(true), - Err(e) => { - assert!(false, "signature verification failed with error: {e:?}") + #[cfg(feature = "redpallas")] + { + let verify_signature = + verify_randomized_signature(randomizer, message, group_signature, pubkey); + + match verify_signature { + Ok(()) => assert!(true), + Err(e) => { + assert!(false, "signature verification failed with error: {e:?}") + } + } + } + #[cfg(not(feature = "redpallas"))] + { + let verify_signature = verify_signature(message, group_signature, pubkey.clone()); + + match verify_signature { + Ok(()) => assert!(true), + Err(e) => { + assert!(false, "signature verification failed with error: {e:?}") + } } } } diff --git a/frost-uniffi-sdk/tests/integration_tests.rs b/frost-uniffi-sdk/tests/integration_tests.rs index 7ea1e7f..98b0a60 100644 --- a/frost-uniffi-sdk/tests/integration_tests.rs +++ b/frost-uniffi-sdk/tests/integration_tests.rs @@ -10,33 +10,21 @@ use rand::thread_rng; #[cfg(not(feature = "redpallas"))] use frost_uniffi_sdk::coordinator::aggregate; -#[cfg(feature = "redpallas")] -use frost_uniffi_sdk::{randomized::coordinator::aggregate, randomized::tests::helpers::round_2}; + #[cfg(not(feature = "redpallas"))] use helpers::round_2; - -#[cfg(feature = "redpallas")] -type E = reddsa::frost::redpallas::PallasBlake2b512; -#[cfg(not(feature = "redpallas"))] type E = frost_ed25519::Ed25519Sha512; +#[cfg(not(feature = "redpallas"))] +#[test] +fn test_trusted_from_configuration_with_secret() { + let mut rng = thread_rng(); -fn test_signing_key() -> Vec { - #[cfg(feature = "redpallas")] - return hex::decode("f500df73b2b416bec6a2b6bbb44e97164e05520b63aa27554cfc7ba82f5ba215") - .unwrap(); - - #[cfg(not(feature = "redpallas"))] - return vec![ + let secret: Vec = vec![ 123, 28, 51, 211, 245, 41, 29, 133, 222, 102, 72, 51, 190, 177, 173, 70, 159, 127, 182, 2, 90, 14, 199, 139, 58, 121, 12, 110, 19, 169, 131, 4, ]; -} -#[test] -fn test_trusted_from_configuration_with_secret() { - let mut rng = thread_rng(); - let secret: Vec = test_signing_key(); let secret_config = Configuration { min_signers: 2, max_signers: 3, @@ -50,17 +38,6 @@ fn test_trusted_from_configuration_with_secret() { data: "i am a message".as_bytes().to_vec(), }; - #[cfg(feature = "redpallas")] - let (signing_package, signature_shares, randomizer) = round_2( - &mut rng, - &nonces, - &key_packages, - commitments, - message.clone(), - None, - ); - - #[cfg(not(feature = "redpallas"))] let (signing_package, signature_shares) = round_2(&nonces, &key_packages, commitments, message.clone()); @@ -68,8 +45,6 @@ fn test_trusted_from_configuration_with_secret() { signing_package, signature_shares.into_iter().map(|s| s.1).collect(), pubkeys.clone(), - #[cfg(feature = "redpallas")] - randomizer.unwrap(), ) .unwrap(); @@ -82,11 +57,15 @@ fn test_trusted_from_configuration_with_secret() { } } } - +#[cfg(not(feature = "redpallas"))] #[test] fn check_keygen_with_dealer_with_secret_with_large_num_of_signers() { let mut rng = thread_rng(); - let secret: Vec = test_signing_key(); + let secret: Vec = vec![ + 123, 28, 51, 211, 245, 41, 29, 133, 222, 102, 72, 51, 190, 177, 173, 70, 159, 127, 182, 2, + 90, 14, 199, 139, 58, 121, 12, 110, 19, 169, 131, 4, + ]; + let secret_config = Configuration { min_signers: 14, max_signers: 20, @@ -101,29 +80,13 @@ fn check_keygen_with_dealer_with_secret_with_large_num_of_signers() { data: "i am a message".as_bytes().to_vec(), }; - #[cfg(feature = "redpallas")] - let (signing_package, signature_shares, randomizer) = round_2( - &mut rng, - &nonces, - &key_packages, - commitments, - message.clone(), - None, - ); - - #[cfg(not(feature = "redpallas"))] let (signing_package, signature_shares) = round_2(&nonces, &key_packages, commitments, message.clone()); - #[cfg(feature = "redpallas")] - let frost_randomizer = randomizer.unwrap(); - let group_signature = aggregate( signing_package, signature_shares.into_iter().map(|s| s.1).collect(), pubkeys.clone(), - #[cfg(feature = "redpallas")] - frost_randomizer, ) .unwrap(); diff --git a/frost-uniffi-sdk/tests/randomized_integration_tests.rs b/frost-uniffi-sdk/tests/randomized_integration_tests.rs new file mode 100644 index 0000000..67415e0 --- /dev/null +++ b/frost-uniffi-sdk/tests/randomized_integration_tests.rs @@ -0,0 +1,162 @@ +use frost_uniffi_sdk::{ + coordinator::Message, trusted_dealer::trusted_dealer_keygen_from_configuration, Configuration, +}; + +use frost_uniffi_sdk::{ + coordinator::new_signing_package, participant::FrostSignatureShare, ParticipantIdentifier, +}; +use std::collections::HashMap; + +mod helpers; +use helpers::{key_package, round_1}; +use rand::thread_rng; + +#[cfg(not(feature = "redpallas"))] +use frost_uniffi_sdk::coordinator::aggregate; +#[cfg(feature = "redpallas")] +use frost_uniffi_sdk::{ + randomized::tests::helpers::round_2, + randomized::{ + coordinator::{aggregate, verify_randomized_signature}, + participant::sign, + randomizer::FrostRandomizer, + }, +}; +#[cfg(not(feature = "redpallas"))] +use helpers::round_2; +#[cfg(feature = "redpallas")] +use reddsa::frost::redpallas::RandomizedParams; + +#[cfg(feature = "redpallas")] +type E = reddsa::frost::redpallas::PallasBlake2b512; +#[cfg(not(feature = "redpallas"))] +type E = frost_ed25519::Ed25519Sha512; + +fn test_signing_key() -> Vec { + #[cfg(feature = "redpallas")] + return vec![]; //hex::decode("f500df73b2b416bec6a2b6bbb44e97164e05520b63aa27554cfc7ba82f5ba215") + // .unwrap(); + + #[cfg(not(feature = "redpallas"))] + return vec![ + 123, 28, 51, 211, 245, 41, 29, 133, 222, 102, 72, 51, 190, 177, 173, 70, 159, 127, 182, 2, + 90, 14, 199, 139, 58, 121, 12, 110, 19, 169, 131, 4, + ]; +} + +#[cfg(feature = "redpallas")] +#[test] +fn test_randomized_trusted_from_configuration_with_secret() { + use frost_uniffi_sdk::randomized::coordinator::verify_randomized_signature; + + let mut rng = thread_rng(); + + let secret: Vec = test_signing_key(); + let secret_config = Configuration { + min_signers: 2, + max_signers: 3, + secret, + }; + + let (pubkeys, shares) = trusted_dealer_keygen_from_configuration::(&secret_config).unwrap(); + let key_packages = key_package::(&shares); + let (nonces, commitments) = round_1::(&mut rng, &key_packages); + let message = Message { + data: "i am a message".as_bytes().to_vec(), + }; + + let commitments = commitments.into_iter().map(|c| c.1).collect(); + let signing_package = new_signing_package(message.clone(), commitments).unwrap(); + let mut signature_shares: HashMap = HashMap::new(); + + let pallas_signing_package = signing_package.to_signing_package().unwrap(); + let randomized_params = RandomizedParams::new( + pubkeys.into_public_key_package().unwrap().verifying_key(), + &pallas_signing_package, + rng, + ) + .unwrap(); + let randomizer = randomized_params.randomizer(); + + let frost_randomizer = FrostRandomizer::from_randomizer::(*randomizer).unwrap(); + + for participant_identifier in nonces.keys() { + let key_package = key_packages[participant_identifier].clone(); + + let nonces = nonces[participant_identifier].clone(); + + let signature_share = sign( + signing_package.clone(), + nonces, + key_package, + &frost_randomizer, + ) + .unwrap(); + + signature_shares.insert(participant_identifier.clone(), signature_share); + } + + let randomizer = + FrostRandomizer::from_randomizer::(*randomized_params.randomizer()).unwrap(); + + let group_signature = aggregate( + signing_package, + signature_shares.into_iter().map(|s| s.1).collect(), + pubkeys.clone(), + randomizer.clone(), + ) + .unwrap(); + + let verify_signature = + verify_randomized_signature(randomizer, message, group_signature, pubkeys); + + match verify_signature { + Ok(()) => assert!(true), + Err(e) => { + assert!(false, "signature verification failed with error: {e:?}") + } + } +} +#[cfg(feature = "redpallas")] +#[test] +fn check_keygen_with_dealer_with_secret_with_large_num_of_signers() { + let mut rng = thread_rng(); + let secret: Vec = test_signing_key(); + let secret_config = Configuration { + min_signers: 14, + max_signers: 20, + secret, + }; + + let (pubkeys, shares) = trusted_dealer_keygen_from_configuration::(&secret_config).unwrap(); + + let key_packages = key_package::(&shares); + let (nonces, commitments) = round_1::(&mut rng, &key_packages); + let message = Message { + data: "i am a message".as_bytes().to_vec(), + }; + + let (signing_package, signature_shares, randomized_params) = round_2( + &mut rng, + &nonces, + &key_packages, + commitments, + pubkeys.clone(), + message.clone(), + ); + + let frost_randomizer = + FrostRandomizer::from_randomizer::(*randomized_params.randomizer()).unwrap(); + + let group_signature = aggregate( + signing_package, + signature_shares.into_iter().map(|s| s.1).collect(), + pubkeys.clone(), + frost_randomizer.clone(), + ) + .unwrap(); + + assert!( + verify_randomized_signature(frost_randomizer, message, group_signature, pubkeys).is_ok() + ) +}