2022-04-22 01:36:18 +00:00
|
|
|
use core::{marker::PhantomData, fmt::Debug};
|
|
|
|
|
|
|
|
use rand_core::{RngCore, CryptoRng};
|
|
|
|
|
|
|
|
use group::Group;
|
|
|
|
|
2022-05-03 11:20:24 +00:00
|
|
|
use transcript::{Transcript, DigestTranscript};
|
|
|
|
|
2022-04-30 08:32:19 +00:00
|
|
|
use crate::{Curve, FrostError, MultisigView};
|
2022-04-22 01:36:18 +00:00
|
|
|
|
2022-04-23 07:49:30 +00:00
|
|
|
/// Algorithm to use FROST with
|
|
|
|
pub trait Algorithm<C: Curve>: Clone {
|
2022-05-03 11:20:24 +00:00
|
|
|
type Transcript: Transcript + Clone + Debug;
|
2022-04-22 01:36:18 +00:00
|
|
|
/// The resulting type of the signatures this algorithm will produce
|
|
|
|
type Signature: Clone + Debug;
|
|
|
|
|
|
|
|
/// Generate an addendum to FROST"s preprocessing stage
|
|
|
|
fn preprocess_addendum<R: RngCore + CryptoRng>(
|
|
|
|
rng: &mut R,
|
2022-04-30 08:32:19 +00:00
|
|
|
params: &MultisigView<C>,
|
2022-04-22 01:36:18 +00:00
|
|
|
nonces: &[C::F; 2],
|
|
|
|
) -> Vec<u8>;
|
|
|
|
|
|
|
|
/// Proccess the addendum for the specified participant. Guaranteed to be ordered
|
|
|
|
fn process_addendum(
|
|
|
|
&mut self,
|
2022-04-30 08:32:19 +00:00
|
|
|
params: &MultisigView<C>,
|
2022-04-22 01:36:18 +00:00
|
|
|
l: usize,
|
|
|
|
commitments: &[C::G; 2],
|
|
|
|
serialized: &[u8],
|
|
|
|
) -> Result<(), FrostError>;
|
|
|
|
|
2022-05-03 11:20:24 +00:00
|
|
|
/// Transcript for this algorithm to be used to create the binding factor
|
|
|
|
fn transcript(&self) -> Option<Self::Transcript>;
|
2022-04-29 05:34:48 +00:00
|
|
|
|
2022-04-22 01:36:18 +00:00
|
|
|
/// Sign a share with the given secret/nonce
|
|
|
|
/// The secret will already have been its lagrange coefficient applied so it is the necessary
|
|
|
|
/// key share
|
|
|
|
/// The nonce will already have been processed into the combined form d + (e * p)
|
|
|
|
fn sign_share(
|
|
|
|
&mut self,
|
2022-04-30 08:32:19 +00:00
|
|
|
params: &MultisigView<C>,
|
2022-04-22 01:36:18 +00:00
|
|
|
nonce_sum: C::G,
|
2022-04-30 02:03:34 +00:00
|
|
|
b: C::F,
|
2022-04-22 01:36:18 +00:00
|
|
|
nonce: C::F,
|
|
|
|
msg: &[u8],
|
|
|
|
) -> C::F;
|
|
|
|
|
|
|
|
/// Verify a signature
|
|
|
|
fn verify(&self, group_key: C::G, nonce: C::G, sum: C::F) -> Option<Self::Signature>;
|
|
|
|
|
|
|
|
/// Verify a specific share given as a response. Used to determine blame if signature
|
|
|
|
/// verification fails
|
|
|
|
fn verify_share(
|
|
|
|
&self,
|
|
|
|
verification_share: C::G,
|
|
|
|
nonce: C::G,
|
|
|
|
share: C::F,
|
|
|
|
) -> bool;
|
|
|
|
}
|
|
|
|
|
2022-04-23 07:49:30 +00:00
|
|
|
pub trait Hram<C: Curve>: Clone {
|
|
|
|
/// HRAM function to generate a challenge
|
|
|
|
/// H2 from the IETF draft despite having a different argument set (not pre-formatted)
|
2022-04-22 01:36:18 +00:00
|
|
|
#[allow(non_snake_case)]
|
2022-04-23 07:49:30 +00:00
|
|
|
fn hram(R: &C::G, A: &C::G, m: &[u8]) -> C::F;
|
2022-04-22 01:36:18 +00:00
|
|
|
}
|
|
|
|
|
2022-04-23 07:49:30 +00:00
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct Schnorr<C: Curve, H: Hram<C>> {
|
2022-04-22 01:36:18 +00:00
|
|
|
c: Option<C::F>,
|
2022-04-23 07:49:30 +00:00
|
|
|
_hram: PhantomData<H>,
|
2022-04-22 01:36:18 +00:00
|
|
|
}
|
|
|
|
|
2022-04-23 07:49:30 +00:00
|
|
|
impl<C: Curve, H: Hram<C>> Schnorr<C, H> {
|
2022-04-22 01:36:18 +00:00
|
|
|
pub fn new() -> Schnorr<C, H> {
|
|
|
|
Schnorr {
|
|
|
|
c: None,
|
2022-04-23 07:49:30 +00:00
|
|
|
_hram: PhantomData
|
2022-04-22 01:36:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[allow(non_snake_case)]
|
|
|
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
|
|
|
pub struct SchnorrSignature<C: Curve> {
|
|
|
|
pub R: C::G,
|
|
|
|
pub s: C::F,
|
|
|
|
}
|
|
|
|
|
2022-04-23 07:49:30 +00:00
|
|
|
/// Implementation of Schnorr signatures for use with FROST
|
|
|
|
impl<C: Curve, H: Hram<C>> Algorithm<C> for Schnorr<C, H> {
|
2022-05-03 11:20:24 +00:00
|
|
|
// Specify a firm type which either won't matter as it won't be used or will be used (offset) and
|
|
|
|
// is accordingly solid
|
|
|
|
type Transcript = DigestTranscript::<blake2::Blake2b512>;
|
2022-04-22 01:36:18 +00:00
|
|
|
type Signature = SchnorrSignature<C>;
|
|
|
|
|
|
|
|
fn preprocess_addendum<R: RngCore + CryptoRng>(
|
|
|
|
_: &mut R,
|
2022-04-30 08:32:19 +00:00
|
|
|
_: &MultisigView<C>,
|
2022-04-22 01:36:18 +00:00
|
|
|
_: &[C::F; 2],
|
|
|
|
) -> Vec<u8> {
|
|
|
|
vec![]
|
|
|
|
}
|
|
|
|
|
|
|
|
fn process_addendum(
|
|
|
|
&mut self,
|
2022-04-30 08:32:19 +00:00
|
|
|
_: &MultisigView<C>,
|
2022-04-22 01:36:18 +00:00
|
|
|
_: usize,
|
|
|
|
_: &[C::G; 2],
|
|
|
|
_: &[u8],
|
|
|
|
) -> Result<(), FrostError> {
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2022-05-03 11:20:24 +00:00
|
|
|
fn transcript(&self) -> Option<DigestTranscript::<blake2::Blake2b512>> {
|
|
|
|
None
|
2022-04-29 05:34:48 +00:00
|
|
|
}
|
|
|
|
|
2022-04-22 01:36:18 +00:00
|
|
|
fn sign_share(
|
|
|
|
&mut self,
|
2022-04-30 08:32:19 +00:00
|
|
|
params: &MultisigView<C>,
|
2022-04-22 01:36:18 +00:00
|
|
|
nonce_sum: C::G,
|
2022-04-30 02:03:34 +00:00
|
|
|
_: C::F,
|
2022-04-22 01:36:18 +00:00
|
|
|
nonce: C::F,
|
|
|
|
msg: &[u8],
|
|
|
|
) -> C::F {
|
2022-04-23 07:49:30 +00:00
|
|
|
let c = H::hram(&nonce_sum, ¶ms.group_key(), msg);
|
2022-04-22 01:36:18 +00:00
|
|
|
self.c = Some(c);
|
|
|
|
|
|
|
|
nonce + (params.secret_share() * c)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn verify(&self, group_key: C::G, nonce: C::G, sum: C::F) -> Option<Self::Signature> {
|
|
|
|
if (C::generator_table() * sum) + (C::G::identity() - (group_key * self.c.unwrap())) == nonce {
|
|
|
|
Some(SchnorrSignature { R: nonce, s: sum })
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn verify_share(
|
|
|
|
&self,
|
|
|
|
verification_share: C::G,
|
|
|
|
nonce: C::G,
|
|
|
|
share: C::F,
|
|
|
|
) -> bool {
|
|
|
|
(C::generator_table() * share) == (nonce + (verification_share * self.c.unwrap()))
|
|
|
|
}
|
|
|
|
}
|