2022-05-24 21:41:14 -04:00
|
|
|
use core::fmt;
|
2022-07-13 02:38:29 -04:00
|
|
|
use std::{io::{Read, Cursor}, sync::Arc, collections::HashMap};
|
2022-04-21 21:36:18 -04:00
|
|
|
|
|
|
|
|
use rand_core::{RngCore, CryptoRng};
|
|
|
|
|
|
2022-05-03 07:20:24 -04:00
|
|
|
use transcript::Transcript;
|
|
|
|
|
|
2022-07-12 03:21:22 -04:00
|
|
|
use group::{ff::{Field, PrimeField}, Group, GroupEncoding};
|
|
|
|
|
use multiexp::multiexp_vartime;
|
|
|
|
|
|
2022-07-12 01:28:01 -04:00
|
|
|
use dleq::{Generators, DLEqProof};
|
|
|
|
|
|
2022-05-24 21:41:14 -04:00
|
|
|
use crate::{
|
2022-07-13 02:38:29 -04:00
|
|
|
curve::Curve,
|
|
|
|
|
FrostError, FrostParams, FrostKeys, FrostView,
|
2022-05-24 21:41:14 -04:00
|
|
|
algorithm::Algorithm,
|
|
|
|
|
validate_map
|
|
|
|
|
};
|
2022-04-21 21:36:18 -04:00
|
|
|
|
2022-06-28 00:06:12 -04:00
|
|
|
/// Pairing of an Algorithm with a FrostKeys instance and this specific signing set
|
2022-04-21 21:36:18 -04:00
|
|
|
#[derive(Clone)]
|
|
|
|
|
pub struct Params<C: Curve, A: Algorithm<C>> {
|
|
|
|
|
algorithm: A,
|
2022-06-28 00:06:12 -04:00
|
|
|
keys: Arc<FrostKeys<C>>,
|
|
|
|
|
view: FrostView<C>,
|
2022-04-21 21:36:18 -04:00
|
|
|
}
|
|
|
|
|
|
2022-04-29 22:36:43 -04:00
|
|
|
// Currently public to enable more complex operations as desired, yet solely used in testing
|
2022-04-21 21:36:18 -04:00
|
|
|
impl<C: Curve, A: Algorithm<C>> Params<C, A> {
|
|
|
|
|
pub fn new(
|
|
|
|
|
algorithm: A,
|
2022-06-28 00:06:12 -04:00
|
|
|
keys: Arc<FrostKeys<C>>,
|
2022-05-24 21:41:14 -04:00
|
|
|
included: &[u16],
|
2022-04-29 15:28:04 -04:00
|
|
|
) -> Result<Params<C, A>, FrostError> {
|
2022-04-21 21:36:18 -04:00
|
|
|
let mut included = included.to_vec();
|
|
|
|
|
(&mut included).sort_unstable();
|
|
|
|
|
|
2022-04-30 04:32:19 -04:00
|
|
|
// Included < threshold
|
2022-05-24 21:41:14 -04:00
|
|
|
if included.len() < usize::from(keys.params.t) {
|
2022-07-13 02:38:29 -04:00
|
|
|
Err(FrostError::InvalidSigningSet("not enough signers"))?;
|
2022-04-21 21:36:18 -04:00
|
|
|
}
|
|
|
|
|
// Invalid index
|
|
|
|
|
if included[0] == 0 {
|
|
|
|
|
Err(FrostError::InvalidParticipantIndex(included[0], keys.params.n))?;
|
|
|
|
|
}
|
|
|
|
|
// OOB index
|
|
|
|
|
if included[included.len() - 1] > keys.params.n {
|
|
|
|
|
Err(FrostError::InvalidParticipantIndex(included[included.len() - 1], keys.params.n))?;
|
|
|
|
|
}
|
|
|
|
|
// Same signer included multiple times
|
|
|
|
|
for i in 0 .. included.len() - 1 {
|
|
|
|
|
if included[i] == included[i + 1] {
|
2022-07-13 02:38:29 -04:00
|
|
|
Err(FrostError::DuplicatedIndex(included[i]))?;
|
2022-04-21 21:36:18 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Not included
|
|
|
|
|
if !included.contains(&keys.params.i) {
|
2022-07-13 02:38:29 -04:00
|
|
|
Err(FrostError::InvalidSigningSet("signing despite not being included"))?;
|
2022-04-21 21:36:18 -04:00
|
|
|
}
|
|
|
|
|
|
2022-04-30 04:32:19 -04:00
|
|
|
// Out of order arguments to prevent additional cloning
|
|
|
|
|
Ok(Params { algorithm, view: keys.view(&included).unwrap(), keys })
|
2022-04-21 21:36:18 -04:00
|
|
|
}
|
|
|
|
|
|
2022-06-28 00:06:12 -04:00
|
|
|
pub fn multisig_params(&self) -> FrostParams {
|
2022-04-21 21:36:18 -04:00
|
|
|
self.keys.params
|
|
|
|
|
}
|
2022-04-29 15:28:04 -04:00
|
|
|
|
2022-06-28 00:06:12 -04:00
|
|
|
pub fn view(&self) -> FrostView<C> {
|
2022-04-29 15:28:04 -04:00
|
|
|
self.view.clone()
|
|
|
|
|
}
|
2022-04-21 21:36:18 -04:00
|
|
|
}
|
|
|
|
|
|
2022-07-12 01:28:01 -04:00
|
|
|
fn nonce_transcript<T: Transcript>() -> T {
|
|
|
|
|
T::new(b"FROST_nonce_dleq")
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-03 01:25:46 -04:00
|
|
|
pub(crate) struct PreprocessPackage<C: Curve> {
|
2022-07-12 01:28:01 -04:00
|
|
|
pub(crate) nonces: Vec<[C::F; 2]>,
|
2022-07-13 02:38:29 -04:00
|
|
|
pub(crate) commitments: Vec<Vec<[C::G; 2]>>,
|
|
|
|
|
pub(crate) addendum: Vec<u8>,
|
2022-04-21 21:36:18 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This library unifies the preprocessing step with signing due to security concerns and to provide
|
|
|
|
|
// a simpler UX
|
|
|
|
|
fn preprocess<R: RngCore + CryptoRng, C: Curve, A: Algorithm<C>>(
|
|
|
|
|
rng: &mut R,
|
2022-04-29 01:34:48 -04:00
|
|
|
params: &mut Params<C, A>,
|
2022-07-13 02:38:29 -04:00
|
|
|
) -> (PreprocessPackage<C>, Vec<u8>) {
|
|
|
|
|
let mut serialized = Vec::with_capacity(2 * C::G_len());
|
|
|
|
|
let (nonces, commitments) = params.algorithm.nonces().iter().cloned().map(
|
2022-07-12 01:28:01 -04:00
|
|
|
|mut generators| {
|
|
|
|
|
let nonces = [
|
|
|
|
|
C::random_nonce(params.view().secret_share(), &mut *rng),
|
|
|
|
|
C::random_nonce(params.view().secret_share(), &mut *rng)
|
|
|
|
|
];
|
|
|
|
|
|
2022-07-13 02:38:29 -04:00
|
|
|
let commit = |generator: C::G, buf: &mut Vec<u8>| {
|
2022-07-12 01:28:01 -04:00
|
|
|
let commitments = [generator * nonces[0], generator * nonces[1]];
|
2022-07-13 02:38:29 -04:00
|
|
|
buf.extend(commitments[0].to_bytes().as_ref());
|
|
|
|
|
buf.extend(commitments[1].to_bytes().as_ref());
|
|
|
|
|
commitments
|
2022-07-12 01:28:01 -04:00
|
|
|
};
|
|
|
|
|
|
2022-07-13 02:38:29 -04:00
|
|
|
let mut commitments = Vec::with_capacity(generators.len());
|
2022-07-12 01:28:01 -04:00
|
|
|
let first = generators.remove(0);
|
2022-07-13 02:38:29 -04:00
|
|
|
commitments.push(commit(first, &mut serialized));
|
2022-07-12 01:28:01 -04:00
|
|
|
|
|
|
|
|
// Iterate over the rest
|
|
|
|
|
for generator in generators.iter() {
|
2022-07-13 02:38:29 -04:00
|
|
|
commitments.push(commit(*generator, &mut serialized));
|
2022-07-12 01:28:01 -04:00
|
|
|
// Provide a DLEq to verify these commitments are for the same nonce
|
|
|
|
|
// TODO: Provide a single DLEq. See https://github.com/serai-dex/serai/issues/34
|
|
|
|
|
for nonce in nonces {
|
|
|
|
|
DLEqProof::prove(
|
|
|
|
|
&mut *rng,
|
|
|
|
|
// Uses an independent transcript as each signer must do this now, yet we validate them
|
|
|
|
|
// sequentially by the global order. Avoids needing to clone the transcript around
|
|
|
|
|
&mut nonce_transcript::<A::Transcript>(),
|
|
|
|
|
Generators::new(first, *generator),
|
|
|
|
|
nonce
|
|
|
|
|
).serialize(&mut serialized).unwrap();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-13 02:38:29 -04:00
|
|
|
(nonces, commitments)
|
2022-07-12 01:28:01 -04:00
|
|
|
}
|
2022-07-13 02:38:29 -04:00
|
|
|
).unzip();
|
2022-07-12 01:28:01 -04:00
|
|
|
|
2022-07-13 02:38:29 -04:00
|
|
|
let addendum = params.algorithm.preprocess_addendum(rng, ¶ms.view);
|
|
|
|
|
serialized.extend(&addendum);
|
2022-04-21 21:36:18 -04:00
|
|
|
|
2022-07-13 02:38:29 -04:00
|
|
|
(PreprocessPackage { nonces, commitments, addendum }, serialized)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[allow(non_snake_case)]
|
|
|
|
|
fn read_D_E<Re: Read, C: Curve>(cursor: &mut Re, l: u16) -> Result<[C::G; 2], FrostError> {
|
|
|
|
|
Ok([
|
|
|
|
|
C::read_G(cursor).map_err(|_| FrostError::InvalidCommitment(l))?,
|
|
|
|
|
C::read_G(cursor).map_err(|_| FrostError::InvalidCommitment(l))?
|
|
|
|
|
])
|
2022-04-21 21:36:18 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[allow(non_snake_case)]
|
|
|
|
|
struct Package<C: Curve> {
|
2022-07-12 02:45:18 -04:00
|
|
|
B: HashMap<u16, (Vec<Vec<[C::G; 2]>>, C::F)>,
|
2022-07-12 01:28:01 -04:00
|
|
|
Rs: Vec<Vec<C::G>>,
|
2022-07-13 02:38:29 -04:00
|
|
|
share: C::F,
|
2022-04-21 21:36:18 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Has every signer perform the role of the signature aggregator
|
|
|
|
|
// Step 1 was already deprecated by performing nonce generation as needed
|
|
|
|
|
// Step 2 is simply the broadcast round from step 1
|
2022-07-13 02:38:29 -04:00
|
|
|
fn sign_with_share<Re: Read, C: Curve, A: Algorithm<C>>(
|
2022-04-21 21:36:18 -04:00
|
|
|
params: &mut Params<C, A>,
|
|
|
|
|
our_preprocess: PreprocessPackage<C>,
|
2022-07-13 02:38:29 -04:00
|
|
|
mut commitments: HashMap<u16, Re>,
|
2022-04-21 21:36:18 -04:00
|
|
|
msg: &[u8],
|
|
|
|
|
) -> Result<(Package<C>, Vec<u8>), FrostError> {
|
|
|
|
|
let multisig_params = params.multisig_params();
|
2022-07-13 02:38:29 -04:00
|
|
|
validate_map(&mut commitments, ¶ms.view.included, multisig_params.i)?;
|
2022-04-21 21:36:18 -04:00
|
|
|
|
2022-05-06 07:33:08 -04:00
|
|
|
{
|
2022-05-23 03:24:33 -04:00
|
|
|
// Domain separate FROST
|
2022-07-13 02:38:29 -04:00
|
|
|
params.algorithm.transcript().domain_separate(b"FROST");
|
2022-05-06 07:33:08 -04:00
|
|
|
}
|
|
|
|
|
|
2022-07-13 02:38:29 -04:00
|
|
|
let nonces = params.algorithm.nonces();
|
2022-04-21 21:36:18 -04:00
|
|
|
#[allow(non_snake_case)]
|
2022-05-24 21:41:14 -04:00
|
|
|
let mut B = HashMap::<u16, _>::with_capacity(params.view.included.len());
|
2022-07-12 02:45:18 -04:00
|
|
|
{
|
2022-05-24 21:41:14 -04:00
|
|
|
// Parse the commitments
|
|
|
|
|
for l in ¶ms.view.included {
|
2022-07-13 02:38:29 -04:00
|
|
|
{
|
|
|
|
|
params.algorithm.transcript().append_message(b"participant", &l.to_be_bytes());
|
|
|
|
|
}
|
2022-05-24 21:41:14 -04:00
|
|
|
|
2022-07-12 01:28:01 -04:00
|
|
|
// While this doesn't note which nonce/basepoint this is for, those are expected to be
|
|
|
|
|
// static. Beyond that, they're committed to in the DLEq proof transcripts, ensuring
|
|
|
|
|
// consistency. While this is suboptimal, it maintains IETF compliance, and Algorithm is
|
|
|
|
|
// documented accordingly
|
2022-07-13 02:38:29 -04:00
|
|
|
let transcript = |t: &mut A::Transcript, commitments: [C::G; 2]| {
|
|
|
|
|
t.append_message(b"commitment_D", commitments[0].to_bytes().as_ref());
|
|
|
|
|
t.append_message(b"commitment_E", commitments[1].to_bytes().as_ref());
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if *l == params.keys.params.i {
|
|
|
|
|
for nonce_commitments in &our_preprocess.commitments {
|
|
|
|
|
for commitments in nonce_commitments {
|
|
|
|
|
transcript(params.algorithm.transcript(), *commitments);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
B.insert(*l, (our_preprocess.commitments.clone(), C::F::zero()));
|
|
|
|
|
params.algorithm.process_addendum(
|
|
|
|
|
¶ms.view,
|
|
|
|
|
*l,
|
|
|
|
|
&mut Cursor::new(our_preprocess.addendum.clone())
|
|
|
|
|
)?;
|
|
|
|
|
} else {
|
|
|
|
|
let mut cursor = commitments.remove(l).unwrap();
|
|
|
|
|
|
|
|
|
|
let mut commitments = Vec::with_capacity(nonces.len());
|
|
|
|
|
for (n, nonce_generators) in nonces.clone().iter_mut().enumerate() {
|
|
|
|
|
commitments.push(Vec::with_capacity(nonce_generators.len()));
|
|
|
|
|
|
|
|
|
|
let first = nonce_generators.remove(0);
|
|
|
|
|
commitments[n].push(read_D_E::<_, C>(&mut cursor, *l)?);
|
|
|
|
|
transcript(params.algorithm.transcript(), commitments[n][0]);
|
|
|
|
|
|
|
|
|
|
for generator in nonce_generators {
|
|
|
|
|
commitments[n].push(read_D_E::<_, C>(&mut cursor, *l)?);
|
|
|
|
|
transcript(params.algorithm.transcript(), commitments[n][commitments[n].len() - 1]);
|
|
|
|
|
for de in 0 .. 2 {
|
|
|
|
|
DLEqProof::deserialize(
|
|
|
|
|
&mut cursor
|
|
|
|
|
).map_err(|_| FrostError::InvalidCommitment(*l))?.verify(
|
|
|
|
|
&mut nonce_transcript::<A::Transcript>(),
|
|
|
|
|
Generators::new(first, *generator),
|
|
|
|
|
(commitments[n][0][de], commitments[n][commitments[n].len() - 1][de])
|
|
|
|
|
).map_err(|_| FrostError::InvalidCommitment(*l))?;
|
|
|
|
|
}
|
2022-07-12 01:28:01 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-13 02:38:29 -04:00
|
|
|
B.insert(*l, (commitments, C::F::zero()));
|
|
|
|
|
params.algorithm.process_addendum(¶ms.view, *l, &mut cursor)?;
|
2022-07-12 01:28:01 -04:00
|
|
|
}
|
2022-05-24 21:41:14 -04:00
|
|
|
}
|
|
|
|
|
|
2022-07-12 02:45:18 -04:00
|
|
|
// Re-format into the FROST-expected rho transcript
|
|
|
|
|
let mut rho_transcript = A::Transcript::new(b"FROST_rho");
|
|
|
|
|
rho_transcript.append_message(b"message", &C::hash_msg(&msg));
|
2022-07-12 03:38:59 -04:00
|
|
|
// This won't just be the commitments, yet the full existing transcript if used in an extended
|
|
|
|
|
// protocol
|
2022-07-12 02:45:18 -04:00
|
|
|
rho_transcript.append_message(
|
|
|
|
|
b"commitments",
|
2022-07-13 02:38:29 -04:00
|
|
|
&C::hash_msg(params.algorithm.transcript().challenge(b"commitments").as_ref())
|
2022-07-12 02:45:18 -04:00
|
|
|
);
|
|
|
|
|
// Include the offset, if one exists
|
|
|
|
|
// While this isn't part of the FROST-expected rho transcript, the offset being here coincides
|
|
|
|
|
// with another specification
|
|
|
|
|
if let Some(offset) = params.keys.offset {
|
|
|
|
|
rho_transcript.append_message(b"offset", offset.to_repr().as_ref());
|
|
|
|
|
}
|
2022-05-24 21:41:14 -04:00
|
|
|
|
2022-07-12 02:45:18 -04:00
|
|
|
// Generate the per-signer binding factors
|
|
|
|
|
for (l, commitments) in B.iter_mut() {
|
|
|
|
|
let mut rho_transcript = rho_transcript.clone();
|
|
|
|
|
rho_transcript.append_message(b"participant", &l.to_be_bytes());
|
|
|
|
|
commitments.1 = C::hash_binding_factor(rho_transcript.challenge(b"rho").as_ref());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Merge the rho transcript back into the global one to ensure its advanced while committing to
|
|
|
|
|
// everything
|
2022-07-13 02:38:29 -04:00
|
|
|
params.algorithm.transcript().append_message(
|
|
|
|
|
b"rho_transcript",
|
|
|
|
|
rho_transcript.challenge(b"merge").as_ref()
|
|
|
|
|
);
|
2022-04-21 21:36:18 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[allow(non_snake_case)]
|
2022-07-12 01:28:01 -04:00
|
|
|
let mut Rs = Vec::with_capacity(nonces.len());
|
|
|
|
|
for n in 0 .. nonces.len() {
|
|
|
|
|
Rs.push(vec![C::G::identity(); nonces[n].len()]);
|
|
|
|
|
for g in 0 .. nonces[n].len() {
|
2022-07-12 03:21:22 -04:00
|
|
|
#[allow(non_snake_case)]
|
|
|
|
|
let mut D = C::G::identity();
|
|
|
|
|
let mut statements = Vec::with_capacity(B.len());
|
|
|
|
|
#[allow(non_snake_case)]
|
|
|
|
|
for (B, binding) in B.values() {
|
|
|
|
|
D += B[n][g][0];
|
|
|
|
|
statements.push((*binding, B[n][g][1]));
|
|
|
|
|
}
|
|
|
|
|
Rs[n][g] = D + multiexp_vartime(&statements);
|
2022-07-12 01:28:01 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-28 01:25:26 -04:00
|
|
|
let share = params.algorithm.sign_share(
|
|
|
|
|
¶ms.view,
|
2022-07-12 01:28:01 -04:00
|
|
|
&Rs,
|
|
|
|
|
&our_preprocess.nonces.iter().map(
|
2022-07-12 02:45:18 -04:00
|
|
|
|nonces| nonces[0] + (nonces[1] * B[¶ms.keys.params.i()].1)
|
2022-07-12 01:28:01 -04:00
|
|
|
).collect::<Vec<_>>(),
|
2022-06-28 01:25:26 -04:00
|
|
|
msg
|
2022-07-13 02:38:29 -04:00
|
|
|
);
|
|
|
|
|
Ok((Package { B, Rs, share }, share.to_repr().as_ref().to_vec()))
|
2022-04-21 21:36:18 -04:00
|
|
|
}
|
|
|
|
|
|
2022-07-13 02:38:29 -04:00
|
|
|
fn complete<Re: Read, C: Curve, A: Algorithm<C>>(
|
2022-04-21 21:36:18 -04:00
|
|
|
sign_params: &Params<C, A>,
|
|
|
|
|
sign: Package<C>,
|
2022-07-13 02:38:29 -04:00
|
|
|
mut shares: HashMap<u16, Re>,
|
2022-04-21 21:36:18 -04:00
|
|
|
) -> Result<A::Signature, FrostError> {
|
|
|
|
|
let params = sign_params.multisig_params();
|
2022-07-13 02:38:29 -04:00
|
|
|
validate_map(&mut shares, &sign_params.view.included, params.i)?;
|
2022-04-21 21:36:18 -04:00
|
|
|
|
2022-05-24 21:41:14 -04:00
|
|
|
let mut responses = HashMap::new();
|
|
|
|
|
let mut sum = C::F::zero();
|
|
|
|
|
for l in &sign_params.view.included {
|
2022-07-13 02:38:29 -04:00
|
|
|
let part = if *l == params.i {
|
|
|
|
|
sign.share
|
|
|
|
|
} else {
|
|
|
|
|
C::read_F(shares.get_mut(l).unwrap()).map_err(|_| FrostError::InvalidShare(*l))?
|
|
|
|
|
};
|
2022-04-21 21:36:18 -04:00
|
|
|
sum += part;
|
2022-05-24 21:41:14 -04:00
|
|
|
responses.insert(*l, part);
|
2022-04-21 21:36:18 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Perform signature validation instead of individual share validation
|
|
|
|
|
// For the success route, which should be much more frequent, this should be faster
|
|
|
|
|
// It also acts as an integrity check of this library's signing function
|
2022-07-12 01:28:01 -04:00
|
|
|
let res = sign_params.algorithm.verify(sign_params.view.group_key, &sign.Rs, sum);
|
2022-05-18 01:08:54 -04:00
|
|
|
if let Some(res) = res {
|
|
|
|
|
return Ok(res);
|
2022-04-21 21:36:18 -04:00
|
|
|
}
|
|
|
|
|
|
2022-05-30 01:46:30 -04:00
|
|
|
// Find out who misbehaved. It may be beneficial to randomly sort this to have detection be
|
|
|
|
|
// within n / 2 on average, and not gameable to n, though that should be minor
|
2022-05-24 21:41:14 -04:00
|
|
|
for l in &sign_params.view.included {
|
|
|
|
|
if !sign_params.algorithm.verify_share(
|
|
|
|
|
sign_params.view.verification_share(*l),
|
2022-07-12 02:45:18 -04:00
|
|
|
&sign.B[l].0.iter().map(
|
2022-07-12 01:28:01 -04:00
|
|
|
|nonces| nonces.iter().map(
|
2022-07-12 02:45:18 -04:00
|
|
|
|commitments| commitments[0] + (commitments[1] * sign.B[l].1)
|
2022-07-12 01:28:01 -04:00
|
|
|
).collect()
|
|
|
|
|
).collect::<Vec<_>>(),
|
2022-05-24 21:41:14 -04:00
|
|
|
responses[l]
|
|
|
|
|
) {
|
|
|
|
|
Err(FrostError::InvalidShare(*l))?;
|
2022-04-21 21:36:18 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If everyone has a valid share and there were enough participants, this should've worked
|
|
|
|
|
Err(
|
2022-07-13 02:38:29 -04:00
|
|
|
FrostError::InternalError("everyone had a valid share yet the signature was still invalid")
|
2022-04-21 21:36:18 -04:00
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-24 08:40:14 -04:00
|
|
|
pub trait PreprocessMachine {
|
2022-05-25 00:21:01 -04:00
|
|
|
type Signature: Clone + PartialEq + fmt::Debug;
|
2022-06-24 08:40:14 -04:00
|
|
|
type SignMachine: SignMachine<Self::Signature>;
|
2022-04-29 22:36:43 -04:00
|
|
|
|
|
|
|
|
/// Perform the preprocessing round required in order to sign
|
|
|
|
|
/// Returns a byte vector which must be transmitted to all parties selected for this signing
|
|
|
|
|
/// process, over an authenticated channel
|
|
|
|
|
fn preprocess<R: RngCore + CryptoRng>(
|
2022-06-24 08:40:14 -04:00
|
|
|
self,
|
2022-04-29 22:36:43 -04:00
|
|
|
rng: &mut R
|
2022-06-24 08:40:14 -04:00
|
|
|
) -> (Self::SignMachine, Vec<u8>);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub trait SignMachine<S> {
|
|
|
|
|
type SignatureMachine: SignatureMachine<S>;
|
2022-04-29 22:36:43 -04:00
|
|
|
|
|
|
|
|
/// Sign a message
|
|
|
|
|
/// Takes in the participant's commitments, which are expected to be in a Vec where participant
|
|
|
|
|
/// index = Vec index. None is expected at index 0 to allow for this. None is also expected at
|
|
|
|
|
/// index i which is locally handled. Returns a byte vector representing a share of the signature
|
|
|
|
|
/// for every other participant to receive, over an authenticated channel
|
2022-07-13 02:38:29 -04:00
|
|
|
fn sign<Re: Read>(
|
2022-06-24 08:40:14 -04:00
|
|
|
self,
|
2022-07-13 02:38:29 -04:00
|
|
|
commitments: HashMap<u16, Re>,
|
2022-04-29 22:36:43 -04:00
|
|
|
msg: &[u8],
|
2022-06-24 08:40:14 -04:00
|
|
|
) -> Result<(Self::SignatureMachine, Vec<u8>), FrostError>;
|
|
|
|
|
}
|
2022-04-29 22:36:43 -04:00
|
|
|
|
2022-06-24 08:40:14 -04:00
|
|
|
pub trait SignatureMachine<S> {
|
2022-04-29 22:36:43 -04:00
|
|
|
/// Complete signing
|
|
|
|
|
/// Takes in everyone elses' shares submitted to us as a Vec, expecting participant index =
|
|
|
|
|
/// Vec index with None at index 0 and index i. Returns a byte vector representing the serialized
|
|
|
|
|
/// signature
|
2022-07-13 02:38:29 -04:00
|
|
|
fn complete<Re: Read>(self, shares: HashMap<u16, Re>) -> Result<S, FrostError>;
|
2022-04-29 22:36:43 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// State machine which manages signing for an arbitrary signature algorithm
|
|
|
|
|
pub struct AlgorithmMachine<C: Curve, A: Algorithm<C>> {
|
2022-06-24 08:40:14 -04:00
|
|
|
params: Params<C, A>
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub struct AlgorithmSignMachine<C: Curve, A: Algorithm<C>> {
|
2022-04-21 21:36:18 -04:00
|
|
|
params: Params<C, A>,
|
2022-06-24 08:40:14 -04:00
|
|
|
preprocess: PreprocessPackage<C>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub struct AlgorithmSignatureMachine<C: Curve, A: Algorithm<C>> {
|
|
|
|
|
params: Params<C, A>,
|
|
|
|
|
sign: Package<C>,
|
2022-04-21 21:36:18 -04:00
|
|
|
}
|
|
|
|
|
|
2022-04-29 22:36:43 -04:00
|
|
|
impl<C: Curve, A: Algorithm<C>> AlgorithmMachine<C, A> {
|
2022-04-21 21:36:18 -04:00
|
|
|
/// Creates a new machine to generate a key for the specified curve in the specified multisig
|
2022-04-29 22:36:43 -04:00
|
|
|
pub fn new(
|
|
|
|
|
algorithm: A,
|
2022-06-28 00:06:12 -04:00
|
|
|
keys: Arc<FrostKeys<C>>,
|
2022-05-24 21:41:14 -04:00
|
|
|
included: &[u16],
|
2022-04-29 22:36:43 -04:00
|
|
|
) -> Result<AlgorithmMachine<C, A>, FrostError> {
|
2022-06-24 08:40:14 -04:00
|
|
|
Ok(AlgorithmMachine { params: Params::new(algorithm, keys, included)? })
|
2022-04-21 21:36:18 -04:00
|
|
|
}
|
2022-06-03 01:25:46 -04:00
|
|
|
|
2022-06-24 08:40:14 -04:00
|
|
|
pub(crate) fn unsafe_override_preprocess(
|
|
|
|
|
self,
|
|
|
|
|
preprocess: PreprocessPackage<C>
|
2022-07-13 02:38:29 -04:00
|
|
|
) -> AlgorithmSignMachine<C, A> {
|
|
|
|
|
AlgorithmSignMachine { params: self.params, preprocess }
|
2022-06-03 01:25:46 -04:00
|
|
|
}
|
2022-04-29 22:36:43 -04:00
|
|
|
}
|
2022-04-21 21:36:18 -04:00
|
|
|
|
2022-06-24 08:40:14 -04:00
|
|
|
impl<C: Curve, A: Algorithm<C>> PreprocessMachine for AlgorithmMachine<C, A> {
|
2022-04-29 22:36:43 -04:00
|
|
|
type Signature = A::Signature;
|
2022-06-24 08:40:14 -04:00
|
|
|
type SignMachine = AlgorithmSignMachine<C, A>;
|
2022-04-29 22:36:43 -04:00
|
|
|
|
|
|
|
|
fn preprocess<R: RngCore + CryptoRng>(
|
2022-06-24 08:40:14 -04:00
|
|
|
self,
|
2022-04-21 21:36:18 -04:00
|
|
|
rng: &mut R
|
2022-06-24 08:40:14 -04:00
|
|
|
) -> (Self::SignMachine, Vec<u8>) {
|
|
|
|
|
let mut params = self.params;
|
2022-07-13 02:38:29 -04:00
|
|
|
let (preprocess, serialized) = preprocess::<R, C, A>(rng, &mut params);
|
2022-06-24 08:40:14 -04:00
|
|
|
(AlgorithmSignMachine { params, preprocess }, serialized)
|
2022-04-21 21:36:18 -04:00
|
|
|
}
|
2022-06-24 08:40:14 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<C: Curve, A: Algorithm<C>> SignMachine<A::Signature> for AlgorithmSignMachine<C, A> {
|
|
|
|
|
type SignatureMachine = AlgorithmSignatureMachine<C, A>;
|
2022-04-21 21:36:18 -04:00
|
|
|
|
2022-07-13 02:38:29 -04:00
|
|
|
fn sign<Re: Read>(
|
2022-06-24 08:40:14 -04:00
|
|
|
self,
|
2022-07-13 02:38:29 -04:00
|
|
|
commitments: HashMap<u16, Re>,
|
2022-06-24 08:40:14 -04:00
|
|
|
msg: &[u8]
|
|
|
|
|
) -> Result<(Self::SignatureMachine, Vec<u8>), FrostError> {
|
|
|
|
|
let mut params = self.params;
|
|
|
|
|
let (sign, serialized) = sign_with_share(&mut params, self.preprocess, commitments, msg)?;
|
|
|
|
|
Ok((AlgorithmSignatureMachine { params, sign }, serialized))
|
2022-04-21 21:36:18 -04:00
|
|
|
}
|
2022-06-24 08:40:14 -04:00
|
|
|
}
|
2022-04-21 21:36:18 -04:00
|
|
|
|
2022-06-24 08:40:14 -04:00
|
|
|
impl<
|
|
|
|
|
C: Curve,
|
|
|
|
|
A: Algorithm<C>
|
|
|
|
|
> SignatureMachine<A::Signature> for AlgorithmSignatureMachine<C, A> {
|
2022-07-13 02:38:29 -04:00
|
|
|
fn complete<Re: Read>(self, shares: HashMap<u16, Re>) -> Result<A::Signature, FrostError> {
|
2022-06-24 08:40:14 -04:00
|
|
|
complete(&self.params, self.sign, shares)
|
2022-04-21 21:36:18 -04:00
|
|
|
}
|
|
|
|
|
}
|