Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add error type to FROST #88

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions src/batch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ impl Item {
/// borrowing the message data, the `Item` type is unlinked from the lifetime of
/// the message.
#[allow(non_snake_case)]
pub fn verify_single(self) -> Result<(), Error> {
pub fn verify_single(self) -> Result<(), SignatureError> {
match self.inner {
Inner::Binding { vk_bytes, sig, c } => VerificationKey::<Binding>::try_from(vk_bytes)
.and_then(|vk| vk.verify_prehashed(&sig, c)),
Expand Down Expand Up @@ -178,7 +178,7 @@ impl Verifier {
///
/// [ps]: https://zips.z.cash/protocol/protocol.pdf#reddsabatchverify
#[allow(non_snake_case)]
pub fn verify<R: RngCore + CryptoRng>(self, mut rng: R) -> Result<(), Error> {
pub fn verify<R: RngCore + CryptoRng>(self, mut rng: R) -> Result<(), SignatureError> {
let n = self.signatures.len();

let mut VK_coeffs = Vec::with_capacity(n);
Expand All @@ -200,7 +200,7 @@ impl Verifier {
if maybe_scalar.is_some().into() {
maybe_scalar.unwrap()
} else {
return Err(Error::InvalidSignature);
return Err(SignatureError::Invalid);
}
};

Expand All @@ -211,7 +211,7 @@ impl Verifier {
if maybe_point.is_some().into() {
jubjub::ExtendedPoint::from(maybe_point.unwrap())
} else {
return Err(Error::InvalidSignature);
return Err(SignatureError::Invalid);
}
};

Expand Down Expand Up @@ -258,7 +258,7 @@ impl Verifier {
if check.is_small_order().into() {
Ok(())
} else {
Err(Error::InvalidSignature)
Err(SignatureError::Invalid)
}
}
}
42 changes: 40 additions & 2 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use thiserror::Error;

/// An error related to RedJubJub signatures.
#[derive(Error, Debug, Copy, Clone, Eq, PartialEq)]
pub enum Error {
pub enum SignatureError {
/// The encoding of a signing key was malformed.
#[error("Malformed signing key encoding.")]
MalformedSigningKey,
Expand All @@ -21,5 +21,43 @@ pub enum Error {
MalformedVerificationKey,
/// Signature verification failed.
#[error("Invalid signature.")]
InvalidSignature,
Invalid,
}

/// An error related to FROST functions.
#[derive(Error, Debug, Copy, Clone, Eq, PartialEq)]
pub enum FrostError {
/// Share verification failed.
#[error("Share is invalid.")]
InvalidShare,
/// The threshold must be greater than 0.
#[error("Threshold cannot be 0.")]
ZeroThreshold,
/// The number of shares must be greater than 0.
#[error("Number of shares cannot be 0.")]
ZeroShares,
/// The threshold must be smaller or equal than the number of shares.
#[error("Threshold cannot exceed numshares.")]
ThresholdExceedShares,
/// Share signature verification.
#[error("Invalid signature share")]
InvalidSignatureShare,
/// The commitment must not be the identity.
#[error("Commitment equals the identity.")]
IdentiyCommitment,
/// The shares provided must not be duplicated.
#[error("Duplicate shares provided")]
DuplicateShares,
/// At least 1 share must be provided.
#[error("No shares provided")]
NoShares,
/// No match in the commitment index.
#[error("No matching commitment index")]
NoMatchCommitment,
/// No match in the binding.
#[error("No matching binding")]
NoMatchBinding,
/// No match in the signing commitment.
#[error("No matching signing commitment for signer")]
NoMatchSigningCommitment,
}
48 changes: 24 additions & 24 deletions src/frost.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ use rand_core::{CryptoRng, RngCore};
use zeroize::DefaultIsZeroes;

use crate::private::Sealed;
use crate::{HStar, Signature, SpendAuth, VerificationKey};
use crate::{error::FrostError, HStar, Signature, SpendAuth, VerificationKey};

/// A secret scalar value representing a single signer's secret key.
#[derive(Clone, Copy, Default)]
Expand Down Expand Up @@ -112,7 +112,7 @@ pub struct SharePackage {
}

impl TryFrom<SharePackage> for KeyPackage {
type Error = &'static str;
type Error = FrostError;

/// Tries to verify a share and construct a [`KeyPackage`] from it.
///
Expand All @@ -122,7 +122,7 @@ impl TryFrom<SharePackage> for KeyPackage {
/// 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(sharepackage: SharePackage) -> Result<Self, &'static str> {
fn try_from(sharepackage: SharePackage) -> Result<Self, FrostError> {
verify_share(&sharepackage.share)?;

Ok(KeyPackage {
Expand Down Expand Up @@ -172,7 +172,7 @@ pub fn keygen_with_dealer<R: RngCore + CryptoRng>(
num_signers: u8,
threshold: u8,
mut rng: R,
) -> Result<(Vec<SharePackage>, PublicKeyPackage), &'static str> {
) -> Result<(Vec<SharePackage>, PublicKeyPackage), FrostError> {
let mut bytes = [0; 64];
rng.fill_bytes(&mut bytes);

Expand Down Expand Up @@ -209,7 +209,7 @@ pub fn keygen_with_dealer<R: RngCore + CryptoRng>(
/// mechanism as all other signing participants. Note that participants *MUST*
/// ensure that they have the same view as all other participants of the
/// commitment!
fn verify_share(share: &Share) -> Result<(), &'static str> {
fn verify_share(share: &Share) -> Result<(), FrostError> {
let f_result = SpendAuth::basepoint() * share.value.0;

let x = Scalar::from(share.receiver_index as u64);
Expand All @@ -220,7 +220,7 @@ fn verify_share(share: &Share) -> Result<(), &'static str> {
);

if !(f_result == result) {
return Err("Share is invalid.");
return Err(FrostError::InvalidShare);
}

Ok(())
Expand All @@ -246,17 +246,17 @@ fn generate_shares<R: RngCore + CryptoRng>(
numshares: u8,
threshold: u8,
mut rng: R,
) -> Result<Vec<Share>, &'static str> {
) -> Result<Vec<Share>, FrostError> {
if threshold < 1 {
return Err("Threshold cannot be 0");
return Err(FrostError::ZeroThreshold);
}

if numshares < 1 {
return Err("Number of shares cannot be 0");
return Err(FrostError::ZeroShares);
}

if threshold > numshares {
return Err("Threshold cannot exceed numshares");
return Err(FrostError::ThresholdExceedShares);
}

let numcoeffs = threshold - 1;
Expand Down Expand Up @@ -411,11 +411,11 @@ impl SignatureShare {
lambda_i: Scalar,
commitment: jubjub::ExtendedPoint,
challenge: Scalar,
) -> Result<(), &'static str> {
) -> Result<(), FrostError> {
if (SpendAuth::basepoint() * self.signature)
!= (commitment + pubkey.0 * challenge * lambda_i)
{
return Err("Invalid signature share");
return Err(FrostError::InvalidSignatureShare);
}
Ok(())
}
Expand Down Expand Up @@ -481,20 +481,20 @@ fn gen_rho_i(index: u8, signing_package: &SigningPackage) -> Scalar {
fn gen_group_commitment(
signing_package: &SigningPackage,
bindings: &HashMap<u8, Scalar>,
) -> Result<GroupCommitment, &'static str> {
) -> Result<GroupCommitment, FrostError> {
let identity = jubjub::ExtendedPoint::identity();
let mut accumulator = identity;

for commitment in signing_package.signing_commitments.iter() {
// The following check prevents a party from accidentally revealing their share.
// Note that the '&&' operator would be sufficient.
if identity == commitment.binding || identity == commitment.hiding {
return Err("Commitment equals the identity.");
return Err(FrostError::IdentiyCommitment);
}

let rho_i = bindings
.get(&commitment.index)
.ok_or("No matching commitment index")?;
.ok_or(FrostError::NoMatchCommitment)?;
accumulator += commitment.hiding + (commitment.binding * rho_i)
}

Expand All @@ -520,7 +520,7 @@ fn gen_challenge(
fn gen_lagrange_coeff(
signer_index: u8,
signing_package: &SigningPackage,
) -> Result<Scalar, &'static str> {
) -> Result<Scalar, FrostError> {
let mut num = Scalar::one();
let mut den = Scalar::one();
for commitment in signing_package.signing_commitments.iter() {
Expand All @@ -532,7 +532,7 @@ fn gen_lagrange_coeff(
}

if den == Scalar::zero() {
return Err("Duplicate shares provided");
return Err(FrostError::DuplicateShares);
}

// TODO: handle this unwrap better like other CtOption's
Expand All @@ -553,7 +553,7 @@ pub fn sign(
signing_package: &SigningPackage,
participant_nonces: SigningNonces,
share_package: &SharePackage,
) -> Result<SignatureShare, &'static str> {
) -> Result<SignatureShare, FrostError> {
let mut bindings: HashMap<u8, Scalar> =
HashMap::with_capacity(signing_package.signing_commitments.len());

Expand All @@ -574,7 +574,7 @@ pub fn sign(

let participant_rho_i = bindings
.get(&share_package.index)
.ok_or("No matching binding!")?;
.ok_or(FrostError::NoMatchBinding)?;

// The Schnorr signature share
let signature: Scalar = participant_nonces.hiding
Expand Down Expand Up @@ -606,7 +606,7 @@ pub fn aggregate(
signing_package: &SigningPackage,
signing_shares: &[SignatureShare],
pubkeys: &PublicKeyPackage,
) -> Result<Signature<SpendAuth>, &'static str> {
) -> Result<Signature<SpendAuth>, FrostError> {
let mut bindings: HashMap<u8, Scalar> =
HashMap::with_capacity(signing_package.signing_commitments.len());

Expand All @@ -626,7 +626,7 @@ pub fn aggregate(
.signing_commitments
.iter()
.find(|comm| comm.index == signing_share.index)
.ok_or("No matching signing commitment for signer")?;
.ok_or(FrostError::NoMatchSigningCommitment)?;

let commitment_i =
signer_commitment.hiding + (signer_commitment.binding * bindings[&signing_share.index]);
Expand All @@ -653,11 +653,11 @@ mod tests {
use super::*;
use rand::thread_rng;

fn reconstruct_secret(shares: Vec<Share>) -> Result<Scalar, &'static str> {
fn reconstruct_secret(shares: Vec<Share>) -> Result<Scalar, FrostError> {
let numshares = shares.len();

if numshares < 1 {
return Err("No shares provided");
return Err(FrostError::NoShares);
}

let mut lagrange_coeffs: Vec<Scalar> = Vec::with_capacity(numshares as usize);
Expand All @@ -674,7 +674,7 @@ mod tests {
- Scalar::from(shares[i].receiver_index as u64);
}
if den == Scalar::zero() {
return Err("Duplicate shares provided");
return Err(FrostError::DuplicateShares);
}
lagrange_coeffs.push(num * den.invert().unwrap());
}
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ pub type Randomizer = jubjub::Scalar;

use hash::HStar;

pub use error::Error;
pub use error::SignatureError;
pub use signature::Signature;
pub use signing_key::SigningKey;
pub use verification_key::{VerificationKey, VerificationKeyBytes};
Expand Down
8 changes: 4 additions & 4 deletions src/signing_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use std::{
marker::PhantomData,
};

use crate::{Error, Randomizer, SigType, Signature, SpendAuth, VerificationKey};
use crate::{error::SignatureError, Randomizer, SigType, Signature, SpendAuth, VerificationKey};

use jubjub::Scalar;
use rand_core::{CryptoRng, RngCore};
Expand Down Expand Up @@ -42,7 +42,7 @@ impl<T: SigType> From<SigningKey<T>> for [u8; 32] {
}

impl<T: SigType> TryFrom<[u8; 32]> for SigningKey<T> {
type Error = Error;
type Error = SignatureError;

fn try_from(bytes: [u8; 32]) -> Result<Self, Self::Error> {
// XXX-jubjub: this should not use CtOption
Expand All @@ -52,7 +52,7 @@ impl<T: SigType> TryFrom<[u8; 32]> for SigningKey<T> {
let pk = VerificationKey::from(&sk);
Ok(SigningKey { sk, pk })
} else {
Err(Error::MalformedSigningKey)
Err(SignatureError::MalformedSigningKey)
}
}
}
Expand All @@ -61,7 +61,7 @@ impl<T: SigType> TryFrom<[u8; 32]> for SigningKey<T> {
struct SerdeHelper([u8; 32]);

impl<T: SigType> TryFrom<SerdeHelper> for SigningKey<T> {
type Error = Error;
type Error = SignatureError;

fn try_from(helper: SerdeHelper) -> Result<Self, Self::Error> {
helper.0.try_into()
Expand Down
Loading