mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-08 20:29:23 +00:00
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
use core::{marker::PhantomData, fmt::Debug};
|
||||
use std::io::{self, Read, Write};
|
||||
|
||||
use zeroize::Zeroizing;
|
||||
use rand_core::{RngCore, CryptoRng};
|
||||
|
||||
use transcript::Transcript;
|
||||
@@ -66,7 +67,7 @@ pub trait Algorithm<C: Curve>: Clone {
|
||||
&mut self,
|
||||
params: &ThresholdView<C>,
|
||||
nonce_sums: &[Vec<C::G>],
|
||||
nonces: &[C::F],
|
||||
nonces: Vec<Zeroizing<C::F>>,
|
||||
msg: &[u8],
|
||||
) -> C::F;
|
||||
|
||||
@@ -161,12 +162,12 @@ impl<C: Curve, H: Hram<C>> Algorithm<C> for Schnorr<C, H> {
|
||||
&mut self,
|
||||
params: &ThresholdView<C>,
|
||||
nonce_sums: &[Vec<C::G>],
|
||||
nonces: &[C::F],
|
||||
mut nonces: Vec<Zeroizing<C::F>>,
|
||||
msg: &[u8],
|
||||
) -> C::F {
|
||||
let c = H::hram(&nonce_sums[0][0], ¶ms.group_key(), msg);
|
||||
self.c = Some(c);
|
||||
SchnorrSignature::<C>::sign(params.secret_share(), nonces[0], c).s
|
||||
SchnorrSignature::<C>::sign(params.secret_share(), nonces.swap_remove(0), c).s
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
use core::ops::Deref;
|
||||
use std::io::{self, Read};
|
||||
|
||||
use rand_core::{RngCore, CryptoRng};
|
||||
|
||||
use zeroize::Zeroize;
|
||||
use zeroize::{Zeroize, Zeroizing};
|
||||
use subtle::ConstantTimeEq;
|
||||
|
||||
use digest::Digest;
|
||||
@@ -67,26 +68,29 @@ pub trait Curve: Ciphersuite {
|
||||
}
|
||||
|
||||
/// Securely generate a random nonce. H3 from the IETF draft.
|
||||
fn random_nonce<R: RngCore + CryptoRng>(mut secret: Self::F, rng: &mut R) -> Self::F {
|
||||
let mut seed = vec![0; 32];
|
||||
rng.fill_bytes(&mut seed);
|
||||
fn random_nonce<R: RngCore + CryptoRng>(
|
||||
secret: &Zeroizing<Self::F>,
|
||||
rng: &mut R,
|
||||
) -> Zeroizing<Self::F> {
|
||||
let mut seed = Zeroizing::new(vec![0; 32]);
|
||||
rng.fill_bytes(seed.as_mut());
|
||||
|
||||
let mut repr = secret.to_repr();
|
||||
secret.zeroize();
|
||||
|
||||
let mut res;
|
||||
while {
|
||||
seed.extend(repr.as_ref());
|
||||
res = <Self as Curve>::hash_to_F(b"nonce", &seed);
|
||||
res = Zeroizing::new(<Self as Curve>::hash_to_F(b"nonce", seed.deref()));
|
||||
res.ct_eq(&Self::F::zero()).into()
|
||||
} {
|
||||
seed = Zeroizing::new(vec![0; 32]);
|
||||
rng.fill_bytes(&mut seed);
|
||||
}
|
||||
|
||||
for i in repr.as_mut() {
|
||||
i.zeroize();
|
||||
}
|
||||
seed.zeroize();
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
// Each nonce remains of the form (d, e) and made into a proper nonce with d + (e * b)
|
||||
// When multiple D, E pairs are provided, a DLEq proof is also provided to confirm their integrity
|
||||
|
||||
use core::ops::Deref;
|
||||
use std::{
|
||||
io::{self, Read, Write},
|
||||
collections::HashMap,
|
||||
@@ -15,7 +16,7 @@ use std::{
|
||||
|
||||
use rand_core::{RngCore, CryptoRng};
|
||||
|
||||
use zeroize::{Zeroize, ZeroizeOnDrop};
|
||||
use zeroize::{Zeroize, Zeroizing};
|
||||
|
||||
use transcript::Transcript;
|
||||
|
||||
@@ -33,13 +34,7 @@ fn dleq_transcript<T: Transcript>() -> T {
|
||||
// Each nonce is actually a pair of random scalars, notated as d, e under the FROST paper
|
||||
// This is considered a single nonce as r = d + be
|
||||
#[derive(Clone, Zeroize)]
|
||||
pub(crate) struct Nonce<C: Curve>(pub(crate) [C::F; 2]);
|
||||
impl<C: Curve> Drop for Nonce<C> {
|
||||
fn drop(&mut self) {
|
||||
self.zeroize();
|
||||
}
|
||||
}
|
||||
impl<C: Curve> ZeroizeOnDrop for Nonce<C> {}
|
||||
pub(crate) struct Nonce<C: Curve>(pub(crate) [Zeroizing<C::F>; 2]);
|
||||
|
||||
// Commitments to a specific generator for this nonce
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
@@ -70,16 +65,20 @@ pub(crate) struct NonceCommitments<C: Curve> {
|
||||
impl<C: Curve> NonceCommitments<C> {
|
||||
pub(crate) fn new<R: RngCore + CryptoRng, T: Transcript>(
|
||||
rng: &mut R,
|
||||
mut secret_share: C::F,
|
||||
secret_share: &Zeroizing<C::F>,
|
||||
generators: &[C::G],
|
||||
) -> (Nonce<C>, NonceCommitments<C>) {
|
||||
let nonce =
|
||||
Nonce([C::random_nonce(secret_share, &mut *rng), C::random_nonce(secret_share, &mut *rng)]);
|
||||
secret_share.zeroize();
|
||||
let nonce = Nonce::<C>([
|
||||
C::random_nonce(secret_share, &mut *rng),
|
||||
C::random_nonce(secret_share, &mut *rng),
|
||||
]);
|
||||
|
||||
let mut commitments = Vec::with_capacity(generators.len());
|
||||
for generator in generators {
|
||||
commitments.push(GeneratorCommitments([*generator * nonce.0[0], *generator * nonce.0[1]]));
|
||||
commitments.push(GeneratorCommitments([
|
||||
*generator * nonce.0[0].deref(),
|
||||
*generator * nonce.0[1].deref(),
|
||||
]));
|
||||
}
|
||||
|
||||
let mut dleqs = None;
|
||||
@@ -91,7 +90,7 @@ impl<C: Curve> NonceCommitments<C> {
|
||||
// TODO: At least include a challenge from the existing transcript
|
||||
DLEqProof::prove(&mut *rng, &mut dleq_transcript::<T>(), generators, nonce)
|
||||
};
|
||||
dleqs = Some([dleq(nonce.0[0]), dleq(nonce.0[1])]);
|
||||
dleqs = Some([dleq(&nonce.0[0]), dleq(&nonce.0[1])]);
|
||||
}
|
||||
|
||||
(nonce, NonceCommitments { generators: commitments, dleqs })
|
||||
@@ -145,7 +144,7 @@ pub(crate) struct Commitments<C: Curve> {
|
||||
impl<C: Curve> Commitments<C> {
|
||||
pub(crate) fn new<R: RngCore + CryptoRng, T: Transcript>(
|
||||
rng: &mut R,
|
||||
secret_share: C::F,
|
||||
secret_share: &Zeroizing<C::F>,
|
||||
planned_nonces: &[Vec<C::G>],
|
||||
) -> (Vec<Nonce<C>>, Commitments<C>) {
|
||||
let mut nonces = vec![];
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use core::fmt;
|
||||
use core::{ops::Deref, fmt::Debug};
|
||||
use std::{
|
||||
io::{self, Read, Write},
|
||||
collections::HashMap,
|
||||
@@ -6,7 +6,7 @@ use std::{
|
||||
|
||||
use rand_core::{RngCore, CryptoRng};
|
||||
|
||||
use zeroize::{Zeroize, ZeroizeOnDrop};
|
||||
use zeroize::Zeroize;
|
||||
|
||||
use transcript::Transcript;
|
||||
|
||||
@@ -49,12 +49,6 @@ pub struct Params<C: Curve, A: Algorithm<C>> {
|
||||
keys: ThresholdKeys<C>,
|
||||
view: ThresholdView<C>,
|
||||
}
|
||||
impl<C: Curve, A: Algorithm<C>> Drop for Params<C, A> {
|
||||
fn drop(&mut self) {
|
||||
self.zeroize()
|
||||
}
|
||||
}
|
||||
impl<C: Curve, A: Algorithm<C>> ZeroizeOnDrop for Params<C, A> {}
|
||||
|
||||
impl<C: Curve, A: Algorithm<C>> Params<C, A> {
|
||||
pub fn new(
|
||||
@@ -122,7 +116,7 @@ pub trait PreprocessMachine {
|
||||
/// Preprocess message for this machine.
|
||||
type Preprocess: Clone + PartialEq + Writable;
|
||||
/// Signature produced by this machine.
|
||||
type Signature: Clone + PartialEq + fmt::Debug;
|
||||
type Signature: Clone + PartialEq + Debug;
|
||||
/// SignMachine this PreprocessMachine turns into.
|
||||
type SignMachine: SignMachine<Self::Signature, Preprocess = Self::Preprocess>;
|
||||
|
||||
@@ -213,22 +207,13 @@ pub trait SignMachine<S> {
|
||||
}
|
||||
|
||||
/// Next step of the state machine for the signing process.
|
||||
#[derive(Zeroize)]
|
||||
pub struct AlgorithmSignMachine<C: Curve, A: Algorithm<C>> {
|
||||
params: Params<C, A>,
|
||||
pub(crate) nonces: Vec<Nonce<C>>,
|
||||
#[zeroize(skip)]
|
||||
pub(crate) preprocess: Preprocess<C, A::Addendum>,
|
||||
}
|
||||
impl<C: Curve, A: Algorithm<C>> Zeroize for AlgorithmSignMachine<C, A> {
|
||||
fn zeroize(&mut self) {
|
||||
self.nonces.zeroize()
|
||||
}
|
||||
}
|
||||
impl<C: Curve, A: Algorithm<C>> Drop for AlgorithmSignMachine<C, A> {
|
||||
fn drop(&mut self) {
|
||||
self.zeroize()
|
||||
}
|
||||
}
|
||||
impl<C: Curve, A: Algorithm<C>> ZeroizeOnDrop for AlgorithmSignMachine<C, A> {}
|
||||
|
||||
impl<C: Curve, A: Algorithm<C>> SignMachine<A::Signature> for AlgorithmSignMachine<C, A> {
|
||||
type Preprocess = Preprocess<C, A::Addendum>;
|
||||
@@ -336,16 +321,19 @@ impl<C: Curve, A: Algorithm<C>> SignMachine<A::Signature> for AlgorithmSignMachi
|
||||
let Rs = B.nonces(&nonces);
|
||||
|
||||
let our_binding_factors = B.binding_factors(multisig_params.i());
|
||||
let mut nonces = self
|
||||
let nonces = self
|
||||
.nonces
|
||||
.iter()
|
||||
.drain(..)
|
||||
.enumerate()
|
||||
.map(|(n, nonces)| nonces.0[0] + (nonces.0[1] * our_binding_factors[n]))
|
||||
.map(|(n, nonces)| {
|
||||
let [base, mut actual] = nonces.0;
|
||||
*actual *= our_binding_factors[n];
|
||||
*actual += base.deref();
|
||||
actual
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
self.nonces.zeroize();
|
||||
|
||||
let share = self.params.algorithm.sign_share(&self.params.view, &Rs, &nonces, msg);
|
||||
nonces.zeroize();
|
||||
let share = self.params.algorithm.sign_share(&self.params.view, &Rs, nonces, msg);
|
||||
|
||||
Ok((
|
||||
AlgorithmSignatureMachine { params: self.params.clone(), B, Rs, share },
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
use core::ops::Deref;
|
||||
|
||||
use std::collections::HashMap;
|
||||
#[cfg(test)]
|
||||
use std::str::FromStr;
|
||||
|
||||
use zeroize::Zeroizing;
|
||||
use rand_core::{RngCore, CryptoRng};
|
||||
|
||||
use group::{ff::PrimeField, GroupEncoding};
|
||||
@@ -103,7 +106,7 @@ fn vectors_to_multisig_keys<C: Curve>(vectors: &Vectors) -> HashMap<u16, Thresho
|
||||
assert_eq!(these_keys.params().t(), vectors.threshold);
|
||||
assert_eq!(usize::from(these_keys.params().n()), shares.len());
|
||||
assert_eq!(these_keys.params().i(), i);
|
||||
assert_eq!(these_keys.secret_share(), shares[usize::from(i - 1)]);
|
||||
assert_eq!(these_keys.secret_share().deref(), &shares[usize::from(i - 1)]);
|
||||
assert_eq!(hex::encode(these_keys.group_key().to_bytes().as_ref()), vectors.group_key);
|
||||
keys.insert(i, ThresholdKeys::new(these_keys));
|
||||
}
|
||||
@@ -148,12 +151,15 @@ pub fn test_with_vectors<R: RngCore + CryptoRng, C: Curve, H: Hram<C>>(
|
||||
let mut machines = machines
|
||||
.drain(..)
|
||||
.map(|(i, machine)| {
|
||||
let nonces = [
|
||||
C::read_F::<&[u8]>(&mut hex::decode(&vectors.nonces[c][0]).unwrap().as_ref()).unwrap(),
|
||||
C::read_F::<&[u8]>(&mut hex::decode(&vectors.nonces[c][1]).unwrap().as_ref()).unwrap(),
|
||||
];
|
||||
let nonce = |i| {
|
||||
Zeroizing::new(
|
||||
C::read_F::<&[u8]>(&mut hex::decode(&vectors.nonces[c][i]).unwrap().as_ref()).unwrap(),
|
||||
)
|
||||
};
|
||||
let nonces = [nonce(0), nonce(1)];
|
||||
c += 1;
|
||||
let these_commitments = [C::generator() * nonces[0], C::generator() * nonces[1]];
|
||||
let these_commitments =
|
||||
[C::generator() * nonces[0].deref(), C::generator() * nonces[1].deref()];
|
||||
let machine = machine.unsafe_override_preprocess(
|
||||
vec![Nonce(nonces)],
|
||||
Preprocess {
|
||||
|
||||
Reference in New Issue
Block a user