add integration tests to cover taproot-tweaked signing

This commit is contained in:
conduition 2024-03-16 04:40:00 +00:00 committed by zebra-lucky
parent 5d2d683e1d
commit 20c2c98a93
9 changed files with 174 additions and 34 deletions

View File

@ -5,7 +5,8 @@ use std::{collections::BTreeMap, convert::TryFrom};
use crate as frost;
use crate::{
keys::PublicKeyPackage, Error, Field, Group, Identifier, Signature, SigningKey, VerifyingKey,
keys::PublicKeyPackage, Error, Field, Group, Identifier, Signature, SigningKey, SigningTarget,
VerifyingKey,
};
use rand_core::{CryptoRng, RngCore};
@ -100,7 +101,8 @@ pub fn check_share_generation_fails_with_invalid_signers<C: Ciphersuite, R: RngC
/// Test FROST signing with trusted dealer with a Ciphersuite.
pub fn check_sign_with_dealer<C: Ciphersuite, R: RngCore + CryptoRng>(
mut rng: R,
) -> (Vec<u8>, Signature<C>, VerifyingKey<C>) {
signing_target: SigningTarget<C>,
) -> (SigningTarget<C>, Signature<C>, VerifyingKey<C>) {
////////////////////////////////////////////////////////////////////////////
// Key generation
////////////////////////////////////////////////////////////////////////////
@ -144,10 +146,11 @@ pub fn check_sign_with_dealer<C: Ciphersuite, R: RngCore + CryptoRng>(
.collect(),
&mut rng,
pubkeys.clone(),
signing_target.clone(),
);
assert_eq!(r, Err(Error::InvalidSignature));
check_sign(min_signers, key_packages, rng, pubkeys).unwrap()
check_sign(min_signers, key_packages, rng, pubkeys, signing_target).unwrap()
}
/// Test FROST signing with trusted dealer fails with invalid numbers of signers.
@ -192,7 +195,8 @@ pub fn check_sign<C: Ciphersuite + PartialEq, R: RngCore + CryptoRng>(
key_packages: BTreeMap<frost::Identifier<C>, frost::keys::KeyPackage<C>>,
mut rng: R,
pubkey_package: PublicKeyPackage<C>,
) -> Result<(Vec<u8>, Signature<C>, VerifyingKey<C>), Error<C>> {
signing_target: SigningTarget<C>,
) -> Result<(SigningTarget<C>, Signature<C>, VerifyingKey<C>), Error<C>> {
let mut nonces_map: BTreeMap<frost::Identifier<C>, frost::round1::SigningNonces<C>> =
BTreeMap::new();
let mut commitments_map: BTreeMap<frost::Identifier<C>, frost::round1::SigningCommitments<C>> =
@ -220,8 +224,7 @@ pub fn check_sign<C: Ciphersuite + PartialEq, R: RngCore + CryptoRng>(
// - decide what message to sign
// - take one (unused) commitment per signing participant
let mut signature_shares = BTreeMap::new();
let message = "message to sign".as_bytes();
let signing_package = frost::SigningPackage::new(commitments_map, message);
let signing_package = frost::SigningPackage::new(commitments_map, signing_target.clone());
////////////////////////////////////////////////////////////////////////////
// Round 2: each participant generates their signature share
@ -268,7 +271,14 @@ pub fn check_sign<C: Ciphersuite + PartialEq, R: RngCore + CryptoRng>(
// key (the verification key).
pubkey_package
.verifying_key
.verify(message, &group_signature)?;
.verify(signing_target.clone(), &group_signature)?;
// Check that the effective verifying key can be verified against the raw message,
// without exposing the SigningParameters.
pubkey_package
.verifying_key
.effective_key(signing_target.sig_params())
.verify(signing_target.message(), &group_signature)?;
// Check that the threshold signature can be verified by the group public
// key (the verification key) from KeyPackage.verifying_key
@ -277,11 +287,11 @@ pub fn check_sign<C: Ciphersuite + PartialEq, R: RngCore + CryptoRng>(
key_package
.verifying_key
.verify(message, &group_signature)?;
.verify(signing_target.clone(), &group_signature)?;
}
Ok((
message.to_owned(),
signing_target,
group_signature,
pubkey_package.verifying_key,
))
@ -363,7 +373,8 @@ fn check_aggregate_invalid_share_identifier_for_verifying_shares<C: Ciphersuite
/// Test FROST signing with DKG with a Ciphersuite.
pub fn check_sign_with_dkg<C: Ciphersuite + PartialEq, R: RngCore + CryptoRng>(
mut rng: R,
) -> (Vec<u8>, Signature<C>, VerifyingKey<C>)
signing_target: SigningTarget<C>,
) -> (SigningTarget<C>, Signature<C>, VerifyingKey<C>)
where
C::Group: std::cmp::PartialEq,
{
@ -520,7 +531,7 @@ where
let pubkeys = frost::keys::PublicKeyPackage::new(verifying_keys, verifying_key.unwrap());
// Proceed with the signing test.
check_sign(min_signers, key_packages, rng, pubkeys).unwrap()
check_sign(min_signers, key_packages, rng, pubkeys, signing_target).unwrap()
}
/// Check that calling dkg::part3() with distinct sets of participants fail.
@ -564,7 +575,8 @@ fn check_part3_different_participants<C: Ciphersuite>(
/// Identifiers.
pub fn check_sign_with_dealer_and_identifiers<C: Ciphersuite, R: RngCore + CryptoRng>(
mut rng: R,
) -> (Vec<u8>, Signature<C>, VerifyingKey<C>) {
signing_target: SigningTarget<C>,
) -> (SigningTarget<C>, Signature<C>, VerifyingKey<C>) {
// Check error cases first
// Check repeated identifiers
@ -630,7 +642,7 @@ pub fn check_sign_with_dealer_and_identifiers<C: Ciphersuite, R: RngCore + Crypt
let key_package = frost::keys::KeyPackage::try_from(v).unwrap();
key_packages.insert(k, key_package);
}
check_sign(min_signers, key_packages, rng, pubkeys).unwrap()
check_sign(min_signers, key_packages, rng, pubkeys, signing_target).unwrap()
}
fn check_part2_error<C: Ciphersuite>(

View File

@ -12,7 +12,10 @@ fn check_zero_key_fails() {
fn check_sign_with_dkg() {
let rng = thread_rng();
frost_core::tests::ciphersuite_generic::check_sign_with_dkg::<Ed25519Sha512, _>(rng);
frost_core::tests::ciphersuite_generic::check_sign_with_dkg::<Ed25519Sha512, _>(
rng,
b"message".into(),
);
}
#[test]
@ -68,7 +71,10 @@ fn check_rts() {
fn check_sign_with_dealer() {
let rng = thread_rng();
frost_core::tests::ciphersuite_generic::check_sign_with_dealer::<Ed25519Sha512, _>(rng);
frost_core::tests::ciphersuite_generic::check_sign_with_dealer::<Ed25519Sha512, _>(
rng,
b"message".into(),
);
}
#[test]
@ -220,7 +226,7 @@ fn check_sign_with_dealer_and_identifiers() {
frost_core::tests::ciphersuite_generic::check_sign_with_dealer_and_identifiers::<
Ed25519Sha512,
_,
>(rng);
>(rng, b"message".into());
}
#[test]

View File

@ -12,12 +12,13 @@ fn check_interoperability_in_sign_with_dkg() {
// and the interoperability check. A smaller number of iterations is used
// because DKG takes longer and otherwise the test would be too slow.
for _ in 0..32 {
let (msg, group_signature, group_pubkey) =
let (target, group_signature, group_pubkey) =
frost_core::tests::ciphersuite_generic::check_sign_with_dkg::<Ed25519Sha512, _>(
rng.clone(),
b"message".into(),
);
helpers::verify_signature(&msg, group_signature, group_pubkey);
helpers::verify_signature(target.message(), group_signature, group_pubkey);
}
}
@ -28,13 +29,14 @@ fn check_interoperability_in_sign_with_dealer() {
// Test with multiple keys/signatures to better exercise the key generation
// and the interoperability check.
for _ in 0..256 {
let (msg, group_signature, group_pubkey) =
let (target, group_signature, group_pubkey) =
frost_core::tests::ciphersuite_generic::check_sign_with_dealer::<Ed25519Sha512, _>(
rng.clone(),
b"message".into(),
);
// Check that the threshold signature can be verified by the `ed25519_dalek` crate
// public key (interoperability test)
helpers::verify_signature(&msg, group_signature, group_pubkey);
helpers::verify_signature(target.message(), group_signature, group_pubkey);
}
}

View File

@ -12,7 +12,10 @@ fn check_zero_key_fails() {
fn check_sign_with_dkg() {
let rng = thread_rng();
frost_core::tests::ciphersuite_generic::check_sign_with_dkg::<Ed448Shake256, _>(rng);
frost_core::tests::ciphersuite_generic::check_sign_with_dkg::<Ed448Shake256, _>(
rng,
b"message".into(),
);
}
#[test]
@ -68,7 +71,10 @@ fn check_rts() {
fn check_sign_with_dealer() {
let rng = thread_rng();
frost_core::tests::ciphersuite_generic::check_sign_with_dealer::<Ed448Shake256, _>(rng);
frost_core::tests::ciphersuite_generic::check_sign_with_dealer::<Ed448Shake256, _>(
rng,
b"message".into(),
);
}
#[test]
@ -220,7 +226,7 @@ fn check_sign_with_dealer_and_identifiers() {
frost_core::tests::ciphersuite_generic::check_sign_with_dealer_and_identifiers::<
Ed448Shake256,
_,
>(rng);
>(rng, b"message".into());
}
#[test]

View File

@ -12,7 +12,10 @@ fn check_zero_key_fails() {
fn check_sign_with_dkg() {
let rng = thread_rng();
frost_core::tests::ciphersuite_generic::check_sign_with_dkg::<P256Sha256, _>(rng);
frost_core::tests::ciphersuite_generic::check_sign_with_dkg::<P256Sha256, _>(
rng,
b"message".into(),
);
}
#[test]
@ -68,7 +71,10 @@ fn check_rts() {
fn check_sign_with_dealer() {
let rng = thread_rng();
frost_core::tests::ciphersuite_generic::check_sign_with_dealer::<P256Sha256, _>(rng);
frost_core::tests::ciphersuite_generic::check_sign_with_dealer::<P256Sha256, _>(
rng,
b"message".into(),
);
}
#[test]
@ -217,6 +223,7 @@ fn check_sign_with_dealer_and_identifiers() {
frost_core::tests::ciphersuite_generic::check_sign_with_dealer_and_identifiers::<P256Sha256, _>(
rng,
b"message".into(),
);
}

View File

@ -12,7 +12,10 @@ fn check_zero_key_fails() {
fn check_sign_with_dkg() {
let rng = thread_rng();
frost_core::tests::ciphersuite_generic::check_sign_with_dkg::<Ristretto255Sha512, _>(rng);
frost_core::tests::ciphersuite_generic::check_sign_with_dkg::<Ristretto255Sha512, _>(
rng,
b"message".into(),
);
}
#[test]
@ -68,7 +71,10 @@ fn check_rts() {
fn check_sign_with_dealer() {
let rng = thread_rng();
frost_core::tests::ciphersuite_generic::check_sign_with_dealer::<Ristretto255Sha512, _>(rng);
frost_core::tests::ciphersuite_generic::check_sign_with_dealer::<Ristretto255Sha512, _>(
rng,
b"message".into(),
);
}
#[test]
@ -220,7 +226,7 @@ fn check_sign_with_dealer_and_identifiers() {
frost_core::tests::ciphersuite_generic::check_sign_with_dealer_and_identifiers::<
Ristretto255Sha512,
_,
>(rng);
>(rng, b"message".into());
}
#[test]

View File

@ -12,7 +12,10 @@ fn check_zero_key_fails() {
fn check_sign_with_dkg() {
let rng = thread_rng();
frost_core::tests::ciphersuite_generic::check_sign_with_dkg::<Secp256K1Sha256, _>(rng);
frost_core::tests::ciphersuite_generic::check_sign_with_dkg::<Secp256K1Sha256, _>(
rng,
b"message".into(),
);
}
#[test]
@ -68,7 +71,10 @@ fn check_rts() {
fn check_sign_with_dealer() {
let rng = thread_rng();
frost_core::tests::ciphersuite_generic::check_sign_with_dealer::<Secp256K1Sha256, _>(rng);
frost_core::tests::ciphersuite_generic::check_sign_with_dealer::<Secp256K1Sha256, _>(
rng,
b"message".into(),
);
}
#[test]
@ -220,7 +226,7 @@ fn check_sign_with_dealer_and_identifiers() {
frost_core::tests::ciphersuite_generic::check_sign_with_dealer_and_identifiers::<
Secp256K1Sha256,
_,
>(rng);
>(rng, b"message".into());
}
#[test]

View File

@ -0,0 +1,89 @@
use frost_secp256k1_tr::*;
use rand::thread_rng;
#[test]
fn check_tweaked_signing_key() {
let signing_key = SigningKey::deserialize([0xAA; 32]).unwrap();
let untweaked_verifying_key = VerifyingKey::from(signing_key);
let mut rng = rand::thread_rng();
let message = b"message";
let untweaked_signature = signing_key.sign(&mut rng, &message);
untweaked_verifying_key
.verify(&message, &untweaked_signature)
.expect("untweaked signature should be valid under untweaked verifying key");
let signing_target = SigningTarget::new(
&message,
SigningParameters {
tapscript_merkle_root: Some(vec![]),
},
);
let tweaked_signature = signing_key.sign(&mut rng, signing_target.clone());
untweaked_verifying_key
.verify(&message, &tweaked_signature)
.expect_err("tweaked signature should not be valid under untweaked verifying key");
let tweaked_verifying_key = untweaked_verifying_key.effective_key(signing_target.sig_params());
tweaked_verifying_key
.verify(&message, &tweaked_signature)
.expect("tweaked signature should be valid under tweaked verifying key");
untweaked_verifying_key
.verify(signing_target.clone(), &tweaked_signature)
.expect(
"tweaked signature should be valid under untweaked verifying key\
when signing params are provided",
);
}
#[test]
fn check_tweaked_sign_with_dkg() {
let rng = thread_rng();
frost_core::tests::ciphersuite_generic::check_sign_with_dkg::<Secp256K1Sha256, _>(
rng,
SigningTarget::new(
b"message",
SigningParameters {
tapscript_merkle_root: Some(vec![]),
},
),
);
}
#[test]
fn check_tweaked_sign_with_dealer() {
let rng = thread_rng();
frost_core::tests::ciphersuite_generic::check_sign_with_dealer::<Secp256K1Sha256, _>(
rng,
SigningTarget::new(
b"message",
SigningParameters {
tapscript_merkle_root: Some(vec![]),
},
),
);
}
#[test]
fn check_tweaked_sign_with_dealer_and_identifiers() {
let rng = thread_rng();
frost_core::tests::ciphersuite_generic::check_sign_with_dealer_and_identifiers::<
Secp256K1Sha256,
_,
>(
rng,
SigningTarget::new(
b"message",
SigningParameters {
tapscript_merkle_root: Some(vec![]),
},
),
);
}

View File

@ -12,7 +12,10 @@ fn check_zero_key_fails() {
fn check_sign_with_dkg() {
let rng = thread_rng();
frost_core::tests::ciphersuite_generic::check_sign_with_dkg::<Secp256K1Sha256, _>(rng);
frost_core::tests::ciphersuite_generic::check_sign_with_dkg::<Secp256K1Sha256, _>(
rng,
b"message".into(),
);
}
#[test]
@ -68,7 +71,10 @@ fn check_rts() {
fn check_sign_with_dealer() {
let rng = thread_rng();
frost_core::tests::ciphersuite_generic::check_sign_with_dealer::<Secp256K1Sha256, _>(rng);
frost_core::tests::ciphersuite_generic::check_sign_with_dealer::<Secp256K1Sha256, _>(
rng,
b"message".into(),
);
}
#[test]
@ -220,7 +226,7 @@ fn check_sign_with_dealer_and_identifiers() {
frost_core::tests::ciphersuite_generic::check_sign_with_dealer_and_identifiers::<
Secp256K1Sha256,
_,
>(rng);
>(rng, b"message".into());
}
#[test]