Remove pub from fields, add getters (#401)
* derive getters; remove any existing ones; use BTreeMap for signing commitments * add recreation tests * make tests ciphersuite-specific
This commit is contained in:
parent
47121537e8
commit
c851bbb8fa
|
@ -19,6 +19,7 @@ features = ["nightly"]
|
|||
[dependencies]
|
||||
byteorder = "1.4"
|
||||
debugless-unwrap = "0.0.4"
|
||||
derive-getters = "0.3.0"
|
||||
digest = "0.10"
|
||||
hex = { version = "0.4.3", features = ["serde"] }
|
||||
rand_core = "0.6"
|
||||
|
|
|
@ -11,11 +11,12 @@
|
|||
//! Sharing, where shares are generated using Shamir Secret Sharing.
|
||||
|
||||
use std::{
|
||||
collections::{BTreeMap, HashMap},
|
||||
collections::BTreeMap,
|
||||
fmt::{self, Debug},
|
||||
ops::Index,
|
||||
};
|
||||
|
||||
use derive_getters::Getters;
|
||||
#[cfg(any(test, feature = "test-impl"))]
|
||||
use hex::FromHex;
|
||||
|
||||
|
@ -161,7 +162,7 @@ fn derive_interpolating_value<C: Ciphersuite>(
|
|||
// Ala the sorting of B, just always sort by identifier in ascending order
|
||||
//
|
||||
// https://github.com/cfrg/draft-irtf-cfrg-frost/blob/master/draft-irtf-cfrg-frost.md#encoding-operations-dep-encoding
|
||||
for commitment in signing_package.signing_commitments() {
|
||||
for commitment in signing_package.signing_commitments().values() {
|
||||
if commitment.identifier == *signer_id {
|
||||
continue;
|
||||
}
|
||||
|
@ -183,13 +184,13 @@ fn derive_interpolating_value<C: Ciphersuite>(
|
|||
|
||||
/// Generated by the coordinator of the signing operation and distributed to
|
||||
/// each signing party
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
#[derive(Clone, PartialEq, Eq, Getters)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
|
||||
pub struct SigningPackage<C: Ciphersuite> {
|
||||
/// The set of commitments participants published in the first round of the
|
||||
/// protocol.
|
||||
signing_commitments: HashMap<Identifier<C>, round1::SigningCommitments<C>>,
|
||||
/// protocol, ordered by their identifiers.
|
||||
signing_commitments: BTreeMap<Identifier<C>, round1::SigningCommitments<C>>,
|
||||
/// Message which each participant will sign.
|
||||
///
|
||||
/// Each signer should perform protocol-specific verification on the
|
||||
|
@ -211,6 +212,7 @@ pub struct SigningPackage<C: Ciphersuite> {
|
|||
feature = "serde",
|
||||
serde(deserialize_with = "crate::ciphersuite_deserialize::<_, C>")
|
||||
)]
|
||||
#[getter(skip)]
|
||||
ciphersuite: (),
|
||||
}
|
||||
|
||||
|
@ -240,19 +242,6 @@ where
|
|||
self.signing_commitments[identifier]
|
||||
}
|
||||
|
||||
/// Get the signing commitments, sorted by the participant indices
|
||||
pub fn signing_commitments(&self) -> Vec<round1::SigningCommitments<C>> {
|
||||
let mut signing_commitments: Vec<round1::SigningCommitments<C>> =
|
||||
self.signing_commitments.values().cloned().collect();
|
||||
signing_commitments.sort_by_key(|a| a.identifier);
|
||||
signing_commitments
|
||||
}
|
||||
|
||||
/// Get the message to be signed
|
||||
pub fn message(&self) -> &Vec<u8> {
|
||||
&self.message
|
||||
}
|
||||
|
||||
/// Compute the preimages to H1 to compute the per-signer binding factors
|
||||
// We separate this out into its own method so it can be tested
|
||||
#[cfg_attr(feature = "internals", visibility::make(pub))]
|
||||
|
@ -272,7 +261,7 @@ where
|
|||
binding_factor_input_prefix.extend_from_slice(additional_prefix);
|
||||
|
||||
self.signing_commitments()
|
||||
.iter()
|
||||
.values()
|
||||
.map(|c| {
|
||||
let mut binding_factor_input = vec![];
|
||||
|
||||
|
@ -336,7 +325,7 @@ where
|
|||
// Ala the sorting of B, just always sort by identifier in ascending order
|
||||
//
|
||||
// https://github.com/cfrg/draft-irtf-cfrg-frost/blob/master/draft-irtf-cfrg-frost.md#encoding-operations-dep-encoding
|
||||
for commitment in signing_package.signing_commitments() {
|
||||
for commitment in signing_package.signing_commitments().values() {
|
||||
// The following check prevents a party from accidentally revealing their share.
|
||||
// Note that the '&&' operator would be sufficient.
|
||||
if identity == commitment.binding.0 || identity == commitment.hiding.0 {
|
||||
|
|
|
@ -9,6 +9,7 @@ use std::{
|
|||
iter,
|
||||
};
|
||||
|
||||
use derive_getters::Getters;
|
||||
#[cfg(any(test, feature = "test-impl"))]
|
||||
use hex::FromHex;
|
||||
|
||||
|
@ -298,18 +299,18 @@ where
|
|||
///
|
||||
/// To derive a FROST keypair, the receiver of the [`SecretShare`] *must* call
|
||||
/// .into(), which under the hood also performs validation.
|
||||
#[derive(Clone, Zeroize, PartialEq, Eq)]
|
||||
#[derive(Clone, Zeroize, PartialEq, Eq, Getters)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
|
||||
pub struct SecretShare<C: Ciphersuite> {
|
||||
/// The participant identifier of this [`SecretShare`].
|
||||
#[zeroize(skip)]
|
||||
pub identifier: Identifier<C>,
|
||||
pub(crate) identifier: Identifier<C>,
|
||||
/// Secret Key.
|
||||
pub value: SigningShare<C>,
|
||||
pub(crate) value: SigningShare<C>,
|
||||
#[zeroize(skip)]
|
||||
/// The commitments to be distributed among signers.
|
||||
pub commitment: VerifiableSecretSharingCommitment<C>,
|
||||
pub(crate) commitment: VerifiableSecretSharingCommitment<C>,
|
||||
/// Ciphersuite ID for serialization
|
||||
#[cfg_attr(
|
||||
feature = "serde",
|
||||
|
@ -319,6 +320,7 @@ pub struct SecretShare<C: Ciphersuite> {
|
|||
feature = "serde",
|
||||
serde(deserialize_with = "crate::ciphersuite_deserialize::<_, C>")
|
||||
)]
|
||||
#[getter(skip)]
|
||||
ciphersuite: (),
|
||||
}
|
||||
|
||||
|
@ -485,18 +487,18 @@ fn evaluate_vss<C: Ciphersuite>(
|
|||
/// When using a central dealer, [`SecretShare`]s are distributed to
|
||||
/// participants, who then perform verification, before deriving
|
||||
/// [`KeyPackage`]s, which they store to later use during signing.
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
#[derive(Clone, PartialEq, Eq, Getters)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
|
||||
pub struct KeyPackage<C: Ciphersuite> {
|
||||
/// Denotes the participant identifier each secret share key package is owned by.
|
||||
pub identifier: Identifier<C>,
|
||||
pub(crate) identifier: Identifier<C>,
|
||||
/// This participant's secret share.
|
||||
pub secret_share: SigningShare<C>,
|
||||
pub(crate) secret_share: SigningShare<C>,
|
||||
/// This participant's public key.
|
||||
pub public: VerifyingShare<C>,
|
||||
pub(crate) public: VerifyingShare<C>,
|
||||
/// The public signing key that represents the entire group.
|
||||
pub group_public: VerifyingKey<C>,
|
||||
pub(crate) group_public: VerifyingKey<C>,
|
||||
/// Ciphersuite ID for serialization
|
||||
#[cfg_attr(
|
||||
feature = "serde",
|
||||
|
@ -506,6 +508,7 @@ pub struct KeyPackage<C: Ciphersuite> {
|
|||
feature = "serde",
|
||||
serde(deserialize_with = "crate::ciphersuite_deserialize::<_, C>")
|
||||
)]
|
||||
#[getter(skip)]
|
||||
ciphersuite: (),
|
||||
}
|
||||
|
||||
|
@ -528,26 +531,6 @@ where
|
|||
ciphersuite: (),
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the participant identifier associated with this [`KeyPackage`].
|
||||
pub fn identifier(&self) -> &Identifier<C> {
|
||||
&self.identifier
|
||||
}
|
||||
|
||||
/// Gets the participant's [`SigningShare`] associated with this [`KeyPackage`].
|
||||
pub fn secret_share(&self) -> &SigningShare<C> {
|
||||
&self.secret_share
|
||||
}
|
||||
|
||||
/// Gets the participant's [`VerifyingShare`] associated with the [`SigningShare`] in this [`KeyPackage`].
|
||||
pub fn public(&self) -> &VerifyingShare<C> {
|
||||
&self.public
|
||||
}
|
||||
|
||||
/// Gets the group [`VerifyingKey`] associated with the entire group in this [`KeyPackage`].
|
||||
pub fn group_public(&self) -> &VerifyingKey<C> {
|
||||
&self.group_public
|
||||
}
|
||||
}
|
||||
|
||||
impl<C> TryFrom<SecretShare<C>> for KeyPackage<C>
|
||||
|
@ -581,7 +564,7 @@ where
|
|||
/// group public key.
|
||||
///
|
||||
/// Used for verification purposes before publishing a signature.
|
||||
#[derive(PartialEq, Eq)]
|
||||
#[derive(PartialEq, Eq, Getters)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
|
||||
pub struct PublicKeyPackage<C: Ciphersuite> {
|
||||
|
@ -589,9 +572,9 @@ pub struct PublicKeyPackage<C: Ciphersuite> {
|
|||
/// correct view of participants' public keys to perform verification before
|
||||
/// publishing a signature. `signer_pubkeys` represents all signers for a
|
||||
/// signing operation.
|
||||
pub signer_pubkeys: HashMap<Identifier<C>, VerifyingShare<C>>,
|
||||
pub(crate) signer_pubkeys: HashMap<Identifier<C>, VerifyingShare<C>>,
|
||||
/// The joint public key for the entire group.
|
||||
pub group_public: VerifyingKey<C>,
|
||||
pub(crate) group_public: VerifyingKey<C>,
|
||||
/// Ciphersuite ID for serialization
|
||||
#[cfg_attr(
|
||||
feature = "serde",
|
||||
|
@ -601,6 +584,7 @@ pub struct PublicKeyPackage<C: Ciphersuite> {
|
|||
feature = "serde",
|
||||
serde(deserialize_with = "crate::ciphersuite_deserialize::<_, C>")
|
||||
)]
|
||||
#[getter(skip)]
|
||||
ciphersuite: (),
|
||||
}
|
||||
|
||||
|
|
|
@ -47,20 +47,22 @@ use super::{
|
|||
|
||||
/// DKG Round 1 structures.
|
||||
pub mod round1 {
|
||||
use derive_getters::Getters;
|
||||
|
||||
use super::*;
|
||||
|
||||
/// The package that must be broadcast by each participant to all other participants
|
||||
/// between the first and second parts of the DKG protocol (round 1).
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
#[derive(Clone, PartialEq, Eq, Getters)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
|
||||
pub struct Package<C: Ciphersuite> {
|
||||
/// The identifier of the participant who is sending the package (i).
|
||||
pub sender_identifier: Identifier<C>,
|
||||
pub(crate) sender_identifier: Identifier<C>,
|
||||
/// The public commitment from the participant (C_i)
|
||||
pub commitment: VerifiableSecretSharingCommitment<C>,
|
||||
pub(crate) commitment: VerifiableSecretSharingCommitment<C>,
|
||||
/// The proof of knowledge of the temporary secret (σ_i = (R_i, μ_i))
|
||||
pub proof_of_knowledge: Signature<C>,
|
||||
pub(crate) proof_of_knowledge: Signature<C>,
|
||||
/// Ciphersuite ID for serialization
|
||||
#[cfg_attr(
|
||||
feature = "serde",
|
||||
|
@ -70,6 +72,7 @@ pub mod round1 {
|
|||
feature = "serde",
|
||||
serde(deserialize_with = "crate::ciphersuite_deserialize::<_, C>")
|
||||
)]
|
||||
#[getter(skip)]
|
||||
pub(super) ciphersuite: (),
|
||||
}
|
||||
|
||||
|
@ -101,19 +104,21 @@ pub mod round1 {
|
|||
#[derive(Clone)]
|
||||
pub struct SecretPackage<C: Ciphersuite> {
|
||||
/// The identifier of the participant holding the secret.
|
||||
pub identifier: Identifier<C>,
|
||||
pub(crate) identifier: Identifier<C>,
|
||||
/// Coefficients of the temporary secret polynomial for the participant.
|
||||
/// These are (a_{i0}, ..., a_{i(t−1)})) which define the polynomial f_i(x)
|
||||
pub coefficients: Vec<Scalar<C>>,
|
||||
pub(crate) coefficients: Vec<Scalar<C>>,
|
||||
/// The public commitment for the participant (C_i)
|
||||
pub commitment: VerifiableSecretSharingCommitment<C>,
|
||||
pub(crate) commitment: VerifiableSecretSharingCommitment<C>,
|
||||
/// The total number of signers.
|
||||
pub max_signers: u16,
|
||||
pub(crate) max_signers: u16,
|
||||
}
|
||||
}
|
||||
|
||||
/// DKG Round 2 structures.
|
||||
pub mod round2 {
|
||||
use derive_getters::Getters;
|
||||
|
||||
use super::*;
|
||||
|
||||
/// A package that must be sent by each participant to some other participants
|
||||
|
@ -123,16 +128,16 @@ pub mod round2 {
|
|||
/// # Security
|
||||
///
|
||||
/// The package must be sent on an *confidential* and *authenticated* channel.
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
#[derive(Clone, PartialEq, Eq, Getters)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
|
||||
pub struct Package<C: Ciphersuite> {
|
||||
/// The identifier of the participant that generated the package (i).
|
||||
pub sender_identifier: Identifier<C>,
|
||||
pub(crate) sender_identifier: Identifier<C>,
|
||||
/// The identifier of the participant what will receive the package (ℓ).
|
||||
pub receiver_identifier: Identifier<C>,
|
||||
pub(crate) receiver_identifier: Identifier<C>,
|
||||
/// The secret share being sent.
|
||||
pub secret_share: SigningShare<C>,
|
||||
pub(crate) secret_share: SigningShare<C>,
|
||||
/// Ciphersuite ID for serialization
|
||||
#[cfg_attr(
|
||||
feature = "serde",
|
||||
|
@ -142,6 +147,7 @@ pub mod round2 {
|
|||
feature = "serde",
|
||||
serde(deserialize_with = "crate::ciphersuite_deserialize::<_, C>")
|
||||
)]
|
||||
#[getter(skip)]
|
||||
pub(super) ciphersuite: (),
|
||||
}
|
||||
|
||||
|
@ -172,13 +178,13 @@ pub mod round2 {
|
|||
/// This package MUST NOT be sent to other participants!
|
||||
pub struct SecretPackage<C: Ciphersuite> {
|
||||
/// The identifier of the participant holding the secret.
|
||||
pub identifier: Identifier<C>,
|
||||
pub(crate) identifier: Identifier<C>,
|
||||
/// The public commitment from the participant (C_i)
|
||||
pub commitment: VerifiableSecretSharingCommitment<C>,
|
||||
pub(crate) commitment: VerifiableSecretSharingCommitment<C>,
|
||||
/// The participant's own secret share (f_i(i)).
|
||||
pub secret_share: Scalar<C>,
|
||||
pub(crate) secret_share: Scalar<C>,
|
||||
/// The total number of signers.
|
||||
pub max_signers: u16,
|
||||
pub(crate) max_signers: u16,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
//! FROST Round 1 functionality and types
|
||||
|
||||
use std::fmt::{self, Debug};
|
||||
use std::{
|
||||
collections::BTreeMap,
|
||||
fmt::{self, Debug},
|
||||
};
|
||||
|
||||
use derive_getters::Getters;
|
||||
#[cfg(any(test, feature = "test-impl"))]
|
||||
use hex::FromHex;
|
||||
|
||||
|
@ -207,9 +211,9 @@ where
|
|||
#[derive(Clone, Zeroize)]
|
||||
pub struct SigningNonces<C: Ciphersuite> {
|
||||
/// The hiding [`Nonce`].
|
||||
pub hiding: Nonce<C>,
|
||||
pub(crate) hiding: Nonce<C>,
|
||||
/// The binding [`Nonce`].
|
||||
pub binding: Nonce<C>,
|
||||
pub(crate) binding: Nonce<C>,
|
||||
}
|
||||
|
||||
impl<C> SigningNonces<C>
|
||||
|
@ -247,16 +251,16 @@ where
|
|||
///
|
||||
/// This step can be batched if desired by the implementation. Each
|
||||
/// SigningCommitment can be used for exactly *one* signature.
|
||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Getters)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
|
||||
pub struct SigningCommitments<C: Ciphersuite> {
|
||||
/// The participant identifier.
|
||||
pub identifier: Identifier<C>,
|
||||
pub(crate) identifier: Identifier<C>,
|
||||
/// Commitment to the hiding [`Nonce`].
|
||||
pub hiding: NonceCommitment<C>,
|
||||
pub(crate) hiding: NonceCommitment<C>,
|
||||
/// Commitment to the binding [`Nonce`].
|
||||
pub binding: NonceCommitment<C>,
|
||||
pub(crate) binding: NonceCommitment<C>,
|
||||
/// Ciphersuite ID for serialization
|
||||
#[cfg_attr(
|
||||
feature = "serde",
|
||||
|
@ -266,6 +270,7 @@ pub struct SigningCommitments<C: Ciphersuite> {
|
|||
feature = "serde",
|
||||
serde(deserialize_with = "crate::ciphersuite_deserialize::<_, C>")
|
||||
)]
|
||||
#[getter(skip)]
|
||||
ciphersuite: (),
|
||||
}
|
||||
|
||||
|
@ -297,16 +302,6 @@ where
|
|||
) -> GroupCommitmentShare<C> {
|
||||
GroupCommitmentShare::<C>(self.hiding.0 + (self.binding.0 * binding_factor.0))
|
||||
}
|
||||
|
||||
/// Gets the hiding [`NonceCommitment`].
|
||||
pub fn hiding(&self) -> &NonceCommitment<C> {
|
||||
&self.hiding
|
||||
}
|
||||
|
||||
/// Gets the binding [`NonceCommitment`].
|
||||
pub fn binding(&self) -> &NonceCommitment<C> {
|
||||
&self.binding
|
||||
}
|
||||
}
|
||||
|
||||
impl<C> From<(Identifier<C>, &SigningNonces<C>)> for SigningCommitments<C>
|
||||
|
@ -343,17 +338,11 @@ pub struct GroupCommitmentShare<C: Ciphersuite>(pub(super) Element<C>);
|
|||
///
|
||||
/// [`encode_group_commitment_list()`]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-11.html#name-list-operations
|
||||
pub(super) fn encode_group_commitments<C: Ciphersuite>(
|
||||
signing_commitments: Vec<SigningCommitments<C>>,
|
||||
signing_commitments: &BTreeMap<Identifier<C>, SigningCommitments<C>>,
|
||||
) -> Vec<u8> {
|
||||
// B MUST be sorted in ascending order by signer identifier.
|
||||
//
|
||||
// TODO: AtLeastOne or other explicitly Sorted wrapper types?
|
||||
let mut sorted_signing_commitments = signing_commitments;
|
||||
sorted_signing_commitments.sort_by_key(|a| a.identifier);
|
||||
|
||||
let mut bytes = vec![];
|
||||
|
||||
for item in sorted_signing_commitments {
|
||||
for item in signing_commitments.values() {
|
||||
bytes.extend_from_slice(item.identifier.serialize().as_ref());
|
||||
bytes.extend_from_slice(<C::Group>::serialize(&item.hiding.0).as_ref());
|
||||
bytes.extend_from_slice(<C::Group>::serialize(&item.binding.0).as_ref());
|
||||
|
|
|
@ -12,13 +12,13 @@ use crate::{
|
|||
use crate::ScalarSerialization;
|
||||
|
||||
/// A representation of a single signature share used in FROST structures and messages.
|
||||
#[derive(Clone, Copy)]
|
||||
#[derive(Clone, Copy, Getters)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
#[cfg_attr(feature = "serde", serde(try_from = "ScalarSerialization<C>"))]
|
||||
#[cfg_attr(feature = "serde", serde(into = "ScalarSerialization<C>"))]
|
||||
pub struct SignatureResponse<C: Ciphersuite> {
|
||||
/// The scalar contribution to the group signature.
|
||||
pub z_share: Scalar<C>,
|
||||
pub(crate) z_share: Scalar<C>,
|
||||
}
|
||||
|
||||
impl<C> SignatureResponse<C>
|
||||
|
@ -87,14 +87,14 @@ where
|
|||
|
||||
/// A participant's signature share, which the coordinator will aggregate with all other signer's
|
||||
/// shares into the joint signature.
|
||||
#[derive(Clone, Copy, Eq, PartialEq)]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Getters)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
|
||||
pub struct SignatureShare<C: Ciphersuite> {
|
||||
/// Represents the participant identifier.
|
||||
pub identifier: Identifier<C>,
|
||||
pub(crate) identifier: Identifier<C>,
|
||||
/// This participant's signature over the message.
|
||||
pub signature: SignatureResponse<C>,
|
||||
pub(crate) signature: SignatureResponse<C>,
|
||||
/// Ciphersuite ID for serialization
|
||||
#[cfg_attr(
|
||||
feature = "serde",
|
||||
|
@ -120,11 +120,6 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// Gets the participant identifier associated with this [`SignatureShare`].
|
||||
pub fn identifier(&self) -> &Identifier<C> {
|
||||
&self.identifier
|
||||
}
|
||||
|
||||
/// Tests if a signature share issued by a participant is valid before
|
||||
/// aggregating it into a final joint signature to publish.
|
||||
///
|
||||
|
|
|
@ -108,7 +108,7 @@ let group_signature = frost::aggregate(&signing_package, &signature_shares[..],
|
|||
// key (the verification key).
|
||||
# // ANCHOR: verify
|
||||
let is_signature_valid = pubkey_package
|
||||
.group_public
|
||||
.group_public()
|
||||
.verify(message, &group_signature)
|
||||
.is_ok();
|
||||
# // ANCHOR_END: verify
|
||||
|
|
|
@ -123,7 +123,7 @@ for participant_index in 1..=max_signers {
|
|||
// gets its own specific package.
|
||||
for round2_package in round2_packages {
|
||||
received_round2_packages
|
||||
.entry(round2_package.receiver_identifier)
|
||||
.entry(*round2_package.receiver_identifier())
|
||||
.or_insert_with(Vec::new)
|
||||
.push(round2_package);
|
||||
}
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
// Required since each integration test is compiled as a separated crate,
|
||||
// and each one uses only part of the module.
|
||||
#![allow(dead_code)]
|
||||
|
||||
pub mod samples;
|
||||
|
||||
use ed25519_dalek::Verifier;
|
||||
use frost_ed25519::*;
|
||||
|
||||
|
|
|
@ -0,0 +1,131 @@
|
|||
//! Generate sample, fixed instances of structs for testing.
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use frost_core::{Ciphersuite, Element, Group, Scalar};
|
||||
use frost_ed25519::{
|
||||
keys::{
|
||||
dkg::{round1, round2},
|
||||
KeyPackage, PublicKeyPackage, SecretShare, SigningShare, VerifiableSecretSharingCommitment,
|
||||
VerifyingShare,
|
||||
},
|
||||
round1::{NonceCommitment, SigningCommitments},
|
||||
round2::{SignatureResponse, SignatureShare},
|
||||
Field, Signature, SigningPackage, VerifyingKey,
|
||||
};
|
||||
|
||||
type C = frost_ed25519::Ed25519Sha512;
|
||||
|
||||
fn element1() -> Element<C> {
|
||||
<C as Ciphersuite>::Group::generator()
|
||||
}
|
||||
|
||||
fn element2() -> Element<C> {
|
||||
element1() + element1()
|
||||
}
|
||||
|
||||
fn scalar1() -> Scalar<C> {
|
||||
let one = <<C as Ciphersuite>::Group as Group>::Field::one();
|
||||
let two = one + one;
|
||||
// To return a fixed non-small number, get the inverse of 2
|
||||
<<C as Ciphersuite>::Group as Group>::Field::invert(&two)
|
||||
.expect("nonzero elements have inverses")
|
||||
}
|
||||
|
||||
/// Generate a sample SigningCommitments.
|
||||
pub fn signing_commitments() -> SigningCommitments {
|
||||
let serialized_element1 = <C as Ciphersuite>::Group::serialize(&element1());
|
||||
let serialized_element2 = <C as Ciphersuite>::Group::serialize(&element2());
|
||||
let hiding_nonce_commitment = NonceCommitment::from_bytes(serialized_element1).unwrap();
|
||||
let binding_nonce_commitment = NonceCommitment::from_bytes(serialized_element2).unwrap();
|
||||
let identifier = 42u16.try_into().unwrap();
|
||||
|
||||
SigningCommitments::new(
|
||||
identifier,
|
||||
hiding_nonce_commitment,
|
||||
binding_nonce_commitment,
|
||||
)
|
||||
}
|
||||
|
||||
/// Generate a sample SigningPackage.
|
||||
pub fn signing_package() -> SigningPackage {
|
||||
let commitments = vec![signing_commitments()];
|
||||
let message = "hello world".as_bytes();
|
||||
|
||||
SigningPackage::new(commitments, message)
|
||||
}
|
||||
|
||||
/// Generate a sample SignatureShare.
|
||||
pub fn signature_share() -> SignatureShare {
|
||||
let identifier = 42u16.try_into().unwrap();
|
||||
let serialized_scalar = <<C as Ciphersuite>::Group as Group>::Field::serialize(&scalar1());
|
||||
let signature_response = SignatureResponse::from_bytes(serialized_scalar).unwrap();
|
||||
|
||||
SignatureShare::new(identifier, signature_response)
|
||||
}
|
||||
|
||||
/// Generate a sample SecretShare.
|
||||
pub fn secret_share() -> SecretShare {
|
||||
let identifier = 42u16.try_into().unwrap();
|
||||
let serialized_scalar = <<C as Ciphersuite>::Group as Group>::Field::serialize(&scalar1());
|
||||
let serialized_element = <C as Ciphersuite>::Group::serialize(&element1());
|
||||
let signing_share = SigningShare::from_bytes(serialized_scalar).unwrap();
|
||||
let vss_commitment =
|
||||
VerifiableSecretSharingCommitment::deserialize(vec![serialized_element]).unwrap();
|
||||
|
||||
SecretShare::new(identifier, signing_share, vss_commitment)
|
||||
}
|
||||
|
||||
/// Generate a sample KeyPackage.
|
||||
pub fn key_package() -> KeyPackage {
|
||||
let identifier = 42u16.try_into().unwrap();
|
||||
let serialized_scalar = <<C as Ciphersuite>::Group as Group>::Field::serialize(&scalar1());
|
||||
let serialized_element = <C as Ciphersuite>::Group::serialize(&element1());
|
||||
let signing_share = SigningShare::from_bytes(serialized_scalar).unwrap();
|
||||
let verifying_share = VerifyingShare::from_bytes(serialized_element).unwrap();
|
||||
let serialized_element = <C as Ciphersuite>::Group::serialize(&element1());
|
||||
let verifying_key = VerifyingKey::from_bytes(serialized_element).unwrap();
|
||||
|
||||
KeyPackage::new(identifier, signing_share, verifying_share, verifying_key)
|
||||
}
|
||||
|
||||
/// Generate a sample PublicKeyPackage.
|
||||
pub fn public_key_package() -> PublicKeyPackage {
|
||||
let identifier = 42u16.try_into().unwrap();
|
||||
let serialized_element = <C as Ciphersuite>::Group::serialize(&element1());
|
||||
let verifying_share = VerifyingShare::from_bytes(serialized_element).unwrap();
|
||||
let serialized_element = <C as Ciphersuite>::Group::serialize(&element1());
|
||||
let verifying_key = VerifyingKey::from_bytes(serialized_element).unwrap();
|
||||
let signer_pubkeys = HashMap::from([(identifier, verifying_share)]);
|
||||
|
||||
PublicKeyPackage::new(signer_pubkeys, verifying_key)
|
||||
}
|
||||
|
||||
/// Generate a sample round1::Package.
|
||||
pub fn round1_package() -> round1::Package {
|
||||
let identifier = 42u16.try_into().unwrap();
|
||||
let serialized_scalar = <<C as Ciphersuite>::Group as Group>::Field::serialize(&scalar1());
|
||||
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::from_bytes(serialized_signature).unwrap();
|
||||
|
||||
round1::Package::new(identifier, vss_commitment, signature)
|
||||
}
|
||||
|
||||
/// Generate a sample round2::Package.
|
||||
pub fn round2_package() -> round2::Package {
|
||||
let identifier = 42u16.try_into().unwrap();
|
||||
let serialized_scalar = <<C as Ciphersuite>::Group as Group>::Field::serialize(&scalar1());
|
||||
let signing_share = SigningShare::from_bytes(serialized_scalar).unwrap();
|
||||
|
||||
round2::Package::new(identifier, identifier, signing_share)
|
||||
}
|
|
@ -0,0 +1,131 @@
|
|||
//! Test for recreating packages from their components, which shows that they
|
||||
//! can be serialized and deserialized as the user wishes.
|
||||
|
||||
use frost_ed25519::{
|
||||
keys::{
|
||||
dkg::{round1, round2},
|
||||
KeyPackage, PublicKeyPackage, SecretShare,
|
||||
},
|
||||
round1::SigningCommitments,
|
||||
round2::SignatureShare,
|
||||
SigningPackage,
|
||||
};
|
||||
|
||||
mod helpers;
|
||||
|
||||
use helpers::samples;
|
||||
|
||||
/// Check if SigningCommitments can be recreated.
|
||||
#[test]
|
||||
fn check_signing_commitments_recreation() {
|
||||
let commitments = samples::signing_commitments();
|
||||
let identifier = commitments.identifier();
|
||||
let hiding = commitments.hiding();
|
||||
let binding = commitments.binding();
|
||||
let new_commitments = SigningCommitments::new(*identifier, *hiding, *binding);
|
||||
assert!(commitments == new_commitments);
|
||||
}
|
||||
|
||||
/// Check if SigningPackage can be recreated.
|
||||
#[test]
|
||||
fn check_signing_package_recreation() {
|
||||
let signing_package = samples::signing_package();
|
||||
|
||||
let commitments = signing_package
|
||||
.signing_commitments()
|
||||
.values()
|
||||
.cloned()
|
||||
.collect();
|
||||
let message = signing_package.message();
|
||||
|
||||
let new_signing_package = SigningPackage::new(commitments, message);
|
||||
assert!(signing_package == new_signing_package);
|
||||
}
|
||||
|
||||
/// Check if SignatureShare can be recreated.
|
||||
#[test]
|
||||
fn check_signature_share_recreation() {
|
||||
let signature_share = samples::signature_share();
|
||||
|
||||
let identifier = signature_share.identifier();
|
||||
let signature_response = signature_share.signature();
|
||||
|
||||
let new_signature_share = SignatureShare::new(*identifier, *signature_response);
|
||||
assert!(signature_share == new_signature_share);
|
||||
}
|
||||
|
||||
/// Check if SecretShare can be recreated.
|
||||
#[test]
|
||||
fn check_secret_share_recreation() {
|
||||
let secret_share = samples::secret_share();
|
||||
|
||||
let identifier = secret_share.identifier();
|
||||
let value = secret_share.value();
|
||||
let commitment = secret_share.commitment();
|
||||
|
||||
let new_secret_share = SecretShare::new(*identifier, *value, commitment.clone());
|
||||
|
||||
assert!(secret_share == new_secret_share);
|
||||
}
|
||||
|
||||
/// Check if KeyPackage can be recreated.
|
||||
#[test]
|
||||
fn check_key_package_recreation() {
|
||||
let key_package = samples::key_package();
|
||||
|
||||
let identifier = key_package.identifier();
|
||||
let signing_share = key_package.secret_share();
|
||||
let verifying_share = key_package.public();
|
||||
let verifying_key = key_package.group_public();
|
||||
|
||||
let new_key_package = KeyPackage::new(
|
||||
*identifier,
|
||||
*signing_share,
|
||||
*verifying_share,
|
||||
*verifying_key,
|
||||
);
|
||||
|
||||
assert!(key_package == new_key_package);
|
||||
}
|
||||
|
||||
/// Check if PublicKeyPackage can be recreated.
|
||||
#[test]
|
||||
fn check_public_key_package_recreation() {
|
||||
let public_key_package = samples::public_key_package();
|
||||
|
||||
let signer_pubkeys = public_key_package.signer_pubkeys();
|
||||
let verifying_key = public_key_package.group_public();
|
||||
|
||||
let new_public_key_package = PublicKeyPackage::new(signer_pubkeys.clone(), *verifying_key);
|
||||
|
||||
assert!(public_key_package == new_public_key_package);
|
||||
}
|
||||
|
||||
/// Check if round1::Package can be recreated.
|
||||
#[test]
|
||||
fn check_round1_package_recreation() {
|
||||
let round1_package = samples::round1_package();
|
||||
|
||||
let identifier = round1_package.sender_identifier();
|
||||
let vss_commitment = round1_package.commitment();
|
||||
let signature = round1_package.proof_of_knowledge();
|
||||
|
||||
let new_round1_package = round1::Package::new(*identifier, vss_commitment.clone(), *signature);
|
||||
|
||||
assert!(round1_package == new_round1_package);
|
||||
}
|
||||
|
||||
/// Check if round2::Package can be recreated.
|
||||
#[test]
|
||||
fn check_round2_package_recreation() {
|
||||
let round2_package = samples::round2_package();
|
||||
|
||||
let sender_identifier = round2_package.sender_identifier();
|
||||
let receiver_identifier = round2_package.receiver_identifier();
|
||||
let signing_share = round2_package.secret_share();
|
||||
|
||||
let new_round2_package =
|
||||
round2::Package::new(*sender_identifier, *receiver_identifier, *signing_share);
|
||||
|
||||
assert!(round2_package == new_round2_package);
|
||||
}
|
|
@ -108,7 +108,7 @@ let group_signature = frost::aggregate(&signing_package, &signature_shares[..],
|
|||
// key (the verification key).
|
||||
# // ANCHOR: verify
|
||||
let is_signature_valid = pubkey_package
|
||||
.group_public
|
||||
.group_public()
|
||||
.verify(message, &group_signature)
|
||||
.is_ok();
|
||||
# // ANCHOR_END: verify
|
||||
|
|
|
@ -123,7 +123,7 @@ for participant_index in 1..=max_signers {
|
|||
// gets its own specific package.
|
||||
for round2_package in round2_packages {
|
||||
received_round2_packages
|
||||
.entry(round2_package.receiver_identifier)
|
||||
.entry(*round2_package.receiver_identifier())
|
||||
.or_insert_with(Vec::new)
|
||||
.push(round2_package);
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
pub mod samples;
|
|
@ -0,0 +1,131 @@
|
|||
//! Generate sample, fixed instances of structs for testing.
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use frost_core::{Ciphersuite, Element, Group, Scalar};
|
||||
use frost_ed448::{
|
||||
keys::{
|
||||
dkg::{round1, round2},
|
||||
KeyPackage, PublicKeyPackage, SecretShare, SigningShare, VerifiableSecretSharingCommitment,
|
||||
VerifyingShare,
|
||||
},
|
||||
round1::{NonceCommitment, SigningCommitments},
|
||||
round2::{SignatureResponse, SignatureShare},
|
||||
Field, Signature, SigningPackage, VerifyingKey,
|
||||
};
|
||||
|
||||
type C = frost_ed448::Ed448Shake256;
|
||||
|
||||
fn element1() -> Element<C> {
|
||||
<C as Ciphersuite>::Group::generator()
|
||||
}
|
||||
|
||||
fn element2() -> Element<C> {
|
||||
element1() + element1()
|
||||
}
|
||||
|
||||
fn scalar1() -> Scalar<C> {
|
||||
let one = <<C as Ciphersuite>::Group as Group>::Field::one();
|
||||
let two = one + one;
|
||||
// To return a fixed non-small number, get the inverse of 2
|
||||
<<C as Ciphersuite>::Group as Group>::Field::invert(&two)
|
||||
.expect("nonzero elements have inverses")
|
||||
}
|
||||
|
||||
/// Generate a sample SigningCommitments.
|
||||
pub fn signing_commitments() -> SigningCommitments {
|
||||
let serialized_element1 = <C as Ciphersuite>::Group::serialize(&element1());
|
||||
let serialized_element2 = <C as Ciphersuite>::Group::serialize(&element2());
|
||||
let hiding_nonce_commitment = NonceCommitment::from_bytes(serialized_element1).unwrap();
|
||||
let binding_nonce_commitment = NonceCommitment::from_bytes(serialized_element2).unwrap();
|
||||
let identifier = 42u16.try_into().unwrap();
|
||||
|
||||
SigningCommitments::new(
|
||||
identifier,
|
||||
hiding_nonce_commitment,
|
||||
binding_nonce_commitment,
|
||||
)
|
||||
}
|
||||
|
||||
/// Generate a sample SigningPackage.
|
||||
pub fn signing_package() -> SigningPackage {
|
||||
let commitments = vec![signing_commitments()];
|
||||
let message = "hello world".as_bytes();
|
||||
|
||||
SigningPackage::new(commitments, message)
|
||||
}
|
||||
|
||||
/// Generate a sample SignatureShare.
|
||||
pub fn signature_share() -> SignatureShare {
|
||||
let identifier = 42u16.try_into().unwrap();
|
||||
let serialized_scalar = <<C as Ciphersuite>::Group as Group>::Field::serialize(&scalar1());
|
||||
let signature_response = SignatureResponse::from_bytes(serialized_scalar).unwrap();
|
||||
|
||||
SignatureShare::new(identifier, signature_response)
|
||||
}
|
||||
|
||||
/// Generate a sample SecretShare.
|
||||
pub fn secret_share() -> SecretShare {
|
||||
let identifier = 42u16.try_into().unwrap();
|
||||
let serialized_scalar = <<C as Ciphersuite>::Group as Group>::Field::serialize(&scalar1());
|
||||
let serialized_element = <C as Ciphersuite>::Group::serialize(&element1());
|
||||
let signing_share = SigningShare::from_bytes(serialized_scalar).unwrap();
|
||||
let vss_commitment =
|
||||
VerifiableSecretSharingCommitment::deserialize(vec![serialized_element]).unwrap();
|
||||
|
||||
SecretShare::new(identifier, signing_share, vss_commitment)
|
||||
}
|
||||
|
||||
/// Generate a sample KeyPackage.
|
||||
pub fn key_package() -> KeyPackage {
|
||||
let identifier = 42u16.try_into().unwrap();
|
||||
let serialized_scalar = <<C as Ciphersuite>::Group as Group>::Field::serialize(&scalar1());
|
||||
let serialized_element = <C as Ciphersuite>::Group::serialize(&element1());
|
||||
let signing_share = SigningShare::from_bytes(serialized_scalar).unwrap();
|
||||
let verifying_share = VerifyingShare::from_bytes(serialized_element).unwrap();
|
||||
let serialized_element = <C as Ciphersuite>::Group::serialize(&element1());
|
||||
let verifying_key = VerifyingKey::from_bytes(serialized_element).unwrap();
|
||||
|
||||
KeyPackage::new(identifier, signing_share, verifying_share, verifying_key)
|
||||
}
|
||||
|
||||
/// Generate a sample PublicKeyPackage.
|
||||
pub fn public_key_package() -> PublicKeyPackage {
|
||||
let identifier = 42u16.try_into().unwrap();
|
||||
let serialized_element = <C as Ciphersuite>::Group::serialize(&element1());
|
||||
let verifying_share = VerifyingShare::from_bytes(serialized_element).unwrap();
|
||||
let serialized_element = <C as Ciphersuite>::Group::serialize(&element1());
|
||||
let verifying_key = VerifyingKey::from_bytes(serialized_element).unwrap();
|
||||
let signer_pubkeys = HashMap::from([(identifier, verifying_share)]);
|
||||
|
||||
PublicKeyPackage::new(signer_pubkeys, verifying_key)
|
||||
}
|
||||
|
||||
/// Generate a sample round1::Package.
|
||||
pub fn round1_package() -> round1::Package {
|
||||
let identifier = 42u16.try_into().unwrap();
|
||||
let serialized_scalar = <<C as Ciphersuite>::Group as Group>::Field::serialize(&scalar1());
|
||||
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::from_bytes(serialized_signature).unwrap();
|
||||
|
||||
round1::Package::new(identifier, vss_commitment, signature)
|
||||
}
|
||||
|
||||
/// Generate a sample round2::Package.
|
||||
pub fn round2_package() -> round2::Package {
|
||||
let identifier = 42u16.try_into().unwrap();
|
||||
let serialized_scalar = <<C as Ciphersuite>::Group as Group>::Field::serialize(&scalar1());
|
||||
let signing_share = SigningShare::from_bytes(serialized_scalar).unwrap();
|
||||
|
||||
round2::Package::new(identifier, identifier, signing_share)
|
||||
}
|
|
@ -0,0 +1,131 @@
|
|||
//! Test for recreating packages from their components, which shows that they
|
||||
//! can be serialized and deserialized as the user wishes.
|
||||
|
||||
use frost_ed448::{
|
||||
keys::{
|
||||
dkg::{round1, round2},
|
||||
KeyPackage, PublicKeyPackage, SecretShare,
|
||||
},
|
||||
round1::SigningCommitments,
|
||||
round2::SignatureShare,
|
||||
SigningPackage,
|
||||
};
|
||||
|
||||
mod helpers;
|
||||
|
||||
use helpers::samples;
|
||||
|
||||
/// Check if SigningCommitments can be recreated.
|
||||
#[test]
|
||||
fn check_signing_commitments_recreation() {
|
||||
let commitments = samples::signing_commitments();
|
||||
let identifier = commitments.identifier();
|
||||
let hiding = commitments.hiding();
|
||||
let binding = commitments.binding();
|
||||
let new_commitments = SigningCommitments::new(*identifier, *hiding, *binding);
|
||||
assert!(commitments == new_commitments);
|
||||
}
|
||||
|
||||
/// Check if SigningPackage can be recreated.
|
||||
#[test]
|
||||
fn check_signing_package_recreation() {
|
||||
let signing_package = samples::signing_package();
|
||||
|
||||
let commitments = signing_package
|
||||
.signing_commitments()
|
||||
.values()
|
||||
.cloned()
|
||||
.collect();
|
||||
let message = signing_package.message();
|
||||
|
||||
let new_signing_package = SigningPackage::new(commitments, message);
|
||||
assert!(signing_package == new_signing_package);
|
||||
}
|
||||
|
||||
/// Check if SignatureShare can be recreated.
|
||||
#[test]
|
||||
fn check_signature_share_recreation() {
|
||||
let signature_share = samples::signature_share();
|
||||
|
||||
let identifier = signature_share.identifier();
|
||||
let signature_response = signature_share.signature();
|
||||
|
||||
let new_signature_share = SignatureShare::new(*identifier, *signature_response);
|
||||
assert!(signature_share == new_signature_share);
|
||||
}
|
||||
|
||||
/// Check if SecretShare can be recreated.
|
||||
#[test]
|
||||
fn check_secret_share_recreation() {
|
||||
let secret_share = samples::secret_share();
|
||||
|
||||
let identifier = secret_share.identifier();
|
||||
let value = secret_share.value();
|
||||
let commitment = secret_share.commitment();
|
||||
|
||||
let new_secret_share = SecretShare::new(*identifier, *value, commitment.clone());
|
||||
|
||||
assert!(secret_share == new_secret_share);
|
||||
}
|
||||
|
||||
/// Check if KeyPackage can be recreated.
|
||||
#[test]
|
||||
fn check_key_package_recreation() {
|
||||
let key_package = samples::key_package();
|
||||
|
||||
let identifier = key_package.identifier();
|
||||
let signing_share = key_package.secret_share();
|
||||
let verifying_share = key_package.public();
|
||||
let verifying_key = key_package.group_public();
|
||||
|
||||
let new_key_package = KeyPackage::new(
|
||||
*identifier,
|
||||
*signing_share,
|
||||
*verifying_share,
|
||||
*verifying_key,
|
||||
);
|
||||
|
||||
assert!(key_package == new_key_package);
|
||||
}
|
||||
|
||||
/// Check if PublicKeyPackage can be recreated.
|
||||
#[test]
|
||||
fn check_public_key_package_recreation() {
|
||||
let public_key_package = samples::public_key_package();
|
||||
|
||||
let signer_pubkeys = public_key_package.signer_pubkeys();
|
||||
let verifying_key = public_key_package.group_public();
|
||||
|
||||
let new_public_key_package = PublicKeyPackage::new(signer_pubkeys.clone(), *verifying_key);
|
||||
|
||||
assert!(public_key_package == new_public_key_package);
|
||||
}
|
||||
|
||||
/// Check if round1::Package can be recreated.
|
||||
#[test]
|
||||
fn check_round1_package_recreation() {
|
||||
let round1_package = samples::round1_package();
|
||||
|
||||
let identifier = round1_package.sender_identifier();
|
||||
let vss_commitment = round1_package.commitment();
|
||||
let signature = round1_package.proof_of_knowledge();
|
||||
|
||||
let new_round1_package = round1::Package::new(*identifier, vss_commitment.clone(), *signature);
|
||||
|
||||
assert!(round1_package == new_round1_package);
|
||||
}
|
||||
|
||||
/// Check if round2::Package can be recreated.
|
||||
#[test]
|
||||
fn check_round2_package_recreation() {
|
||||
let round2_package = samples::round2_package();
|
||||
|
||||
let sender_identifier = round2_package.sender_identifier();
|
||||
let receiver_identifier = round2_package.receiver_identifier();
|
||||
let signing_share = round2_package.secret_share();
|
||||
|
||||
let new_round2_package =
|
||||
round2::Package::new(*sender_identifier, *receiver_identifier, *signing_share);
|
||||
|
||||
assert!(round2_package == new_round2_package);
|
||||
}
|
|
@ -108,7 +108,7 @@ let group_signature = frost::aggregate(&signing_package, &signature_shares[..],
|
|||
// key (the verification key).
|
||||
# // ANCHOR: verify
|
||||
let is_signature_valid = pubkey_package
|
||||
.group_public
|
||||
.group_public()
|
||||
.verify(message, &group_signature)
|
||||
.is_ok();
|
||||
# // ANCHOR_END: verify
|
||||
|
|
|
@ -123,7 +123,7 @@ for participant_index in 1..=max_signers {
|
|||
// gets its own specific package.
|
||||
for round2_package in round2_packages {
|
||||
received_round2_packages
|
||||
.entry(round2_package.receiver_identifier)
|
||||
.entry(*round2_package.receiver_identifier())
|
||||
.or_insert_with(Vec::new)
|
||||
.push(round2_package);
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
pub mod samples;
|
|
@ -0,0 +1,131 @@
|
|||
//! Generate sample, fixed instances of structs for testing.
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use frost_core::{Ciphersuite, Element, Group, Scalar};
|
||||
use frost_p256::{
|
||||
keys::{
|
||||
dkg::{round1, round2},
|
||||
KeyPackage, PublicKeyPackage, SecretShare, SigningShare, VerifiableSecretSharingCommitment,
|
||||
VerifyingShare,
|
||||
},
|
||||
round1::{NonceCommitment, SigningCommitments},
|
||||
round2::{SignatureResponse, SignatureShare},
|
||||
Field, Signature, SigningPackage, VerifyingKey,
|
||||
};
|
||||
|
||||
type C = frost_p256::P256Sha256;
|
||||
|
||||
fn element1() -> Element<C> {
|
||||
<C as Ciphersuite>::Group::generator()
|
||||
}
|
||||
|
||||
fn element2() -> Element<C> {
|
||||
element1() + element1()
|
||||
}
|
||||
|
||||
fn scalar1() -> Scalar<C> {
|
||||
let one = <<C as Ciphersuite>::Group as Group>::Field::one();
|
||||
let two = one + one;
|
||||
// To return a fixed non-small number, get the inverse of 2
|
||||
<<C as Ciphersuite>::Group as Group>::Field::invert(&two)
|
||||
.expect("nonzero elements have inverses")
|
||||
}
|
||||
|
||||
/// Generate a sample SigningCommitments.
|
||||
pub fn signing_commitments() -> SigningCommitments {
|
||||
let serialized_element1 = <C as Ciphersuite>::Group::serialize(&element1());
|
||||
let serialized_element2 = <C as Ciphersuite>::Group::serialize(&element2());
|
||||
let hiding_nonce_commitment = NonceCommitment::from_bytes(serialized_element1).unwrap();
|
||||
let binding_nonce_commitment = NonceCommitment::from_bytes(serialized_element2).unwrap();
|
||||
let identifier = 42u16.try_into().unwrap();
|
||||
|
||||
SigningCommitments::new(
|
||||
identifier,
|
||||
hiding_nonce_commitment,
|
||||
binding_nonce_commitment,
|
||||
)
|
||||
}
|
||||
|
||||
/// Generate a sample SigningPackage.
|
||||
pub fn signing_package() -> SigningPackage {
|
||||
let commitments = vec![signing_commitments()];
|
||||
let message = "hello world".as_bytes();
|
||||
|
||||
SigningPackage::new(commitments, message)
|
||||
}
|
||||
|
||||
/// Generate a sample SignatureShare.
|
||||
pub fn signature_share() -> SignatureShare {
|
||||
let identifier = 42u16.try_into().unwrap();
|
||||
let serialized_scalar = <<C as Ciphersuite>::Group as Group>::Field::serialize(&scalar1());
|
||||
let signature_response = SignatureResponse::from_bytes(serialized_scalar).unwrap();
|
||||
|
||||
SignatureShare::new(identifier, signature_response)
|
||||
}
|
||||
|
||||
/// Generate a sample SecretShare.
|
||||
pub fn secret_share() -> SecretShare {
|
||||
let identifier = 42u16.try_into().unwrap();
|
||||
let serialized_scalar = <<C as Ciphersuite>::Group as Group>::Field::serialize(&scalar1());
|
||||
let serialized_element = <C as Ciphersuite>::Group::serialize(&element1());
|
||||
let signing_share = SigningShare::from_bytes(serialized_scalar).unwrap();
|
||||
let vss_commitment =
|
||||
VerifiableSecretSharingCommitment::deserialize(vec![serialized_element]).unwrap();
|
||||
|
||||
SecretShare::new(identifier, signing_share, vss_commitment)
|
||||
}
|
||||
|
||||
/// Generate a sample KeyPackage.
|
||||
pub fn key_package() -> KeyPackage {
|
||||
let identifier = 42u16.try_into().unwrap();
|
||||
let serialized_scalar = <<C as Ciphersuite>::Group as Group>::Field::serialize(&scalar1());
|
||||
let serialized_element = <C as Ciphersuite>::Group::serialize(&element1());
|
||||
let signing_share = SigningShare::from_bytes(serialized_scalar).unwrap();
|
||||
let verifying_share = VerifyingShare::from_bytes(serialized_element).unwrap();
|
||||
let serialized_element = <C as Ciphersuite>::Group::serialize(&element1());
|
||||
let verifying_key = VerifyingKey::from_bytes(serialized_element).unwrap();
|
||||
|
||||
KeyPackage::new(identifier, signing_share, verifying_share, verifying_key)
|
||||
}
|
||||
|
||||
/// Generate a sample PublicKeyPackage.
|
||||
pub fn public_key_package() -> PublicKeyPackage {
|
||||
let identifier = 42u16.try_into().unwrap();
|
||||
let serialized_element = <C as Ciphersuite>::Group::serialize(&element1());
|
||||
let verifying_share = VerifyingShare::from_bytes(serialized_element).unwrap();
|
||||
let serialized_element = <C as Ciphersuite>::Group::serialize(&element1());
|
||||
let verifying_key = VerifyingKey::from_bytes(serialized_element).unwrap();
|
||||
let signer_pubkeys = HashMap::from([(identifier, verifying_share)]);
|
||||
|
||||
PublicKeyPackage::new(signer_pubkeys, verifying_key)
|
||||
}
|
||||
|
||||
/// Generate a sample round1::Package.
|
||||
pub fn round1_package() -> round1::Package {
|
||||
let identifier = 42u16.try_into().unwrap();
|
||||
let serialized_scalar = <<C as Ciphersuite>::Group as Group>::Field::serialize(&scalar1());
|
||||
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::from_bytes(serialized_signature).unwrap();
|
||||
|
||||
round1::Package::new(identifier, vss_commitment, signature)
|
||||
}
|
||||
|
||||
/// Generate a sample round2::Package.
|
||||
pub fn round2_package() -> round2::Package {
|
||||
let identifier = 42u16.try_into().unwrap();
|
||||
let serialized_scalar = <<C as Ciphersuite>::Group as Group>::Field::serialize(&scalar1());
|
||||
let signing_share = SigningShare::from_bytes(serialized_scalar).unwrap();
|
||||
|
||||
round2::Package::new(identifier, identifier, signing_share)
|
||||
}
|
|
@ -0,0 +1,131 @@
|
|||
//! Test for recreating packages from their components, which shows that they
|
||||
//! can be serialized and deserialized as the user wishes.
|
||||
|
||||
use frost_p256::{
|
||||
keys::{
|
||||
dkg::{round1, round2},
|
||||
KeyPackage, PublicKeyPackage, SecretShare,
|
||||
},
|
||||
round1::SigningCommitments,
|
||||
round2::SignatureShare,
|
||||
SigningPackage,
|
||||
};
|
||||
|
||||
mod helpers;
|
||||
|
||||
use helpers::samples;
|
||||
|
||||
/// Check if SigningCommitments can be recreated.
|
||||
#[test]
|
||||
fn check_signing_commitments_recreation() {
|
||||
let commitments = samples::signing_commitments();
|
||||
let identifier = commitments.identifier();
|
||||
let hiding = commitments.hiding();
|
||||
let binding = commitments.binding();
|
||||
let new_commitments = SigningCommitments::new(*identifier, *hiding, *binding);
|
||||
assert!(commitments == new_commitments);
|
||||
}
|
||||
|
||||
/// Check if SigningPackage can be recreated.
|
||||
#[test]
|
||||
fn check_signing_package_recreation() {
|
||||
let signing_package = samples::signing_package();
|
||||
|
||||
let commitments = signing_package
|
||||
.signing_commitments()
|
||||
.values()
|
||||
.cloned()
|
||||
.collect();
|
||||
let message = signing_package.message();
|
||||
|
||||
let new_signing_package = SigningPackage::new(commitments, message);
|
||||
assert!(signing_package == new_signing_package);
|
||||
}
|
||||
|
||||
/// Check if SignatureShare can be recreated.
|
||||
#[test]
|
||||
fn check_signature_share_recreation() {
|
||||
let signature_share = samples::signature_share();
|
||||
|
||||
let identifier = signature_share.identifier();
|
||||
let signature_response = signature_share.signature();
|
||||
|
||||
let new_signature_share = SignatureShare::new(*identifier, *signature_response);
|
||||
assert!(signature_share == new_signature_share);
|
||||
}
|
||||
|
||||
/// Check if SecretShare can be recreated.
|
||||
#[test]
|
||||
fn check_secret_share_recreation() {
|
||||
let secret_share = samples::secret_share();
|
||||
|
||||
let identifier = secret_share.identifier();
|
||||
let value = secret_share.value();
|
||||
let commitment = secret_share.commitment();
|
||||
|
||||
let new_secret_share = SecretShare::new(*identifier, *value, commitment.clone());
|
||||
|
||||
assert!(secret_share == new_secret_share);
|
||||
}
|
||||
|
||||
/// Check if KeyPackage can be recreated.
|
||||
#[test]
|
||||
fn check_key_package_recreation() {
|
||||
let key_package = samples::key_package();
|
||||
|
||||
let identifier = key_package.identifier();
|
||||
let signing_share = key_package.secret_share();
|
||||
let verifying_share = key_package.public();
|
||||
let verifying_key = key_package.group_public();
|
||||
|
||||
let new_key_package = KeyPackage::new(
|
||||
*identifier,
|
||||
*signing_share,
|
||||
*verifying_share,
|
||||
*verifying_key,
|
||||
);
|
||||
|
||||
assert!(key_package == new_key_package);
|
||||
}
|
||||
|
||||
/// Check if PublicKeyPackage can be recreated.
|
||||
#[test]
|
||||
fn check_public_key_package_recreation() {
|
||||
let public_key_package = samples::public_key_package();
|
||||
|
||||
let signer_pubkeys = public_key_package.signer_pubkeys();
|
||||
let verifying_key = public_key_package.group_public();
|
||||
|
||||
let new_public_key_package = PublicKeyPackage::new(signer_pubkeys.clone(), *verifying_key);
|
||||
|
||||
assert!(public_key_package == new_public_key_package);
|
||||
}
|
||||
|
||||
/// Check if round1::Package can be recreated.
|
||||
#[test]
|
||||
fn check_round1_package_recreation() {
|
||||
let round1_package = samples::round1_package();
|
||||
|
||||
let identifier = round1_package.sender_identifier();
|
||||
let vss_commitment = round1_package.commitment();
|
||||
let signature = round1_package.proof_of_knowledge();
|
||||
|
||||
let new_round1_package = round1::Package::new(*identifier, vss_commitment.clone(), *signature);
|
||||
|
||||
assert!(round1_package == new_round1_package);
|
||||
}
|
||||
|
||||
/// Check if round2::Package can be recreated.
|
||||
#[test]
|
||||
fn check_round2_package_recreation() {
|
||||
let round2_package = samples::round2_package();
|
||||
|
||||
let sender_identifier = round2_package.sender_identifier();
|
||||
let receiver_identifier = round2_package.receiver_identifier();
|
||||
let signing_share = round2_package.secret_share();
|
||||
|
||||
let new_round2_package =
|
||||
round2::Package::new(*sender_identifier, *receiver_identifier, *signing_share);
|
||||
|
||||
assert!(round2_package == new_round2_package);
|
||||
}
|
|
@ -34,7 +34,7 @@ pub fn sign<C: Ciphersuite>(
|
|||
key_package: &frost::keys::KeyPackage<C>,
|
||||
randomizer_point: &<C::Group as Group>::Element,
|
||||
) -> Result<frost::round2::SignatureShare<C>, Error<C>> {
|
||||
let public_key = key_package.group_public.to_element() + *randomizer_point;
|
||||
let public_key = key_package.group_public().to_element() + *randomizer_point;
|
||||
|
||||
// Encodes the signing commitment list produced in round one as part of generating [`Rho`], the
|
||||
// binding factor.
|
||||
|
@ -43,7 +43,7 @@ pub fn sign<C: Ciphersuite>(
|
|||
<C::Group as Group>::serialize(randomizer_point).as_ref(),
|
||||
);
|
||||
|
||||
let rho: frost::BindingFactor<C> = binding_factor_list[key_package.identifier].clone();
|
||||
let rho: frost::BindingFactor<C> = binding_factor_list[*key_package.identifier()].clone();
|
||||
|
||||
// Compute the group commitment from signing commitments produced in round one.
|
||||
let group_commitment = frost::compute_group_commitment(signing_package, &binding_factor_list)?;
|
||||
|
@ -126,7 +126,7 @@ where
|
|||
let mut z = <<C::Group as Group>::Field as Field>::zero();
|
||||
|
||||
for signature_share in signature_shares {
|
||||
z = z + signature_share.signature.z_share;
|
||||
z = z + *signature_share.signature().z_share();
|
||||
}
|
||||
|
||||
z = z + challenge.clone().to_scalar() * randomized_params.randomizer;
|
||||
|
@ -145,19 +145,19 @@ where
|
|||
// Look up the public key for this signer, where `signer_pubkey` = _G.ScalarBaseMult(s[i])_,
|
||||
// and where s[i] is a secret share of the constant term of _f_, the secret polynomial.
|
||||
let signer_pubkey = pubkeys
|
||||
.signer_pubkeys
|
||||
.get(&signature_share.identifier)
|
||||
.signer_pubkeys()
|
||||
.get(signature_share.identifier())
|
||||
.unwrap();
|
||||
|
||||
// Compute Lagrange coefficient.
|
||||
let lambda_i =
|
||||
frost::derive_interpolating_value(&signature_share.identifier, signing_package)?;
|
||||
frost::derive_interpolating_value(signature_share.identifier(), signing_package)?;
|
||||
|
||||
let binding_factor = binding_factor_list[signature_share.identifier].clone();
|
||||
let binding_factor = binding_factor_list[*signature_share.identifier()].clone();
|
||||
|
||||
// Compute the commitment share.
|
||||
let R_share = signing_package
|
||||
.signing_commitment(&signature_share.identifier)
|
||||
.signing_commitment(signature_share.identifier())
|
||||
.to_group_commitment_share(&binding_factor);
|
||||
|
||||
// Compute relation values to verify this signature share.
|
||||
|
@ -193,7 +193,7 @@ where
|
|||
let randomizer = <<C::Group as Group>::Field as Field>::random(&mut rng);
|
||||
let randomizer_point = <C::Group as Group>::generator() * randomizer;
|
||||
|
||||
let group_public_point = public_key_package.group_public.to_element();
|
||||
let group_public_point = public_key_package.group_public().to_element();
|
||||
|
||||
let randomized_group_public_point = group_public_point + randomizer_point;
|
||||
let randomized_group_public_key = VerifyingKey::new(randomized_group_public_point);
|
||||
|
|
|
@ -108,7 +108,7 @@ let group_signature = frost::aggregate(&signing_package, &signature_shares[..],
|
|||
// key (the verification key).
|
||||
# // ANCHOR: verify
|
||||
let is_signature_valid = pubkey_package
|
||||
.group_public
|
||||
.group_public()
|
||||
.verify(message, &group_signature)
|
||||
.is_ok();
|
||||
# // ANCHOR_END: verify
|
||||
|
|
|
@ -123,7 +123,7 @@ for participant_index in 1..=max_signers {
|
|||
// gets its own specific package.
|
||||
for round2_package in round2_packages {
|
||||
received_round2_packages
|
||||
.entry(round2_package.receiver_identifier)
|
||||
.entry(*round2_package.receiver_identifier())
|
||||
.or_insert_with(Vec::new)
|
||||
.push(round2_package);
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
pub mod samples;
|
|
@ -0,0 +1,131 @@
|
|||
//! Generate sample, fixed instances of structs for testing.
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use frost_core::{Ciphersuite, Element, Group, Scalar};
|
||||
use frost_ristretto255::{
|
||||
keys::{
|
||||
dkg::{round1, round2},
|
||||
KeyPackage, PublicKeyPackage, SecretShare, SigningShare, VerifiableSecretSharingCommitment,
|
||||
VerifyingShare,
|
||||
},
|
||||
round1::{NonceCommitment, SigningCommitments},
|
||||
round2::{SignatureResponse, SignatureShare},
|
||||
Field, Signature, SigningPackage, VerifyingKey,
|
||||
};
|
||||
|
||||
type C = frost_ristretto255::Ristretto255Sha512;
|
||||
|
||||
fn element1() -> Element<C> {
|
||||
<C as Ciphersuite>::Group::generator()
|
||||
}
|
||||
|
||||
fn element2() -> Element<C> {
|
||||
element1() + element1()
|
||||
}
|
||||
|
||||
fn scalar1() -> Scalar<C> {
|
||||
let one = <<C as Ciphersuite>::Group as Group>::Field::one();
|
||||
let two = one + one;
|
||||
// To return a fixed non-small number, get the inverse of 2
|
||||
<<C as Ciphersuite>::Group as Group>::Field::invert(&two)
|
||||
.expect("nonzero elements have inverses")
|
||||
}
|
||||
|
||||
/// Generate a sample SigningCommitments.
|
||||
pub fn signing_commitments() -> SigningCommitments {
|
||||
let serialized_element1 = <C as Ciphersuite>::Group::serialize(&element1());
|
||||
let serialized_element2 = <C as Ciphersuite>::Group::serialize(&element2());
|
||||
let hiding_nonce_commitment = NonceCommitment::from_bytes(serialized_element1).unwrap();
|
||||
let binding_nonce_commitment = NonceCommitment::from_bytes(serialized_element2).unwrap();
|
||||
let identifier = 42u16.try_into().unwrap();
|
||||
|
||||
SigningCommitments::new(
|
||||
identifier,
|
||||
hiding_nonce_commitment,
|
||||
binding_nonce_commitment,
|
||||
)
|
||||
}
|
||||
|
||||
/// Generate a sample SigningPackage.
|
||||
pub fn signing_package() -> SigningPackage {
|
||||
let commitments = vec![signing_commitments()];
|
||||
let message = "hello world".as_bytes();
|
||||
|
||||
SigningPackage::new(commitments, message)
|
||||
}
|
||||
|
||||
/// Generate a sample SignatureShare.
|
||||
pub fn signature_share() -> SignatureShare {
|
||||
let identifier = 42u16.try_into().unwrap();
|
||||
let serialized_scalar = <<C as Ciphersuite>::Group as Group>::Field::serialize(&scalar1());
|
||||
let signature_response = SignatureResponse::from_bytes(serialized_scalar).unwrap();
|
||||
|
||||
SignatureShare::new(identifier, signature_response)
|
||||
}
|
||||
|
||||
/// Generate a sample SecretShare.
|
||||
pub fn secret_share() -> SecretShare {
|
||||
let identifier = 42u16.try_into().unwrap();
|
||||
let serialized_scalar = <<C as Ciphersuite>::Group as Group>::Field::serialize(&scalar1());
|
||||
let serialized_element = <C as Ciphersuite>::Group::serialize(&element1());
|
||||
let signing_share = SigningShare::from_bytes(serialized_scalar).unwrap();
|
||||
let vss_commitment =
|
||||
VerifiableSecretSharingCommitment::deserialize(vec![serialized_element]).unwrap();
|
||||
|
||||
SecretShare::new(identifier, signing_share, vss_commitment)
|
||||
}
|
||||
|
||||
/// Generate a sample KeyPackage.
|
||||
pub fn key_package() -> KeyPackage {
|
||||
let identifier = 42u16.try_into().unwrap();
|
||||
let serialized_scalar = <<C as Ciphersuite>::Group as Group>::Field::serialize(&scalar1());
|
||||
let serialized_element = <C as Ciphersuite>::Group::serialize(&element1());
|
||||
let signing_share = SigningShare::from_bytes(serialized_scalar).unwrap();
|
||||
let verifying_share = VerifyingShare::from_bytes(serialized_element).unwrap();
|
||||
let serialized_element = <C as Ciphersuite>::Group::serialize(&element1());
|
||||
let verifying_key = VerifyingKey::from_bytes(serialized_element).unwrap();
|
||||
|
||||
KeyPackage::new(identifier, signing_share, verifying_share, verifying_key)
|
||||
}
|
||||
|
||||
/// Generate a sample PublicKeyPackage.
|
||||
pub fn public_key_package() -> PublicKeyPackage {
|
||||
let identifier = 42u16.try_into().unwrap();
|
||||
let serialized_element = <C as Ciphersuite>::Group::serialize(&element1());
|
||||
let verifying_share = VerifyingShare::from_bytes(serialized_element).unwrap();
|
||||
let serialized_element = <C as Ciphersuite>::Group::serialize(&element1());
|
||||
let verifying_key = VerifyingKey::from_bytes(serialized_element).unwrap();
|
||||
let signer_pubkeys = HashMap::from([(identifier, verifying_share)]);
|
||||
|
||||
PublicKeyPackage::new(signer_pubkeys, verifying_key)
|
||||
}
|
||||
|
||||
/// Generate a sample round1::Package.
|
||||
pub fn round1_package() -> round1::Package {
|
||||
let identifier = 42u16.try_into().unwrap();
|
||||
let serialized_scalar = <<C as Ciphersuite>::Group as Group>::Field::serialize(&scalar1());
|
||||
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::from_bytes(serialized_signature).unwrap();
|
||||
|
||||
round1::Package::new(identifier, vss_commitment, signature)
|
||||
}
|
||||
|
||||
/// Generate a sample round2::Package.
|
||||
pub fn round2_package() -> round2::Package {
|
||||
let identifier = 42u16.try_into().unwrap();
|
||||
let serialized_scalar = <<C as Ciphersuite>::Group as Group>::Field::serialize(&scalar1());
|
||||
let signing_share = SigningShare::from_bytes(serialized_scalar).unwrap();
|
||||
|
||||
round2::Package::new(identifier, identifier, signing_share)
|
||||
}
|
|
@ -0,0 +1,131 @@
|
|||
//! Test for recreating packages from their components, which shows that they
|
||||
//! can be serialized and deserialized as the user wishes.
|
||||
|
||||
use frost_ristretto255::{
|
||||
keys::{
|
||||
dkg::{round1, round2},
|
||||
KeyPackage, PublicKeyPackage, SecretShare,
|
||||
},
|
||||
round1::SigningCommitments,
|
||||
round2::SignatureShare,
|
||||
SigningPackage,
|
||||
};
|
||||
|
||||
mod helpers;
|
||||
|
||||
use helpers::samples;
|
||||
|
||||
/// Check if SigningCommitments can be recreated.
|
||||
#[test]
|
||||
fn check_signing_commitments_recreation() {
|
||||
let commitments = samples::signing_commitments();
|
||||
let identifier = commitments.identifier();
|
||||
let hiding = commitments.hiding();
|
||||
let binding = commitments.binding();
|
||||
let new_commitments = SigningCommitments::new(*identifier, *hiding, *binding);
|
||||
assert!(commitments == new_commitments);
|
||||
}
|
||||
|
||||
/// Check if SigningPackage can be recreated.
|
||||
#[test]
|
||||
fn check_signing_package_recreation() {
|
||||
let signing_package = samples::signing_package();
|
||||
|
||||
let commitments = signing_package
|
||||
.signing_commitments()
|
||||
.values()
|
||||
.cloned()
|
||||
.collect();
|
||||
let message = signing_package.message();
|
||||
|
||||
let new_signing_package = SigningPackage::new(commitments, message);
|
||||
assert!(signing_package == new_signing_package);
|
||||
}
|
||||
|
||||
/// Check if SignatureShare can be recreated.
|
||||
#[test]
|
||||
fn check_signature_share_recreation() {
|
||||
let signature_share = samples::signature_share();
|
||||
|
||||
let identifier = signature_share.identifier();
|
||||
let signature_response = signature_share.signature();
|
||||
|
||||
let new_signature_share = SignatureShare::new(*identifier, *signature_response);
|
||||
assert!(signature_share == new_signature_share);
|
||||
}
|
||||
|
||||
/// Check if SecretShare can be recreated.
|
||||
#[test]
|
||||
fn check_secret_share_recreation() {
|
||||
let secret_share = samples::secret_share();
|
||||
|
||||
let identifier = secret_share.identifier();
|
||||
let value = secret_share.value();
|
||||
let commitment = secret_share.commitment();
|
||||
|
||||
let new_secret_share = SecretShare::new(*identifier, *value, commitment.clone());
|
||||
|
||||
assert!(secret_share == new_secret_share);
|
||||
}
|
||||
|
||||
/// Check if KeyPackage can be recreated.
|
||||
#[test]
|
||||
fn check_key_package_recreation() {
|
||||
let key_package = samples::key_package();
|
||||
|
||||
let identifier = key_package.identifier();
|
||||
let signing_share = key_package.secret_share();
|
||||
let verifying_share = key_package.public();
|
||||
let verifying_key = key_package.group_public();
|
||||
|
||||
let new_key_package = KeyPackage::new(
|
||||
*identifier,
|
||||
*signing_share,
|
||||
*verifying_share,
|
||||
*verifying_key,
|
||||
);
|
||||
|
||||
assert!(key_package == new_key_package);
|
||||
}
|
||||
|
||||
/// Check if PublicKeyPackage can be recreated.
|
||||
#[test]
|
||||
fn check_public_key_package_recreation() {
|
||||
let public_key_package = samples::public_key_package();
|
||||
|
||||
let signer_pubkeys = public_key_package.signer_pubkeys();
|
||||
let verifying_key = public_key_package.group_public();
|
||||
|
||||
let new_public_key_package = PublicKeyPackage::new(signer_pubkeys.clone(), *verifying_key);
|
||||
|
||||
assert!(public_key_package == new_public_key_package);
|
||||
}
|
||||
|
||||
/// Check if round1::Package can be recreated.
|
||||
#[test]
|
||||
fn check_round1_package_recreation() {
|
||||
let round1_package = samples::round1_package();
|
||||
|
||||
let identifier = round1_package.sender_identifier();
|
||||
let vss_commitment = round1_package.commitment();
|
||||
let signature = round1_package.proof_of_knowledge();
|
||||
|
||||
let new_round1_package = round1::Package::new(*identifier, vss_commitment.clone(), *signature);
|
||||
|
||||
assert!(round1_package == new_round1_package);
|
||||
}
|
||||
|
||||
/// Check if round2::Package can be recreated.
|
||||
#[test]
|
||||
fn check_round2_package_recreation() {
|
||||
let round2_package = samples::round2_package();
|
||||
|
||||
let sender_identifier = round2_package.sender_identifier();
|
||||
let receiver_identifier = round2_package.receiver_identifier();
|
||||
let signing_share = round2_package.secret_share();
|
||||
|
||||
let new_round2_package =
|
||||
round2::Package::new(*sender_identifier, *receiver_identifier, *signing_share);
|
||||
|
||||
assert!(round2_package == new_round2_package);
|
||||
}
|
|
@ -108,7 +108,7 @@ let group_signature = frost::aggregate(&signing_package, &signature_shares[..],
|
|||
// key (the verification key).
|
||||
# // ANCHOR: verify
|
||||
let is_signature_valid = pubkey_package
|
||||
.group_public
|
||||
.group_public()
|
||||
.verify(message, &group_signature)
|
||||
.is_ok();
|
||||
# // ANCHOR_END: verify
|
||||
|
|
|
@ -123,7 +123,7 @@ for participant_index in 1..=max_signers {
|
|||
// gets its own specific package.
|
||||
for round2_package in round2_packages {
|
||||
received_round2_packages
|
||||
.entry(round2_package.receiver_identifier)
|
||||
.entry(*round2_package.receiver_identifier())
|
||||
.or_insert_with(Vec::new)
|
||||
.push(round2_package);
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
pub mod samples;
|
|
@ -0,0 +1,131 @@
|
|||
//! Generate sample, fixed instances of structs for testing.
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use frost_core::{Ciphersuite, Element, Group, Scalar};
|
||||
use frost_secp256k1::{
|
||||
keys::{
|
||||
dkg::{round1, round2},
|
||||
KeyPackage, PublicKeyPackage, SecretShare, SigningShare, VerifiableSecretSharingCommitment,
|
||||
VerifyingShare,
|
||||
},
|
||||
round1::{NonceCommitment, SigningCommitments},
|
||||
round2::{SignatureResponse, SignatureShare},
|
||||
Field, Signature, SigningPackage, VerifyingKey,
|
||||
};
|
||||
|
||||
type C = frost_secp256k1::Secp256K1Sha256;
|
||||
|
||||
fn element1() -> Element<C> {
|
||||
<C as Ciphersuite>::Group::generator()
|
||||
}
|
||||
|
||||
fn element2() -> Element<C> {
|
||||
element1() + element1()
|
||||
}
|
||||
|
||||
fn scalar1() -> Scalar<C> {
|
||||
let one = <<C as Ciphersuite>::Group as Group>::Field::one();
|
||||
let two = one + one;
|
||||
// To return a fixed non-small number, get the inverse of 2
|
||||
<<C as Ciphersuite>::Group as Group>::Field::invert(&two)
|
||||
.expect("nonzero elements have inverses")
|
||||
}
|
||||
|
||||
/// Generate a sample SigningCommitments.
|
||||
pub fn signing_commitments() -> SigningCommitments {
|
||||
let serialized_element1 = <C as Ciphersuite>::Group::serialize(&element1());
|
||||
let serialized_element2 = <C as Ciphersuite>::Group::serialize(&element2());
|
||||
let hiding_nonce_commitment = NonceCommitment::from_bytes(serialized_element1).unwrap();
|
||||
let binding_nonce_commitment = NonceCommitment::from_bytes(serialized_element2).unwrap();
|
||||
let identifier = 42u16.try_into().unwrap();
|
||||
|
||||
SigningCommitments::new(
|
||||
identifier,
|
||||
hiding_nonce_commitment,
|
||||
binding_nonce_commitment,
|
||||
)
|
||||
}
|
||||
|
||||
/// Generate a sample SigningPackage.
|
||||
pub fn signing_package() -> SigningPackage {
|
||||
let commitments = vec![signing_commitments()];
|
||||
let message = "hello world".as_bytes();
|
||||
|
||||
SigningPackage::new(commitments, message)
|
||||
}
|
||||
|
||||
/// Generate a sample SignatureShare.
|
||||
pub fn signature_share() -> SignatureShare {
|
||||
let identifier = 42u16.try_into().unwrap();
|
||||
let serialized_scalar = <<C as Ciphersuite>::Group as Group>::Field::serialize(&scalar1());
|
||||
let signature_response = SignatureResponse::from_bytes(serialized_scalar).unwrap();
|
||||
|
||||
SignatureShare::new(identifier, signature_response)
|
||||
}
|
||||
|
||||
/// Generate a sample SecretShare.
|
||||
pub fn secret_share() -> SecretShare {
|
||||
let identifier = 42u16.try_into().unwrap();
|
||||
let serialized_scalar = <<C as Ciphersuite>::Group as Group>::Field::serialize(&scalar1());
|
||||
let serialized_element = <C as Ciphersuite>::Group::serialize(&element1());
|
||||
let signing_share = SigningShare::from_bytes(serialized_scalar).unwrap();
|
||||
let vss_commitment =
|
||||
VerifiableSecretSharingCommitment::deserialize(vec![serialized_element]).unwrap();
|
||||
|
||||
SecretShare::new(identifier, signing_share, vss_commitment)
|
||||
}
|
||||
|
||||
/// Generate a sample KeyPackage.
|
||||
pub fn key_package() -> KeyPackage {
|
||||
let identifier = 42u16.try_into().unwrap();
|
||||
let serialized_scalar = <<C as Ciphersuite>::Group as Group>::Field::serialize(&scalar1());
|
||||
let serialized_element = <C as Ciphersuite>::Group::serialize(&element1());
|
||||
let signing_share = SigningShare::from_bytes(serialized_scalar).unwrap();
|
||||
let verifying_share = VerifyingShare::from_bytes(serialized_element).unwrap();
|
||||
let serialized_element = <C as Ciphersuite>::Group::serialize(&element1());
|
||||
let verifying_key = VerifyingKey::from_bytes(serialized_element).unwrap();
|
||||
|
||||
KeyPackage::new(identifier, signing_share, verifying_share, verifying_key)
|
||||
}
|
||||
|
||||
/// Generate a sample PublicKeyPackage.
|
||||
pub fn public_key_package() -> PublicKeyPackage {
|
||||
let identifier = 42u16.try_into().unwrap();
|
||||
let serialized_element = <C as Ciphersuite>::Group::serialize(&element1());
|
||||
let verifying_share = VerifyingShare::from_bytes(serialized_element).unwrap();
|
||||
let serialized_element = <C as Ciphersuite>::Group::serialize(&element1());
|
||||
let verifying_key = VerifyingKey::from_bytes(serialized_element).unwrap();
|
||||
let signer_pubkeys = HashMap::from([(identifier, verifying_share)]);
|
||||
|
||||
PublicKeyPackage::new(signer_pubkeys, verifying_key)
|
||||
}
|
||||
|
||||
/// Generate a sample round1::Package.
|
||||
pub fn round1_package() -> round1::Package {
|
||||
let identifier = 42u16.try_into().unwrap();
|
||||
let serialized_scalar = <<C as Ciphersuite>::Group as Group>::Field::serialize(&scalar1());
|
||||
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::from_bytes(serialized_signature).unwrap();
|
||||
|
||||
round1::Package::new(identifier, vss_commitment, signature)
|
||||
}
|
||||
|
||||
/// Generate a sample round2::Package.
|
||||
pub fn round2_package() -> round2::Package {
|
||||
let identifier = 42u16.try_into().unwrap();
|
||||
let serialized_scalar = <<C as Ciphersuite>::Group as Group>::Field::serialize(&scalar1());
|
||||
let signing_share = SigningShare::from_bytes(serialized_scalar).unwrap();
|
||||
|
||||
round2::Package::new(identifier, identifier, signing_share)
|
||||
}
|
|
@ -0,0 +1,131 @@
|
|||
//! Test for recreating packages from their components, which shows that they
|
||||
//! can be serialized and deserialized as the user wishes.
|
||||
|
||||
use frost_secp256k1::{
|
||||
keys::{
|
||||
dkg::{round1, round2},
|
||||
KeyPackage, PublicKeyPackage, SecretShare,
|
||||
},
|
||||
round1::SigningCommitments,
|
||||
round2::SignatureShare,
|
||||
SigningPackage,
|
||||
};
|
||||
|
||||
mod helpers;
|
||||
|
||||
use helpers::samples;
|
||||
|
||||
/// Check if SigningCommitments can be recreated.
|
||||
#[test]
|
||||
fn check_signing_commitments_recreation() {
|
||||
let commitments = samples::signing_commitments();
|
||||
let identifier = commitments.identifier();
|
||||
let hiding = commitments.hiding();
|
||||
let binding = commitments.binding();
|
||||
let new_commitments = SigningCommitments::new(*identifier, *hiding, *binding);
|
||||
assert!(commitments == new_commitments);
|
||||
}
|
||||
|
||||
/// Check if SigningPackage can be recreated.
|
||||
#[test]
|
||||
fn check_signing_package_recreation() {
|
||||
let signing_package = samples::signing_package();
|
||||
|
||||
let commitments = signing_package
|
||||
.signing_commitments()
|
||||
.values()
|
||||
.cloned()
|
||||
.collect();
|
||||
let message = signing_package.message();
|
||||
|
||||
let new_signing_package = SigningPackage::new(commitments, message);
|
||||
assert!(signing_package == new_signing_package);
|
||||
}
|
||||
|
||||
/// Check if SignatureShare can be recreated.
|
||||
#[test]
|
||||
fn check_signature_share_recreation() {
|
||||
let signature_share = samples::signature_share();
|
||||
|
||||
let identifier = signature_share.identifier();
|
||||
let signature_response = signature_share.signature();
|
||||
|
||||
let new_signature_share = SignatureShare::new(*identifier, *signature_response);
|
||||
assert!(signature_share == new_signature_share);
|
||||
}
|
||||
|
||||
/// Check if SecretShare can be recreated.
|
||||
#[test]
|
||||
fn check_secret_share_recreation() {
|
||||
let secret_share = samples::secret_share();
|
||||
|
||||
let identifier = secret_share.identifier();
|
||||
let value = secret_share.value();
|
||||
let commitment = secret_share.commitment();
|
||||
|
||||
let new_secret_share = SecretShare::new(*identifier, *value, commitment.clone());
|
||||
|
||||
assert!(secret_share == new_secret_share);
|
||||
}
|
||||
|
||||
/// Check if KeyPackage can be recreated.
|
||||
#[test]
|
||||
fn check_key_package_recreation() {
|
||||
let key_package = samples::key_package();
|
||||
|
||||
let identifier = key_package.identifier();
|
||||
let signing_share = key_package.secret_share();
|
||||
let verifying_share = key_package.public();
|
||||
let verifying_key = key_package.group_public();
|
||||
|
||||
let new_key_package = KeyPackage::new(
|
||||
*identifier,
|
||||
*signing_share,
|
||||
*verifying_share,
|
||||
*verifying_key,
|
||||
);
|
||||
|
||||
assert!(key_package == new_key_package);
|
||||
}
|
||||
|
||||
/// Check if PublicKeyPackage can be recreated.
|
||||
#[test]
|
||||
fn check_public_key_package_recreation() {
|
||||
let public_key_package = samples::public_key_package();
|
||||
|
||||
let signer_pubkeys = public_key_package.signer_pubkeys();
|
||||
let verifying_key = public_key_package.group_public();
|
||||
|
||||
let new_public_key_package = PublicKeyPackage::new(signer_pubkeys.clone(), *verifying_key);
|
||||
|
||||
assert!(public_key_package == new_public_key_package);
|
||||
}
|
||||
|
||||
/// Check if round1::Package can be recreated.
|
||||
#[test]
|
||||
fn check_round1_package_recreation() {
|
||||
let round1_package = samples::round1_package();
|
||||
|
||||
let identifier = round1_package.sender_identifier();
|
||||
let vss_commitment = round1_package.commitment();
|
||||
let signature = round1_package.proof_of_knowledge();
|
||||
|
||||
let new_round1_package = round1::Package::new(*identifier, vss_commitment.clone(), *signature);
|
||||
|
||||
assert!(round1_package == new_round1_package);
|
||||
}
|
||||
|
||||
/// Check if round2::Package can be recreated.
|
||||
#[test]
|
||||
fn check_round2_package_recreation() {
|
||||
let round2_package = samples::round2_package();
|
||||
|
||||
let sender_identifier = round2_package.sender_identifier();
|
||||
let receiver_identifier = round2_package.receiver_identifier();
|
||||
let signing_share = round2_package.secret_share();
|
||||
|
||||
let new_round2_package =
|
||||
round2::Package::new(*sender_identifier, *receiver_identifier, *signing_share);
|
||||
|
||||
assert!(round2_package == new_round2_package);
|
||||
}
|
|
@ -286,6 +286,8 @@ fn main() -> ExitCode {
|
|||
"src/tests/coefficient_commitment.rs",
|
||||
"src/tests/proptests.rs",
|
||||
"src/tests/vss_commitment.rs",
|
||||
"tests/recreation_tests.rs",
|
||||
"tests/helpers/samples.rs",
|
||||
] {
|
||||
replaced |= copy_and_replace(
|
||||
format!("{original_folder}/{filename}").as_str(),
|
||||
|
|
Loading…
Reference in New Issue