Apply an initial set of rustfmt rules

This commit is contained in:
Luke Parker
2022-07-15 01:26:07 -04:00
parent 0b879a53fa
commit e67033a207
67 changed files with 1983 additions and 1796 deletions

View File

@@ -55,12 +55,7 @@ pub trait Algorithm<C: Curve>: Clone {
/// Verify a specific share given as a response. Used to determine blame if signature
/// verification fails
#[must_use]
fn verify_share(
&self,
verification_share: C::G,
nonces: &[Vec<C::G>],
share: C::F,
) -> bool;
fn verify_share(&self, verification_share: C::G, nonces: &[Vec<C::G>], share: C::F) -> bool;
}
// Transcript which will create an IETF compliant serialization for the binding factor
@@ -88,7 +83,6 @@ impl Transcript for IetfTranscript {
}
}
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)
@@ -105,11 +99,7 @@ pub struct Schnorr<C: Curve, H: Hram<C>> {
impl<C: Curve, H: Hram<C>> Schnorr<C, H> {
pub fn new() -> Schnorr<C, H> {
Schnorr {
transcript: IetfTranscript(vec![]),
c: None,
_hram: PhantomData
}
Schnorr { transcript: IetfTranscript(vec![]), c: None, _hram: PhantomData }
}
}
@@ -166,16 +156,11 @@ impl<C: Curve, H: Hram<C>> Algorithm<C> for Schnorr<C, H> {
}
#[must_use]
fn verify_share(
&self,
verification_share: C::G,
nonces: &[Vec<C::G>],
share: C::F,
) -> bool {
fn verify_share(&self, verification_share: C::G, nonces: &[Vec<C::G>], share: C::F) -> bool {
schnorr::verify::<C>(
verification_share,
self.c.unwrap(),
&SchnorrSignature { R: nonces[0][0], s: share}
&SchnorrSignature { R: nonces[0][0], s: share },
)
}
}

View File

@@ -63,7 +63,7 @@ macro_rules! dalek_curve {
$Curve::hash_to_F($chal, &[&R.compress().to_bytes(), &A.compress().to_bytes(), m].concat())
}
}
}
};
}
#[cfg(any(test, feature = "ristretto"))]

View File

@@ -6,7 +6,10 @@ use sha2::{digest::Update, Digest, Sha256};
use group::{ff::Field, GroupEncoding};
use elliptic_curve::{bigint::{Encoding, U384}, hash2curve::{Expander, ExpandMsg, ExpandMsgXmd}};
use elliptic_curve::{
bigint::{Encoding, U384},
hash2curve::{Expander, ExpandMsg, ExpandMsgXmd},
};
use crate::{curve::Curve, algorithm::Hram};
@@ -36,12 +39,7 @@ macro_rules! kp_curve {
}
fn hash_msg(msg: &[u8]) -> Vec<u8> {
(&Sha256::new()
.chain($CONTEXT)
.chain(b"digest")
.chain(msg)
.finalize()
).to_vec()
(&Sha256::new().chain($CONTEXT).chain(b"digest").chain(msg).finalize()).to_vec()
}
fn hash_binding_factor(binding: &[u8]) -> Self::F {
@@ -60,19 +58,17 @@ macro_rules! kp_curve {
let mut modulus = vec![0; 16];
modulus.extend((Self::F::zero() - Self::F::one()).to_bytes());
let modulus = U384::from_be_slice(&modulus).wrapping_add(&U384::ONE);
Self::read_F(
&mut Cursor::new(
&U384::from_be_slice(&{
let mut bytes = [0; 48];
ExpandMsgXmd::<Sha256>::expand_message(
&[msg],
dst,
48
).unwrap().fill_bytes(&mut bytes);
bytes
}).reduce(&modulus).unwrap().to_be_bytes()[16 ..]
)
).unwrap()
Self::read_F(&mut Cursor::new(
&U384::from_be_slice(&{
let mut bytes = [0; 48];
ExpandMsgXmd::<Sha256>::expand_message(&[msg], dst, 48).unwrap().fill_bytes(&mut bytes);
bytes
})
.reduce(&modulus)
.unwrap()
.to_be_bytes()[16 ..],
))
.unwrap()
}
}
@@ -83,27 +79,15 @@ macro_rules! kp_curve {
fn hram(R: &$lib::ProjectivePoint, A: &$lib::ProjectivePoint, m: &[u8]) -> $lib::Scalar {
$Curve::hash_to_F(
&[$CONTEXT as &[u8], b"chal"].concat(),
&[R.to_bytes().as_ref(), A.to_bytes().as_ref(), m].concat()
&[R.to_bytes().as_ref(), A.to_bytes().as_ref(), m].concat(),
)
}
}
}
};
}
#[cfg(feature = "p256")]
kp_curve!(
p256,
P256,
IetfP256Hram,
b"P-256",
b"FROST-P256-SHA256-v5"
);
kp_curve!(p256, P256, IetfP256Hram, b"P-256", b"FROST-P256-SHA256-v5");
#[cfg(feature = "secp256k1")]
kp_curve!(
k256,
Secp256k1,
NonIetfSecp256k1Hram,
b"secp256k1",
b"FROST-secp256k1-SHA256-v7"
);
kp_curve!(k256, Secp256k1, NonIetfSecp256k1Hram, b"secp256k1", b"FROST-secp256k1-SHA256-v7");

View File

