add Identifier to InvalidSignatureShare and split Error type (#183)
* add Identifier to InvalidSignatureShare
* rustdoc
* also update secp256k1
* add Identifier::deserialize; make serialize public
* make it work with Ed448
* Some space
* Fixing spacing for rustfmt
* Revert 🤦♂️
Co-authored-by: Deirdre Connolly <durumcrustulum@gmail.com>
This commit is contained in:
parent
359434b14f
commit
e8dc692ca0
|
@ -49,7 +49,7 @@ where
|
|||
/// [`VerifyingKey::verify`](crate::VerifyingKey::verify), which
|
||||
/// requires borrowing the message data, the `Item` type is unlinked
|
||||
/// from the lifetime of the message.
|
||||
pub fn verify_single(self) -> Result<(), Error> {
|
||||
pub fn verify_single(self) -> Result<(), Error<C>> {
|
||||
self.vk.verify_prehashed(self.c, &self.sig)
|
||||
}
|
||||
}
|
||||
|
@ -103,7 +103,7 @@ where
|
|||
/// notation in the [protocol specification §B.1][ps].
|
||||
///
|
||||
/// [ps]: https://zips.z.cash/protocol/protocol.pdf#reddsabatchverify
|
||||
pub fn verify<R: RngCore + CryptoRng>(self, mut rng: R) -> Result<(), Error> {
|
||||
pub fn verify<R: RngCore + CryptoRng>(self, mut rng: R) -> Result<(), Error<C>> {
|
||||
let n = self.signatures.len();
|
||||
|
||||
let mut VK_coeffs = Vec::with_capacity(n);
|
||||
|
|
|
@ -2,10 +2,12 @@
|
|||
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::{frost::Identifier, Ciphersuite};
|
||||
|
||||
/// An error related to FROST.
|
||||
#[non_exhaustive]
|
||||
#[derive(Error, Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub enum Error {
|
||||
pub enum Error<C: Ciphersuite> {
|
||||
/// min_signers is invalid
|
||||
#[error("min_signers must be at least 2 and not larger than max_signers")]
|
||||
InvalidMinSigners,
|
||||
|
@ -18,12 +20,6 @@ pub enum Error {
|
|||
/// This identifier is unserializable.
|
||||
#[error("Malformed identifier is unserializable.")]
|
||||
MalformedIdentifier,
|
||||
/// The encoding of a group scalar was malformed.
|
||||
#[error("Malformed scalar encoding.")]
|
||||
MalformedScalar,
|
||||
/// The encoding of a group element was malformed.
|
||||
#[error("Malformed group element encoding.")]
|
||||
MalformedElement,
|
||||
/// The encoding of a signing key was malformed.
|
||||
#[error("Malformed signing key encoding.")]
|
||||
MalformedSigningKey,
|
||||
|
@ -36,15 +32,6 @@ pub enum Error {
|
|||
/// Signature verification failed.
|
||||
#[error("Invalid signature.")]
|
||||
InvalidSignature,
|
||||
/// This scalar MUST NOT be zero.
|
||||
#[error("Invalid for this scalar to be zero.")]
|
||||
InvalidZeroScalar,
|
||||
/// This element MUST NOT be the identity.
|
||||
#[error("Invalid for this element to be the identity.")]
|
||||
InvalidIdentityElement,
|
||||
/// This element MUST have (large) prime order.
|
||||
#[error("Invalid for this element to not have large prime order.")]
|
||||
InvalidNonPrimeOrderElement,
|
||||
/// Duplicated shares provided
|
||||
#[error("Duplicated shares provided.")]
|
||||
DuplicatedShares,
|
||||
|
@ -53,7 +40,10 @@ pub enum Error {
|
|||
IdentityCommitment,
|
||||
/// Signature share verification failed.
|
||||
#[error("Invalid signature share.")]
|
||||
InvalidSignatureShare,
|
||||
InvalidSignatureShare {
|
||||
/// The identifier of the signer whose share validation failed.
|
||||
signer: Identifier<C>,
|
||||
},
|
||||
/// Secret share verification failed.
|
||||
#[error("Invalid secret share.")]
|
||||
InvalidSecretShare,
|
||||
|
@ -72,4 +62,37 @@ pub enum Error {
|
|||
/// The proof of knowledge is not valid.
|
||||
#[error("The proof of knowledge is not valid.")]
|
||||
InvalidProofOfKnowledge,
|
||||
/// Error in scalar Field.
|
||||
#[error("Error in scalar Field.")]
|
||||
FieldError(#[from] FieldError),
|
||||
/// Error in elliptic curve Group.
|
||||
#[error("Error in elliptic curve Group.")]
|
||||
GroupError(#[from] GroupError),
|
||||
}
|
||||
|
||||
/// An error related to a scalar Field.
|
||||
#[non_exhaustive]
|
||||
#[derive(Error, Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub enum FieldError {
|
||||
/// The encoding of a group scalar was malformed.
|
||||
#[error("Malformed scalar encoding.")]
|
||||
MalformedScalar,
|
||||
/// This scalar MUST NOT be zero.
|
||||
#[error("Invalid for this scalar to be zero.")]
|
||||
InvalidZeroScalar,
|
||||
}
|
||||
|
||||
/// An error related to a Group (usually an elliptic curve or constructed from one) or one of its Elements.
|
||||
#[non_exhaustive]
|
||||
#[derive(Error, Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub enum GroupError {
|
||||
/// The encoding of a group element was malformed.
|
||||
#[error("Malformed group element encoding.")]
|
||||
MalformedElement,
|
||||
/// This element MUST NOT be the identity.
|
||||
#[error("Invalid for this element to be the identity.")]
|
||||
InvalidIdentityElement,
|
||||
/// This element MUST have (large) prime order.
|
||||
#[error("Invalid for this element to not have large prime order.")]
|
||||
InvalidNonPrimeOrderElement,
|
||||
}
|
||||
|
|
|
@ -44,8 +44,10 @@ where
|
|||
/// Deserializes [`BindingFactor`] from bytes.
|
||||
pub fn from_bytes(
|
||||
bytes: <<C::Group as Group>::Field as Field>::Serialization,
|
||||
) -> Result<Self, Error> {
|
||||
<<C::Group as Group>::Field>::deserialize(&bytes).map(|scalar| Self(scalar))
|
||||
) -> Result<Self, Error<C>> {
|
||||
<<C::Group as Group>::Field>::deserialize(&bytes)
|
||||
.map(|scalar| Self(scalar))
|
||||
.map_err(|e| e.into())
|
||||
}
|
||||
|
||||
/// Serializes [`BindingFactor`] to bytes.
|
||||
|
@ -139,7 +141,7 @@ where
|
|||
fn derive_lagrange_coeff<C: Ciphersuite>(
|
||||
signer_id: &Identifier<C>,
|
||||
signing_package: &SigningPackage<C>,
|
||||
) -> Result<Scalar<C>, Error> {
|
||||
) -> Result<Scalar<C>, Error<C>> {
|
||||
let zero = <<C::Group as Group>::Field>::zero();
|
||||
|
||||
let mut num = <<C::Group as Group>::Field>::one();
|
||||
|
@ -259,7 +261,7 @@ impl<C> TryFrom<&SigningPackage<C>> for GroupCommitment<C>
|
|||
where
|
||||
C: Ciphersuite,
|
||||
{
|
||||
type Error = Error;
|
||||
type Error = Error<C>;
|
||||
|
||||
/// Generates the group commitment which is published as part of the joint
|
||||
/// Schnorr signature.
|
||||
|
@ -267,7 +269,7 @@ where
|
|||
/// Implements [`compute_group_commitment`] from the spec.
|
||||
///
|
||||
/// [`compute_group_commitment`]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-11.html#section-4.5
|
||||
fn try_from(signing_package: &SigningPackage<C>) -> Result<GroupCommitment<C>, Error> {
|
||||
fn try_from(signing_package: &SigningPackage<C>) -> Result<GroupCommitment<C>, Error<C>> {
|
||||
let binding_factor_list: BindingFactorList<C> = signing_package.into();
|
||||
|
||||
let identity = <C::Group>::identity();
|
||||
|
@ -317,7 +319,7 @@ pub fn aggregate<C>(
|
|||
signing_package: &SigningPackage<C>,
|
||||
signature_shares: &[round2::SignatureShare<C>],
|
||||
pubkeys: &keys::PublicKeyPackage<C>,
|
||||
) -> Result<Signature<C>, Error>
|
||||
) -> Result<Signature<C>, Error<C>>
|
||||
where
|
||||
C: Ciphersuite,
|
||||
{
|
||||
|
|
|
@ -5,7 +5,7 @@ use std::{
|
|||
hash::{Hash, Hasher},
|
||||
};
|
||||
|
||||
use crate::{Ciphersuite, Error, Field, Group, Scalar};
|
||||
use crate::{Ciphersuite, Error, Field, FieldError, Group, Scalar};
|
||||
|
||||
/// A FROST participant identifier.
|
||||
///
|
||||
|
@ -19,10 +19,23 @@ impl<C> Identifier<C>
|
|||
where
|
||||
C: Ciphersuite,
|
||||
{
|
||||
// Serialize the underlying scalar.
|
||||
pub(crate) fn serialize(&self) -> <<C::Group as Group>::Field as Field>::Serialization {
|
||||
/// Serialize the identifier using the ciphersuite encoding.
|
||||
pub fn serialize(&self) -> <<C::Group as Group>::Field as Field>::Serialization {
|
||||
<<C::Group as Group>::Field>::serialize(&self.0)
|
||||
}
|
||||
|
||||
/// Deserialize an Identifier from a serialized buffer.
|
||||
/// Returns an error if it attempts to deserialize zero.
|
||||
pub fn deserialize(
|
||||
buf: &<<C::Group as Group>::Field as Field>::Serialization,
|
||||
) -> Result<Self, Error<C>> {
|
||||
let scalar = <<C::Group as Group>::Field>::deserialize(buf)?;
|
||||
if scalar == <<C::Group as Group>::Field>::zero() {
|
||||
Err(FieldError::InvalidZeroScalar.into())
|
||||
} else {
|
||||
Ok(Self(scalar))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<C> Eq for Identifier<C> where C: Ciphersuite {}
|
||||
|
@ -109,11 +122,11 @@ impl<C> TryFrom<u16> for Identifier<C>
|
|||
where
|
||||
C: Ciphersuite,
|
||||
{
|
||||
type Error = Error;
|
||||
type Error = Error<C>;
|
||||
|
||||
fn try_from(n: u16) -> Result<Identifier<C>, Self::Error> {
|
||||
if n == 0 {
|
||||
Err(Self::Error::InvalidZeroScalar)
|
||||
Err(FieldError::InvalidZeroScalar.into())
|
||||
} 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.
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
//! FROST keys, keygen, key shares
|
||||
#![allow(clippy::type_complexity)]
|
||||
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
|
@ -44,8 +45,10 @@ where
|
|||
/// Deserialize from bytes
|
||||
pub fn from_bytes(
|
||||
bytes: <<C::Group as Group>::Field as Field>::Serialization,
|
||||
) -> Result<Self, Error> {
|
||||
<<C::Group as Group>::Field>::deserialize(&bytes).map(|scalar| Self(scalar))
|
||||
) -> Result<Self, Error<C>> {
|
||||
<<C::Group as Group>::Field>::deserialize(&bytes)
|
||||
.map(|scalar| Self(scalar))
|
||||
.map_err(|e| e.into())
|
||||
}
|
||||
|
||||
/// Serialize to bytes
|
||||
|
@ -124,8 +127,10 @@ where
|
|||
/// Deserialize from bytes
|
||||
pub fn from_bytes(
|
||||
bytes: <<C::Group as Group>::Field as Field>::Serialization,
|
||||
) -> Result<Self, Error> {
|
||||
<<C::Group as Group>::Field>::deserialize(&bytes).map(|scalar| Self(scalar))
|
||||
) -> Result<Self, Error<C>> {
|
||||
<<C::Group as Group>::Field>::deserialize(&bytes)
|
||||
.map(|scalar| Self(scalar))
|
||||
.map_err(|e| e.into())
|
||||
}
|
||||
|
||||
/// Serialize to bytes
|
||||
|
@ -184,8 +189,10 @@ where
|
|||
C: Ciphersuite,
|
||||
{
|
||||
/// Deserialize 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))
|
||||
pub fn from_bytes(bytes: <C::Group as Group>::Serialization) -> Result<Self, Error<C>> {
|
||||
<C::Group as Group>::deserialize(&bytes)
|
||||
.map(|element| Self(element))
|
||||
.map_err(|e| e.into())
|
||||
}
|
||||
|
||||
/// Serialize to bytes
|
||||
|
@ -282,7 +289,7 @@ where
|
|||
/// but only for this participant.
|
||||
///
|
||||
/// [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>), Error> {
|
||||
pub fn verify(&self) -> Result<(VerifyingShare<C>, VerifyingKey<C>), Error<C>> {
|
||||
let f_result = <C::Group>::generator() * self.value.0;
|
||||
let result = evaluate_vss(&self.commitment, self.identifier);
|
||||
|
||||
|
@ -314,7 +321,7 @@ pub fn keygen_with_dealer<C: Ciphersuite, R: RngCore + CryptoRng>(
|
|||
max_signers: u16,
|
||||
min_signers: u16,
|
||||
mut rng: R,
|
||||
) -> Result<(Vec<SecretShare<C>>, PublicKeyPackage<C>), Error> {
|
||||
) -> Result<(Vec<SecretShare<C>>, PublicKeyPackage<C>), Error<C>> {
|
||||
let mut bytes = [0; 64];
|
||||
rng.fill_bytes(&mut bytes);
|
||||
|
||||
|
@ -425,7 +432,7 @@ impl<C> TryFrom<SecretShare<C>> for KeyPackage<C>
|
|||
where
|
||||
C: Ciphersuite,
|
||||
{
|
||||
type Error = Error;
|
||||
type Error = Error<C>;
|
||||
|
||||
/// Tries to verify a share and construct a [`KeyPackage`] from it.
|
||||
///
|
||||
|
@ -435,7 +442,7 @@ where
|
|||
/// every participant has the same view of the commitment issued by the
|
||||
/// dealer, but implementations *MUST* make sure that all participants have
|
||||
/// a consistent view of this commitment in practice.
|
||||
fn try_from(secret_share: SecretShare<C>) -> Result<Self, Error> {
|
||||
fn try_from(secret_share: SecretShare<C>) -> Result<Self, Error<C>> {
|
||||
let (public, group_public) = secret_share.verify()?;
|
||||
|
||||
Ok(KeyPackage {
|
||||
|
@ -474,7 +481,7 @@ pub(crate) fn generate_secret_polynomial<C: Ciphersuite>(
|
|||
max_signers: u16,
|
||||
min_signers: u16,
|
||||
mut coefficients: Vec<Scalar<C>>,
|
||||
) -> Result<(Vec<Scalar<C>>, VerifiableSecretSharingCommitment<C>), Error> {
|
||||
) -> Result<(Vec<Scalar<C>>, VerifiableSecretSharingCommitment<C>), Error<C>> {
|
||||
if min_signers < 2 {
|
||||
return Err(Error::InvalidMinSigners);
|
||||
}
|
||||
|
@ -529,7 +536,7 @@ pub(crate) fn generate_secret_shares<C: Ciphersuite>(
|
|||
max_signers: u16,
|
||||
min_signers: u16,
|
||||
coefficients: Vec<Scalar<C>>,
|
||||
) -> Result<Vec<SecretShare<C>>, Error> {
|
||||
) -> Result<Vec<SecretShare<C>>, Error<C>> {
|
||||
let mut secret_shares: Vec<SecretShare<C>> = Vec::with_capacity(max_signers as usize);
|
||||
|
||||
let (coefficients, commitment) =
|
||||
|
|
|
@ -97,7 +97,7 @@ pub fn keygen_part1<C: Ciphersuite, R: RngCore + CryptoRng>(
|
|||
max_signers: u16,
|
||||
min_signers: u16,
|
||||
mut rng: R,
|
||||
) -> Result<(Round1SecretPackage<C>, Round1Package<C>), Error> {
|
||||
) -> Result<(Round1SecretPackage<C>, Round1Package<C>), Error<C>> {
|
||||
let secret: SharedSecret<C> = SharedSecret::random(&mut rng);
|
||||
|
||||
// Round 1, Step 1
|
||||
|
@ -167,7 +167,7 @@ where
|
|||
pub fn keygen_part2<C: Ciphersuite>(
|
||||
secret_package: Round1SecretPackage<C>,
|
||||
round1_packages: &[Round1Package<C>],
|
||||
) -> Result<(Round2SecretPackage<C>, Vec<Round2Package<C>>), Error> {
|
||||
) -> Result<(Round2SecretPackage<C>, Vec<Round2Package<C>>), Error<C>> {
|
||||
if round1_packages.len() != (secret_package.max_signers - 1) as usize {
|
||||
return Err(Error::IncorrectNumberOfPackages);
|
||||
}
|
||||
|
@ -221,7 +221,7 @@ fn compute_verifying_keys<C: Ciphersuite>(
|
|||
round2_packages: &[Round2Package<C>],
|
||||
round1_packages_map: HashMap<Identifier<C>, &Round1Package<C>>,
|
||||
round2_secret_package: &Round2SecretPackage<C>,
|
||||
) -> Result<HashMap<Identifier<C>, VerifyingShare<C>>, Error> {
|
||||
) -> Result<HashMap<Identifier<C>, VerifyingShare<C>>, Error<C>> {
|
||||
// Round 2, Step 4
|
||||
//
|
||||
// > Any participant can compute the public verification share of any other participant
|
||||
|
@ -239,7 +239,7 @@ fn compute_verifying_keys<C: Ciphersuite>(
|
|||
.iter()
|
||||
.map(|p| {
|
||||
// Get the commitment vector for this participant
|
||||
Ok::<&VerifiableSecretSharingCommitment<C>, Error>(
|
||||
Ok::<&VerifiableSecretSharingCommitment<C>, Error<C>>(
|
||||
&round1_packages_map
|
||||
.get(&p.sender_identifier)
|
||||
.ok_or(Error::PackageNotFound)?
|
||||
|
@ -270,7 +270,7 @@ pub fn keygen_part3<C: Ciphersuite>(
|
|||
round2_secret_package: &Round2SecretPackage<C>,
|
||||
round1_packages: &[Round1Package<C>],
|
||||
round2_packages: &[Round2Package<C>],
|
||||
) -> Result<(KeyPackage<C>, PublicKeyPackage<C>), Error> {
|
||||
) -> Result<(KeyPackage<C>, PublicKeyPackage<C>), Error<C>> {
|
||||
if round1_packages.len() != (round2_secret_package.max_signers - 1) as usize {
|
||||
return Err(Error::IncorrectNumberOfPackages);
|
||||
}
|
||||
|
|
|
@ -57,8 +57,10 @@ where
|
|||
/// Deserialize [`Nonce`] from bytes
|
||||
pub fn from_bytes(
|
||||
bytes: <<C::Group as Group>::Field as Field>::Serialization,
|
||||
) -> Result<Self, Error> {
|
||||
<<C::Group as Group>::Field>::deserialize(&bytes).map(|scalar| Self(scalar))
|
||||
) -> Result<Self, Error<C>> {
|
||||
<<C::Group as Group>::Field>::deserialize(&bytes)
|
||||
.map(|scalar| Self(scalar))
|
||||
.map_err(|e| e.into())
|
||||
}
|
||||
|
||||
/// Serialize [`Nonce`] to bytes
|
||||
|
@ -101,8 +103,10 @@ where
|
|||
C: Ciphersuite,
|
||||
{
|
||||
/// Deserialize [`NonceCommitment`] from bytes
|
||||
pub fn from_bytes(bytes: <C::Group as Group>::Serialization) -> Result<Self, Error> {
|
||||
<C::Group>::deserialize(&bytes).map(|element| Self(element))
|
||||
pub fn from_bytes(bytes: <C::Group as Group>::Serialization) -> Result<Self, Error<C>> {
|
||||
<C::Group>::deserialize(&bytes)
|
||||
.map(|element| Self(element))
|
||||
.map_err(|e| e.into())
|
||||
}
|
||||
|
||||
/// Serialize [`NonceCommitment`] to bytes
|
||||
|
|
|
@ -22,8 +22,10 @@ where
|
|||
/// Deserialize [`SignatureResponse`] from bytes
|
||||
pub fn from_bytes(
|
||||
bytes: <<C::Group as Group>::Field as Field>::Serialization,
|
||||
) -> Result<Self, Error> {
|
||||
<<C::Group as Group>::Field>::deserialize(&bytes).map(|scalar| Self { z_share: scalar })
|
||||
) -> Result<Self, Error<C>> {
|
||||
<<C::Group as Group>::Field>::deserialize(&bytes)
|
||||
.map(|scalar| Self { z_share: scalar })
|
||||
.map_err(|e| e.into())
|
||||
}
|
||||
|
||||
/// Serialize [`SignatureResponse`] to bytes
|
||||
|
@ -86,11 +88,13 @@ where
|
|||
public_key: &frost::keys::VerifyingShare<C>,
|
||||
lambda_i: Scalar<C>,
|
||||
challenge: &Challenge<C>,
|
||||
) -> Result<(), Error> {
|
||||
) -> Result<(), Error<C>> {
|
||||
if (<C::Group>::generator() * self.signature.z_share)
|
||||
!= (group_commitment_share.0 + (public_key.0 * challenge.0 * lambda_i))
|
||||
{
|
||||
return Err(Error::InvalidSignatureShare);
|
||||
return Err(Error::InvalidSignatureShare {
|
||||
signer: self.identifier,
|
||||
});
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -131,7 +135,7 @@ pub fn sign<C: Ciphersuite>(
|
|||
signing_package: &SigningPackage<C>,
|
||||
signer_nonces: &round1::SigningNonces<C>,
|
||||
key_package: &frost::keys::KeyPackage<C>,
|
||||
) -> Result<SignatureShare<C>, Error> {
|
||||
) -> Result<SignatureShare<C>, Error<C>> {
|
||||
// Encodes the signing commitment list produced in round one as part of generating [`BindingFactor`], the
|
||||
// binding factor.
|
||||
let binding_factor_list: frost::BindingFactorList<C> = signing_package.into();
|
||||
|
|
|
@ -23,7 +23,7 @@ mod signing_key;
|
|||
pub mod tests;
|
||||
mod verifying_key;
|
||||
|
||||
pub use error::Error;
|
||||
pub use error::{Error, FieldError, GroupError};
|
||||
pub use signature::Signature;
|
||||
pub use signing_key::SigningKey;
|
||||
pub use verifying_key::VerifyingKey;
|
||||
|
@ -57,7 +57,7 @@ pub trait Field: Copy + Clone {
|
|||
|
||||
/// Computes the multiplicative inverse of an element of the scalar field, failing if the
|
||||
/// element is zero.
|
||||
fn invert(scalar: &Self::Scalar) -> Result<Self::Scalar, Error>;
|
||||
fn invert(scalar: &Self::Scalar) -> Result<Self::Scalar, FieldError>;
|
||||
|
||||
/// Generate a random scalar from the entire space [0, l-1]
|
||||
///
|
||||
|
@ -83,7 +83,7 @@ pub trait Field: Copy + Clone {
|
|||
/// resulting [`Scalar`] is zero
|
||||
///
|
||||
/// <https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-11.html#section-3.1-3.9>
|
||||
fn deserialize(buf: &Self::Serialization) -> Result<Self::Scalar, Error>;
|
||||
fn deserialize(buf: &Self::Serialization) -> Result<Self::Scalar, FieldError>;
|
||||
}
|
||||
|
||||
/// An element of the [`Ciphersuite`] `C`'s [`Group`]'s scalar [`Field`].
|
||||
|
@ -146,7 +146,7 @@ pub trait Group: Copy + Clone + PartialEq {
|
|||
/// resulting [`Element`] is the identity element of the group
|
||||
///
|
||||
/// <https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-11.html#section-3.1-3.7>
|
||||
fn deserialize(buf: &Self::Serialization) -> Result<Self::Element, Error>;
|
||||
fn deserialize(buf: &Self::Serialization) -> Result<Self::Element, GroupError>;
|
||||
}
|
||||
|
||||
/// An element of the [`Ciphersuite`] `C`'s [`Group`].
|
||||
|
@ -156,7 +156,7 @@ pub type Element<C> = <<C as Ciphersuite>::Group as Group>::Element;
|
|||
/// function.
|
||||
///
|
||||
/// [FROST ciphersuite]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-11.html#name-ciphersuites
|
||||
pub trait Ciphersuite: Copy + Clone + PartialEq {
|
||||
pub trait Ciphersuite: Copy + Clone + PartialEq + Debug {
|
||||
/// The prime order group (or subgroup) that this ciphersuite operates over.
|
||||
type Group: Group;
|
||||
|
||||
|
@ -226,7 +226,7 @@ pub trait Ciphersuite: Copy + Clone + PartialEq {
|
|||
msg: &[u8],
|
||||
signature: &Signature<Self>,
|
||||
public_key: &VerifyingKey<Self>,
|
||||
) -> Result<(), Error> {
|
||||
) -> Result<(), Error<Self>> {
|
||||
let c = crate::challenge::<Self>(&signature.R, &public_key.element, msg);
|
||||
|
||||
public_key.verify_prehashed(c, signature)
|
||||
|
|
|
@ -21,7 +21,7 @@ where
|
|||
<C::Group as Group>::Field: Field,
|
||||
{
|
||||
/// Converts bytes as [`Ciphersuite::SignatureSerialization`] into a `Signature<C>`.
|
||||
pub fn from_bytes(bytes: C::SignatureSerialization) -> Result<Self, Error> {
|
||||
pub fn from_bytes(bytes: C::SignatureSerialization) -> Result<Self, Error<C>> {
|
||||
// To compute the expected length of the encoded point, encode the generator
|
||||
// and get its length. Note that we can't use the identity because it can be encoded
|
||||
// shorter in some cases (e.g. P-256, which uses SEC1 encoding).
|
||||
|
|
|
@ -27,9 +27,10 @@ where
|
|||
/// Deserialize from bytes
|
||||
pub fn from_bytes(
|
||||
bytes: <<C::Group as Group>::Field as Field>::Serialization,
|
||||
) -> Result<SigningKey<C>, Error> {
|
||||
) -> Result<SigningKey<C>, Error<C>> {
|
||||
<<C::Group as Group>::Field as Field>::deserialize(&bytes)
|
||||
.map(|scalar| SigningKey { scalar })
|
||||
.map_err(|e| e.into())
|
||||
}
|
||||
|
||||
/// Serialize `SigningKey` to bytes
|
||||
|
|
|
@ -24,8 +24,12 @@ where
|
|||
// }
|
||||
|
||||
/// Deserialize from bytes
|
||||
pub fn from_bytes(bytes: <C::Group as Group>::Serialization) -> Result<VerifyingKey<C>, Error> {
|
||||
<C::Group>::deserialize(&bytes).map(|element| VerifyingKey { element })
|
||||
pub fn from_bytes(
|
||||
bytes: <C::Group as Group>::Serialization,
|
||||
) -> Result<VerifyingKey<C>, Error<C>> {
|
||||
<C::Group>::deserialize(&bytes)
|
||||
.map(|element| VerifyingKey { element })
|
||||
.map_err(|e| e.into())
|
||||
}
|
||||
|
||||
/// Serialize `VerifyingKey` to bytes
|
||||
|
@ -39,7 +43,7 @@ where
|
|||
&self,
|
||||
challenge: Challenge<C>,
|
||||
signature: &Signature<C>,
|
||||
) -> Result<(), Error> {
|
||||
) -> Result<(), Error<C>> {
|
||||
// Verify check is h * ( - z * B + R + c * A) == 0
|
||||
// h * ( z * B - c * A - R) == 0
|
||||
//
|
||||
|
@ -56,7 +60,7 @@ where
|
|||
}
|
||||
|
||||
/// Verify a purported `signature` over `msg` made by this verification key.
|
||||
pub fn verify(&self, msg: &[u8], signature: &Signature<C>) -> Result<(), Error> {
|
||||
pub fn verify(&self, msg: &[u8], signature: &Signature<C>) -> Result<(), Error<C>> {
|
||||
C::verify_signature(msg, signature, self)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ let (shares, pubkeys) = frost::keys::keygen_with_dealer(max_signers, min_signers
|
|||
let key_packages: HashMap<_, _> = shares
|
||||
.into_iter()
|
||||
.map(|share| Ok((share.identifier, frost::keys::KeyPackage::try_from(share)?)))
|
||||
.collect::<Result<_, _>>()?;
|
||||
.collect::<Result<_, frost::Error>>()?;
|
||||
|
||||
let mut nonces = HashMap::new();
|
||||
let mut commitments = HashMap::new();
|
||||
|
|
|
@ -11,12 +11,13 @@ use curve25519_dalek::{
|
|||
use rand_core::{CryptoRng, RngCore};
|
||||
use sha2::{digest::Update, Digest, Sha512};
|
||||
|
||||
use frost_core::{frost, Ciphersuite, Field, Group};
|
||||
use frost_core::{frost, Ciphersuite, Field, Group, GroupError};
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
pub use frost_core::Error;
|
||||
/// An error.
|
||||
pub type Error = frost_core::Error<Ed25519Sha512>;
|
||||
|
||||
/// An implementation of the FROST(Ed25519, SHA-512) ciphersuite scalar field.
|
||||
pub type Ed25519ScalarField = frost_ristretto255::RistrettoScalarField;
|
||||
|
@ -48,18 +49,18 @@ impl Group for Ed25519Group {
|
|||
element.compress().to_bytes()
|
||||
}
|
||||
|
||||
fn deserialize(buf: &Self::Serialization) -> Result<Self::Element, Error> {
|
||||
fn deserialize(buf: &Self::Serialization) -> Result<Self::Element, GroupError> {
|
||||
match CompressedEdwardsY::from_slice(buf.as_ref()).decompress() {
|
||||
Some(point) => {
|
||||
if point == Self::identity() {
|
||||
Err(Error::InvalidIdentityElement)
|
||||
Err(GroupError::InvalidIdentityElement)
|
||||
} else if point.is_torsion_free() {
|
||||
Ok(point)
|
||||
} else {
|
||||
Err(Error::InvalidNonPrimeOrderElement)
|
||||
Err(GroupError::InvalidNonPrimeOrderElement)
|
||||
}
|
||||
}
|
||||
None => Err(Error::MalformedElement),
|
||||
None => Err(GroupError::MalformedElement),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -69,7 +70,7 @@ impl Group for Ed25519Group {
|
|||
/// [spec]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-11.html#section-6.1-1
|
||||
const CONTEXT_STRING: &str = "FROST-ED25519-SHA512-v11";
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
/// An implementation of the FROST(Ed25519, SHA-512) ciphersuite.
|
||||
pub struct Ed25519Sha512;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use curve25519_dalek::{edwards::EdwardsPoint, traits::Identity};
|
||||
use frost_core::{Ciphersuite, Group};
|
||||
use frost_core::{Ciphersuite, Group, GroupError};
|
||||
use frost_ed25519::*;
|
||||
use rand::thread_rng;
|
||||
|
||||
|
@ -36,5 +36,5 @@ fn check_deserialize_identity() {
|
|||
let encoded_identity = EdwardsPoint::identity().compress().to_bytes();
|
||||
|
||||
let r = <<Ed25519Sha512 as Ciphersuite>::Group as Group>::deserialize(&encoded_identity);
|
||||
assert_eq!(r, Err(Error::InvalidIdentityElement));
|
||||
assert_eq!(r, Err(GroupError::InvalidIdentityElement));
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ let (shares, pubkeys) = frost::keys::keygen_with_dealer(max_signers, min_signers
|
|||
let key_packages: HashMap<_, _> = shares
|
||||
.into_iter()
|
||||
.map(|share| Ok((share.identifier, frost::keys::KeyPackage::try_from(share)?)))
|
||||
.collect::<Result<_, _>>()?;
|
||||
.collect::<Result<_, frost::Error>>()?;
|
||||
|
||||
let mut nonces = HashMap::new();
|
||||
let mut commitments = HashMap::new();
|
||||
|
|
|
@ -12,12 +12,13 @@ use sha3::{
|
|||
Shake256,
|
||||
};
|
||||
|
||||
use frost_core::{frost, Ciphersuite, Field, Group};
|
||||
use frost_core::{frost, Ciphersuite, Field, FieldError, Group, GroupError};
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
pub use frost_core::Error;
|
||||
/// An error.
|
||||
pub type Error = frost_core::Error<Ed448Shake256>;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
/// An implementation of the FROST(Ed448, SHAKE256) ciphersuite scalar field.
|
||||
|
@ -36,9 +37,9 @@ impl Field for Ed448ScalarField {
|
|||
Scalar::one()
|
||||
}
|
||||
|
||||
fn invert(scalar: &Self::Scalar) -> Result<Self::Scalar, Error> {
|
||||
fn invert(scalar: &Self::Scalar) -> Result<Self::Scalar, FieldError> {
|
||||
if *scalar == <Self as Field>::zero() {
|
||||
Err(Error::InvalidZeroScalar)
|
||||
Err(FieldError::InvalidZeroScalar)
|
||||
} else {
|
||||
Ok(scalar.invert())
|
||||
}
|
||||
|
@ -53,10 +54,10 @@ impl Field for Ed448ScalarField {
|
|||
std::array::from_fn(|i| if i < 56 { bytes[i] } else { 0 })
|
||||
}
|
||||
|
||||
fn deserialize(buf: &Self::Serialization) -> Result<Self::Scalar, Error> {
|
||||
fn deserialize(buf: &Self::Serialization) -> Result<Self::Scalar, FieldError> {
|
||||
match Scalar::from_canonical_bytes(*buf) {
|
||||
Some(s) => Ok(s),
|
||||
None => Err(Error::MalformedScalar),
|
||||
None => Err(FieldError::MalformedScalar),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -92,18 +93,18 @@ impl Group for Ed448Group {
|
|||
element.compress().0
|
||||
}
|
||||
|
||||
fn deserialize(buf: &Self::Serialization) -> Result<Self::Element, Error> {
|
||||
fn deserialize(buf: &Self::Serialization) -> Result<Self::Element, GroupError> {
|
||||
match CompressedEdwardsY(*buf).decompress() {
|
||||
Some(point) => {
|
||||
if point == Self::identity() {
|
||||
Err(Error::InvalidIdentityElement)
|
||||
Err(GroupError::InvalidIdentityElement)
|
||||
} else if point.is_torsion_free() {
|
||||
Ok(point)
|
||||
} else {
|
||||
Err(Error::InvalidNonPrimeOrderElement)
|
||||
Err(GroupError::InvalidNonPrimeOrderElement)
|
||||
}
|
||||
}
|
||||
None => Err(Error::MalformedElement),
|
||||
None => Err(GroupError::MalformedElement),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -129,7 +130,7 @@ fn hash_to_scalar(inputs: &[&[u8]]) -> Scalar {
|
|||
/// [spec]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-11.html#section-6.3-1
|
||||
const CONTEXT_STRING: &str = "FROST-ED448-SHAKE256-v11";
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
/// An implementation of the FROST(Ed448, SHAKE256) ciphersuite.
|
||||
pub struct Ed448Shake256;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use ed448_goldilocks::curve::ExtendedPoint;
|
||||
use frost_core::{Ciphersuite, Group};
|
||||
use frost_core::{Ciphersuite, Group, GroupError};
|
||||
use frost_ed448::*;
|
||||
use rand::thread_rng;
|
||||
|
||||
|
@ -40,5 +40,5 @@ fn check_deserialize_identity() {
|
|||
let encoded_identity = ExtendedPoint::identity().compress().0;
|
||||
|
||||
let r = <<Ed448Shake256 as Ciphersuite>::Group as Group>::deserialize(&encoded_identity);
|
||||
assert_eq!(r, Err(Error::InvalidIdentityElement));
|
||||
assert_eq!(r, Err(GroupError::InvalidIdentityElement));
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ let (shares, pubkeys) = frost::keys::keygen_with_dealer(max_signers, min_signers
|
|||
let key_packages: HashMap<_, _> = shares
|
||||
.into_iter()
|
||||
.map(|share| Ok((share.identifier, frost::keys::KeyPackage::try_from(share)?)))
|
||||
.collect::<Result<_, _>>()?;
|
||||
.collect::<Result<_, frost::Error>>()?;
|
||||
|
||||
let mut nonces = HashMap::new();
|
||||
let mut commitments = HashMap::new();
|
||||
|
|
|
@ -14,12 +14,13 @@ use p256::{
|
|||
use rand_core::{CryptoRng, RngCore};
|
||||
use sha2::{digest::Update, Digest, Sha256};
|
||||
|
||||
use frost_core::{frost, Ciphersuite, Field, Group};
|
||||
use frost_core::{frost, Ciphersuite, Field, FieldError, Group, GroupError};
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
pub use frost_core::Error;
|
||||
/// An error.
|
||||
pub type Error = frost_core::Error<P256Sha256>;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
/// An implementation of the FROST(P-256, SHA-256) ciphersuite scalar field.
|
||||
|
@ -38,11 +39,11 @@ impl Field for P256ScalarField {
|
|||
Scalar::ONE
|
||||
}
|
||||
|
||||
fn invert(scalar: &Self::Scalar) -> Result<Self::Scalar, Error> {
|
||||
fn invert(scalar: &Self::Scalar) -> Result<Self::Scalar, FieldError> {
|
||||
// [`p256::Scalar`]'s Eq/PartialEq does a constant-time comparison using
|
||||
// `ConstantTimeEq`
|
||||
if *scalar == <Self as Field>::zero() {
|
||||
Err(Error::InvalidZeroScalar)
|
||||
Err(FieldError::InvalidZeroScalar)
|
||||
} else {
|
||||
Ok(scalar.invert().unwrap())
|
||||
}
|
||||
|
@ -56,11 +57,11 @@ impl Field for P256ScalarField {
|
|||
scalar.to_bytes().into()
|
||||
}
|
||||
|
||||
fn deserialize(buf: &Self::Serialization) -> Result<Self::Scalar, Error> {
|
||||
fn deserialize(buf: &Self::Serialization) -> Result<Self::Scalar, FieldError> {
|
||||
let field_bytes: &p256::FieldBytes = buf.into();
|
||||
match Scalar::from_repr(*field_bytes).into() {
|
||||
Some(s) => Ok(s),
|
||||
None => Err(Error::MalformedScalar),
|
||||
None => Err(FieldError::MalformedScalar),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -119,9 +120,9 @@ impl Group for P256Group {
|
|||
fixed_serialized
|
||||
}
|
||||
|
||||
fn deserialize(buf: &Self::Serialization) -> Result<Self::Element, Error> {
|
||||
fn deserialize(buf: &Self::Serialization) -> Result<Self::Element, GroupError> {
|
||||
let encoded_point =
|
||||
p256::EncodedPoint::from_bytes(buf).map_err(|_| Error::MalformedElement)?;
|
||||
p256::EncodedPoint::from_bytes(buf).map_err(|_| GroupError::MalformedElement)?;
|
||||
|
||||
match Option::<AffinePoint>::from(AffinePoint::from_encoded_point(&encoded_point)) {
|
||||
Some(point) => {
|
||||
|
@ -129,12 +130,12 @@ impl Group for P256Group {
|
|||
// This is actually impossible since the identity is encoded a a single byte
|
||||
// which will never happen since we receive a 33-byte buffer.
|
||||
// We leave the check for consistency.
|
||||
Err(Error::InvalidIdentityElement)
|
||||
Err(GroupError::InvalidIdentityElement)
|
||||
} else {
|
||||
Ok(ProjectivePoint::from(point))
|
||||
}
|
||||
}
|
||||
None => Err(Error::MalformedElement),
|
||||
None => Err(GroupError::MalformedElement),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -144,7 +145,7 @@ impl Group for P256Group {
|
|||
/// [spec]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-11.html#section-6.4-1
|
||||
const CONTEXT_STRING: &str = "FROST-P256-SHA256-v11";
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
/// An implementation of the FROST(P-256, SHA-256) ciphersuite.
|
||||
pub struct P256Sha256;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use frost_core::{Ciphersuite, Group};
|
||||
use frost_core::{Ciphersuite, Group, GroupError};
|
||||
use frost_p256::*;
|
||||
use rand::thread_rng;
|
||||
|
||||
|
@ -37,5 +37,5 @@ fn check_deserialize_identity() {
|
|||
let encoded_identity = [0u8; 33];
|
||||
|
||||
let r = <<P256Sha256 as Ciphersuite>::Group as Group>::deserialize(&encoded_identity);
|
||||
assert_eq!(r, Err(Error::MalformedElement));
|
||||
assert_eq!(r, Err(GroupError::MalformedElement));
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ let (shares, pubkeys) = frost::keys::keygen_with_dealer(max_signers, min_signers
|
|||
let key_packages: HashMap<_, _> = shares
|
||||
.into_iter()
|
||||
.map(|share| Ok((share.identifier, frost::keys::KeyPackage::try_from(share)?)))
|
||||
.collect::<Result<_, _>>()?;
|
||||
.collect::<Result<_, frost::Error>>()?;
|
||||
|
||||
let mut nonces = HashMap::new();
|
||||
let mut commitments = HashMap::new();
|
||||
|
|
|
@ -11,12 +11,13 @@ use curve25519_dalek::{
|
|||
use rand_core::{CryptoRng, RngCore};
|
||||
use sha2::{digest::Update, Digest, Sha512};
|
||||
|
||||
use frost_core::{frost, Ciphersuite, Field, Group};
|
||||
use frost_core::{frost, Ciphersuite, Field, FieldError, Group, GroupError};
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
pub use frost_core::Error;
|
||||
/// An error.
|
||||
pub type Error = frost_core::Error<Ristretto255Sha512>;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
/// An implementation of the FROST(ristretto255, SHA-512) ciphersuite scalar field.
|
||||
|
@ -35,11 +36,11 @@ impl Field for RistrettoScalarField {
|
|||
Scalar::one()
|
||||
}
|
||||
|
||||
fn invert(scalar: &Self::Scalar) -> Result<Self::Scalar, Error> {
|
||||
fn invert(scalar: &Self::Scalar) -> Result<Self::Scalar, FieldError> {
|
||||
// [`curve25519_dalek::scalar::Scalar`]'s Eq/PartialEq does a constant-time comparison using
|
||||
// `ConstantTimeEq`
|
||||
if *scalar == <Self as Field>::zero() {
|
||||
Err(Error::InvalidZeroScalar)
|
||||
Err(FieldError::InvalidZeroScalar)
|
||||
} else {
|
||||
Ok(scalar.invert())
|
||||
}
|
||||
|
@ -53,10 +54,10 @@ impl Field for RistrettoScalarField {
|
|||
scalar.to_bytes()
|
||||
}
|
||||
|
||||
fn deserialize(buf: &Self::Serialization) -> Result<Self::Scalar, Error> {
|
||||
fn deserialize(buf: &Self::Serialization) -> Result<Self::Scalar, FieldError> {
|
||||
match Scalar::from_canonical_bytes(*buf) {
|
||||
Some(s) => Ok(s),
|
||||
None => Err(Error::MalformedScalar),
|
||||
None => Err(FieldError::MalformedScalar),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -92,16 +93,16 @@ impl Group for RistrettoGroup {
|
|||
element.compress().to_bytes()
|
||||
}
|
||||
|
||||
fn deserialize(buf: &Self::Serialization) -> Result<Self::Element, Error> {
|
||||
fn deserialize(buf: &Self::Serialization) -> Result<Self::Element, GroupError> {
|
||||
match CompressedRistretto::from_slice(buf.as_ref()).decompress() {
|
||||
Some(point) => {
|
||||
if point == Self::identity() {
|
||||
Err(Error::InvalidIdentityElement)
|
||||
Err(GroupError::InvalidIdentityElement)
|
||||
} else {
|
||||
Ok(point)
|
||||
}
|
||||
}
|
||||
None => Err(Error::MalformedElement),
|
||||
None => Err(GroupError::MalformedElement),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -111,7 +112,7 @@ impl Group for RistrettoGroup {
|
|||
/// [spec]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-11.html#section-6.2-1
|
||||
const CONTEXT_STRING: &str = "FROST-RISTRETTO255-SHA512-v11";
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
/// An implementation of the FROST(ristretto255, SHA-512) ciphersuite.
|
||||
pub struct Ristretto255Sha512;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use curve25519_dalek::{ristretto::RistrettoPoint, traits::Identity};
|
||||
use frost_core::{Ciphersuite, Group};
|
||||
use frost_core::{Ciphersuite, Group, GroupError};
|
||||
use frost_ristretto255::*;
|
||||
use rand::thread_rng;
|
||||
|
||||
|
@ -36,5 +36,5 @@ fn check_deserialize_identity() {
|
|||
let encoded_identity = RistrettoPoint::identity().compress().to_bytes();
|
||||
|
||||
let r = <<Ristretto255Sha512 as Ciphersuite>::Group as Group>::deserialize(&encoded_identity);
|
||||
assert_eq!(r, Err(Error::InvalidIdentityElement));
|
||||
assert_eq!(r, Err(GroupError::InvalidIdentityElement));
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ let (shares, pubkeys) = frost::keys::keygen_with_dealer(max_signers, min_signers
|
|||
let key_packages: HashMap<_, _> = shares
|
||||
.into_iter()
|
||||
.map(|share| Ok((share.identifier, frost::keys::KeyPackage::try_from(share)?)))
|
||||
.collect::<Result<_, _>>()?;
|
||||
.collect::<Result<_, frost::Error>>()?;
|
||||
|
||||
let mut nonces = HashMap::new();
|
||||
let mut commitments = HashMap::new();
|
||||
|
|
|
@ -16,12 +16,13 @@ use k256::{
|
|||
use rand_core::{CryptoRng, RngCore};
|
||||
use sha2::{digest::Update, Digest, Sha256};
|
||||
|
||||
use frost_core::{frost, Ciphersuite, Field, Group};
|
||||
use frost_core::{frost, Ciphersuite, Field, FieldError, Group, GroupError};
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
pub use frost_core::Error;
|
||||
/// An error.
|
||||
pub type Error = frost_core::Error<Secp256K1Sha256>;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
/// An implementation of the FROST(secp256k1, SHA-256) ciphersuite scalar field.
|
||||
|
@ -40,10 +41,10 @@ impl Field for Secp256K1ScalarField {
|
|||
Scalar::ONE
|
||||
}
|
||||
|
||||
fn invert(scalar: &Self::Scalar) -> Result<Self::Scalar, Error> {
|
||||
fn invert(scalar: &Self::Scalar) -> Result<Self::Scalar, FieldError> {
|
||||
// [`Scalar`]'s Eq/PartialEq does a constant-time comparison
|
||||
if *scalar == <Self as Field>::zero() {
|
||||
Err(Error::InvalidZeroScalar)
|
||||
Err(FieldError::InvalidZeroScalar)
|
||||
} else {
|
||||
Ok(scalar.invert().unwrap())
|
||||
}
|
||||
|
@ -57,11 +58,11 @@ impl Field for Secp256K1ScalarField {
|
|||
scalar.to_bytes().into()
|
||||
}
|
||||
|
||||
fn deserialize(buf: &Self::Serialization) -> Result<Self::Scalar, Error> {
|
||||
fn deserialize(buf: &Self::Serialization) -> Result<Self::Scalar, FieldError> {
|
||||
let field_bytes: &k256::FieldBytes = buf.into();
|
||||
match Scalar::from_repr(*field_bytes).into() {
|
||||
Some(s) => Ok(s),
|
||||
None => Err(Error::MalformedScalar),
|
||||
None => Err(FieldError::MalformedScalar),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -121,9 +122,9 @@ impl Group for Secp256K1Group {
|
|||
fixed_serialized
|
||||
}
|
||||
|
||||
fn deserialize(buf: &Self::Serialization) -> Result<Self::Element, Error> {
|
||||
fn deserialize(buf: &Self::Serialization) -> Result<Self::Element, GroupError> {
|
||||
let encoded_point =
|
||||
k256::EncodedPoint::from_bytes(buf).map_err(|_| Error::MalformedElement)?;
|
||||
k256::EncodedPoint::from_bytes(buf).map_err(|_| GroupError::MalformedElement)?;
|
||||
|
||||
match Option::<AffinePoint>::from(AffinePoint::from_encoded_point(&encoded_point)) {
|
||||
Some(point) => {
|
||||
|
@ -131,12 +132,12 @@ impl Group for Secp256K1Group {
|
|||
// This is actually impossible since the identity is encoded a a single byte
|
||||
// which will never happen since we receive a 33-byte buffer.
|
||||
// We leave the check for consistency.
|
||||
Err(Error::InvalidIdentityElement)
|
||||
Err(GroupError::InvalidIdentityElement)
|
||||
} else {
|
||||
Ok(ProjectivePoint::from(point))
|
||||
}
|
||||
}
|
||||
None => Err(Error::MalformedElement),
|
||||
None => Err(GroupError::MalformedElement),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -172,7 +173,7 @@ fn hash_to_field(msg: &[u8], dst: &[u8]) -> Scalar {
|
|||
/// [spec]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-11.html#section-6.5-1
|
||||
const CONTEXT_STRING: &str = "FROST-secp256k1-SHA256-v11";
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
/// An implementation of the FROST(secp256k1, SHA-256) ciphersuite.
|
||||
pub struct Secp256K1Sha256;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use frost_core::{Ciphersuite, Group};
|
||||
use frost_core::{Ciphersuite, Group, GroupError};
|
||||
use frost_secp256k1::*;
|
||||
use rand::thread_rng;
|
||||
|
||||
|
@ -37,5 +37,5 @@ fn check_deserialize_identity() {
|
|||
let encoded_identity = [0u8; 33];
|
||||
|
||||
let r = <<Secp256K1Sha256 as Ciphersuite>::Group as Group>::deserialize(&encoded_identity);
|
||||
assert_eq!(r, Err(Error::MalformedElement));
|
||||
assert_eq!(r, Err(GroupError::MalformedElement));
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue