serai/crypto/frost/src/algorithm.rs
Luke Parker 7b4c5dbe52
Remove rng_seed's additional entropy
It was never used as we derive entropy via the other fields in the 
transcript, and explicitly add fields directly as needed for entropy.

Also drops an unused crate and corrects a bug in FROST's Schnorr 
implementation which used the Group's generator, instead of the Curve's.

Also updates the Monero crate's description.
2022-05-31 02:12:14 -04:00

167 lines
4 KiB
Rust

use core::{marker::PhantomData, fmt::Debug};
use rand_core::{RngCore, CryptoRng};
use transcript::Transcript;
use crate::{Curve, FrostError, MultisigView, schnorr};
pub use schnorr::SchnorrSignature;
/// Algorithm to use FROST with
pub trait Algorithm<C: Curve>: Clone {
type Transcript: Transcript + Clone + Debug;
/// The resulting type of the signatures this algorithm will produce
type Signature: Clone + PartialEq + Debug;
fn transcript(&mut self) -> &mut Self::Transcript;
/// Generate an addendum to FROST"s preprocessing stage
fn preprocess_addendum<R: RngCore + CryptoRng>(
&mut self,
rng: &mut R,
params: &MultisigView<C>,
nonces: &[C::F; 2],
) -> Vec<u8>;
/// Proccess the addendum for the specified participant. Guaranteed to be ordered
fn process_addendum(
&mut self,
params: &MultisigView<C>,
l: u16,
commitments: &[C::G; 2],
serialized: &[u8],
) -> Result<(), FrostError>;
/// 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,
params: &MultisigView<C>,
nonce_sum: C::G,
binding: C::F,
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;
}
// Transcript which will create an IETF compliant serialization for the binding factor
#[derive(Clone, Debug)]
pub struct IetfTranscript(Vec<u8>);
impl Transcript for IetfTranscript {
fn domain_separate(&mut self, _: &[u8]) {}
fn append_message(&mut self, _: &'static [u8], message: &[u8]) {
self.0.extend(message);
}
fn challenge(&mut self, _: &'static [u8]) -> Vec<u8> {
self.0.clone()
}
fn rng_seed(&mut self, _: &'static [u8]) -> [u8; 32] {
unimplemented!()
}
}
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)
#[allow(non_snake_case)]
fn hram(R: &C::G, A: &C::G, m: &[u8]) -> C::F;
}
#[derive(Clone)]
pub struct Schnorr<C: Curve, H: Hram<C>> {
transcript: IetfTranscript,
c: Option<C::F>,
_hram: PhantomData<H>,
}
impl<C: Curve, H: Hram<C>> Schnorr<C, H> {
pub fn new() -> Schnorr<C, H> {
Schnorr {
transcript: IetfTranscript(vec![]),
c: None,
_hram: PhantomData
}
}
}
/// Implementation of Schnorr signatures for use with FROST
impl<C: Curve, H: Hram<C>> Algorithm<C> for Schnorr<C, H> {
type Transcript = IetfTranscript;
type Signature = SchnorrSignature<C>;
fn transcript(&mut self) -> &mut Self::Transcript {
&mut self.transcript
}
fn preprocess_addendum<R: RngCore + CryptoRng>(
&mut self,
_: &mut R,
_: &MultisigView<C>,
_: &[C::F; 2],
) -> Vec<u8> {
vec![]
}
fn process_addendum(
&mut self,
_: &MultisigView<C>,
_: u16,
_: &[C::G; 2],
_: &[u8],
) -> Result<(), FrostError> {
Ok(())
}
fn sign_share(
&mut self,
params: &MultisigView<C>,
nonce_sum: C::G,
_: C::F,
nonce: C::F,
msg: &[u8],
) -> C::F {
let c = H::hram(&nonce_sum, &params.group_key(), msg);
self.c = Some(c);
schnorr::sign::<C>(params.secret_share(), nonce, c).s
}
fn verify(&self, group_key: C::G, nonce: C::G, sum: C::F) -> Option<Self::Signature> {
let sig = SchnorrSignature { R: nonce, s: sum };
if schnorr::verify::<C>(group_key, self.c.unwrap(), &sig) {
Some(sig)
} else {
None
}
}
fn verify_share(
&self,
verification_share: C::G,
nonce: C::G,
share: C::F,
) -> bool {
schnorr::verify::<C>(
verification_share,
self.c.unwrap(),
&SchnorrSignature { R: nonce, s: share}
)
}
}