@@ -102,9 +102,8 @@ pub trait Curve: Clone + Copy + PartialEq + Eq + Debug {
let mut encoding = <Self::G as GroupEncoding>::Repr::default();
r.read_exact(encoding.as_mut()).map_err(|_| CurveError::InvalidPoint)?;
let point = Option::<Self::G>::from(
Self::G::from_bytes(&encoding)
).ok_or(CurveError::InvalidPoint)?;
let point =
Option::<Self::G>::from(Self::G::from_bytes(&encoding)).ok_or(CurveError::InvalidPoint)?;
// Ban the identity, per the FROST spec, and non-canonical points
if (point.is_identity().into()) || (point.to_bytes().as_ref() != encoding.as_ref()) {
Err(CurveError::InvalidPoint)?;

View File

@@ -1,8 +1,15 @@
use std::{marker::PhantomData, io::{Read, Cursor}, collections::HashMap};
use std::{
marker::PhantomData,
io::{Read, Cursor},
collections::HashMap,
};
use rand_core::{RngCore, CryptoRng};
use group::{ff::{Field, PrimeField}, GroupEncoding};
use group::{
ff::{Field, PrimeField},
GroupEncoding,
};
use multiexp::{multiexp_vartime, BatchVerifier};
@@ -10,7 +17,7 @@ use crate::{
curve::Curve,
FrostError, FrostParams, FrostKeys,
schnorr::{self, SchnorrSignature},
validate_map
validate_map,
};
#[allow(non_snake_case)]
@@ -56,13 +63,9 @@ fn generate_key_r1<R: RngCore + CryptoRng, C: Curve>(
// There's no reason to spend the time and effort to make this deterministic besides a
// general obsession with canonicity and determinism though
r,
challenge::<C>(
context,
params.i(),
(C::GENERATOR * r).to_bytes().as_ref(),
&serialized
)
).serialize()
challenge::<C>(context, params.i(), (C::GENERATOR * r).to_bytes().as_ref(), &serialized),
)
.serialize(),
);
// Step 4: Broadcast
@@ -114,7 +117,7 @@ fn verify_r1<Re: Read, R: RngCore + CryptoRng, C: Curve>(
l,
these_commitments[0],
challenge::<C>(context, l, R.to_bytes().as_ref(), &Am),
SchnorrSignature::<C> { R, s }
SchnorrSignature::<C> { R, s },
));
}
@@ -126,10 +129,7 @@ fn verify_r1<Re: Read, R: RngCore + CryptoRng, C: Curve>(
Ok(commitments)
}
fn polynomial<F: PrimeField>(
coefficients: &[F],
l: u16
) -> F {
fn polynomial<F: PrimeField>(coefficients: &[F], l: u16) -> F {
let l = F::from(u64::from(l));
let mut share = F::zero();
for (idx, coefficient) in coefficients.iter().rev().enumerate() {
@@ -207,13 +207,10 @@ fn complete_r2<Re: Read, R: RngCore + CryptoRng, C: Curve>(
let exponential = |i: u16, values: &[_]| {
let i = C::F::from(i.into());
let mut res = Vec::with_capacity(params.t().into());
(0 .. usize::from(params.t())).into_iter().fold(
C::F::one(),
|exp, l| {
res.push((exp, values[l]));
exp * i
}
);
(0 .. usize::from(params.t())).into_iter().fold(C::F::one(), |exp, l| {
res.push((exp, values[l]));
exp * i
});
res
};
@@ -254,15 +251,7 @@ fn complete_r2<Re: Read, R: RngCore + CryptoRng, C: Curve>(
// TODO: Clear serialized and shares
Ok(
FrostKeys {
params,
secret_share,
group_key: stripes[0],
verification_shares,
offset: None
}
)
Ok(FrostKeys { params, secret_share, group_key: stripes[0], verification_shares, offset: None })
}
pub struct KeyGenMachine<C: Curve> {
@@ -298,11 +287,8 @@ impl<C: Curve> KeyGenMachine<C> {
self,
rng: &mut R,
) -> (SecretShareMachine<C>, Vec<u8>) {
let (
coefficients,
our_commitments,
serialized
) = generate_key_r1::<_, C>(rng, &self.params, &self.context);
let (coefficients, our_commitments, serialized) =
generate_key_r1::<_, C>(rng, &self.params, &self.context);
(
SecretShareMachine {

View File

@@ -3,7 +3,10 @@ use std::{io::Read, collections::HashMap};
use thiserror::Error;
use group::{ff::{Field, PrimeField}, GroupEncoding};
use group::{
ff::{Field, PrimeField},
GroupEncoding,
};
mod schnorr;
@@ -28,11 +31,7 @@ pub struct FrostParams {
}
impl FrostParams {
pub fn new(
t: u16,
n: u16,
i: u16
) -> Result<FrostParams, FrostError> {
pub fn new(t: u16, n: u16, i: u16) -> Result<FrostParams, FrostError> {
if (t == 0) || (n == 0) {
Err(FrostError::ZeroParameter(t, n))?;
}
@@ -46,12 +45,18 @@ impl FrostParams {
Err(FrostError::InvalidParticipantIndex(n, i))?;
}
Ok(FrostParams{ t, n, i })
Ok(FrostParams { t, n, i })
}
pub fn t(&self) -> u16 { self.t }
pub fn n(&self) -> u16 { self.n }
pub fn i(&self) -> u16 { self.i }
pub fn t(&self) -> u16 {
self.t
}
pub fn n(&self) -> u16 {
self.n
}
pub fn i(&self) -> u16 {
self.i
}
}
#[derive(Copy, Clone, Error, Debug)]
@@ -112,10 +117,7 @@ impl<C: Curve> FrostView<C> {
}
/// Calculate the lagrange coefficient for a signing set
pub fn lagrange<F: PrimeField>(
i: u16,
included: &[u16],
) -> F {
pub fn lagrange<F: PrimeField>(i: u16, included: &[u16]) -> F {
let mut num = F::one();
let mut denom = F::one();
for l in included {
@@ -192,12 +194,13 @@ impl<C: Curve> FrostKeys<C> {
Ok(FrostView {
group_key: self.group_key,
secret_share: secret_share + offset_share,
verification_shares: self.verification_shares.iter().map(
|(l, share)| (
*l,
(*share * lagrange::<C::F>(*l, &included)) + (C::GENERATOR * offset_share)
)
).collect(),
verification_shares: self
.verification_shares
.iter()
.map(|(l, share)| {
(*l, (*share * lagrange::<C::F>(*l, &included)) + (C::GENERATOR * offset_share))
})
.collect(),
included: included.to_vec(),
})
}
@@ -242,36 +245,35 @@ impl<C: Curve> FrostKeys<C> {
let (t, n, i) = {
let mut read_u16 = || {
let mut value = [0; 2];
cursor.read_exact(&mut value).map_err(
|_| FrostError::InternalError("missing participant quantities")
)?;
cursor
.read_exact(&mut value)
.map_err(|_| FrostError::InternalError("missing participant quantities"))?;
Ok(u16::from_be_bytes(value))
};
(read_u16()?, read_u16()?, read_u16()?)
};
let secret_share = C::read_F(cursor)
.map_err(|_| FrostError::InternalError("invalid secret share"))?;
let group_key = C::read_G(cursor).map_err(|_| FrostError::InternalError("invalid group key"))?;
let secret_share =
C::read_F(cursor).map_err(|_| FrostError::InternalError("invalid secret share"))?;
let group_key =
C::read_G(cursor).map_err(|_| FrostError::InternalError("invalid group key"))?;
let mut verification_shares = HashMap::new();
for l in 1 ..= n {
verification_shares.insert(
l,
C::read_G(cursor).map_err(|_| FrostError::InternalError("invalid verification share"))?
C::read_G(cursor).map_err(|_| FrostError::InternalError("invalid verification share"))?,
);
}
Ok(
FrostKeys {
params: FrostParams::new(t, n, i)
.map_err(|_| FrostError::InternalError("invalid parameters"))?,
secret_share,
group_key,
verification_shares,
offset: None
}
)
Ok(FrostKeys {
params: FrostParams::new(t, n, i)
.map_err(|_| FrostError::InternalError("invalid parameters"))?,
secret_share,
group_key,
verification_shares,
offset: None,
})
}
}
@@ -279,7 +281,7 @@ impl<C: Curve> FrostKeys<C> {
pub(crate) fn validate_map<T>(
map: &mut HashMap<u16, T>,
included: &[u16],
ours: u16
ours: u16,
) -> Result<(), FrostError> {
if (map.len() + 1) != included.len() {
Err(FrostError::InvalidParticipantQuantity(included.len(), map.len() + 1))?;

View File

@@ -1,6 +1,9 @@
use rand_core::{RngCore, CryptoRng};
use group::{ff::{Field, PrimeField}, GroupEncoding};
use group::{
ff::{Field, PrimeField},
GroupEncoding,
};
use multiexp::BatchVerifier;
@@ -25,26 +28,23 @@ impl<C: Curve> SchnorrSignature<C> {
pub(crate) fn sign<C: Curve>(
private_key: C::F,
nonce: C::F,
challenge: C::F
challenge: C::F,
) -> SchnorrSignature<C> {
SchnorrSignature {
R: C::GENERATOR * nonce,
s: nonce + (private_key * challenge)
}
SchnorrSignature { R: C::GENERATOR * nonce, s: nonce + (private_key * challenge) }
}
#[must_use]
pub(crate) fn verify<C: Curve>(
public_key: C::G,
challenge: C::F,
signature: &SchnorrSignature<C>
signature: &SchnorrSignature<C>,
) -> bool {
(C::GENERATOR * signature.s) == (signature.R + (public_key * challenge))
}
pub(crate) fn batch_verify<C: Curve, R: RngCore + CryptoRng>(
rng: &mut R,
triplets: &[(u16, C::G, C::F, SchnorrSignature<C>)]
triplets: &[(u16, C::G, C::F, SchnorrSignature<C>)],
) -> Result<(), u16> {
let mut values = [(C::F::one(), C::GENERATOR); 3];
let mut batch = BatchVerifier::new(triplets.len());

View File

@@ -1,20 +1,24 @@
use core::fmt;
use std::{io::{Read, Cursor}, sync::Arc, collections::HashMap};
use std::{
io::{Read, Cursor},
sync::Arc,
collections::HashMap,
};
use rand_core::{RngCore, CryptoRng};
use transcript::Transcript;
use group::{ff::{Field, PrimeField}, Group, GroupEncoding};
use group::{
ff::{Field, PrimeField},
Group, GroupEncoding,
};
use multiexp::multiexp_vartime;
use dleq::DLEqProof;
use crate::{
curve::Curve,
FrostError, FrostParams, FrostKeys, FrostView,
algorithm::Algorithm,
validate_map
curve::Curve, FrostError, FrostParams, FrostKeys, FrostView, algorithm::Algorithm, validate_map,
};
/// Pairing of an Algorithm with a FrostKeys instance and this specific signing set
@@ -88,11 +92,14 @@ fn preprocess<R: RngCore + CryptoRng, C: Curve, A: Algorithm<C>>(
params: &mut Params<C, A>,
) -> (PreprocessPackage<C>, Vec<u8>) {
let mut serialized = Vec::with_capacity(2 * C::G_len());
let (nonces, commitments) = params.algorithm.nonces().iter().map(
|generators| {
let (nonces, commitments) = params
.algorithm
.nonces()
.iter()
.map(|generators| {
let nonces = [
C::random_nonce(params.view().secret_share(), &mut *rng),
C::random_nonce(params.view().secret_share(), &mut *rng)
C::random_nonce(params.view().secret_share(), &mut *rng),
];
let commit = |generator: C::G, buf: &mut Vec<u8>| {
@@ -116,18 +123,15 @@ fn preprocess<R: RngCore + CryptoRng, C: Curve, A: Algorithm<C>>(
// This could be further optimized with a multi-nonce proof.
// See https://github.com/serai-dex/serai/issues/38
for nonce in nonces {
DLEqProof::prove(
&mut *rng,
&mut transcript,
&generators,
nonce
).serialize(&mut serialized).unwrap();
DLEqProof::prove(&mut *rng, &mut transcript, &generators, nonce)
.serialize(&mut serialized)
.unwrap();
}
}
(nonces, commitments)
}
).unzip();
})
.unzip();
let addendum = params.algorithm.preprocess_addendum(rng, &params.view);
serialized.extend(&addendum);
@@ -139,7 +143,7 @@ fn preprocess<R: RngCore + CryptoRng, C: Curve, A: Algorithm<C>>(
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))?
C::read_G(cursor).map_err(|_| FrostError::InvalidCommitment(l))?,
])
}
@@ -197,7 +201,7 @@ fn sign_with_share<Re: Read, C: Curve, A: Algorithm<C>>(
params.algorithm.process_addendum(
&params.view,
*l,
&mut Cursor::new(our_preprocess.addendum.clone())
&mut Cursor::new(our_preprocess.addendum.clone()),
)?;
} else {
let mut cursor = commitments.remove(l).unwrap();
@@ -213,13 +217,14 @@ fn sign_with_share<Re: Read, C: Curve, A: Algorithm<C>>(
if nonce_generators.len() >= 2 {
let mut transcript = nonce_transcript::<A::Transcript>();
for de in 0 .. 2 {
DLEqProof::deserialize(
&mut cursor
).map_err(|_| FrostError::InvalidCommitment(*l))?.verify(
&mut transcript,
&nonce_generators,
&commitments[n].iter().map(|commitments| commitments[de]).collect::<Vec<_>>(),
).map_err(|_| FrostError::InvalidCommitment(*l))?;
DLEqProof::deserialize(&mut cursor)
.map_err(|_| FrostError::InvalidCommitment(*l))?
.verify(
&mut transcript,
&nonce_generators,
&commitments[n].iter().map(|commitments| commitments[de]).collect::<Vec<_>>(),
)
.map_err(|_| FrostError::InvalidCommitment(*l))?;
}
}
}
@@ -236,7 +241,7 @@ fn sign_with_share<Re: Read, C: Curve, A: Algorithm<C>>(
// protocol
rho_transcript.append_message(
b"commitments",
&C::hash_msg(params.algorithm.transcript().challenge(b"commitments").as_ref())
&C::hash_msg(params.algorithm.transcript().challenge(b"commitments").as_ref()),
);
// Include the offset, if one exists
// While this isn't part of the FROST-expected rho transcript, the offset being here coincides
@@ -254,10 +259,10 @@ fn sign_with_share<Re: Read, C: Curve, A: Algorithm<C>>(
// Merge the rho transcript back into the global one to ensure its advanced while committing to
// everything
params.algorithm.transcript().append_message(
b"rho_transcript",
rho_transcript.challenge(b"merge").as_ref()
);
params
.algorithm
.transcript()
.append_message(b"rho_transcript", rho_transcript.challenge(b"merge").as_ref());
}
#[allow(non_snake_case)]
@@ -280,10 +285,12 @@ fn sign_with_share<Re: Read, C: Curve, A: Algorithm<C>>(
let share = params.algorithm.sign_share(
&params.view,
&Rs,
&our_preprocess.nonces.iter().map(
|nonces| nonces[0] + (nonces[1] * B[&params.keys.params.i()].1)
).collect::<Vec<_>>(),
msg
&our_preprocess
.nonces
.iter()
.map(|nonces| nonces[0] + (nonces[1] * B[&params.keys.params.i()].1))
.collect::<Vec<_>>(),
msg,
);
Ok((Package { B, Rs, share }, share.to_repr().as_ref().to_vec()))
}
@@ -321,21 +328,21 @@ fn complete<Re: Read, C: Curve, A: Algorithm<C>>(
for l in &sign_params.view.included {
if !sign_params.algorithm.verify_share(
sign_params.view.verification_share(*l),
&sign.B[l].0.iter().map(
|nonces| nonces.iter().map(
|commitments| commitments[0] + (commitments[1] * sign.B[l].1)
).collect()
).collect::<Vec<_>>(),
responses[l]
&sign.B[l]
.0
.iter()
.map(|nonces| {
nonces.iter().map(|commitments| commitments[0] + (commitments[1] * sign.B[l].1)).collect()
})
.collect::<Vec<_>>(),
responses[l],
) {
Err(FrostError::InvalidShare(*l))?;
}
}
// If everyone has a valid share and there were enough participants, this should've worked
Err(
FrostError::InternalError("everyone had a valid share yet the signature was still invalid")
)
Err(FrostError::InternalError("everyone had a valid share yet the signature was still invalid"))
}
pub trait PreprocessMachine {
@@ -345,10 +352,7 @@ pub trait PreprocessMachine {
/// 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>(
self,
rng: &mut R
) -> (Self::SignMachine, Vec<u8>);
fn preprocess<R: RngCore + CryptoRng>(self, rng: &mut R) -> (Self::SignMachine, Vec<u8>);
}
pub trait SignMachine<S> {
@@ -376,7 +380,7 @@ pub trait SignatureMachine<S> {
/// State machine which manages signing for an arbitrary signature algorithm
pub struct AlgorithmMachine<C: Curve, A: Algorithm<C>> {
params: Params<C, A>
params: Params<C, A>,
}
pub struct AlgorithmSignMachine<C: Curve, A: Algorithm<C>> {
@@ -401,7 +405,7 @@ impl<C: Curve, A: Algorithm<C>> AlgorithmMachine<C, A> {
pub(crate) fn unsafe_override_preprocess(
self,
preprocess: PreprocessPackage<C>
preprocess: PreprocessPackage<C>,
) -> AlgorithmSignMachine<C, A> {
AlgorithmSignMachine { params: self.params, preprocess }
}
@@ -411,10 +415,7 @@ impl<C: Curve, A: Algorithm<C>> PreprocessMachine for AlgorithmMachine<C, A> {
type Signature = A::Signature;
type SignMachine = AlgorithmSignMachine<C, A>;
fn preprocess<R: RngCore + CryptoRng>(
self,
rng: &mut R
) -> (Self::SignMachine, Vec<u8>) {
fn preprocess<R: RngCore + CryptoRng>(self, rng: &mut R) -> (Self::SignMachine, Vec<u8>) {
let mut params = self.params;
let (preprocess, serialized) = preprocess::<R, C, A>(rng, &mut params);
(AlgorithmSignMachine { params, preprocess }, serialized)
@@ -427,7 +428,7 @@ impl<C: Curve, A: Algorithm<C>> SignMachine<A::Signature> for AlgorithmSignMachi
fn sign<Re: Read>(
self,
commitments: HashMap<u16, Re>,
msg: &[u8]
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)?;
@@ -435,10 +436,7 @@ impl<C: Curve, A: Algorithm<C>> SignMachine<A::Signature> for AlgorithmSignMachi
}
}
impl<
C: Curve,
A: Algorithm<C>
> SignatureMachine<A::Signature> for AlgorithmSignatureMachine<C, A> {
impl<C: Curve, A: Algorithm<C>> SignatureMachine<A::Signature> for AlgorithmSignatureMachine<C, A> {
fn complete<Re: Read>(self, shares: HashMap<u16, Re>) -> Result<A::Signature, FrostError> {
complete(&self.params, self.sign, shares)
}

View File

@@ -1,6 +1,9 @@
use rand::rngs::OsRng;
use crate::{curve, tests::vectors::{Vectors, test_with_vectors}};
use crate::{
curve,
tests::vectors::{Vectors, test_with_vectors},
};
#[cfg(any(test, feature = "ristretto"))]
#[test]
@@ -12,7 +15,7 @@ fn ristretto_vectors() {
shares: &[
"5c3430d391552f6e60ecdc093ff9f6f4488756aa6cebdbad75a768010b8f830e",
"b06fc5eac20b4f6e1b271d9df2343d843e1e1fb03c4cbb673f2872d459ce6f01",
"f17e505f0e2581c6acfe54d3846a622834b5e7b50cad9a2109a97ba7a80d5c04"
"f17e505f0e2581c6acfe54d3846a622834b5e7b50cad9a2109a97ba7a80d5c04",
],
group_secret: "1b25a55e463cfd15cf14a5d3acc3d15053f08da49c8afcf3ab265f2ebc4f970b",
group_key: "e2a62f39eede11269e3bd5a7d97554f5ca384f9f6d3dd9c3c0d05083c7254f57",
@@ -22,20 +25,20 @@ fn ristretto_vectors() {
nonces: &[
[
"eb0dc12ae7b746d36e3f2de46ce3833a05b9d4af5434eeb8cafaefda76906d00",
"491e91aa9df514ef598d5e0c7c5cdd088fbde4965b96069d546c0f04f1822b03"
"491e91aa9df514ef598d5e0c7c5cdd088fbde4965b96069d546c0f04f1822b03",
],
[
"abd12b8e6f255ee1e540eab029003a6e956567617720f61115f0941615892209",
"218e22625f93f262f025bd2d13c46ba722aa29fe585ceed66ff442d98fe4e509"
]
"218e22625f93f262f025bd2d13c46ba722aa29fe585ceed66ff442d98fe4e509",
],
],
sig_shares: &[
"efae3a83437fa8cd96194aacc56a7eb841630c280da99e7764a81d1340323306",
"96ddc4582e45eabce46f07b9e9375f8b49d35d1510fd34ac02b1e79d6100a602"
"96ddc4582e45eabce46f07b9e9375f8b49d35d1510fd34ac02b1e79d6100a602",
],
sig: "7ec584cef9a383afb43883b73bcaa6313afe878bd5fe75a608311b866a76ec67".to_owned() +
"858cffdb71c4928a7b895165afa2dd438b366a3d1da6d323675905b1a132d908"
}
"858cffdb71c4928a7b895165afa2dd438b366a3d1da6d323675905b1a132d908",
},
);
}
@@ -49,7 +52,7 @@ fn ed25519_vectors() {
shares: &[
"929dcc590407aae7d388761cddb0c0db6f5627aea8e217f4a033f2ec83d93509",
"a91e66e012e4364ac9aaa405fcafd370402d9859f7b6685c07eed76bf409e80d",
"d3cb090a075eb154e82fdb4b3cb507f110040905468bb9c46da8bdea643a9a02"
"d3cb090a075eb154e82fdb4b3cb507f110040905468bb9c46da8bdea643a9a02",
],
group_secret: "7b1c33d3f5291d85de664833beb1ad469f7fb6025a0ec78b3a790c6e13a98304",
group_key: "15d21ccd7ee42959562fc8aa63224c8851fb3ec85a3faf66040d380fb9738673",
@@ -59,19 +62,19 @@ fn ed25519_vectors() {
nonces: &[
[
"d9aad97e1a1127bb87702ce8d81d8c07c7cbca89e784868d8e3876ff6b459700",
"5063be2774520d08a5ccd7f1213fb1179a5fa292bf13bc91cb28e7bd4d4a690c"
"5063be2774520d08a5ccd7f1213fb1179a5fa292bf13bc91cb28e7bd4d4a690c",
],
[
"86961f3a429ac0c5696f49e6d796817ff653f83c07f34e9e1f4d4c8c515b7900",
"72225ec11c1315d9f1ea0e78b1160ed95800fadd0191d23fd2f2c90ac96cb307"
]
"72225ec11c1315d9f1ea0e78b1160ed95800fadd0191d23fd2f2c90ac96cb307",
],
],
sig_shares: &[
"caae171b83bff0c2c6f56a1276892918ba228146f6344b85d2ec6efeb6f16d0d",
"ea6fdbf61683cf5f1f742e1b91583f0f667f0369efd2e33399b96d5a3ff0300d"
"ea6fdbf61683cf5f1f742e1b91583f0f667f0369efd2e33399b96d5a3ff0300d",
],
sig: "5da10008c13c04dd72328ba8e0f72b63cad43c3bf4b7eaada1c78225afbd977e".to_owned() +
"c74afdb47fdfadca0fcda18a28e8891220a284afe5072fb96ba6dc58f6e19e0a"
}
"c74afdb47fdfadca0fcda18a28e8891220a284afe5072fb96ba6dc58f6e19e0a",
},
);
}

View File

@@ -19,7 +19,7 @@ fn secp256k1_non_ietf() {
shares: &[
"08f89ffe80ac94dcb920c26f3f46140bfc7f95b493f8310f5fc1ea2b01f4254c",
"04f0feac2edcedc6ce1253b7fab8c86b856a797f44d83d82a385554e6e401984",
"00e95d59dd0d46b0e303e500b62b7ccb0e555d49f5b849f5e748c071da8c0dbc"
"00e95d59dd0d46b0e303e500b62b7ccb0e555d49f5b849f5e748c071da8c0dbc",
],
group_secret: "0d004150d27c3bf2a42f312683d35fac7394b1e9e318249c1bfe7f0795a83114",
group_key: "02f37c34b66ced1fb51c34a90bdae006901f10625cc06c4f64663b0eae87d87b4f",
@@ -29,20 +29,20 @@ fn secp256k1_non_ietf() {
nonces: &[
[
"31c3c1b76b76664569859b9251fbabed9d4d432c6f5aaa03ed41f9c231935798",
"206f4ffaeb602ccb57cbe50e146ac690e6d7317d4b93377061d9d1b4caf78a26"
"206f4ffaeb602ccb57cbe50e146ac690e6d7317d4b93377061d9d1b4caf78a26",
],
[
"0d3945bc1553676a5dd910cb4f14437d99ed421516b2617357b984820fdca520",
"635e0fd90caaf40b5e986d0ee0f58778e4d88731bc6ac70350ef702ffe20a21b"
]
"635e0fd90caaf40b5e986d0ee0f58778e4d88731bc6ac70350ef702ffe20a21b",
],
],
sig_shares: &[
"18b71e284c5d008896ed8847b234ec829eda376d6208838ee7faf2ce21b154c1",
"a452a49c8116124d0a283f3589a96b704894b43246e47e59d376353bcc638311"
"a452a49c8116124d0a283f3589a96b704894b43246e47e59d376353bcc638311",
],
sig: "03dafb28ee7ad033fd15ed470d07156617260d74a9d76a15d371d7b613d2b111e".to_owned() +
"7bd09c2c4cd7312d5a115c77d3bde57f2e76eeb9fa8ed01e8bb712809ee14d7d2"
}
"7bd09c2c4cd7312d5a115c77d3bde57f2e76eeb9fa8ed01e8bb712809ee14d7d2",
},
);
}
@@ -56,7 +56,7 @@ fn p256_vectors() {
shares: &[
"0c9c1a0fe806c184add50bbdcac913dda73e482daf95dcb9f35dbb0d8a9f7731",
"8d8e787bef0ff6c2f494ca45f4dad198c6bee01212d6c84067159c52e1863ad5",
"0e80d6e8f6192c003b5488ce1eec8f5429587d48cf001541e713b2d53c09d928"
"0e80d6e8f6192c003b5488ce1eec8f5429587d48cf001541e713b2d53c09d928",
],
group_secret: "8ba9bba2e0fd8c4767154d35a0b7562244a4aaf6f36c8fb8735fa48b301bd8de",
group_key: "023a309ad94e9fe8a7ba45dfc58f38bf091959d3c99cfbd02b4dc00585ec45ab70",
@@ -66,19 +66,19 @@ fn p256_vectors() {
nonces: &[
[
"33a519cf070a166f9ef41a798d03423743f3e7d0b0efd5d0d963773c4c53205e",
"307d208d0c5728f323ae374f1ebd7f14a1a49b77d9d4bc1eab222218a17765ff"
"307d208d0c5728f323ae374f1ebd7f14a1a49b77d9d4bc1eab222218a17765ff",
],
[
"a614eadb972dc37b88aeceb6e899903f3104742d13f379a0e014541decbea4a4",
"e509791018504c5bb87edaf0f44761cc840888507c4cd80237971d78e65f70f2"
]
"e509791018504c5bb87edaf0f44761cc840888507c4cd80237971d78e65f70f2",
],
],
sig_shares: &[
"61e8b9c474df2e66ad19fd80a6e6cec1c6fe43c0a1cffd2d1c28299e93e1bbdb",
"9651d355ca1dea2557ba1f73e38a9f4ff1f1afc565323ef27f88a9d14df8370e"
"9651d355ca1dea2557ba1f73e38a9f4ff1f1afc565323ef27f88a9d14df8370e",
],
sig: "02dfba781e17b830229ae4ed22ebe402873683d9dfd945d01762217fb3172c2a7".to_owned() +
"1f83a8d1a3efd188c04d41cf48a716e11b8eff38607023c1f9bb0d36fe1d9f2e9"
}
"1f83a8d1a3efd188c04d41cf48a716e11b8eff38607023c1f9bb0d36fe1d9f2e9",
},
);
}

View File

@@ -5,12 +5,10 @@ use rand_core::{RngCore, CryptoRng};
use group::ff::Field;
use crate::{
Curve,
FrostParams, FrostKeys,
lagrange,
Curve, FrostParams, FrostKeys, lagrange,
key_gen::KeyGenMachine,
algorithm::Algorithm,
sign::{PreprocessMachine, SignMachine, SignatureMachine, AlgorithmMachine}
sign::{PreprocessMachine, SignMachine, SignatureMachine, AlgorithmMachine},
};
// Test suites for public usage
@@ -27,22 +25,20 @@ pub const THRESHOLD: u16 = ((PARTICIPANTS / 3) * 2) + 1;
pub fn clone_without<K: Clone + std::cmp::Eq + std::hash::Hash, V: Clone>(
map: &HashMap<K, V>,
without: &K
without: &K,
) -> HashMap<K, V> {
let mut res = map.clone();
res.remove(without).unwrap();
res
}
pub fn key_gen<R: RngCore + CryptoRng, C: Curve>(
rng: &mut R
) -> HashMap<u16, Arc<FrostKeys<C>>> {
pub fn key_gen<R: RngCore + CryptoRng, C: Curve>(rng: &mut R) -> HashMap<u16, Arc<FrostKeys<C>>> {
let mut machines = HashMap::new();
let mut commitments = HashMap::new();
for i in 1 ..= PARTICIPANTS {
let machine = KeyGenMachine::<C>::new(
FrostParams::new(THRESHOLD, PARTICIPANTS, i).unwrap(),
"FROST Test key_gen".to_string()
"FROST Test key_gen".to_string(),
);
let (machine, these_commitments) = machine.generate_coefficients(rng);
machines.insert(i, machine);
@@ -50,41 +46,45 @@ pub fn key_gen<R: RngCore + CryptoRng, C: Curve>(
}
let mut secret_shares = HashMap::new();
let mut machines = machines.drain().map(|(l, machine)| {
let (machine, shares) = machine.generate_secret_shares(
rng,
clone_without(&commitments, &l)
).unwrap();
secret_shares.insert(l, shares);
(l, machine)
}).collect::<HashMap<_, _>>();
let mut machines = machines
.drain()
.map(|(l, machine)| {
let (machine, shares) =
machine.generate_secret_shares(rng, clone_without(&commitments, &l)).unwrap();
secret_shares.insert(l, shares);
(l, machine)
})
.collect::<HashMap<_, _>>();
let mut verification_shares = None;
let mut group_key = None;
machines.drain().map(|(i, machine)| {
let mut our_secret_shares = HashMap::new();
for (l, shares) in &secret_shares {
if i == *l {
continue;
machines
.drain()
.map(|(i, machine)| {
let mut our_secret_shares = HashMap::new();
for (l, shares) in &secret_shares {
if i == *l {
continue;
}
our_secret_shares.insert(*l, Cursor::new(shares[&i].clone()));
}
our_secret_shares.insert(*l, Cursor::new(shares[&i].clone()));
}
let these_keys = machine.complete(rng, our_secret_shares).unwrap();
let these_keys = machine.complete(rng, our_secret_shares).unwrap();
// Verify the verification_shares are agreed upon
if verification_shares.is_none() {
verification_shares = Some(these_keys.verification_shares());
}
assert_eq!(verification_shares.as_ref().unwrap(), &these_keys.verification_shares());
// Verify the verification_shares are agreed upon
if verification_shares.is_none() {
verification_shares = Some(these_keys.verification_shares());
}
assert_eq!(verification_shares.as_ref().unwrap(), &these_keys.verification_shares());
// Verify the group keys are agreed upon
if group_key.is_none() {
group_key = Some(these_keys.group_key());
}
assert_eq!(group_key.unwrap(), these_keys.group_key());
// Verify the group keys are agreed upon
if group_key.is_none() {
group_key = Some(these_keys.group_key());
}
assert_eq!(group_key.unwrap(), these_keys.group_key());
(i, Arc::new(these_keys))
}).collect::<HashMap<_, _>>()
(i, Arc::new(these_keys))
})
.collect::<HashMap<_, _>>()
}
pub fn recover<C: Curve>(keys: &HashMap<u16, FrostKeys<C>>) -> C::F {
@@ -92,10 +92,9 @@ pub fn recover<C: Curve>(keys: &HashMap<u16, FrostKeys<C>>) -> C::F {
assert!(keys.len() >= first.params().t().into(), "not enough keys provided");
let included = keys.keys().cloned().collect::<Vec<_>>();
let group_private = keys.iter().fold(
C::F::zero(),
|accum, (i, keys)| accum + (keys.secret_share() * lagrange::<C::F>(*i, &included))
);
let group_private = keys.iter().fold(C::F::zero(), |accum, (i, keys)| {
accum + (keys.secret_share() * lagrange::<C::F>(*i, &included))
});
assert_eq!(C::GENERATOR * group_private, first.group_key(), "failed to recover keys");
group_private
}
@@ -114,40 +113,45 @@ pub fn algorithm_machines<R: RngCore, C: Curve, A: Algorithm<C>>(
included.push(n);
}
keys.iter().filter_map(
|(i, keys)| if included.contains(&i) {
Some((
*i,
AlgorithmMachine::new(
algorithm.clone(),
keys.clone(),
&included.clone()
).unwrap()
))
} else {
None
}
).collect()
keys
.iter()
.filter_map(|(i, keys)| {
if included.contains(&i) {
Some((
*i,
AlgorithmMachine::new(algorithm.clone(), keys.clone(), &included.clone()).unwrap(),
))
} else {
None
}
})
.collect()
}
pub fn sign<R: RngCore + CryptoRng, M: PreprocessMachine>(
rng: &mut R,
mut machines: HashMap<u16, M>,
msg: &[u8]
msg: &[u8],
) -> M::Signature {
let mut commitments = HashMap::new();
let mut machines = machines.drain().map(|(i, machine)| {
let (machine, preprocess) = machine.preprocess(rng);
commitments.insert(i, Cursor::new(preprocess));
(i, machine)
}).collect::<HashMap<_, _>>();
let mut machines = machines
.drain()
.map(|(i, machine)| {
let (machine, preprocess) = machine.preprocess(rng);
commitments.insert(i, Cursor::new(preprocess));
(i, machine)
})
.collect::<HashMap<_, _>>();
let mut shares = HashMap::new();
let mut machines = machines.drain().map(|(i, machine)| {
let (machine, share) = machine.sign(clone_without(&commitments, &i), msg).unwrap();
shares.insert(i, Cursor::new(share));
(i, machine)
}).collect::<HashMap<_, _>>();
let mut machines = machines
.drain()
.map(|(i, machine)| {
let (machine, share) = machine.sign(clone_without(&commitments, &i), msg).unwrap();
shares.insert(i, Cursor::new(share));
(i, machine)
})
.collect::<HashMap<_, _>>();
let mut signature = None;
for (i, machine) in machines.drain() {

View File

@@ -5,34 +5,32 @@ use rand_core::{RngCore, CryptoRng};
use group::{ff::Field, GroupEncoding};
use crate::{
Curve, FrostKeys, schnorr::{self, SchnorrSignature}, algorithm::{Hram, Schnorr},
tests::{key_gen, algorithm_machines, sign as sign_test}
Curve, FrostKeys,
schnorr::{self, SchnorrSignature},
algorithm::{Hram, Schnorr},
tests::{key_gen, algorithm_machines, sign as sign_test},
};
pub(crate) fn core_sign<R: RngCore + CryptoRng, C: Curve>(rng: &mut R) {
let private_key = C::F::random(&mut *rng);
let nonce = C::F::random(&mut *rng);
let challenge = C::F::random(rng); // Doesn't bother to craft an HRAM
assert!(
schnorr::verify::<C>(
C::GENERATOR * private_key,
challenge,
&schnorr::sign(private_key, nonce, challenge)
)
);
assert!(schnorr::verify::<C>(
C::GENERATOR * private_key,
challenge,
&schnorr::sign(private_key, nonce, challenge)
));
}
// The above sign function verifies signing works
// This verifies invalid signatures don't pass, using zero signatures, which should effectively be
// random
pub(crate) fn core_verify<R: RngCore + CryptoRng, C: Curve>(rng: &mut R) {
assert!(
!schnorr::verify::<C>(
C::GENERATOR * C::F::random(&mut *rng),
C::F::random(rng),
&SchnorrSignature { R: C::GENERATOR * C::F::zero(), s: C::F::zero() }
)
);
assert!(!schnorr::verify::<C>(
C::GENERATOR * C::F::random(&mut *rng),
C::F::random(rng),
&SchnorrSignature { R: C::GENERATOR * C::F::zero(), s: C::F::zero() }
));
}
pub(crate) fn core_batch_verify<R: RngCore + CryptoRng, C: Curve>(rng: &mut R) {
@@ -47,9 +45,9 @@ pub(crate) fn core_batch_verify<R: RngCore + CryptoRng, C: Curve>(rng: &mut R) {
}
// Batch verify
let triplets = (0 .. 5).map(
|i| (u16::try_from(i + 1).unwrap(), C::GENERATOR * keys[i], challenges[i], sigs[i])
).collect::<Vec<_>>();
let triplets = (0 .. 5)
.map(|i| (u16::try_from(i + 1).unwrap(), C::GENERATOR * keys[i], challenges[i], sigs[i]))
.collect::<Vec<_>>();
schnorr::batch_verify(rng, &triplets).unwrap();
// Shift 1 from s from one to another and verify it fails
@@ -80,7 +78,7 @@ pub(crate) fn core_batch_verify<R: RngCore + CryptoRng, C: Curve>(rng: &mut R) {
fn sign_core<R: RngCore + CryptoRng, C: Curve>(
rng: &mut R,
group_key: C::G,
keys: &HashMap<u16, Arc<FrostKeys<C>>>
keys: &HashMap<u16, Arc<FrostKeys<C>>>,
) {
const MESSAGE: &'static [u8] = b"Hello, World!";
@@ -91,7 +89,7 @@ fn sign_core<R: RngCore + CryptoRng, C: Curve>(
#[derive(Clone)]
pub struct TestHram<C: Curve> {
_curve: PhantomData<C>
_curve: PhantomData<C>,
}
impl<C: Curve> Hram<C> for TestHram<C> {
#[allow(non_snake_case)]

View File

@@ -5,10 +5,11 @@ use rand_core::{RngCore, CryptoRng};
use group::{ff::PrimeField, GroupEncoding};
use crate::{
curve::Curve, FrostKeys,
curve::Curve,
FrostKeys,
algorithm::{Schnorr, Hram},
sign::{PreprocessPackage, SignMachine, SignatureMachine, AlgorithmMachine},
tests::{clone_without, curve::test_curve, schnorr::test_schnorr, recover}
tests::{clone_without, curve::test_curve, schnorr::test_schnorr, recover},
};
pub struct Vectors {
@@ -21,17 +22,17 @@ pub struct Vectors {
pub included: &'static [u16],
pub nonces: &'static [[&'static str; 2]],
pub sig_shares: &'static [&'static str],
pub sig: String
pub sig: String,
}
// Load these vectors into FrostKeys using a custom serialization it'll deserialize
fn vectors_to_multisig_keys<C: Curve>(vectors: &Vectors) -> HashMap<u16, FrostKeys<C>> {
let shares = vectors.shares.iter().map(
|secret| C::read_F(&mut Cursor::new(hex::decode(secret).unwrap())).unwrap()
).collect::<Vec<_>>();
let verification_shares = shares.iter().map(
|secret| C::GENERATOR * secret
).collect::<Vec<_>>();
let shares = vectors
.shares
.iter()
.map(|secret| C::read_F(&mut Cursor::new(hex::decode(secret).unwrap())).unwrap())
.collect::<Vec<_>>();
let verification_shares = shares.iter().map(|secret| C::GENERATOR * secret).collect::<Vec<_>>();
let mut keys = HashMap::new();
for i in 1 ..= u16::try_from(shares.len()).unwrap() {
@@ -59,11 +60,10 @@ fn vectors_to_multisig_keys<C: Curve>(vectors: &Vectors) -> HashMap<u16, FrostKe
keys
}
pub fn test_with_vectors<
R: RngCore + CryptoRng,
C: Curve,
H: Hram<C>
>(rng: &mut R, vectors: Vectors) {
pub fn test_with_vectors<R: RngCore + CryptoRng, C: Curve, H: Hram<C>>(
rng: &mut R,
vectors: Vectors,
) {
// Do basic tests before trying the vectors
test_curve::<_, C>(&mut *rng);
test_schnorr::<_, C>(rng);
@@ -87,54 +87,59 @@ pub fn test_with_vectors<
AlgorithmMachine::new(
Schnorr::<C, H>::new(),
Arc::new(keys[i].clone()),
vectors.included.clone()
).unwrap()
vectors.included.clone(),
)
.unwrap(),
));
}
let mut commitments = HashMap::new();
let mut c = 0;
let mut machines = machines.drain(..).map(|(i, machine)| {
let nonces = [
C::read_F(&mut Cursor::new(hex::decode(vectors.nonces[c][0]).unwrap())).unwrap(),
C::read_F(&mut Cursor::new(hex::decode(vectors.nonces[c][1]).unwrap())).unwrap()
];
c += 1;
let these_commitments = vec![[C::GENERATOR * nonces[0], C::GENERATOR * nonces[1]]];
let machine = machine.unsafe_override_preprocess(
PreprocessPackage {
let mut machines = machines
.drain(..)
.map(|(i, machine)| {
let nonces = [
C::read_F(&mut Cursor::new(hex::decode(vectors.nonces[c][0]).unwrap())).unwrap(),
C::read_F(&mut Cursor::new(hex::decode(vectors.nonces[c][1]).unwrap())).unwrap(),
];
c += 1;
let these_commitments = vec![[C::GENERATOR * nonces[0], C::GENERATOR * nonces[1]]];
let machine = machine.unsafe_override_preprocess(PreprocessPackage {
nonces: vec![nonces],
commitments: vec![these_commitments.clone()],
addendum: vec![]
}
);
addendum: vec![],
});
commitments.insert(
i,
Cursor::new(
[
these_commitments[0][0].to_bytes().as_ref(),
these_commitments[0][1].to_bytes().as_ref()
].concat().to_vec()
)
);
(i, machine)
}).collect::<Vec<_>>();
commitments.insert(
i,
Cursor::new(
[
these_commitments[0][0].to_bytes().as_ref(),
these_commitments[0][1].to_bytes().as_ref(),
]
.concat()
.to_vec(),
),
);
(i, machine)
})
.collect::<Vec<_>>();
let mut shares = HashMap::new();
c = 0;
let mut machines = machines.drain(..).map(|(i, machine)| {
let (machine, share) = machine.sign(
clone_without(&commitments, &i),
&hex::decode(vectors.msg).unwrap()
).unwrap();
let mut machines = machines
.drain(..)
.map(|(i, machine)| {
let (machine, share) =
machine.sign(clone_without(&commitments, &i), &hex::decode(vectors.msg).unwrap()).unwrap();
assert_eq!(share, hex::decode(vectors.sig_shares[c]).unwrap());
c += 1;
assert_eq!(share, hex::decode(vectors.sig_shares[c]).unwrap());
c += 1;
shares.insert(i, Cursor::new(share));
(i, machine)
}).collect::<HashMap<_, _>>();
shares.insert(i, Cursor::new(share));
(i, machine)
})
.collect::<HashMap<_, _>>();
for (i, machine) in machines.drain() {
let sig = machine.complete(clone_without(&shares, &i)).unwrap();