Remove `as` keyword when not needed, use `Scalar`/`Element` shortcuts (#159)

* use Identifier instead of index

* remove pub(crate) from the Identifier index

* Refreshed Identifier newtype of Scalar with traits

* Remove commented out lines

* add test vectors with indices larger than 1 byte

* add little_endian_serialize to implement Ord for Identifier

* remove 'as' keyword when not needed

* use Scalar shortcut

* use Element shortcut

* remove more instances of 'as' keyword when not needed

* rustfmt

Co-authored-by: Deirdre Connolly <durumcrustulum@gmail.com>
This commit is contained in:
Conrado Gouvea 2022-10-26 02:08:06 -03:00 committed by GitHub
parent 278630e183
commit 33b01a7d6f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 114 additions and 134 deletions

View File

@ -110,13 +110,13 @@ where
let mut VKs = Vec::with_capacity(n);
let mut R_coeffs = Vec::with_capacity(self.signatures.len());
let mut Rs = Vec::with_capacity(self.signatures.len());
let mut P_coeff_acc = <<C::Group as Group>::Field as Field>::zero();
let mut P_coeff_acc = <<C::Group as Group>::Field>::zero();
for item in self.signatures.iter() {
let z = item.sig.z;
let R = item.sig.R;
let blind = <<C::Group as Group>::Field as Field>::random(&mut rng);
let blind = <<C::Group as Group>::Field>::random(&mut rng);
let P_coeff = blind * z;
P_coeff_acc = P_coeff_acc - P_coeff;
@ -124,7 +124,7 @@ where
R_coeffs.push(blind);
Rs.push(R);
VK_coeffs.push(<<C::Group as Group>::Field as Field>::zero() + (blind * item.c.0));
VK_coeffs.push(<<C::Group as Group>::Field>::zero() + (blind * item.c.0));
VKs.push(item.vk.element);
}
@ -132,13 +132,13 @@ where
.chain(VK_coeffs.iter())
.chain(R_coeffs.iter());
let basepoints = [<C::Group as Group>::generator()];
let basepoints = [C::Group::generator()];
let points = basepoints.iter().chain(VKs.iter()).chain(Rs.iter());
let check: Element<C> =
VartimeMultiscalarMul::<C>::vartime_multiscalar_mul(scalars, points);
if (check * <C::Group as Group>::cofactor()) == <C::Group as Group>::identity() {
if (check * <C::Group>::cofactor()) == <C::Group>::identity() {
Ok(())
} else {
Err(Error::InvalidSignature)

View File

@ -24,7 +24,7 @@ pub mod keys;
pub mod round1;
pub mod round2;
use crate::{Ciphersuite, Error, Field, Group, Signature};
use crate::{Ciphersuite, Element, Error, Field, Group, Scalar, Signature};
pub use self::identifier::Identifier;
@ -35,7 +35,7 @@ pub use self::identifier::Identifier;
///
/// <https://github.com/cfrg/draft-irtf-cfrg-frost/blob/master/draft-irtf-cfrg-frost.md>
#[derive(Clone, PartialEq, Eq)]
pub struct BindingFactor<C: Ciphersuite>(<<C::Group as Group>::Field as Field>::Scalar);
pub struct BindingFactor<C: Ciphersuite>(Scalar<C>);
impl<C> BindingFactor<C>
where
@ -45,12 +45,12 @@ where
pub fn from_bytes(
bytes: <<C::Group as Group>::Field as Field>::Serialization,
) -> Result<Self, Error> {
<<C::Group as Group>::Field as Field>::deserialize(&bytes).map(|scalar| Self(scalar))
<<C::Group as Group>::Field>::deserialize(&bytes).map(|scalar| Self(scalar))
}
/// Serializes [`BindingFactor`] to bytes.
pub fn to_bytes(&self) -> <<C::Group as Group>::Field as Field>::Serialization {
<<C::Group as Group>::Field as Field>::serialize(&self.0)
<<C::Group as Group>::Field>::serialize(&self.0)
}
}
@ -145,11 +145,11 @@ where
fn derive_lagrange_coeff<C: Ciphersuite>(
signer_id: &Identifier<C>,
signing_package: &SigningPackage<C>,
) -> Result<<<C::Group as Group>::Field as Field>::Scalar, &'static str> {
let zero = <<C::Group as Group>::Field as Field>::zero();
) -> Result<Scalar<C>, &'static str> {
let zero = <<C::Group as Group>::Field>::zero();
let mut num = <<C::Group as Group>::Field as Field>::one();
let mut den = <<C::Group as Group>::Field as Field>::one();
let mut num = <<C::Group as Group>::Field>::one();
let mut den = <<C::Group as Group>::Field>::one();
// Ala the sorting of B, just always sort by identifier in ascending order
//
@ -169,7 +169,7 @@ fn derive_lagrange_coeff<C: Ciphersuite>(
}
// TODO(dconnolly): return this error if the inversion result == zero
let lagrange_coeff = num * <<C::Group as Group>::Field as Field>::invert(&den).unwrap();
let lagrange_coeff = num * <<C::Group as Group>::Field>::invert(&den).unwrap();
Ok(lagrange_coeff)
}
@ -251,7 +251,7 @@ where
/// The product of all signers' individual commitments, published as part of the
/// final signature.
#[derive(PartialEq, Eq)]
pub struct GroupCommitment<C: Ciphersuite>(pub(super) <C::Group as Group>::Element);
pub struct GroupCommitment<C: Ciphersuite>(pub(super) Element<C>);
// impl<C> Debug for GroupCommitment<C> where C: Ciphersuite {
// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@ -276,9 +276,9 @@ where
fn try_from(signing_package: &SigningPackage<C>) -> Result<GroupCommitment<C>, &'static str> {
let binding_factor_list: BindingFactorList<C> = signing_package.into();
let identity = <C::Group as Group>::identity();
let identity = <C::Group>::identity();
let mut group_commitment = <C::Group as Group>::identity();
let mut group_commitment = <C::Group>::identity();
// Ala the sorting of B, just always sort by identifier in ascending order
//
@ -369,8 +369,8 @@ where
//
// Implements [`aggregate`] from the spec.
//
// [`aggregate`]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-11.html#section-5.3
let mut z = <<C::Group as Group>::Field as Field>::zero();
// [`aggregate`]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-10.html#section-5.3
let mut z = <<C::Group as Group>::Field>::zero();
for signature_share in signature_shares {
z = z + signature_share.signature.z_share;

View File

@ -21,7 +21,7 @@ where
{
// Serialize the underlying scalar.
pub(crate) fn serialize(&self) -> <<C::Group as Group>::Field as Field>::Serialization {
<<C::Group as Group>::Field as Field>::serialize(&self.0)
<<C::Group as Group>::Field>::serialize(&self.0)
}
}
@ -33,7 +33,7 @@ where
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_tuple("Identifier")
.field(&<<C::Group as Group>::Field as Field>::serialize(&self.0).as_ref())
.field(&<<C::Group as Group>::Field>::serialize(&self.0).as_ref())
.finish()
}
}
@ -44,7 +44,7 @@ where
C: Ciphersuite,
{
fn hash<H: Hasher>(&self, state: &mut H) {
<<C::Group as Group>::Field as Field>::serialize(&self.0)
<<C::Group as Group>::Field>::serialize(&self.0)
.as_ref()
.hash(state)
}
@ -55,10 +55,8 @@ where
C: Ciphersuite,
{
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
let serialized_self =
<<C::Group as Group>::Field as Field>::little_endian_serialize(&self.0);
let serialized_other =
<<C::Group as Group>::Field as Field>::little_endian_serialize(&other.0);
let serialized_self = <<C::Group as Group>::Field>::little_endian_serialize(&self.0);
let serialized_other = <<C::Group as Group>::Field>::little_endian_serialize(&other.0);
serialized_self.as_ref().cmp(serialized_other.as_ref())
}
}
@ -68,10 +66,8 @@ where
C: Ciphersuite,
{
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
let serialized_self =
<<C::Group as Group>::Field as Field>::little_endian_serialize(&self.0);
let serialized_other =
<<C::Group as Group>::Field as Field>::little_endian_serialize(&other.0);
let serialized_self = <<C::Group as Group>::Field>::little_endian_serialize(&self.0);
let serialized_other = <<C::Group as Group>::Field>::little_endian_serialize(&other.0);
serialized_self
.as_ref()
.partial_cmp(serialized_other.as_ref())
@ -121,8 +117,8 @@ where
} else {
// 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 one = <<C::Group as Group>::Field>::one();
let mut sum = <<C::Group as Group>::Field>::one();
let bits = (n.to_be_bytes().len() as u32) * 8;
for i in (0..(bits - n.leading_zeros() - 1)).rev() {

View File

@ -12,7 +12,7 @@ use hex::FromHex;
use rand_core::{CryptoRng, RngCore};
use zeroize::{DefaultIsZeroes, Zeroize};
use crate::{frost::Identifier, Ciphersuite, Error, Field, Group, Scalar, VerifyingKey};
use crate::{frost::Identifier, Ciphersuite, Element, Error, Field, Group, Scalar, VerifyingKey};
pub mod dkg;
@ -20,8 +20,8 @@ pub mod dkg;
pub(crate) fn generate_coefficients<C: Ciphersuite, R: RngCore + CryptoRng>(
size: usize,
rng: &mut R,
) -> Vec<<<<C as Ciphersuite>::Group as Group>::Field as Field>::Scalar> {
iter::repeat_with(|| <<C::Group as Group>::Field as Field>::random(rng))
) -> Vec<Scalar<C>> {
iter::repeat_with(|| <<C::Group as Group>::Field>::random(rng))
.take(size)
.collect()
}
@ -42,12 +42,12 @@ where
pub fn from_bytes(
bytes: <<C::Group as Group>::Field as Field>::Serialization,
) -> Result<Self, Error> {
<<C::Group as Group>::Field as Field>::deserialize(&bytes).map(|scalar| Self(scalar))
<<C::Group as Group>::Field>::deserialize(&bytes).map(|scalar| Self(scalar))
}
/// Serialize to bytes
pub fn to_bytes(&self) -> <<C::Group as Group>::Field as Field>::Serialization {
<<C::Group as Group>::Field as Field>::serialize(&self.0)
<<C::Group as Group>::Field>::serialize(&self.0)
}
/// Generates a new uniformly random secret value using the provided RNG.
@ -56,9 +56,7 @@ where
where
R: CryptoRng + RngCore,
{
Self(<<C::Group as Group>::Field as Field>::random_nonzero(
&mut rng,
))
Self(<<C::Group as Group>::Field>::random_nonzero(&mut rng))
}
}
@ -78,7 +76,7 @@ where
C: Ciphersuite,
{
fn default() -> Self {
Self(<<C::Group as Group>::Field as Field>::zero())
Self(<<C::Group as Group>::Field>::zero())
}
}
@ -90,7 +88,7 @@ where
C: Ciphersuite,
{
fn from(secret: &SharedSecret<C>) -> Self {
let element = <C::Group as Group>::generator() * secret.0;
let element = <C::Group>::generator() * secret.0;
VerifyingKey { element }
}
@ -123,12 +121,12 @@ where
pub fn from_bytes(
bytes: <<C::Group as Group>::Field as Field>::Serialization,
) -> Result<Self, Error> {
<<C::Group as Group>::Field as Field>::deserialize(&bytes).map(|scalar| Self(scalar))
<<C::Group as Group>::Field>::deserialize(&bytes).map(|scalar| Self(scalar))
}
/// Serialize to bytes
pub fn to_bytes(&self) -> <<C::Group as Group>::Field as Field>::Serialization {
<<C::Group as Group>::Field as Field>::serialize(&self.0)
<<C::Group as Group>::Field>::serialize(&self.0)
}
}
@ -148,7 +146,7 @@ where
C: Ciphersuite,
{
fn default() -> Self {
Self(<<C::Group as Group>::Field as Field>::zero())
Self(<<C::Group as Group>::Field>::zero())
}
}
@ -172,7 +170,7 @@ where
/// A public group element that represents a single signer's public verification share.
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct VerifyingShare<C>(pub(super) <C::Group as Group>::Element)
pub struct VerifyingShare<C>(pub(super) Element<C>)
where
C: Ciphersuite;
@ -207,7 +205,7 @@ where
C: Ciphersuite,
{
fn from(secret: SigningShare<C>) -> VerifyingShare<C> {
VerifyingShare(<C::Group as Group>::generator() * secret.0 as Scalar<C>)
VerifyingShare(<C::Group>::generator() * secret.0 as Scalar<C>)
}
}
@ -216,7 +214,7 @@ where
/// This is a (public) commitment to one coefficient of a secret polynomial used for performing
/// verifiable secret sharing for a Shamir secret share.
#[derive(Clone, Copy, PartialEq)]
pub(super) struct CoefficientCommitment<C: Ciphersuite>(pub(super) <C::Group as Group>::Element);
pub(super) struct CoefficientCommitment<C: Ciphersuite>(pub(super) Element<C>);
/// Contains the commitments to the coefficients for our secret polynomial _f_,
/// used to generate participants' key shares.
@ -280,7 +278,7 @@ where
///
/// [spec]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-11.html#appendix-C.2-4
pub fn verify(&self) -> Result<(VerifyingShare<C>, VerifyingKey<C>), &'static str> {
let f_result = <C::Group as Group>::generator() * self.value.0;
let f_result = <C::Group>::generator() * self.value.0;
let result = evaluate_vss(&self.commitment, self.identifier)?;
if !(f_result == result) {
@ -347,8 +345,9 @@ pub fn keygen_with_dealer<C: Ciphersuite, R: RngCore + CryptoRng>(
fn evaluate_polynomial<C: Ciphersuite>(
identifier: Identifier<C>,
coefficients: &[Scalar<C>],
) -> Result<<<<C as Ciphersuite>::Group as Group>::Field as Field>::Scalar, &'static str> {
let mut value = <<C::Group as Group>::Field as Field>::zero();
) -> Result<Scalar<C>, &'static str> {
let mut value = <<C::Group as Group>::Field>::zero();
let ell_scalar = identifier;
for coeff in coefficients.iter().skip(1).rev() {
value = value + *coeff;
@ -364,14 +363,11 @@ fn evaluate_polynomial<C: Ciphersuite>(
fn evaluate_vss<C: Ciphersuite>(
commitment: &VerifiableSecretSharingCommitment<C>,
identifier: Identifier<C>,
) -> Result<<<C as Ciphersuite>::Group as Group>::Element, &'static str> {
) -> Result<Element<C>, &'static str> {
let i = identifier;
let (_, result) = commitment.0.iter().fold(
(
<<C::Group as Group>::Field as Field>::one(),
<C::Group as Group>::identity(),
),
(<<C::Group as Group>::Field>::one(), <C::Group>::identity()),
|(i_to_the_k, sum_so_far), comm_k| (i * i_to_the_k, sum_so_far + comm_k.0 * i_to_the_k),
);
Ok(result)
@ -560,12 +556,12 @@ pub fn reconstruct_secret<C: Ciphersuite>(
.map(|share| (share.identifier, share))
.collect();
let mut secret = <<C::Group as Group>::Field as Field>::zero();
let mut secret = <<C::Group as Group>::Field>::zero();
// Compute the Lagrange coefficients
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 mut num = <<C::Group as Group>::Field>::one();
let mut den = <<C::Group as Group>::Field>::one();
for j in secret_share_map.clone().into_keys() {
if j == i {
@ -581,20 +577,16 @@ pub fn reconstruct_secret<C: Ciphersuite>(
// If at this step, the denominator is zero in the scalar field, there must be a duplicate
// secret share.
if den == <<C::Group as Group>::Field as Field>::zero() {
if den == <<C::Group as Group>::Field>::zero() {
return Err("Duplicate shares provided");
}
// Save numerator * 1/denomintor in the scalar field
let lagrange_coefficient =
num * <<C::Group as Group>::Field as Field>::invert(&den).unwrap();
let lagrange_coefficient = num * <<C::Group as Group>::Field>::invert(&den).unwrap();
// Compute y = f(0) via polynomial interpolation of these t-of-n solutions ('points) of f
secret = secret + (lagrange_coefficient * secret_share.value.0);
}
Ok(
SharedSecret::from_bytes(<<C::Group as Group>::Field as Field>::serialize(&secret))
.unwrap(),
)
Ok(SharedSecret::from_bytes(<<C::Group as Group>::Field>::serialize(&secret)).unwrap())
}

View File

@ -5,7 +5,8 @@ use std::{collections::HashMap, iter};
use rand_core::{CryptoRng, RngCore};
use crate::{
frost::Identifier, Challenge, Ciphersuite, Field, Group, Scalar, Signature, VerifyingKey,
frost::Identifier, Challenge, Ciphersuite, Element, Field, Group, Scalar, Signature,
VerifyingKey,
};
use super::{
@ -112,8 +113,8 @@ pub fn keygen_part1<C: Ciphersuite, R: RngCore + CryptoRng>(
// > c_i = H(i, Φ, g^{a_{i0}} , R_i), μ_i = k + a_{i0} · c_i, with Φ being
// > a context string to prevent replay attacks.
let k = <<C::Group as Group>::Field as Field>::random(&mut rng);
let R_i = <C::Group as Group>::generator() * k;
let k = <<C::Group as Group>::Field>::random(&mut rng);
let R_i = <C::Group>::generator() * k;
let c_i = challenge::<C>(identifier, &R_i, &commitment.0[0].0)
.ok_or("DKG not supported by ciphersuite")?;
let mu_i = k + coefficients[0] * c_i.0;
@ -136,8 +137,8 @@ pub fn keygen_part1<C: Ciphersuite, R: RngCore + CryptoRng>(
/// Generates the challenge for the proof of knowledge to a secret for the DKG.
fn challenge<C>(
identifier: Identifier<C>,
R: &<C::Group as Group>::Element,
verifying_key: &<C::Group as Group>::Element,
R: &Element<C>,
verifying_key: &Element<C>,
) -> Option<Challenge<C>>
where
C: Ciphersuite,
@ -145,8 +146,8 @@ where
let mut preimage = vec![];
preimage.extend_from_slice(identifier.serialize().as_ref());
preimage.extend_from_slice(<C::Group as Group>::serialize(R).as_ref());
preimage.extend_from_slice(<C::Group as Group>::serialize(verifying_key).as_ref());
preimage.extend_from_slice(<C::Group>::serialize(R).as_ref());
preimage.extend_from_slice(<C::Group>::serialize(verifying_key).as_ref());
Some(Challenge(C::HDKG(&preimage[..])?))
}
@ -181,7 +182,7 @@ pub fn keygen_part2<C: Ciphersuite>(
let c_ell =
challenge::<C>(ell, &R_ell, &phi_ell0).ok_or("DKG not supported by ciphersuite")?;
if R_ell != <C::Group as Group>::generator() * mu_ell - phi_ell0 * c_ell.0 {
if R_ell != <C::Group>::generator() * mu_ell - phi_ell0 * c_ell.0 {
return Err("Invalid proof of knowledge");
}
@ -226,7 +227,7 @@ fn compute_verifying_keys<C: Ciphersuite>(
// Note that in this loop, "i" refers to the other participant whose public verification share
// we are computing, and not the current participant.
for i in round2_packages.iter().map(|p| p.sender_identifier) {
let mut y_i = <C::Group as Group>::identity();
let mut y_i = <C::Group>::identity();
// We need to iterate through all commitment vectors, including our own,
// so chain it manually
@ -274,8 +275,8 @@ pub fn keygen_part3<C: Ciphersuite>(
return Err("inconsistent number of packages");
}
let mut signing_share: Scalar<C> = <<C::Group as Group>::Field as Field>::zero();
let mut group_public: <C::Group as Group>::Element = <C::Group as Group>::identity();
let mut signing_share = <<C::Group as Group>::Field>::zero();
let mut group_public = <C::Group>::identity();
let round1_packages_map: HashMap<Identifier<C>, &Round1Package<C>> = round1_packages
.iter()

View File

@ -6,13 +6,13 @@ use hex::FromHex;
use rand_core::{CryptoRng, RngCore};
use zeroize::Zeroize;
use crate::{frost, Ciphersuite, Error, Field, Group};
use crate::{frost, Ciphersuite, Element, Error, Field, Group, Scalar};
use super::{keys::SigningShare, Identifier};
/// A scalar that is a signing nonce.
#[derive(Clone, PartialEq, Eq, Zeroize)]
pub struct Nonce<C: Ciphersuite>(pub(super) <<C::Group as Group>::Field as Field>::Scalar);
pub struct Nonce<C: Ciphersuite>(pub(super) Scalar<C>);
impl<C> Nonce<C>
where
@ -43,7 +43,7 @@ where
secret: &SigningShare<C>,
random_bytes: [u8; 32],
) -> Self {
let secret_enc = <<C::Group as Group>::Field as Field>::serialize(&secret.0);
let secret_enc = <<C::Group as Group>::Field>::serialize(&secret.0);
let input: Vec<u8> = random_bytes
.iter()
@ -58,12 +58,12 @@ where
pub fn from_bytes(
bytes: <<C::Group as Group>::Field as Field>::Serialization,
) -> Result<Self, Error> {
<<C::Group as Group>::Field as Field>::deserialize(&bytes).map(|scalar| Self(scalar))
<<C::Group as Group>::Field>::deserialize(&bytes).map(|scalar| Self(scalar))
}
/// Serialize [`Nonce`] to bytes
pub fn to_bytes(&self) -> <<C::Group as Group>::Field as Field>::Serialization {
<<C::Group as Group>::Field as Field>::serialize(&self.0)
<<C::Group as Group>::Field>::serialize(&self.0)
}
}
@ -93,7 +93,7 @@ where
/// A Ristretto point that is a commitment to a signing nonce share.
#[derive(Clone, Copy, PartialEq)]
pub struct NonceCommitment<C: Ciphersuite>(pub(super) <C::Group as Group>::Element);
pub struct NonceCommitment<C: Ciphersuite>(pub(super) Element<C>);
impl<C> NonceCommitment<C>
where
@ -101,12 +101,12 @@ where
{
/// Deserialize [`NonceCommitment`] from bytes
pub fn from_bytes(bytes: <C::Group as Group>::Serialization) -> Result<Self, Error> {
<C::Group as Group>::deserialize(&bytes).map(|element| Self(element))
<C::Group>::deserialize(&bytes).map(|element| Self(element))
}
/// Serialize [`NonceCommitment`] to bytes
pub fn to_bytes(&self) -> <C::Group as Group>::Serialization {
<C::Group as Group>::serialize(&self.0)
<C::Group>::serialize(&self.0)
}
}
@ -135,7 +135,7 @@ where
C: Ciphersuite,
{
fn from(nonce: &Nonce<C>) -> Self {
Self(<C::Group as Group>::generator() * nonce.0)
Self(<C::Group>::generator() * nonce.0)
}
}
@ -253,7 +253,7 @@ where
/// One signer's share of the group commitment, derived from their individual signing commitments
/// and the binding factor _rho_.
#[derive(Clone, Copy, PartialEq)]
pub struct GroupCommitmentShare<C: Ciphersuite>(pub(super) <C::Group as Group>::Element);
pub struct GroupCommitmentShare<C: Ciphersuite>(pub(super) Element<C>);
/// Encode the list of group signing commitments.
///
@ -282,8 +282,8 @@ pub(super) fn encode_group_commitments<C: Ciphersuite>(
for item in sorted_signing_commitments {
bytes.extend_from_slice(item.identifier.serialize().as_ref());
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());
bytes.extend_from_slice(<C::Group>::serialize(&item.hiding.0).as_ref());
bytes.extend_from_slice(<C::Group>::serialize(&item.binding.0).as_ref());
}
bytes

View File

@ -12,7 +12,7 @@ use crate::{
#[derive(Clone, Copy)]
pub struct SignatureResponse<C: Ciphersuite> {
/// The scalar contribution to the group signature.
pub z_share: <<C::Group as Group>::Field as Field>::Scalar,
pub z_share: Scalar<C>,
}
impl<C> SignatureResponse<C>
@ -23,13 +23,12 @@ where
pub fn from_bytes(
bytes: <<C::Group as Group>::Field as Field>::Serialization,
) -> Result<Self, Error> {
<<C::Group as Group>::Field as Field>::deserialize(&bytes)
.map(|scalar| Self { z_share: scalar })
<<C::Group as Group>::Field>::deserialize(&bytes).map(|scalar| Self { z_share: scalar })
}
/// Serialize [`SignatureResponse`] to bytes
pub fn to_bytes(&self) -> <<C::Group as Group>::Field as Field>::Serialization {
<<C::Group as Group>::Field as Field>::serialize(&self.z_share)
<<C::Group as Group>::Field>::serialize(&self.z_share)
}
}
@ -85,10 +84,10 @@ where
&self,
group_commitment_share: &round1::GroupCommitmentShare<C>,
public_key: &frost::keys::VerifyingShare<C>,
lambda_i: <<C::Group as Group>::Field as Field>::Scalar,
lambda_i: Scalar<C>,
challenge: &Challenge<C>,
) -> Result<(), &'static str> {
if (<C::Group as Group>::generator() * self.signature.z_share)
if (<C::Group>::generator() * self.signature.z_share)
!= (group_commitment_share.0 + (public_key.0 * challenge.0 * lambda_i))
{
return Err("Invalid signature share");
@ -153,7 +152,7 @@ pub fn sign<C: Ciphersuite>(
);
// Compute the Schnorr signature share.
let z_share: <<C::Group as Group>::Field as Field>::Scalar = signer_nonces.hiding.0
let z_share = signer_nonces.hiding.0
+ (signer_nonces.binding.0 * binding_factor.0)
+ (lambda_i * key_package.secret_share.0 * challenge.0);

View File

@ -254,7 +254,7 @@ where
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("Secret")
.field(&hex::encode(
<<<C as Ciphersuite>::Group as Group>::Field as Field>::serialize(&self.0),
<<<C as Ciphersuite>::Group as Group>::Field>::serialize(&self.0),
))
.finish()
}
@ -267,20 +267,16 @@ where
///
/// This is the only invocation of the H2 hash function from the [RFC].
///
/// [FROST]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-11.html#name-signature-challenge-computa
/// [RFC]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-11.html#section-3.2
fn challenge<C>(
R: &<C::Group as Group>::Element,
verifying_key: &<C::Group as Group>::Element,
msg: &[u8],
) -> Challenge<C>
/// [FROST]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-10.html#name-signature-challenge-computa
/// [RFC]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-10.html#section-3.2
fn challenge<C>(R: &Element<C>, verifying_key: &Element<C>, msg: &[u8]) -> Challenge<C>
where
C: Ciphersuite,
{
let mut preimage = vec![];
preimage.extend_from_slice(<C::Group as Group>::serialize(R).as_ref());
preimage.extend_from_slice(<C::Group as Group>::serialize(verifying_key).as_ref());
preimage.extend_from_slice(<C::Group>::serialize(R).as_ref());
preimage.extend_from_slice(<C::Group>::serialize(verifying_key).as_ref());
preimage.extend_from_slice(msg);
Challenge(C::H2(&preimage[..]))

View File

@ -38,7 +38,7 @@ where
let mut x_u64 = [0u64; 5];
LittleEndian::read_u64_into(
<<C::Group as Group>::Field as Field>::serialize(self).as_ref(),
<<C::Group as Group>::Field>::serialize(self).as_ref(),
&mut x_u64[0..4],
);
@ -147,7 +147,7 @@ where
.map(|P_opt| P_opt.map(|P| LookupTable5::<C, Element<C>>::from(&P)))
.collect::<Option<Vec<_>>>()?;
let mut r = <C::Group as Group>::identity();
let mut r = <C::Group>::identity();
for i in (0..256).rev() {
let mut t = r + r;

View File

@ -2,16 +2,16 @@
use debugless_unwrap::DebuglessUnwrap;
use crate::{Ciphersuite, Error, Field, Group};
use crate::{Ciphersuite, Element, Error, Field, Group, Scalar};
/// A Schnorr signature over some prime order group (or subgroup).
#[derive(Copy, Clone, Eq, PartialEq)]
pub struct Signature<C: Ciphersuite> {
/// The commitment `R` to the signature nonce.
pub(crate) R: <C::Group as Group>::Element,
pub(crate) R: Element<C>,
/// The response `z` to the challenge computed from the commitment `R`, the verifying key, and
/// the message.
pub(crate) z: <<C::Group as Group>::Field as Field>::Scalar,
pub(crate) z: Scalar<C>,
}
impl<C> Signature<C>
@ -25,8 +25,8 @@ where
// To compute the expected length of the encoded point, encode the generator
// and get its length. Note that we can't use the identity because it can be encoded
// shorter in some cases (e.g. P-256, which uses SEC1 encoding).
let generator = <C::Group as Group>::generator();
let mut R_bytes = Vec::from(<C::Group as Group>::serialize(&generator).as_ref());
let generator = <C::Group>::generator();
let mut R_bytes = Vec::from(<C::Group>::serialize(&generator).as_ref());
let R_bytes_len = R_bytes.len();
@ -45,8 +45,8 @@ where
let z_serialization = &z_bytes.try_into().map_err(|_| Error::MalformedSignature)?;
Ok(Self {
R: <C::Group as Group>::deserialize(R_serialization)?,
z: <<C::Group as Group>::Field as Field>::deserialize(z_serialization)?,
R: <C::Group>::deserialize(R_serialization)?,
z: <<C::Group as Group>::Field>::deserialize(z_serialization)?,
})
}
@ -54,8 +54,8 @@ where
pub fn to_bytes(&self) -> C::SignatureSerialization {
let mut bytes = vec![];
bytes.extend(<C::Group as Group>::serialize(&self.R).as_ref());
bytes.extend(<<C::Group as Group>::Field as Field>::serialize(&self.z).as_ref());
bytes.extend(<C::Group>::serialize(&self.R).as_ref());
bytes.extend(<<C::Group as Group>::Field>::serialize(&self.z).as_ref());
bytes.try_into().debugless_unwrap()
}
@ -64,13 +64,10 @@ where
impl<C: Ciphersuite> std::fmt::Debug for Signature<C> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.debug_struct("Signature")
.field(
"R",
&hex::encode(<C::Group as Group>::serialize(&self.R).as_ref()),
)
.field("R", &hex::encode(<C::Group>::serialize(&self.R).as_ref()))
.field(
"z",
&hex::encode(<<C::Group as Group>::Field as Field>::serialize(&self.z).as_ref()),
&hex::encode(<<C::Group as Group>::Field>::serialize(&self.z).as_ref()),
)
.finish()
}

View File

@ -2,7 +2,7 @@
use rand_core::{CryptoRng, RngCore};
use crate::{Ciphersuite, Error, Field, Group, Signature, VerifyingKey};
use crate::{Ciphersuite, Error, Field, Group, Scalar, Signature, VerifyingKey};
/// A signing key for a Schnorr signature on a FROST [`Ciphersuite::Group`].
#[derive(Copy, Clone)]
@ -10,7 +10,7 @@ pub struct SigningKey<C>
where
C: Ciphersuite,
{
pub(crate) scalar: <<C::Group as Group>::Field as Field>::Scalar,
pub(crate) scalar: Scalar<C>,
}
impl<C> SigningKey<C>
@ -19,7 +19,7 @@ where
{
/// Generate a new signing key.
pub fn new<R: RngCore + CryptoRng>(mut rng: R) -> SigningKey<C> {
let scalar = <<C::Group as Group>::Field as Field>::random_nonzero(&mut rng);
let scalar = <<C::Group as Group>::Field>::random_nonzero(&mut rng);
SigningKey { scalar }
}
@ -39,9 +39,9 @@ where
/// Create a signature `msg` using this `SigningKey`.
pub fn sign<R: RngCore + CryptoRng>(&self, mut rng: R, msg: &[u8]) -> Signature<C> {
let k = <<C::Group as Group>::Field as Field>::random_nonzero(&mut rng);
let k = <<C::Group as Group>::Field>::random_nonzero(&mut rng);
let R = <C::Group as Group>::generator() * k;
let R = <C::Group>::generator() * k;
// Generate Schnorr challenge
let c = crate::challenge::<C>(&R, &VerifyingKey::<C>::from(*self).element, msg);

View File

@ -46,8 +46,7 @@ pub fn parse_test_vectors<C: Ciphersuite>(json_vectors: &Value) -> TestVectors<C
.iter()
.map(|v| {
let vec = hex::decode(v.as_str().unwrap()).unwrap();
<<C::Group as Group>::Field as Field>::deserialize(&vec.try_into().debugless_unwrap())
.unwrap()
<<C::Group as Group>::Field>::deserialize(&vec.try_into().debugless_unwrap()).unwrap()
})
.collect();
@ -152,7 +151,7 @@ pub fn parse_test_vectors<C: Ciphersuite>(json_vectors: &Value) -> TestVectors<C
let signature_share = SignatureShare::<C> {
identifier: u16::from_str(i).unwrap().try_into().unwrap(),
signature: SignatureResponse {
z_share: <<C::Group as Group>::Field as Field>::deserialize(&sig_share).unwrap(),
z_share: <<C::Group as Group>::Field>::deserialize(&sig_share).unwrap(),
},
};

View File

@ -2,7 +2,7 @@ use std::fmt::{self, Debug};
use hex::FromHex;
use crate::{Challenge, Ciphersuite, Error, Group, Signature};
use crate::{Challenge, Ciphersuite, Element, Error, Group, Signature};
/// A valid verifying key for Schnorr signatures over a FROST [`Ciphersuite::Group`].
#[derive(Copy, Clone, PartialEq)]
@ -10,7 +10,7 @@ pub struct VerifyingKey<C>
where
C: Ciphersuite,
{
pub(crate) element: <C::Group as Group>::Element,
pub(crate) element: Element<C>,
}
impl<C> VerifyingKey<C>
@ -25,12 +25,12 @@ where
/// Deserialize from bytes
pub fn from_bytes(bytes: <C::Group as Group>::Serialization) -> Result<VerifyingKey<C>, Error> {
<C::Group as Group>::deserialize(&bytes).map(|element| VerifyingKey { element })
<C::Group>::deserialize(&bytes).map(|element| VerifyingKey { element })
}
/// Serialize `VerifyingKey` to bytes
pub fn to_bytes(&self) -> <C::Group as Group>::Serialization {
<C::Group as Group>::serialize(&self.element)
<C::Group>::serialize(&self.element)
}
/// Verify a purported `signature` with a pre-hashed [`Challenge`] made by this verification