use Identifier instead of index (#96)

* use Identifier instead of index

* remove pub(crate) from the Identifier index

* A comment

* Whitespace for readability

* check for zero in Identifier::to_scalar()

Co-authored-by: Deirdre Connolly <durumcrustulum@gmail.com>
This commit is contained in:
Conrado Gouvea 2022-09-01 17:07:50 -03:00 committed by GitHub
parent 789551186a
commit 86e1218fa9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 273 additions and 345 deletions

View File

@ -99,46 +99,28 @@ where
/// Generates the lagrange coefficient for the i'th participant.
fn derive_lagrange_coeff<C: Ciphersuite>(
signer_id: u16,
signer_id: &Identifier<C>,
signing_package: &SigningPackage<C>,
) -> Result<<<C::Group as Group>::Field as Field>::Scalar, &'static str> {
// This should fail and panic if signer_id_scalar is 0 in the scalar field.
let signer_id_scalar = Identifier::<C>::try_from(signer_id).unwrap();
let signer_id_scalar = signer_id.to_scalar()?;
let zero = <<C::Group as Group>::Field as Field>::zero();
// TODO: This is redundant
if signer_id_scalar.0 == zero {
return Err("Invalid parameters");
}
if signing_package
.signing_commitments()
.iter()
.any(|commitment| {
let commitment_id_scalar = Identifier::<C>::try_from(commitment.index).unwrap();
*commitment_id_scalar == zero
})
{
return Err("Invalid parameters");
}
let mut num = <<C::Group as Group>::Field as Field>::one();
let mut den = <<C::Group as Group>::Field as Field>::one();
// Ala the sorting of B, just always sort by index in ascending order
// 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() {
if commitment.index == signer_id {
if commitment.identifier == *signer_id {
continue;
}
let commitment_id_scalar = Identifier::<C>::try_from(commitment.index).unwrap();
let commitment_id_scalar = commitment.identifier.to_scalar()?;
num = num * *commitment_id_scalar;
den = den * (*commitment_id_scalar - *signer_id_scalar);
num = num * commitment_id_scalar;
den = den * (commitment_id_scalar - signer_id_scalar);
}
if den == zero {
@ -156,7 +138,7 @@ fn derive_lagrange_coeff<C: Ciphersuite>(
pub struct SigningPackage<C: Ciphersuite> {
/// The set of commitments participants published in the first round of the
/// protocol.
signing_commitments: HashMap<u16, round1::SigningCommitments<C>>,
signing_commitments: HashMap<Identifier<C>, round1::SigningCommitments<C>>,
/// Message which each participant will sign.
///
/// Each signer should perform protocol-specific verification on the
@ -170,32 +152,30 @@ where
{
/// Create a new `SigingPackage`
///
/// The `signing_commitments` are sorted by participant `index`.
/// The `signing_commitments` are sorted by participant `identifier`.
pub fn new(
mut signing_commitments: Vec<round1::SigningCommitments<C>>,
signing_commitments: Vec<round1::SigningCommitments<C>>,
message: Vec<u8>,
) -> SigningPackage<C> {
signing_commitments.sort_by_key(|a| a.index);
SigningPackage {
signing_commitments: signing_commitments
.into_iter()
.map(|s| (s.index, s))
.map(|s| (s.identifier, s))
.collect(),
message,
}
}
/// Get a signing commitment by its participant index.
pub fn signing_commitment(&self, index: &u16) -> round1::SigningCommitments<C> {
self.signing_commitments[index]
/// Get a signing commitment by its participant identifier.
pub fn signing_commitment(&self, identifier: &Identifier<C>) -> round1::SigningCommitments<C> {
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.index);
signing_commitments.sort_by_key(|a| a.identifier);
signing_commitments
}
@ -250,7 +230,7 @@ where
let mut group_hiding_commitment = <C::Group as Group>::identity();
let mut group_binding_commitment = <C::Group as Group>::identity();
// Ala the sorting of B, just always sort by index in ascending order
// 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() {
@ -314,14 +294,17 @@ where
for signature_share in signature_shares {
// 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.index).unwrap();
let signer_pubkey = pubkeys
.signer_pubkeys
.get(&signature_share.identifier)
.unwrap();
// Compute Lagrange coefficient.
let lambda_i = derive_lagrange_coeff(signature_share.index, signing_package)?;
let lambda_i = derive_lagrange_coeff(&signature_share.identifier, signing_package)?;
// Compute the commitment share.
let R_share = signing_package
.signing_commitment(&signature_share.index)
.signing_commitment(&signature_share.identifier)
.to_group_commitment_share(&rho);
// Compute relation values to verify this signature share.

View File

@ -3,7 +3,7 @@
use std::{
fmt::{self, Debug},
hash::{Hash, Hasher},
ops::{Deref, Index},
marker::PhantomData,
};
use crate::{Ciphersuite, Error, Field, Group, Scalar};
@ -14,14 +14,55 @@ use crate::{Ciphersuite, Error, Field, Group, Scalar};
/// over, corresponding to some x-coordinate for a polynomial f(x) = y. MUST NOT be zero in the
/// field, as f(0) = the shared secret.
#[derive(Copy, Clone)]
pub struct Identifier<C: Ciphersuite>(pub(crate) Scalar<C>);
pub struct Identifier<C>(u16, PhantomData<C>);
impl<C> AsRef<Scalar<C>> for Identifier<C>
impl<C> Identifier<C>
where
C: Ciphersuite,
{
fn as_ref(&self) -> &Scalar<C> {
&self.0
// Convert the identifier to a Scalar.
//
// Ideally this would be a From<Identifier<C>> for Scalar<C> impl, but rustc
// doesn't like that
pub(crate) fn to_scalar(self) -> Result<Scalar<C>, &'static str> {
// This should never happen since we check it when building Identifier,
// but we check again out of abundance of caution.
if self.0 == 0 {
return Err("Identifier must not be zero");
}
// Classic left-to-right double-and-add algorithm that skips the first bit 1 (since
// identifiers are never zero, there is always a bit 1), thus `sum` starts with 1 too.
let one = <<C::Group as Group>::Field as Field>::one();
let mut sum = <<C::Group as Group>::Field as Field>::one();
let bits = (self.0.to_be_bytes().len() as u32) * 8;
for i in (0..(bits - self.0.leading_zeros() - 1)).rev() {
sum = sum + sum;
if self.0 & (1 << i) != 0 {
sum = sum + one;
}
}
Ok(sum)
}
}
impl<C> PartialEq for Identifier<C> {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl<C> Eq for Identifier<C> {}
impl<C> PartialOrd for Identifier<C> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
self.0.partial_cmp(&other.0)
}
}
impl<C> Ord for Identifier<C> {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.0.cmp(&other.0)
}
}
@ -30,52 +71,7 @@ where
C: Ciphersuite,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_tuple("Identifier")
.field(&usize::from(*self))
.finish()
}
}
impl<C> Deref for Identifier<C>
where
C: Ciphersuite,
{
type Target = Scalar<C>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
// impl<C> Deref for &Identifier<C>
// where
// C: Ciphersuite,
// {
// type Target = Scalar<C>;
// fn deref(&self) -> &Self::Target {
// &self.0
// }
// }
impl<C> Eq for Identifier<C> where C: Ciphersuite {}
impl<C> From<Identifier<C>> for usize
where
C: Ciphersuite,
{
// TODO: this feels janky, are we confident we aren't clamping off the higher byte values?
fn from(id: Identifier<C>) -> usize {
// This is 8 bytes because usize is up to 8 bytes depending on the platform.
//
// https://doc.rust-lang.org/stable/std/primitive.usize.html#method.from_le_bytes
let mut bytes = [0u8; 8];
let serialized = <<C::Group as Group>::Field as Field>::serialize(&id.0);
bytes.copy_from_slice(&serialized.as_ref()[..8]);
usize::from_le_bytes(bytes)
f.debug_tuple("Identifier").field(&self.0).finish()
}
}
@ -84,113 +80,30 @@ where
C: Ciphersuite,
{
fn hash<H: Hasher>(&self, state: &mut H) {
<<C::Group as Group>::Field as Field>::serialize(&self.0)
.as_ref()
.hash(state)
self.0.hash(state)
}
}
impl<C, T> Index<Identifier<C>> for Vec<T>
impl<C> From<Identifier<C>> for u16
where
C: Ciphersuite,
{
type Output = T;
fn index(&self, id: Identifier<C>) -> &Self::Output {
&self[usize::from(id)]
fn from(identifier: Identifier<C>) -> Self {
identifier.0
}
}
// impl<C> std::ops::Mul for Identifier<C>
// where
// C: Ciphersuite,
// {
// type Output = Self;
// fn mul(self, rhs: Identifier<C>) -> Self::Output {
// Self(self.0 * rhs.0)
// }
// }
// impl<C> std::ops::Mul<Scalar<C>> for Identifier<C>
// where
// C: Ciphersuite,
// {
// type Output = Scalar<C>;
// fn mul(self, scalar: Scalar<C>) -> Scalar<C> {
// self.0 * scalar
// }
// }
// impl<'a, 'b, C> std::ops::Mul<&'b Identifier<C>> for &'a Scalar<C>
// where
// C: Ciphersuite,
// {
// type Output = Scalar<C>;
// fn mul(self, id: &'b Identifier<C>) -> Scalar<C> {
// self * id.0
// }
// }
impl<C> PartialEq for Identifier<C>
where
C: Ciphersuite,
{
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
// impl<C> std::ops::Sub for Identifier<C>
// where
// C: Ciphersuite,
// {
// type Output = Self;
// fn sub(self, rhs: Identifier<C>) -> Self::Output {
// Self(self.0 - rhs.0)
// }
// }
// impl<C> std::ops::Sub<Scalar<C>> for Identifier<C>
// where
// C: Ciphersuite,
// {
// type Output = Scalar<C>;
// fn sub(self, scalar: Scalar<C>) -> Scalar<C> {
// self.0 - scalar
// }
// }
impl<C> TryFrom<u16> for Identifier<C>
where
C: Ciphersuite,
{
type Error = Error;
// TODO: this feels like a cluster. Improve?
fn try_from(n: u16) -> Result<Identifier<C>, Self::Error> {
let mut bytes =
Vec::from(<<C::Group as Group>::Field as Field>::Serialization::default().as_ref());
for (i, byte) in n.to_le_bytes().iter().enumerate() {
bytes[i] = *byte;
}
let serialization = bytes
.try_into()
.map_err(|_| Self::Error::MalformedIdentifier)?;
let scalar = <<C::Group as Group>::Field as Field>::deserialize(&serialization)?;
// Participant identifiers are public, so this comparison doesn't need to be constant-time.
if scalar == <<C::Group as Group>::Field as Field>::zero() {
if n == 0 {
Err(Self::Error::InvalidZeroScalar)
} else {
Ok(Self(scalar))
Ok(Self(n, Default::default()))
}
}
}

View File

@ -173,12 +173,12 @@ pub struct VerifiableSecretSharingCommitment<C: Ciphersuite>(
/// `n` is the total number of shares and `t` is the threshold required to reconstruct the secret;
/// in this case we use Shamir's secret sharing.
///
/// As a solution to the secret polynomial _f_ (a 'point'), the `index` is the x-coordinate, and the
/// As a solution to the secret polynomial _f_ (a 'point'), the `identifier` is the x-coordinate, and the
/// `value` is the y-coordinate.
#[derive(Clone, Zeroize)]
pub struct SecretShare<C: Ciphersuite> {
/// The participant index of this [`SecretShare`].
pub index: u16,
/// The participant identifier of this [`SecretShare`].
pub identifier: Identifier<C>,
/// Secret Key.
pub value: Secret<C>,
/// The commitments to be distributed among signers.
@ -207,16 +207,14 @@ where
pub fn verify(&self) -> Result<(), &'static str> {
let f_result = <C::Group as Group>::generator() * self.value.0;
let x = Identifier::<C>::try_from(self.index).unwrap();
let x = self.identifier.to_scalar()?;
let (_, result) = self.commitment.0.iter().fold(
(
<<C::Group as Group>::Field as Field>::one(),
<C::Group as Group>::identity(),
),
|(x_to_the_i, sum_so_far), comm_i| {
(*x * x_to_the_i, sum_so_far + comm_i.0 * x_to_the_i)
},
|(x_to_the_i, sum_so_far), comm_i| (x * x_to_the_i, sum_so_far + comm_i.0 * x_to_the_i),
);
if !(f_result == result) {
@ -234,8 +232,8 @@ where
/// .into(), which under the hood also performs validation.
#[derive(Clone)]
pub struct SharePackage<C: Ciphersuite> {
/// Denotes the participant index each share is owned by.
pub index: u16,
/// Denotes the participant identifier each share is owned by.
pub identifier: Identifier<C>,
/// This participant's secret share.
pub secret_share: SecretShare<C>,
/// This participant's public key.
@ -268,19 +266,20 @@ pub fn keygen_with_dealer<C: Ciphersuite, R: RngCore + CryptoRng>(
let group_public = VerifyingKey::from(&secret);
let secret_shares = generate_secret_shares(&secret, num_signers, threshold, rng)?;
let mut share_packages: Vec<SharePackage<C>> = Vec::with_capacity(num_signers as usize);
let mut signer_pubkeys: HashMap<u16, Public<C>> = HashMap::with_capacity(num_signers as usize);
let mut signer_pubkeys: HashMap<Identifier<C>, Public<C>> =
HashMap::with_capacity(num_signers as usize);
for secret_share in secret_shares {
let signer_public = secret_share.value.into();
share_packages.push(SharePackage {
index: secret_share.index,
identifier: secret_share.identifier,
secret_share: secret_share.clone(),
public: signer_public,
group_public,
});
signer_pubkeys.insert(secret_share.index, signer_public);
signer_pubkeys.insert(secret_share.identifier, signer_public);
}
Ok((
@ -300,8 +299,8 @@ pub fn keygen_with_dealer<C: Ciphersuite, R: RngCore + CryptoRng>(
/// [`KeyPackage`]s, which they store to later use during signing.
#[derive(Clone)]
pub struct KeyPackage<C: Ciphersuite> {
/// Denotes the participant index each secret share key package is owned by.
pub index: u16,
/// Denotes the participant identifier each secret share key package is owned by.
pub identifier: Identifier<C>,
/// This participant's secret share.
pub secret_share: Secret<C>,
/// This participant's public key.
@ -314,9 +313,9 @@ impl<C> KeyPackage<C>
where
C: Ciphersuite,
{
/// Gets the participant index associated with this [`KeyPackage`].
pub fn index(&self) -> &u16 {
&self.index
/// Gets the participant identifier associated with this [`KeyPackage`].
pub fn identifier(&self) -> &Identifier<C> {
&self.identifier
}
/// Gets the participant's [`Secret`] share associated with this [`KeyPackage`].
@ -353,7 +352,7 @@ where
share_package.secret_share.verify()?;
Ok(KeyPackage {
index: share_package.index,
identifier: share_package.identifier,
secret_share: share_package.secret_share.value,
public: share_package.public,
group_public: share_package.group_public,
@ -370,7 +369,7 @@ 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<u16, Public<C>>,
pub signer_pubkeys: HashMap<Identifier<C>, Public<C>>,
/// The joint public key for the entire group.
pub group_public: VerifyingKey<C>,
}
@ -438,24 +437,25 @@ pub fn generate_secret_shares<C: Ciphersuite, R: RngCore + CryptoRng>(
}
// Evaluate the polynomial with `secret` as the constant term
// and `coeffs` as the other coefficients at the point x=share_index,
// and `coeffs` as the other coefficients at the point x=share_identifier,
// using Horner's method.
for id in (1..=numshares as u16).map_while(|i| Identifier::<C>::try_from(i).ok()) {
let mut value = <<C::Group as Group>::Field as Field>::zero();
let id_scalar = id.to_scalar()?;
// Polynomial evaluation, for this index
// Polynomial evaluation, for this identifier
//
// We rely only on `Add` and `Mul` here so as to not require `AddAssign` and `MulAssign`
//
// Note that this is from the 'last' coefficient to the 'first'.
for i in (0..numcoeffs).rev() {
value = value + coefficients[i as usize];
value = *id * value;
value = id_scalar * value;
}
value = value + secret.0;
secret_shares.push(SecretShare {
index: usize::from(id) as u16,
identifier: id,
value: Secret(value),
commitment: commitment.clone(),
});
@ -474,7 +474,7 @@ pub fn reconstruct_secret<C: Ciphersuite>(
let secret_share_map: HashMap<Identifier<C>, SecretShare<C>> = secret_shares
.into_iter()
.map(|share| (Identifier::<C>::try_from(share.index).unwrap(), share))
.map(|share| (share.identifier, share))
.collect();
let mut secret = <<C::Group as Group>::Field as Field>::zero();
@ -483,17 +483,19 @@ pub fn reconstruct_secret<C: Ciphersuite>(
for (i, secret_share) in secret_share_map.clone() {
let mut num = <<C::Group as Group>::Field as Field>::one();
let mut den = <<C::Group as Group>::Field as Field>::one();
let i_scalar = i.to_scalar()?;
for j in secret_share_map.clone().into_keys() {
if j == i {
continue;
}
let j_scalar = j.to_scalar()?;
// numerator *= j
num = num * *j;
num = num * j_scalar;
// denominator *= j - i
den = den * (*j - *i);
den = den * (j_scalar - i_scalar);
}
// If at this step, the denominator is zero in the scalar field, there must be a duplicate

View File

@ -8,7 +8,7 @@ use zeroize::Zeroize;
use crate::{frost, Ciphersuite, Error, Field, Group};
use super::keys::Secret;
use super::{keys::Secret, Identifier};
/// A scalar that is a signing nonce.
#[derive(Clone, PartialEq, Zeroize)]
@ -196,8 +196,8 @@ where
/// SigningCommitment can be used for exactly *one* signature.
#[derive(Copy, Clone)]
pub struct SigningCommitments<C: Ciphersuite> {
/// The participant index.
pub index: u16,
/// The participant identifier.
pub identifier: Identifier<C>,
/// Commitment to the hiding [`Nonce`].
pub hiding: NonceCommitment<C>,
/// Commitment to the binding [`Nonce`].
@ -229,13 +229,13 @@ where
}
}
impl<C> From<(u16, &SigningNonces<C>)> for SigningCommitments<C>
impl<C> From<(Identifier<C>, &SigningNonces<C>)> for SigningCommitments<C>
where
C: Ciphersuite,
{
fn from((index, nonces): (u16, &SigningNonces<C>)) -> Self {
fn from((identifier, nonces): (Identifier<C>, &SigningNonces<C>)) -> Self {
Self {
index,
identifier,
hiding: nonces.hiding.clone().into(),
binding: nonces.binding.clone().into(),
}
@ -253,9 +253,9 @@ pub struct GroupCommitmentShare<C: Ciphersuite>(pub(super) <C::Group as Group>::
///
/// Inputs:
/// - commitment_list = [(j, D_j, E_j), ...], a list of commitments issued by each signer,
/// where each element in the list indicates the signer index and their
/// where each element in the list indicates the signer identifier and their
/// two commitment Element values. B MUST be sorted in ascending order
/// by signer index.
/// by signer identifier.
///
/// Outputs:
/// - A byte string containing the serialized representation of B.
@ -264,18 +264,18 @@ pub struct GroupCommitmentShare<C: Ciphersuite>(pub(super) <C::Group as Group>::
pub(super) fn encode_group_commitments<C: Ciphersuite>(
signing_commitments: Vec<SigningCommitments<C>>,
) -> Vec<u8> {
// B MUST be sorted in ascending order by signer index.
// B MUST be sorted in ascending order by signer identifier.
//
// https://github.com/cfrg/draft-irtf-cfrg-frost/blob/master/draft-irtf-cfrg-frost.md#encoding-operations-dep-encoding
//
// TODO: AtLeastOne or other explicitly Sorted wrapper types?
let mut sorted_signing_commitments = signing_commitments;
sorted_signing_commitments.sort_by_key(|a| a.index);
sorted_signing_commitments.sort_by_key(|a| a.identifier);
let mut bytes = vec![];
for item in sorted_signing_commitments {
bytes.extend_from_slice(&item.index.to_be_bytes()); // TODO: 2-bytes until spec moves off u16
bytes.extend_from_slice(&u16::from(item.identifier).to_be_bytes()); // TODO: 2-bytes until spec moves off u16
bytes.extend_from_slice(<C::Group as Group>::serialize(&item.hiding.0).as_ref());
bytes.extend_from_slice(<C::Group as Group>::serialize(&item.binding.0).as_ref());
}
@ -300,7 +300,7 @@ pub(super) fn encode_group_commitments<C: Ciphersuite>(
// https://github.com/ZcashFoundation/redjubjub/issues/111
pub fn preprocess<C, R>(
num_nonces: u8,
participant_index: u16,
participant_identifier: Identifier<C>,
secret: &Secret<C>,
rng: &mut R,
) -> (Vec<SigningNonces<C>>, Vec<SigningCommitments<C>>)
@ -314,7 +314,7 @@ where
for _ in 0..num_nonces {
let nonces = SigningNonces::new(secret, rng);
signing_commitments.push(SigningCommitments::from((participant_index, &nonces)));
signing_commitments.push(SigningCommitments::from((participant_identifier, &nonces)));
signing_nonces.push(nonces);
}
@ -330,7 +330,7 @@ where
///
/// [`commit`]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-05.html#section-5.1
pub fn commit<C, R>(
participant_index: u16,
participant_identifier: Identifier<C>,
secret: &Secret<C>,
rng: &mut R,
) -> (SigningNonces<C>, SigningCommitments<C>)
@ -339,7 +339,7 @@ where
R: CryptoRng + RngCore,
{
let (mut vec_signing_nonces, mut vec_signing_commitments) =
preprocess(1, participant_index, secret, rng);
preprocess(1, participant_identifier, secret, rng);
(
vec_signing_nonces.pop().expect("must have 1 element"),
vec_signing_commitments.pop().expect("must have 1 element"),

View File

@ -60,8 +60,8 @@ where
/// shares into the joint signature.
#[derive(Clone, Copy, Eq, PartialEq)]
pub struct SignatureShare<C: Ciphersuite> {
/// Represents the participant index.
pub index: u16,
/// Represents the participant identifier.
pub identifier: Identifier<C>,
/// This participant's signature over the message.
pub signature: SignatureResponse<C>,
}
@ -70,9 +70,9 @@ impl<C> SignatureShare<C>
where
C: Ciphersuite,
{
/// Gets the participant index associated with this [`SignatureShare`].
pub fn index(&self) -> &u16 {
&self.index
/// 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
@ -104,7 +104,7 @@ where
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("SignatureShare")
.field("index", &self.index)
.field("identifier", &self.identifier)
.field("signature", &self.signature)
.finish()
}
@ -141,7 +141,7 @@ pub fn sign<C: Ciphersuite>(
let group_commitment = GroupCommitment::<C>::try_from(signing_package)?;
// Compute Lagrange coefficient.
let lambda_i = frost::derive_lagrange_coeff(*key_package.index(), signing_package)?;
let lambda_i = frost::derive_lagrange_coeff(key_package.identifier(), signing_package)?;
// Compute the per-message challenge.
let challenge = challenge::<C>(
@ -156,7 +156,7 @@ pub fn sign<C: Ciphersuite>(
+ (lambda_i * key_package.secret_share.0 * challenge.0);
let signature_share = SignatureShare::<C> {
index: *key_package.index(),
identifier: *key_package.identifier(),
signature: SignatureResponse::<C> { z_share },
};

View File

@ -22,14 +22,14 @@ lazy_static! {
#[allow(dead_code)]
pub(crate) fn parse_test_vectors() -> (
VerifyingKey<Ristretto255Sha512>,
HashMap<u16, KeyPackage<Ristretto255Sha512>>,
HashMap<Identifier<Ristretto255Sha512>, KeyPackage<Ristretto255Sha512>>,
&'static str,
Vec<u8>,
HashMap<u16, SigningNonces<Ristretto255Sha512>>,
HashMap<u16, SigningCommitments<Ristretto255Sha512>>,
HashMap<Identifier<Ristretto255Sha512>, SigningNonces<Ristretto255Sha512>>,
HashMap<Identifier<Ristretto255Sha512>, SigningCommitments<Ristretto255Sha512>>,
Vec<u8>,
Rho<Ristretto255Sha512>,
HashMap<u16, SignatureShare<Ristretto255Sha512>>,
HashMap<Identifier<Ristretto255Sha512>, SignatureShare<Ristretto255Sha512>>,
Vec<u8>, // Signature<Ristretto255Sha512>,
) {
type R = Ristretto255Sha512;
@ -39,7 +39,7 @@ pub(crate) fn parse_test_vectors() -> (
let message = inputs["message"].as_str().unwrap();
let message_bytes = hex::decode(message).unwrap();
let mut key_packages: HashMap<u16, KeyPackage<R>> = HashMap::new();
let mut key_packages: HashMap<Identifier<Ristretto255Sha512>, KeyPackage<R>> = HashMap::new();
let possible_signers = RISTRETTO255_SHA512["inputs"]["signers"]
.as_object()
@ -54,13 +54,13 @@ pub(crate) fn parse_test_vectors() -> (
let signer_public = secret.into();
let key_package = KeyPackage::<R> {
index: u16::from_str(i).unwrap(),
identifier: u16::from_str(i).unwrap().try_into().unwrap(),
secret_share: secret,
public: signer_public,
group_public,
};
key_packages.insert(*key_package.index(), key_package);
key_packages.insert(*key_package.identifier(), key_package);
}
// Round one outputs
@ -77,21 +77,21 @@ pub(crate) fn parse_test_vectors() -> (
let group_binding_factor =
Rho::<R>::from_hex(round_one_outputs["group_binding_factor"].as_str().unwrap()).unwrap();
let mut signer_nonces: HashMap<u16, SigningNonces<R>> = HashMap::new();
let mut signer_commitments: HashMap<u16, SigningCommitments<R>> = HashMap::new();
let mut signer_nonces: HashMap<Identifier<R>, SigningNonces<R>> = HashMap::new();
let mut signer_commitments: HashMap<Identifier<R>, SigningCommitments<R>> = HashMap::new();
for (i, signer) in round_one_outputs["signers"].as_object().unwrap().iter() {
let index = u16::from_str(i).unwrap();
let identifier = u16::from_str(i).unwrap().try_into().unwrap();
let signing_nonces = SigningNonces::<R> {
hiding: Nonce::<R>::from_hex(signer["hiding_nonce"].as_str().unwrap()).unwrap(),
binding: Nonce::<R>::from_hex(signer["binding_nonce"].as_str().unwrap()).unwrap(),
};
signer_nonces.insert(index, signing_nonces);
signer_nonces.insert(identifier, signing_nonces);
let signing_commitments = SigningCommitments::<R> {
index,
identifier,
hiding: NonceCommitment::from_hex(signer["hiding_nonce_commitment"].as_str().unwrap())
.unwrap(),
binding: NonceCommitment::from_hex(
@ -100,18 +100,18 @@ pub(crate) fn parse_test_vectors() -> (
.unwrap(),
};
signer_commitments.insert(index, signing_commitments);
signer_commitments.insert(identifier, signing_commitments);
}
// Round two outputs
let round_two_outputs = &RISTRETTO255_SHA512["round_two_outputs"];
let mut signature_shares: HashMap<u16, SignatureShare<R>> = HashMap::new();
let mut signature_shares: HashMap<Identifier<R>, SignatureShare<R>> = HashMap::new();
for (i, signer) in round_two_outputs["signers"].as_object().unwrap().iter() {
let signature_share = SignatureShare::<R> {
index: u16::from_str(i).unwrap(),
identifier: u16::from_str(i).unwrap().try_into().unwrap(),
signature: SignatureResponse {
z_share: Scalar::from_canonical_bytes(
hex::decode(signer["sig_share"].as_str().unwrap())
@ -123,7 +123,10 @@ pub(crate) fn parse_test_vectors() -> (
},
};
signature_shares.insert(u16::from_str(i).unwrap(), signature_share);
signature_shares.insert(
u16::from_str(i).unwrap().try_into().unwrap(),
signature_share,
);
}
// Final output

View File

@ -1,6 +1,6 @@
use std::{collections::HashMap, convert::TryFrom};
use frost_core::frost;
use frost_core::frost::{self, Identifier};
use rand::thread_rng;
mod common;
@ -21,31 +21,38 @@ fn check_sign_with_dealer() {
frost::keys::keygen_with_dealer(numsigners, threshold, &mut rng).unwrap();
// Verifies the secret shares from the dealer
let key_packages: Vec<frost::keys::KeyPackage<R>> = shares
let key_packages: HashMap<frost::Identifier<R>, frost::keys::KeyPackage<R>> = shares
.into_iter()
.map(|share| frost::keys::KeyPackage::try_from(share).unwrap())
.map(|share| {
(
share.identifier,
frost::keys::KeyPackage::try_from(share).unwrap(),
)
})
.collect();
let mut nonces: HashMap<u16, frost::round1::SigningNonces<R>> = HashMap::new();
let mut commitments: HashMap<u16, frost::round1::SigningCommitments<R>> = HashMap::new();
let mut nonces: HashMap<Identifier<R>, frost::round1::SigningNonces<R>> = HashMap::new();
let mut commitments: HashMap<Identifier<R>, frost::round1::SigningCommitments<R>> =
HashMap::new();
////////////////////////////////////////////////////////////////////////////
// Round 1: generating nonces and signing commitments for each participant
////////////////////////////////////////////////////////////////////////////
for participant_index in 1..(threshold + 1) {
for participant_index in 1..(threshold as u16 + 1) {
let participant_identifier = participant_index.try_into().expect("should be nonzero");
// Generate one (1) nonce and one SigningCommitments instance for each
// participant, up to _threshold_.
let (nonce, commitment) = frost::round1::commit(
participant_index as u16,
participant_identifier,
key_packages
.get((participant_index - 1) as usize)
.get(&participant_identifier)
.unwrap()
.secret_share(),
&mut rng,
);
nonces.insert(participant_index as u16, nonce);
commitments.insert(participant_index as u16, commitment);
nonces.insert(participant_identifier, nonce);
commitments.insert(participant_identifier, commitment);
}
// This is what the signature aggregator / coordinator needs to do:
@ -60,13 +67,10 @@ fn check_sign_with_dealer() {
// Round 2: each participant generates their signature share
////////////////////////////////////////////////////////////////////////////
for participant_index in nonces.keys() {
let key_package = key_packages
.iter()
.find(|key_package| *participant_index == key_package.index)
.unwrap();
for participant_identifier in nonces.keys() {
let key_package = key_packages.get(participant_identifier).unwrap();
let nonces_to_use = &nonces.get(participant_index).unwrap();
let nonces_to_use = &nonces.get(participant_identifier).unwrap();
// Each participant generates their signature share.
let signature_share =
@ -95,8 +99,8 @@ fn check_sign_with_dealer() {
// Check that the threshold signature can be verified by the group public
// key (the verification key) from SharePackage.group_public
for (participant_index, _) in nonces.clone() {
let key_package = key_packages.get(participant_index as usize).unwrap();
for (participant_identifier, _) in nonces.clone() {
let key_package = key_packages.get(&participant_identifier).unwrap();
assert!(key_package
.group_public

View File

@ -1,4 +1,4 @@
use frost_core::frost;
use frost_core::frost::{self};
use rand::thread_rng;
mod common;
@ -93,9 +93,9 @@ fn check_sign_with_test_vectors() {
let mut our_signature_shares: Vec<frost::round2::SignatureShare<R>> = Vec::new();
// Each participant generates their signature share
for index in signer_nonces.keys() {
let key_package = &key_packages[index];
let nonces = &signer_nonces[index];
for identifier in signer_nonces.keys() {
let key_package = &key_packages[identifier];
let nonces = &signer_nonces[identifier];
// Each participant generates their signature share.
let signature_share = frost::round2::sign(&signing_package, nonces, key_package).unwrap();
@ -104,7 +104,7 @@ fn check_sign_with_test_vectors() {
}
for sig_share in our_signature_shares.clone() {
assert_eq!(sig_share, signature_shares[sig_share.index()]);
assert_eq!(sig_share, signature_shares[sig_share.identifier()]);
}
let signer_pubkeys = key_packages
@ -150,3 +150,18 @@ fn check_sign_with_test_vectors() {
let group_signature = group_signature_result.unwrap();
assert_eq!(group_signature.to_bytes().to_vec(), signature_bytes);
}
// This allows checking that to_scalar() works for all possible inputs;
// but requires making to_scalar() public.
// #[test]
// fn test_identifier_to_scalar() {
// type R = Ristretto255Sha512;
// let one = <<<R as Ciphersuite>::Group as Group>::Field as Field>::one();
// let mut sum = <<<R as Ciphersuite>::Group as Group>::Field as Field>::one();
// for i in 1..0xFFFFu16 {
// let identifier: Identifier<R> = i.try_into().unwrap();
// assert_eq!(sum, identifier.to_scalar());
// sum = sum + one;
// }
// }

View File

@ -201,6 +201,9 @@ impl Ciphersuite for P256Sha256 {
// Shorthand alias for the ciphersuite
type P = P256Sha256;
///
pub type Identifier = frost::Identifier<P>;
///
pub mod keys {
use super::*;
@ -237,14 +240,14 @@ pub mod round1 {
///
pub fn commit<RNG>(
participant_index: u16,
participant_identifier: frost::Identifier<P>,
secret: &Secret<P>,
rng: &mut RNG,
) -> (SigningNonces, SigningCommitments)
where
RNG: CryptoRng + RngCore,
{
frost::round1::commit::<P, RNG>(participant_index, secret, rng)
frost::round1::commit::<P, RNG>(participant_identifier, secret, rng)
}
}

View File

@ -94,9 +94,9 @@ fn check_sign_with_test_vectors() {
let mut our_signature_shares: Vec<frost::round2::SignatureShare<R>> = Vec::new();
// Each participant generates their signature share
for index in signer_nonces.keys() {
let key_package = &key_packages[index];
let nonces = &signer_nonces[index];
for identifier in signer_nonces.keys() {
let key_package = &key_packages[identifier];
let nonces = &signer_nonces[identifier];
// Each participant generates their signature share.
let signature_share = frost::round2::sign(&signing_package, nonces, key_package).unwrap();
@ -105,7 +105,7 @@ fn check_sign_with_test_vectors() {
}
for sig_share in our_signature_shares.clone() {
assert_eq!(sig_share, signature_shares[sig_share.index()]);
assert_eq!(sig_share, signature_shares[sig_share.identifier()]);
}
let signer_pubkeys = key_packages

View File

@ -22,14 +22,14 @@ lazy_static! {
#[allow(dead_code)]
pub(crate) fn parse_test_vectors() -> (
VerifyingKey<P256Sha256>,
HashMap<u16, KeyPackage<P256Sha256>>,
HashMap<Identifier<P256Sha256>, KeyPackage<P256Sha256>>,
&'static str,
Vec<u8>,
HashMap<u16, SigningNonces<P256Sha256>>,
HashMap<u16, SigningCommitments<P256Sha256>>,
HashMap<Identifier<P256Sha256>, SigningNonces<P256Sha256>>,
HashMap<Identifier<P256Sha256>, SigningCommitments<P256Sha256>>,
Vec<u8>,
Rho<P256Sha256>,
HashMap<u16, SignatureShare<P256Sha256>>,
HashMap<Identifier<P256Sha256>, SignatureShare<P256Sha256>>,
Vec<u8>, // Signature<P256Sha256>,
) {
type R = P256Sha256;
@ -39,7 +39,7 @@ pub(crate) fn parse_test_vectors() -> (
let message = inputs["message"].as_str().unwrap();
let message_bytes = hex::decode(message).unwrap();
let mut key_packages: HashMap<u16, KeyPackage<R>> = HashMap::new();
let mut key_packages: HashMap<Identifier<P256Sha256>, KeyPackage<R>> = HashMap::new();
let possible_signers = P256_SHA256["inputs"]["signers"].as_object().unwrap().iter();
@ -51,13 +51,13 @@ pub(crate) fn parse_test_vectors() -> (
let signer_public = secret.into();
let key_package = KeyPackage::<R> {
index: u16::from_str(i).unwrap(),
identifier: u16::from_str(i).unwrap().try_into().unwrap(),
secret_share: secret,
public: signer_public,
group_public,
};
key_packages.insert(*key_package.index(), key_package);
key_packages.insert(*key_package.identifier(), key_package);
}
// Round one outputs
@ -74,21 +74,21 @@ pub(crate) fn parse_test_vectors() -> (
let group_binding_factor =
Rho::<R>::from_hex(round_one_outputs["group_binding_factor"].as_str().unwrap()).unwrap();
let mut signer_nonces: HashMap<u16, SigningNonces<R>> = HashMap::new();
let mut signer_commitments: HashMap<u16, SigningCommitments<R>> = HashMap::new();
let mut signer_nonces: HashMap<Identifier<R>, SigningNonces<R>> = HashMap::new();
let mut signer_commitments: HashMap<Identifier<R>, SigningCommitments<R>> = HashMap::new();
for (i, signer) in round_one_outputs["signers"].as_object().unwrap().iter() {
let index = u16::from_str(i).unwrap();
let identifier = u16::from_str(i).unwrap().try_into().unwrap();
let signing_nonces = SigningNonces::<R> {
hiding: Nonce::<R>::from_hex(signer["hiding_nonce"].as_str().unwrap()).unwrap(),
binding: Nonce::<R>::from_hex(signer["binding_nonce"].as_str().unwrap()).unwrap(),
};
signer_nonces.insert(index, signing_nonces);
signer_nonces.insert(identifier, signing_nonces);
let signing_commitments = SigningCommitments::<R> {
index,
identifier,
hiding: NonceCommitment::from_hex(signer["hiding_nonce_commitment"].as_str().unwrap())
.unwrap(),
binding: NonceCommitment::from_hex(
@ -97,18 +97,18 @@ pub(crate) fn parse_test_vectors() -> (
.unwrap(),
};
signer_commitments.insert(index, signing_commitments);
signer_commitments.insert(identifier, signing_commitments);
}
// Round two outputs
let round_two_outputs = &P256_SHA256["round_two_outputs"];
let mut signature_shares: HashMap<u16, SignatureShare<R>> = HashMap::new();
let mut signature_shares: HashMap<Identifier<R>, SignatureShare<R>> = HashMap::new();
for (i, signer) in round_two_outputs["signers"].as_object().unwrap().iter() {
let signature_share = SignatureShare::<R> {
index: u16::from_str(i).unwrap(),
identifier: u16::from_str(i).unwrap().try_into().unwrap(),
signature: SignatureResponse {
z_share: Scalar::from_repr(*FieldBytes::from_slice(
hex::decode(signer["sig_share"].as_str().unwrap())
@ -119,7 +119,10 @@ pub(crate) fn parse_test_vectors() -> (
},
};
signature_shares.insert(u16::from_str(i).unwrap(), signature_share);
signature_shares.insert(
u16::from_str(i).unwrap().try_into().unwrap(),
signature_share,
);
}
// Final output

View File

@ -16,31 +16,32 @@ fn check_sign_with_dealer() {
let (shares, pubkeys) = keys::keygen_with_dealer(numsigners, threshold, &mut rng).unwrap();
// Verifies the secret shares from the dealer
let key_packages: Vec<keys::KeyPackage> = shares
let key_packages: HashMap<Identifier, keys::KeyPackage> = shares
.into_iter()
.map(|share| keys::KeyPackage::try_from(share).unwrap())
.map(|share| (share.identifier, keys::KeyPackage::try_from(share).unwrap()))
.collect();
let mut nonces: HashMap<u16, round1::SigningNonces> = HashMap::new();
let mut commitments: HashMap<u16, round1::SigningCommitments> = HashMap::new();
let mut nonces: HashMap<Identifier, round1::SigningNonces> = HashMap::new();
let mut commitments: HashMap<Identifier, round1::SigningCommitments> = HashMap::new();
////////////////////////////////////////////////////////////////////////////
// Round 1: generating nonces and signing commitments for each participant
////////////////////////////////////////////////////////////////////////////
for participant_index in 1..(threshold + 1) {
for participant_index in 1..(threshold as u16 + 1) {
let participant_identifier = participant_index.try_into().expect("should be nonzero");
// Generate one (1) nonce and one SigningCommitments instance for each
// participant, up to _threshold_.
let (nonce, commitment) = round1::commit(
participant_index as u16,
participant_identifier,
key_packages
.get((participant_index - 1) as usize)
.get(&participant_identifier)
.unwrap()
.secret_share(),
&mut rng,
);
nonces.insert(participant_index as u16, nonce);
commitments.insert(participant_index as u16, commitment);
nonces.insert(participant_identifier, nonce);
commitments.insert(participant_identifier, commitment);
}
// This is what the signature aggregator / coordinator needs to do:
@ -55,13 +56,10 @@ fn check_sign_with_dealer() {
// Round 2: each participant generates their signature share
////////////////////////////////////////////////////////////////////////////
for participant_index in nonces.keys() {
let key_package = key_packages
.iter()
.find(|key_package| *participant_index == key_package.index)
.unwrap();
for participant_identifier in nonces.keys() {
let key_package = key_packages.get(participant_identifier).unwrap();
let nonces_to_use = &nonces.get(participant_index).unwrap();
let nonces_to_use = &nonces.get(participant_identifier).unwrap();
// Each participant generates their signature share.
let signature_share = round2::sign(&signing_package, nonces_to_use, key_package).unwrap();
@ -89,8 +87,8 @@ fn check_sign_with_dealer() {
// Check that the threshold signature can be verified by the group public
// key (the verification key) from SharePackage.group_public
for (participant_index, _) in nonces.clone() {
let key_package = key_packages.get(participant_index as usize).unwrap();
for (participant_identifier, _) in nonces.clone() {
let key_package = key_packages.get(&participant_identifier).unwrap();
assert!(key_package
.group_public

View File

@ -182,6 +182,9 @@ impl Ciphersuite for Ristretto255Sha512 {
type R = Ristretto255Sha512;
///
pub type Identifier = frost::Identifier<R>;
///
pub mod keys {
use super::*;
@ -218,14 +221,14 @@ pub mod round1 {
///
pub fn commit<RNG>(
participant_index: u16,
participant_identifier: frost::Identifier<R>,
secret: &Secret<R>,
rng: &mut RNG,
) -> (SigningNonces, SigningCommitments)
where
RNG: CryptoRng + RngCore,
{
frost::round1::commit::<R, RNG>(participant_index, secret, rng)
frost::round1::commit::<R, RNG>(participant_identifier, secret, rng)
}
}

View File

@ -94,9 +94,9 @@ fn check_sign_with_test_vectors() {
let mut our_signature_shares: Vec<frost::round2::SignatureShare<R>> = Vec::new();
// Each participant generates their signature share
for index in signer_nonces.keys() {
let key_package = &key_packages[index];
let nonces = &signer_nonces[index];
for identifier in signer_nonces.keys() {
let key_package = &key_packages[identifier];
let nonces = &signer_nonces[identifier];
// Each participant generates their signature share.
let signature_share = frost::round2::sign(&signing_package, nonces, key_package).unwrap();
@ -105,7 +105,7 @@ fn check_sign_with_test_vectors() {
}
for sig_share in our_signature_shares.clone() {
assert_eq!(sig_share, signature_shares[sig_share.index()]);
assert_eq!(sig_share, signature_shares[sig_share.identifier()]);
}
let signer_pubkeys = key_packages

View File

@ -22,14 +22,14 @@ lazy_static! {
#[allow(dead_code)]
pub(crate) fn parse_test_vectors() -> (
VerifyingKey<Ristretto255Sha512>,
HashMap<u16, KeyPackage<Ristretto255Sha512>>,
HashMap<Identifier<Ristretto255Sha512>, KeyPackage<Ristretto255Sha512>>,
&'static str,
Vec<u8>,
HashMap<u16, SigningNonces<Ristretto255Sha512>>,
HashMap<u16, SigningCommitments<Ristretto255Sha512>>,
HashMap<Identifier<Ristretto255Sha512>, SigningNonces<Ristretto255Sha512>>,
HashMap<Identifier<Ristretto255Sha512>, SigningCommitments<Ristretto255Sha512>>,
Vec<u8>,
Rho<Ristretto255Sha512>,
HashMap<u16, SignatureShare<Ristretto255Sha512>>,
HashMap<Identifier<Ristretto255Sha512>, SignatureShare<Ristretto255Sha512>>,
Vec<u8>, // Signature<Ristretto255Sha512>,
) {
type R = Ristretto255Sha512;
@ -39,7 +39,7 @@ pub(crate) fn parse_test_vectors() -> (
let message = inputs["message"].as_str().unwrap();
let message_bytes = hex::decode(message).unwrap();
let mut key_packages: HashMap<u16, KeyPackage<R>> = HashMap::new();
let mut key_packages: HashMap<Identifier<Ristretto255Sha512>, KeyPackage<R>> = HashMap::new();
let possible_signers = RISTRETTO255_SHA512["inputs"]["signers"]
.as_object()
@ -54,13 +54,13 @@ pub(crate) fn parse_test_vectors() -> (
let signer_public = secret.into();
let key_package = KeyPackage::<R> {
index: u16::from_str(i).unwrap(),
identifier: u16::from_str(i).unwrap().try_into().unwrap(),
secret_share: secret,
public: signer_public,
group_public,
};
key_packages.insert(*key_package.index(), key_package);
key_packages.insert(*key_package.identifier(), key_package);
}
// Round one outputs
@ -77,21 +77,21 @@ pub(crate) fn parse_test_vectors() -> (
let group_binding_factor =
Rho::<R>::from_hex(round_one_outputs["group_binding_factor"].as_str().unwrap()).unwrap();
let mut signer_nonces: HashMap<u16, SigningNonces<R>> = HashMap::new();
let mut signer_commitments: HashMap<u16, SigningCommitments<R>> = HashMap::new();
let mut signer_nonces: HashMap<Identifier<R>, SigningNonces<R>> = HashMap::new();
let mut signer_commitments: HashMap<Identifier<R>, SigningCommitments<R>> = HashMap::new();
for (i, signer) in round_one_outputs["signers"].as_object().unwrap().iter() {
let index = u16::from_str(i).unwrap();
let identifier = u16::from_str(i).unwrap().try_into().unwrap();
let signing_nonces = SigningNonces::<R> {
hiding: Nonce::<R>::from_hex(signer["hiding_nonce"].as_str().unwrap()).unwrap(),
binding: Nonce::<R>::from_hex(signer["binding_nonce"].as_str().unwrap()).unwrap(),
};
signer_nonces.insert(index, signing_nonces);
signer_nonces.insert(identifier, signing_nonces);
let signing_commitments = SigningCommitments::<R> {
index,
identifier,
hiding: NonceCommitment::from_hex(signer["hiding_nonce_commitment"].as_str().unwrap())
.unwrap(),
binding: NonceCommitment::from_hex(
@ -100,18 +100,18 @@ pub(crate) fn parse_test_vectors() -> (
.unwrap(),
};
signer_commitments.insert(index, signing_commitments);
signer_commitments.insert(identifier, signing_commitments);
}
// Round two outputs
let round_two_outputs = &RISTRETTO255_SHA512["round_two_outputs"];
let mut signature_shares: HashMap<u16, SignatureShare<R>> = HashMap::new();
let mut signature_shares: HashMap<Identifier<R>, SignatureShare<R>> = HashMap::new();
for (i, signer) in round_two_outputs["signers"].as_object().unwrap().iter() {
let signature_share = SignatureShare::<R> {
index: u16::from_str(i).unwrap(),
identifier: u16::from_str(i).unwrap().try_into().unwrap(),
signature: SignatureResponse {
z_share: Scalar::from_canonical_bytes(
hex::decode(signer["sig_share"].as_str().unwrap())
@ -123,7 +123,10 @@ pub(crate) fn parse_test_vectors() -> (
},
};
signature_shares.insert(u16::from_str(i).unwrap(), signature_share);
signature_shares.insert(
u16::from_str(i).unwrap().try_into().unwrap(),
signature_share,
);
}
// Final output

View File

@ -16,31 +16,32 @@ fn check_sign_with_dealer() {
let (shares, pubkeys) = keys::keygen_with_dealer(numsigners, threshold, &mut rng).unwrap();
// Verifies the secret shares from the dealer
let key_packages: Vec<keys::KeyPackage> = shares
let key_packages: HashMap<Identifier, keys::KeyPackage> = shares
.into_iter()
.map(|share| keys::KeyPackage::try_from(share).unwrap())
.map(|share| (share.identifier, keys::KeyPackage::try_from(share).unwrap()))
.collect();
let mut nonces: HashMap<u16, round1::SigningNonces> = HashMap::new();
let mut commitments: HashMap<u16, round1::SigningCommitments> = HashMap::new();
let mut nonces: HashMap<Identifier, round1::SigningNonces> = HashMap::new();
let mut commitments: HashMap<Identifier, round1::SigningCommitments> = HashMap::new();
////////////////////////////////////////////////////////////////////////////
// Round 1: generating nonces and signing commitments for each participant
////////////////////////////////////////////////////////////////////////////
for participant_index in 1..(threshold + 1) {
for participant_index in 1..(threshold as u16 + 1) {
let participant_identifier = participant_index.try_into().expect("should be nonzero");
// Generate one (1) nonce and one SigningCommitments instance for each
// participant, up to _threshold_.
let (nonce, commitment) = round1::commit(
participant_index as u16,
participant_identifier,
key_packages
.get((participant_index - 1) as usize)
.get(&participant_identifier)
.unwrap()
.secret_share(),
&mut rng,
);
nonces.insert(participant_index as u16, nonce);
commitments.insert(participant_index as u16, commitment);
nonces.insert(participant_identifier, nonce);
commitments.insert(participant_identifier, commitment);
}
// This is what the signature aggregator / coordinator needs to do:
@ -55,13 +56,10 @@ fn check_sign_with_dealer() {
// Round 2: each participant generates their signature share
////////////////////////////////////////////////////////////////////////////
for participant_index in nonces.keys() {
let key_package = key_packages
.iter()
.find(|key_package| *participant_index == key_package.index)
.unwrap();
for participant_identifier in nonces.keys() {
let key_package = key_packages.get(participant_identifier).unwrap();
let nonces_to_use = &nonces.get(participant_index).unwrap();
let nonces_to_use = &nonces.get(participant_identifier).unwrap();
// Each participant generates their signature share.
let signature_share = round2::sign(&signing_package, nonces_to_use, key_package).unwrap();
@ -89,8 +87,8 @@ fn check_sign_with_dealer() {
// Check that the threshold signature can be verified by the group public
// key (the verification key) from SharePackage.group_public
for (participant_index, _) in nonces.clone() {
let key_package = key_packages.get(participant_index as usize).unwrap();
for (participant_identifier, _) in nonces.clone() {
let key_package = key_packages.get(&participant_identifier).unwrap();
assert!(key_package
.group_public