Compare commits

...

2 Commits

Author SHA1 Message Date
conduition d580241e85 serialize taproot signatures as 64 bytes with x-only nonce
BIP340 signatures are supposed to be serialized as a 64-byte array:
32 bytes for the x-only nonce point 'R', and 32 bytes for the signature
component 's'. This commit customizes the frost-secp256k1-tr crate so
that signatures are serialized with x-only nonces, omitting the leading
parity byte.
2024-04-26 21:32:10 +03:00
conduition 15688ab30a ensure taproot signatures always use even nonce points
BIP340 signatures are usually represented with x-only (even parity)
nonce points. As a step towards normalizing this for the frost-secp256k1-tr
crate, we should ensure all Signature struct instances always use the
effective nonce point, including the DKG proof-of-knowledge.
2024-04-26 21:32:10 +03:00
27 changed files with 175 additions and 148 deletions

View File

@ -126,7 +126,7 @@ where
for item in self.signatures.iter() {
let z = item.sig.z;
let R = <C>::effective_nonce_element(item.sig.R);
let R = item.sig.R;
let vk = <C>::effective_pubkey_element(&item.vk, &item.sig_params);
let blind = <<C::Group as Group>::Field>::random(&mut rng);

View File

@ -36,7 +36,7 @@ use rand_core::{CryptoRng, RngCore};
use crate::{
Challenge, Ciphersuite, Element, Error, Field, Group, Header, Identifier, Scalar, Signature,
SigningKey, VerifyingKey,
SigningKey,
};
use super::{
@ -314,7 +314,7 @@ pub fn part1<C: Ciphersuite, R: RngCore + CryptoRng>(
/// Generates the challenge for the proof of knowledge to a secret for the DKG.
fn challenge<C>(
identifier: Identifier<C>,
verifying_key: &VerifyingKey<C>,
verifying_key: &Element<C>,
R: &Element<C>,
) -> Option<Challenge<C>>
where
@ -323,7 +323,7 @@ where
let mut preimage = vec![];
preimage.extend_from_slice(identifier.serialize().as_ref());
preimage.extend_from_slice(<C::Group>::serialize(&verifying_key.element).as_ref());
preimage.extend_from_slice(<C::Group>::serialize(&verifying_key).as_ref());
preimage.extend_from_slice(<C::Group>::serialize(R).as_ref());
Some(Challenge(C::HDKG(&preimage[..])?))
@ -344,14 +344,23 @@ pub(crate) fn compute_proof_of_knowledge<C: Ciphersuite, R: RngCore + CryptoRng>
// > a_{i0} by calculating σ_i = (R_i, μ_i), such that k ← Z_q, R_i = g^k,
// > c_i = H(i, Φ, g^{a_{i0}} , R_i), μ_i = k + a_{i0} · c_i, with Φ being
// > a context string to prevent replay attacks.
let k = <<C::Group as Group>::Field>::random(&mut rng);
let R_i = <C::Group>::generator() * k;
let c_i = challenge::<C>(identifier, &commitment.verifying_key()?, &R_i)
.ok_or(Error::DKGNotSupported)?;
let mut k = <<C::Group as Group>::Field>::random(&mut rng);
let mut R_i = <C::Group>::generator() * k;
k = <C>::effective_nonce_secret(k, &R_i);
R_i = <C>::effective_nonce_element(R_i);
let verifying_key = commitment.verifying_key()?;
let sig_params = Default::default();
let phi_ell0 = <C>::effective_pubkey_element(&verifying_key, &sig_params);
let c_i = challenge::<C>(identifier, &phi_ell0, &R_i).ok_or(Error::DKGNotSupported)?;
let a_i0 = *coefficients
.first()
.expect("coefficients must have at least one element");
let mu_i = k + a_i0 * c_i.0;
let a_i0_effective = <C>::effective_secret_key(a_i0, &verifying_key, &sig_params);
let mu_i = k + a_i0_effective * c_i.0;
Ok(Signature { R: R_i, z: mu_i })
}
@ -371,9 +380,12 @@ pub(crate) fn verify_proof_of_knowledge<C: Ciphersuite>(
let ell = identifier;
let R_ell = proof_of_knowledge.R;
let mu_ell = proof_of_knowledge.z;
let phi_ell0 = commitment.verifying_key()?;
let verifying_key = commitment.verifying_key()?;
let phi_ell0 = <C>::effective_pubkey_element(&verifying_key, &Default::default());
let c_ell = challenge::<C>(ell, &phi_ell0, &R_ell).ok_or(Error::DKGNotSupported)?;
if R_ell != <C::Group>::generator() * mu_ell - phi_ell0.element * c_ell.0 {
if R_ell != <C::Group>::generator() * mu_ell - phi_ell0 * c_ell.0 {
return Err(Error::InvalidProofOfKnowledge { culprit: ell });
}
Ok(())

View File

@ -623,6 +623,7 @@ where
// Compute the group commitment from signing commitments produced in round one.
let group_commitment = compute_group_commitment(signing_package, &binding_factor_list)?;
let R = <C>::effective_nonce_element(group_commitment.0);
// The aggregation of the signature shares by summing them up, resulting in
// a plain Schnorr signature.
@ -636,12 +637,8 @@ where
z = z + signature_share.share;
}
let signature: Signature<C> = <C>::aggregate_sig_finalize(
z,
group_commitment.0,
&pubkeys.verifying_key,
&signing_package.sig_target,
);
let signature: Signature<C> =
<C>::aggregate_sig_finalize(z, R, &pubkeys.verifying_key, &signing_package.sig_target);
// Verify the aggregate signature
let verification_result = pubkeys
@ -654,11 +651,7 @@ where
#[cfg(feature = "cheater-detection")]
if let Err(err) = verification_result {
// Compute the per-message challenge.
let challenge = <C>::challenge(
&group_commitment.0,
&pubkeys.verifying_key,
&signing_package.sig_target,
);
let challenge = <C>::challenge(&R, &pubkeys.verifying_key, &signing_package.sig_target);
// Verify the signature shares.
for (signature_share_identifier, signature_share) in signature_shares {

View File

@ -1,6 +1,5 @@
//! Schnorr signatures over prime order groups (or subgroups)
use debugless_unwrap::DebuglessUnwrap;
use derive_getters::Getters;
use crate::{Ciphersuite, Element, Error, Field, Group, Scalar};
@ -32,53 +31,12 @@ where
/// Converts bytes as [`Ciphersuite::SignatureSerialization`] into a `Signature<C>`.
pub fn deserialize(bytes: C::SignatureSerialization) -> Result<Self, Error<C>> {
// To compute the expected length of the encoded point, encode the generator
// and get its length. Note that we can't use the identity because it can be encoded
// shorter in some cases (e.g. P-256, which uses SEC1 encoding).
let generator = <C::Group>::generator();
let mut R_bytes = Vec::from(<C::Group>::serialize(&generator).as_ref());
let R_bytes_len = R_bytes.len();
R_bytes[..].copy_from_slice(
bytes
.as_ref()
.get(0..R_bytes_len)
.ok_or(Error::MalformedSignature)?,
);
let R_serialization = &R_bytes.try_into().map_err(|_| Error::MalformedSignature)?;
let one = <<C::Group as Group>::Field as Field>::zero();
let mut z_bytes =
Vec::from(<<C::Group as Group>::Field as Field>::serialize(&one).as_ref());
let z_bytes_len = z_bytes.len();
// We extract the exact length of bytes we expect, not just the remaining bytes with `bytes[R_bytes_len..]`
z_bytes[..].copy_from_slice(
bytes
.as_ref()
.get(R_bytes_len..R_bytes_len + z_bytes_len)
.ok_or(Error::MalformedSignature)?,
);
let z_serialization = &z_bytes.try_into().map_err(|_| Error::MalformedSignature)?;
Ok(Self {
R: <C::Group>::deserialize(R_serialization)?,
z: <<C::Group as Group>::Field>::deserialize(z_serialization)?,
})
C::deserialize_signature(bytes)
}
/// Converts this signature to its [`Ciphersuite::SignatureSerialization`] in bytes.
pub fn serialize(&self) -> C::SignatureSerialization {
let mut bytes = vec![];
bytes.extend(<C::Group>::serialize(&self.R).as_ref());
bytes.extend(<<C::Group as Group>::Field>::serialize(&self.z).as_ref());
bytes.try_into().debugless_unwrap()
C::serialize_signature(self)
}
}

View File

@ -58,8 +58,9 @@ where
let secret = <C>::effective_secret_key(self.scalar, &public, &sig_target.sig_params);
let mut k = random_nonzero::<C, R>(&mut rng);
let R = <C::Group>::generator() * k;
let mut R = <C::Group>::generator() * k;
k = <C>::effective_nonce_secret(k, &R);
R = <C>::effective_nonce_element(R);
// Generate Schnorr challenge
let c: Challenge<C> = <C>::challenge(&R, &public, &sig_target);

View File

@ -5,6 +5,7 @@ use std::{
ops::{Add, Mul, Sub},
};
use debugless_unwrap::DebuglessUnwrap;
use rand_core::{CryptoRng, RngCore};
use crate::{
@ -310,6 +311,63 @@ pub trait Ciphersuite: Copy + Clone + PartialEq + Debug {
Signature { R, z }
}
/// Converts a signature to its [`Ciphersuite::SignatureSerialization`] in bytes.
///
/// The default implementation serializes a signature by serializing its `R` point and
/// `z` component independently, and then concatenating them.
fn serialize_signature(signature: &Signature<Self>) -> Self::SignatureSerialization {
let mut bytes = vec![];
bytes.extend(<Self::Group>::serialize(&signature.R).as_ref());
bytes.extend(<<Self::Group as Group>::Field>::serialize(&signature.z).as_ref());
bytes.try_into().debugless_unwrap()
}
/// Converts bytes as [`Ciphersuite::SignatureSerialization`] into a `Signature<C>`.
///
/// The default implementation assumes the serialization is a serialized `R` point
/// followed by a serialized `z` component with no padding or extra fields.
fn deserialize_signature(
bytes: Self::SignatureSerialization,
) -> Result<Signature<Self>, Error<Self>> {
// To compute the expected length of the encoded point, encode the generator
// and get its length. Note that we can't use the identity because it can be encoded
// shorter in some cases (e.g. P-256, which uses SEC1 encoding).
let generator = <Self::Group>::generator();
let mut R_bytes = Vec::from(<Self::Group>::serialize(&generator).as_ref());
let R_bytes_len = R_bytes.len();
R_bytes[..].copy_from_slice(
bytes
.as_ref()
.get(0..R_bytes_len)
.ok_or(Error::MalformedSignature)?,
);
let R_serialization = &R_bytes.try_into().map_err(|_| Error::MalformedSignature)?;
let one = <<Self::Group as Group>::Field as Field>::zero();
let mut z_bytes =
Vec::from(<<Self::Group as Group>::Field as Field>::serialize(&one).as_ref());
let z_bytes_len = z_bytes.len();
// We extract the exact length of bytes we expect, not just the remaining bytes with `bytes[R_bytes_len..]`
z_bytes[..].copy_from_slice(
bytes
.as_ref()
.get(R_bytes_len..R_bytes_len + z_bytes_len)
.ok_or(Error::MalformedSignature)?,
);
let z_serialization = &z_bytes.try_into().map_err(|_| Error::MalformedSignature)?;
Ok(Signature {
R: <Self::Group>::deserialize(R_serialization)?,
z: <<Self::Group as Group>::Field>::deserialize(z_serialization)?,
})
}
/// Compute the signature share for a particular signer on a given challenge.
fn compute_signature_share(
signer_nonces: &round1::SigningNonces<Self>,

View File

@ -76,7 +76,7 @@ where
// h * ( z * B - c * A - R) == 0
//
// where h is the cofactor
let R = C::effective_nonce_element(signature.R);
let R = signature.R;
let vk = C::effective_pubkey_element(&self, sig_params);
let zB = C::Group::generator() * signature.z;

View File

@ -1,6 +1,7 @@
{
"identifier": "2a00000000000000000000000000000000000000000000000000000000000000",
"proof_of_knowledge": "5866666666666666666666666666666666666666666666666666666666666666498d4e9311420c903913a56c94a694b8aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0a",
"element1": "5866666666666666666666666666666666666666666666666666666666666666",
"element2": "c9a3f86aae465f0e56513864510f3997561fa2c9e85ea21dc2292309f3cd6022",
"scalar1": "498d4e9311420c903913a56c94a694b8aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0a"
}
}

View File

@ -107,19 +107,12 @@ pub fn public_key_package() -> PublicKeyPackage {
/// Generate a sample round1::Package.
pub fn round1_package() -> round1::Package {
let serialized_scalar = <<C as Ciphersuite>::Group as Group>::Field::serialize(&scalar1());
let serialized_signature = Signature::new(element1(), scalar1()).serialize();
let signature = Signature::deserialize(serialized_signature).unwrap();
let serialized_element = <C as Ciphersuite>::Group::serialize(&element1());
let serialized_signature = serialized_element
.as_ref()
.iter()
.chain(serialized_scalar.as_ref().iter())
.cloned()
.collect::<Vec<u8>>()
.try_into()
.unwrap();
let vss_commitment =
VerifiableSecretSharingCommitment::deserialize(vec![serialized_element]).unwrap();
let signature = Signature::deserialize(serialized_signature).unwrap();
round1::Package::new(vss_commitment, signature)
}

View File

@ -1,6 +1,7 @@
{
"identifier": "2a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"proof_of_knowledge": "14fa30f25b790898adc8d74e2c13bdfdc4397ce61cffd33ad7c2a0051e9c78874098a36c7373ea4b62c7c9563720768824bcb66e71463f69004d83e51cb78150c2380ad9b3a18148166024e4c9db3cdf82466d3153aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa2a00",
"element1": "14fa30f25b790898adc8d74e2c13bdfdc4397ce61cffd33ad7c2a0051e9c78874098a36c7373ea4b62c7c9563720768824bcb66e71463f6900",
"element2": "ed8693eacdfbeada6ba0cdd1beb2bcbb98302a3a8365650db8c4d88a726de3b7d74d8835a0d76e03b0c2865020d659b38d04d74a63e905ae80",
"scalar1": "4d83e51cb78150c2380ad9b3a18148166024e4c9db3cdf82466d3153aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa2a00"
}
}

View File

@ -107,19 +107,12 @@ pub fn public_key_package() -> PublicKeyPackage {
/// Generate a sample round1::Package.
pub fn round1_package() -> round1::Package {
let serialized_scalar = <<C as Ciphersuite>::Group as Group>::Field::serialize(&scalar1());
let serialized_signature = Signature::new(element1(), scalar1()).serialize();
let signature = Signature::deserialize(serialized_signature).unwrap();
let serialized_element = <C as Ciphersuite>::Group::serialize(&element1());
let serialized_signature = serialized_element
.as_ref()
.iter()
.chain(serialized_scalar.as_ref().iter())
.cloned()
.collect::<Vec<u8>>()
.try_into()
.unwrap();
let vss_commitment =
VerifiableSecretSharingCommitment::deserialize(vec![serialized_element]).unwrap();
let signature = Signature::deserialize(serialized_signature).unwrap();
round1::Package::new(vss_commitment, signature)
}

View File

@ -1,6 +1,7 @@
{
"identifier": "000000000000000000000000000000000000000000000000000000000000002a",
"proof_of_knowledge": "036b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296aaaaaaaa00000000aaaaaaaaaaaaaaaa7def51c91a0fbf034d26872ca84218e1",
"element1": "036b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296",
"element2": "037cf27b188d034f7e8a52380304b51ac3c08969e277f21b35a60b48fc47669978",
"scalar1": "aaaaaaaa00000000aaaaaaaaaaaaaaaa7def51c91a0fbf034d26872ca84218e1"
}
}

View File

@ -107,19 +107,12 @@ pub fn public_key_package() -> PublicKeyPackage {
/// Generate a sample round1::Package.
pub fn round1_package() -> round1::Package {
let serialized_scalar = <<C as Ciphersuite>::Group as Group>::Field::serialize(&scalar1());
let serialized_signature = Signature::new(element1(), scalar1()).serialize();
let signature = Signature::deserialize(serialized_signature).unwrap();
let serialized_element = <C as Ciphersuite>::Group::serialize(&element1());
let serialized_signature = serialized_element
.as_ref()
.iter()
.chain(serialized_scalar.as_ref().iter())
.cloned()
.collect::<Vec<u8>>()
.try_into()
.unwrap();
let vss_commitment =
VerifiableSecretSharingCommitment::deserialize(vec![serialized_element]).unwrap();
let signature = Signature::deserialize(serialized_signature).unwrap();
round1::Package::new(vss_commitment, signature)
}

View File

@ -1,6 +1,7 @@
{
"identifier": "2a00000000000000000000000000000000000000000000000000000000000000",
"proof_of_knowledge": "e2f2ae0a6abc4e71a884a961c500515f58e30b6aa582dd8db6a65945e08d2d76498d4e9311420c903913a56c94a694b8aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0a",
"element1": "e2f2ae0a6abc4e71a884a961c500515f58e30b6aa582dd8db6a65945e08d2d76",
"element2": "6a493210f7499cd17fecb510ae0cea23a110e8d5b901f8acadd3095c73a3b919",
"scalar1": "498d4e9311420c903913a56c94a694b8aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0a"
}
}

View File

@ -107,19 +107,12 @@ pub fn public_key_package() -> PublicKeyPackage {
/// Generate a sample round1::Package.
pub fn round1_package() -> round1::Package {
let serialized_scalar = <<C as Ciphersuite>::Group as Group>::Field::serialize(&scalar1());
let serialized_signature = Signature::new(element1(), scalar1()).serialize();
let signature = Signature::deserialize(serialized_signature).unwrap();
let serialized_element = <C as Ciphersuite>::Group::serialize(&element1());
let serialized_signature = serialized_element
.as_ref()
.iter()
.chain(serialized_scalar.as_ref().iter())
.cloned()
.collect::<Vec<u8>>()
.try_into()
.unwrap();
let vss_commitment =
VerifiableSecretSharingCommitment::deserialize(vec![serialized_element]).unwrap();
let signature = Signature::deserialize(serialized_signature).unwrap();
round1::Package::new(vss_commitment, signature)
}

View File

@ -23,7 +23,7 @@ rustdoc-args = ["--cfg", "docsrs"]
[dependencies]
document-features = "0.2.7"
frost-core = { path = "../frost-core", version = "1.0.0" }
frost-core = { path = "../frost-core", version = "1.0.0", features = ["internals"] }
frost-rerandomized = { path = "../frost-rerandomized", version = "1.0.0" }
k256 = { version = "0.13.0", features = ["arithmetic", "expose-field", "hash2curve"] }
serde = { version = "1.0.160", features = ["derive"], optional = true }

View File

@ -271,7 +271,7 @@ impl Ciphersuite for Secp256K1Sha256 {
type HashOutput = [u8; 32];
type SignatureSerialization = [u8; 65];
type SignatureSerialization = [u8; 64];
type SigningParameters = SigningParameters;
@ -389,10 +389,39 @@ impl Ciphersuite for Secp256K1Sha256 {
} else {
k + (c * secret)
};
Signature::new(R, z)
}
/// Serialize a signature in compact BIP340 format, with an x-only R point.
fn serialize_signature(signature: &Signature) -> Self::SignatureSerialization {
let R_bytes = Self::Group::serialize(signature.R());
let z_bytes = <Self::Group as Group>::Field::serialize(signature.z());
let mut bytes = [0u8; 64];
bytes[..32].copy_from_slice(&R_bytes[1..]);
bytes[32..].copy_from_slice(&z_bytes);
bytes
}
/// Deserialize a signature in compact BIP340 format, with an x-only R point.
fn deserialize_signature(bytes: Self::SignatureSerialization) -> Result<Signature, Error> {
if bytes.len() != 64 {
return Err(Error::MalformedSignature);
}
let mut R_bytes = [0u8; 33];
R_bytes[0] = 0x02; // taproot signatures always have an even R point
R_bytes[1..].copy_from_slice(&bytes[..32]);
let mut z_bytes = [0u8; 32];
z_bytes.copy_from_slice(&bytes[32..]);
let R = Self::Group::deserialize(&R_bytes)?;
let z = <Self::Group as Group>::Field::deserialize(&z_bytes)?;
Ok(Signature::new(R, z))
}
/// Compute a signature share, negating if required by BIP340.
fn compute_signature_share(
signer_nonces: &round1::SigningNonces,

View File

@ -1,6 +1,7 @@
{
"identifier": "000000000000000000000000000000000000000000000000000000000000002a",
"proof_of_knowledge": "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa9d1c9e899ca306ad27fe1945de0242b81",
"element1": "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
"element2": "02c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5",
"scalar1": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa9d1c9e899ca306ad27fe1945de0242b81"
}
}

View File

@ -107,19 +107,12 @@ pub fn public_key_package() -> PublicKeyPackage {
/// Generate a sample round1::Package.
pub fn round1_package() -> round1::Package {
let serialized_scalar = <<C as Ciphersuite>::Group as Group>::Field::serialize(&scalar1());
let serialized_signature = Signature::new(element1(), scalar1()).serialize();
let signature = Signature::deserialize(serialized_signature).unwrap();
let serialized_element = <C as Ciphersuite>::Group::serialize(&element1());
let serialized_signature = serialized_element
.as_ref()
.iter()
.chain(serialized_scalar.as_ref().iter())
.cloned()
.collect::<Vec<u8>>()
.try_into()
.unwrap();
let vss_commitment =
VerifiableSecretSharingCommitment::deserialize(vec![serialized_element]).unwrap();
let signature = Signature::deserialize(serialized_signature).unwrap();
round1::Package::new(vss_commitment, signature)
}

View File

@ -1104,6 +1104,6 @@
]
},
"final_output": {
"sig": "0354997f922511dba38d16973092a331f4039477bf4a2d77b438a317862795b26793c1a85a62387eabeb5073b01e63afea1c4755b4db6ad5c66758b3c05c76d67a"
"sig": "54997f922511dba38d16973092a331f4039477bf4a2d77b438a317862795b26793c1a85a62387eabeb5073b01e63afea1c4755b4db6ad5c66758b3c05c76d67a"
}
}

View File

@ -72,6 +72,6 @@
]
},
"final_output": {
"sig": "030c776a9516a77808b70a31e74f1464814a6fcf897fb3a6bd84c7a9a9a7a5bcb8d8bfc2b385379c093bcc0579abc5f6f696e8f2c0c01f28ff7b5ef55397fc3c9a"
"sig": "0c776a9516a77808b70a31e74f1464814a6fcf897fb3a6bd84c7a9a9a7a5bcb8d8bfc2b385379c093bcc0579abc5f6f696e8f2c0c01f28ff7b5ef55397fc3c9a"
}
}

View File

@ -13,7 +13,7 @@
"signing_key": "68e3f6904c6043973515a36bf7801a71597da35733f21305d75a5234f06e4529",
"coefficient": "25d2d840a3e2718a431ec69e14ee8a015b000d43c7a9868060f01d5aa52a19d1",
"vss_commitments": ["03e7ba4acb164d2bd5eba4f47b3a788109ddb3f88f1181792424fa332123a25ea8", "037495e920a1f032916193aa80ea97a4c3a611dec9ab47ccc969deb664f5f88bbe"],
"proof_of_knowledge": "03c5e534b1770fc7517983df70823c8a1c879cd9aed515437bdad242cfbdab5e82b0a92d1d6e57e421cbd75159b89d2508c774753476110250fabfa97ff667254d",
"proof_of_knowledge": "6689a8d414eb4961308e21f8caa1045236efded4f3de9209dc07547e88be3b42e192de9bed27fb78a7a4d4e35a0422f11f52631b8e66d69e609398eaff2770b8",
"signing_shares": {
"2": "1dd3cb3e2370e6af22917415f0ad584514807b58b3cc40d2230a26e115f02771",
"3": "dd25ee86acd01f996618aa0d1153f5e8fbc929a8e8a18b8f0a15f91d087217e2"
@ -26,7 +26,7 @@
"signing_key": "2619be8223b23e0453ddc630a4d164e81f7d8a9e07af33c4d4d02190df8bec13",
"coefficient": "f7ba0cbbffbea8aaceb3ade54bdbf35bafb1cda15b65ad490e0c63dd069a7c9f",
"vss_commitments": ["03ef10370a008cd95e179dc51e2cb7828f30b72d254e5166484f927c84ab326582", "022ce0dac0db217ba326fbbe3e6132d45e2a4bfa0a0c3790d91eacce9a1c2d6a10"],
"proof_of_knowledge": "038ef8fa5a833beb3fb0d83907de2ac3cad158927afc04739f5d52ae50681874a6d43da5d6985bc1190d649342cc3999b30b15e57f177f59cbf2d21a64d6b313e2",
"proof_of_knowledge": "19df66bda7724ccfa6a5ea76aac9cc167880d55717fe6887b89aeea94408cc9ce47b65a55f9d00479e9d3ea2c7402e81803e2e724d45d70c2cb93e3b0deb5f78",
"signing_shares": {
"1": "b489a711942526abbb5330a8215d2e740f7dbddec3452006993a8cea3ac278cb",
"3": "20255dc07b1fb78bdf90bd85fd2389c988c8250faee11826656a09142fa9fc97"
@ -39,7 +39,7 @@
"signing_key": "9a267f4cde8087a6eca0969425846209b41b515b73195ebbeeef8a991103f1ec",
"coefficient": "42ff6f39ce4f97f279781378ebcf93df47add84d75882cd31b266e83f76e25f6",
"vss_commitments": ["02da186c3863c5600b471a2799cb6f15ae4d8315a2f225c177798880e75ac820a0", "03e6a36e7fa4b117c1aa428886672e3a35d926bb4c585a9b07d8ee9a3387420067"],
"proof_of_knowledge": "03705c01e6fad6abac2f06211948d93a134c0beb00e98d7e7dc772f166acf1b3c99a674f3d712ebd7e421e59e90310facefcf04a7e7134b0f92f34d0b23afa375e",
"proof_of_knowledge": "6e115d9e63fd15d432b380ccf1ec4ed03340fcf96caeae8985aedb5f905b1a65dc422ffe5878988fbbc55454857736c7755d9c8f5ee6822c8833ea21d54dba36",
"signing_shares": {
"1": "da5c7f5238079835fe71f746364bb8756a7dcb228aeea686fa2aaa44dfec929c",
"2": "0d47e4b622ee3804bff8cfe088653efefe865cce0c065aecbf7e318182b89e2d"

View File

@ -539,7 +539,7 @@ fn check_round1_package_serialization() {
"commitment": [
"0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"
],
"proof_of_knowledge": "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa9d1c9e899ca306ad27fe1945de0242b81"
"proof_of_knowledge": "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa9d1c9e899ca306ad27fe1945de0242b81"
}"#;
let decoded_round1_package: round1::Package = serde_json::from_str(json).unwrap();
assert!(round1_package == decoded_round1_package);
@ -556,7 +556,7 @@ fn check_round1_package_serialization() {
"commitment": [
"0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"
],
"foo": "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa9d1c9e899ca306ad27fe1945de0242b81"
"foo": "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa9d1c9e899ca306ad27fe1945de0242b81"
}"#;
assert!(serde_json::from_str::<round1::Package>(invalid_json).is_err());
@ -581,7 +581,7 @@ fn check_round1_package_serialization() {
"commitment": [
"0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"
],
"proof_of_knowledge": "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa9d1c9e899ca306ad27fe1945de0242b81",
"proof_of_knowledge": "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa9d1c9e899ca306ad27fe1945de0242b81",
"extra": 1
}"#;
assert!(serde_json::from_str::<round1::Package>(invalid_json).is_err());

View File

@ -2,4 +2,4 @@
source: frost-secp256k1-tr/tests/serialization_tests.rs
expression: "hex::encode(&bytes)"
---
00230f8ab3010279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798410279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa9d1c9e899ca306ad27fe1945de0242b81
00230f8ab3010279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f817984079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa9d1c9e899ca306ad27fe1945de0242b81

View File

@ -1,6 +1,7 @@
{
"identifier": "000000000000000000000000000000000000000000000000000000000000002a",
"proof_of_knowledge": "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa9d1c9e899ca306ad27fe1945de0242b81",
"element1": "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
"element2": "02c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5",
"scalar1": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa9d1c9e899ca306ad27fe1945de0242b81"
}
}

View File

@ -107,19 +107,12 @@ pub fn public_key_package() -> PublicKeyPackage {
/// Generate a sample round1::Package.
pub fn round1_package() -> round1::Package {
let serialized_scalar = <<C as Ciphersuite>::Group as Group>::Field::serialize(&scalar1());
let serialized_signature = Signature::new(element1(), scalar1()).serialize();
let signature = Signature::deserialize(serialized_signature).unwrap();
let serialized_element = <C as Ciphersuite>::Group::serialize(&element1());
let serialized_signature = serialized_element
.as_ref()
.iter()
.chain(serialized_scalar.as_ref().iter())
.cloned()
.collect::<Vec<u8>>()
.try_into()
.unwrap();
let vss_commitment =
VerifiableSecretSharingCommitment::deserialize(vec![serialized_element]).unwrap();
let signature = Signature::deserialize(serialized_signature).unwrap();
round1::Package::new(vss_commitment, signature)
}

View File

@ -227,7 +227,13 @@ fn main() -> ExitCode {
&std::fs::read_to_string(format!("{original_folder}/tests/helpers/samples.json")).unwrap(),
)
.unwrap();
for key in &["identifier", "element1", "element2", "scalar1"] {
for key in &[
"identifier",
"proof_of_knowledge",
"element1",
"element2",
"scalar1",
] {
original_strings.push(samples[key].as_str().unwrap().to_owned());
}
let original_strings: Vec<&str> = original_strings.iter().map(|s| s.as_ref()).collect();
@ -313,7 +319,13 @@ fn main() -> ExitCode {
&std::fs::read_to_string(format!("{folder}/tests/helpers/samples.json")).unwrap(),
)
.unwrap();
for key in &["identifier", "element1", "element2", "scalar1"] {
for key in &[
"identifier",
"proof_of_knowledge",
"element1",
"element2",
"scalar1",
] {
replacement_strings.push(samples[key].as_str().unwrap().to_owned());
}
let replacement_strings: Vec<&str> =