241 lines
9.2 KiB
Rust
241 lines
9.2 KiB
Rust
#![allow(non_snake_case)]
|
|
#![deny(missing_docs)]
|
|
#![doc = include_str!("../README.md")]
|
|
#![forbid(unsafe_code)]
|
|
|
|
use std::{
|
|
default::Default,
|
|
fmt::Debug,
|
|
ops::{Add, Mul, Sub},
|
|
};
|
|
|
|
use hex::FromHex;
|
|
use rand_core::{CryptoRng, RngCore};
|
|
|
|
// pub mod batch;
|
|
mod error;
|
|
pub mod frost;
|
|
// mod scalar_mul;
|
|
mod signature;
|
|
mod signing_key;
|
|
mod verifying_key;
|
|
|
|
pub use error::Error;
|
|
pub use signature::Signature;
|
|
pub use signing_key::SigningKey;
|
|
pub use verifying_key::VerifyingKey;
|
|
|
|
/// A prime order finite field GF(q) over which all scalar values for our prime order group can be
|
|
/// multiplied are defined.
|
|
///
|
|
/// This trait does not have to be implemented for a finite field scalar itself, it can be a
|
|
/// pass-through, implemented for a type just for the ciphersuite, and calls through to another
|
|
/// implementation underneath, so that this trait does not have to be implemented for types you
|
|
/// don't own.
|
|
pub trait Field: Copy + Clone {
|
|
/// An element of the scalar field GF(p).
|
|
type Scalar: Add<Output = Self::Scalar>
|
|
+ Copy
|
|
+ Clone
|
|
+ Eq
|
|
+ Mul<Output = Self::Scalar>
|
|
+ PartialEq
|
|
+ Sub<Output = Self::Scalar>;
|
|
|
|
/// A unique byte array buf of fixed length N.
|
|
///
|
|
/// Little-endian!
|
|
type Serialization: AsRef<[u8]> + AsMut<[u8]> + Debug + Default + FromHex + TryFrom<Vec<u8>>;
|
|
|
|
/// Returns the zero element of the field, the additive identity.
|
|
fn zero() -> Self::Scalar;
|
|
|
|
/// Returns the one element of the field, the multiplicative identity.
|
|
fn one() -> Self::Scalar;
|
|
|
|
/// 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>;
|
|
|
|
/// Generate a random scalar from the entire space [0, l-1]
|
|
///
|
|
/// <https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-04.html#section-3.1-3.3>
|
|
fn random<R: RngCore + CryptoRng>(rng: &mut R) -> Self::Scalar;
|
|
|
|
/// Generate a random scalar from the entire space [1, l-1]
|
|
///
|
|
/// <https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-04.html#section-3.1-3.4>
|
|
fn random_nonzero<R: RngCore + CryptoRng>(rng: &mut R) -> Self::Scalar;
|
|
|
|
/// A member function of a group _G_ that maps an [`Element`] to a unique byte array buf of
|
|
/// fixed length Ne.
|
|
///
|
|
/// <https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-04.html#section-3.1-3.5>
|
|
fn serialize(scalar: &Self::Scalar) -> Self::Serialization;
|
|
|
|
/// A member function of a [`Group`] that attempts to map a byte array `buf` to an [`Element`].
|
|
///
|
|
/// Fails if the input is not a valid byte representation of an [`Element`] of the
|
|
/// [`Group`]. This function can raise a [`DeserializeError`] if deserialization fails or if the
|
|
/// resulting [`Element`] is the identity element of the group
|
|
///
|
|
/// <https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-04.html#section-3.1-3.6>
|
|
fn deserialize(buf: &Self::Serialization) -> Result<Self::Scalar, Error>;
|
|
}
|
|
|
|
/// An element of the [`Ciphersuite`] `C`'s [`Group`]'s scalar [`Field`].
|
|
pub type Scalar<C> = <<<C as Ciphersuite>::Group as Group>::Field as Field>::Scalar;
|
|
|
|
/// A prime-order group (or subgroup) that provides everything we need to create and verify Schnorr
|
|
/// signatures.
|
|
///
|
|
/// This trait does not have to be implemented for the curve/element/point itself, it can be a
|
|
/// pass-through, implemented for a type just for the ciphersuite, and calls through to another
|
|
/// implementation underneath, so that this trait does not have to be implemented for types you
|
|
/// don't own.
|
|
pub trait Group: Copy + Clone {
|
|
/// A prime order finite field GF(q) over which all scalar values for our prime order group can
|
|
/// be multiplied are defined.
|
|
type Field: Field;
|
|
|
|
/// An element of our group that we will be computing over.
|
|
type Element: Add<Output = Self::Element>
|
|
+ Copy
|
|
+ Clone
|
|
+ Eq
|
|
+ Mul<<Self::Field as Field>::Scalar, Output = Self::Element>
|
|
+ PartialEq
|
|
+ Sub<Output = Self::Element>;
|
|
|
|
/// A unique byte array buf of fixed length N.
|
|
///
|
|
/// Little-endian!
|
|
type Serialization: AsRef<[u8]> + AsMut<[u8]> + Default + FromHex + TryFrom<Vec<u8>>;
|
|
|
|
/// Outputs the order of G (i.e. p)
|
|
///
|
|
/// <https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-04.html#section-3.1-3.1>
|
|
fn order() -> <Self::Field as Field>::Scalar;
|
|
|
|
/// The order of the the quotient group when the prime order subgroup divides the order of the
|
|
/// full curve group.
|
|
///
|
|
/// If using a prime order elliptic curve, the cofactor should be 1 in the scalar field.
|
|
///
|
|
/// <https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-04.html#section-4.1-3>
|
|
fn cofactor() -> <Self::Field as Field>::Scalar;
|
|
|
|
/// Additive [identity] of the prime order group.
|
|
///
|
|
/// [identity]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-04.html#section-3.1-3.2
|
|
fn identity() -> Self::Element;
|
|
|
|
/// The fixed generator element of the prime order group.
|
|
///
|
|
/// The 'base' of [`ScalarBaseMult()`] from the spec.
|
|
/// [`ScalarBaseMult()`]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-04.html#section-3.1
|
|
fn generator() -> Self::Element;
|
|
|
|
/// A member function of a group _G_ that maps an [`Element`] to a unique byte array buf of
|
|
/// fixed length Ne.
|
|
///
|
|
/// <https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-04.html#section-3.1-3.5>
|
|
fn serialize(element: &Self::Element) -> Self::Serialization;
|
|
|
|
/// A member function of a [`Group`] that attempts to map a byte array `buf` to an [`Element`].
|
|
///
|
|
/// Fails if the input is not a valid byte representation of an [`Element`] of the
|
|
/// [`Group`]. This function can raise a [`DeserializeError`] if deserialization fails or if the
|
|
/// resulting [`Element`] is the identity element of the group
|
|
///
|
|
/// <https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-04.html#section-3.1-3.6>
|
|
fn deserialize(buf: &Self::Serialization) -> Result<Self::Element, Error>;
|
|
}
|
|
|
|
/// An element of the [`Ciphersuite`] `C`'s [`Group`].
|
|
pub type Element<C> = <<C as Ciphersuite>::Group as Group>::Element;
|
|
|
|
/// A [FROST ciphersuite] specifies the underlying prime-order group details and cryptographic hash
|
|
/// function.
|
|
///
|
|
/// [FROST ciphersuite]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-04.html#name-ciphersuites
|
|
pub trait Ciphersuite: Copy + Clone {
|
|
/// The prime order group (or subgroup) that this ciphersuite operates over.
|
|
type Group: Group;
|
|
|
|
/// A unique byte array of fixed length.
|
|
type HashOutput: AsRef<[u8]>;
|
|
|
|
/// A unique byte array of fixed length that is the `Group::ElementSerialization` +
|
|
/// `Group::ScalarSerialization`
|
|
type SignatureSerialization: AsRef<[u8]> + FromHex + TryFrom<Vec<u8>>;
|
|
|
|
/// [H1] for a FROST ciphersuite.
|
|
///
|
|
/// Maps arbitrary inputs to non-zero `Self::Scalar` elements of the prime-order group scalar field.
|
|
///
|
|
/// [H1]: https://github.com/cfrg/draft-irtf-cfrg-frost/blob/master/draft-irtf-cfrg-frost.md#cryptographic-hash
|
|
fn H1(m: &[u8]) -> <<Self::Group as Group>::Field as Field>::Scalar;
|
|
|
|
/// [H2] for a FROST ciphersuite.
|
|
///
|
|
/// Maps arbitrary inputs to non-zero `Self::Scalar` elements of the prime-order group scalar field.
|
|
///
|
|
/// [H2]: https://github.com/cfrg/draft-irtf-cfrg-frost/blob/master/draft-irtf-cfrg-frost.md#cryptographic-hash
|
|
fn H2(m: &[u8]) -> <<Self::Group as Group>::Field as Field>::Scalar;
|
|
|
|
/// H3 for a FROST ciphersuite.
|
|
///
|
|
/// Usually an an alias for the ciphersuite hash function _H_ with domain separation applied.
|
|
///
|
|
/// [spec]: https://github.com/cfrg/draft-irtf-cfrg-frost/blob/master/draft-irtf-cfrg-frost.md#cryptographic-hash
|
|
fn H3(m: &[u8]) -> Self::HashOutput;
|
|
}
|
|
|
|
/// A type refinement for the scalar field element representing the per-message _[challenge]_.
|
|
///
|
|
/// [challenge]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-04.html#name-signature-challenge-computa
|
|
#[derive(Clone)]
|
|
pub struct Challenge<C: Ciphersuite>(
|
|
pub(crate) <<<C as Ciphersuite>::Group as Group>::Field as Field>::Scalar,
|
|
);
|
|
|
|
impl<C> Debug for Challenge<C>
|
|
where
|
|
C: Ciphersuite,
|
|
{
|
|
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),
|
|
))
|
|
.finish()
|
|
}
|
|
}
|
|
|
|
/// Generates the challenge as is required for Schnorr signatures.
|
|
///
|
|
/// Deals in bytes, so that [FROST] and singleton signing and verification can use it with different
|
|
/// types.
|
|
///
|
|
/// This is the only invocation of the H2 hash function from the [RFC].
|
|
///
|
|
/// [FROST]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-04.html#section-4.6
|
|
/// [RFC]: https://www.ietf.org/archive/id/draft-irtf-cfrg-frost-04.html#section-3.2
|
|
fn challenge<C>(
|
|
R: &<C::Group as Group>::Element,
|
|
verifying_key: &<C::Group as Group>::Element,
|
|
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(msg);
|
|
|
|
Challenge(C::H2(&preimage[..]))
|
|
}
|