Create a dedicated crate for the DKG (#141)

* Add dkg crate

* Remove F_len and G_len

They're generally no longer used.

* Replace hash_to_vec with a provided method around associated type H: Digest

Part of trying to minimize this trait so it can be moved elsewhere. Vec, 
which isn't std, may have been a blocker.

* Encrypt secret shares within the FROST library

Reduces requirements on callers in order to be correct.

* Update usage of Zeroize within FROST

* Inline functions in key_gen

There was no reason to have them separated as they were. sign probably 
has the same statement available, yet that isn't the focus right now.

* Add a ciphersuite package which provides hash_to_F

* Set the Ciphersuite version to something valid

* Have ed448 export Scalar/FieldElement/Point at the top level

* Move FROST over to Ciphersuite

* Correct usage of ff in ciphersuite

* Correct documentation handling

* Move Schnorr signatures to their own crate

* Remove unused feature from schnorr

* Fix Schnorr tests

* Split DKG into a separate crate

* Add serialize to Commitments and SecretShare

Helper for buf = vec![]; .write(buf).unwrap(); buf

* Move FROST over to the new dkg crate

* Update Monero lib to latest FROST

* Correct ethereum's usage of features

* Add serialize to GeneratorProof

* Add serialize helper function to FROST

* Rename AddendumSerialize to WriteAddendum

* Update processor

* Slight fix to processor
This commit is contained in:
Luke Parker
2022-10-29 03:54:42 -05:00
committed by GitHub
parent cbceaff678
commit 2379855b31
50 changed files with 2076 additions and 1601 deletions

86
crypto/schnorr/src/lib.rs Normal file
View File

@@ -0,0 +1,86 @@
use std::io::{self, Read, Write};
use rand_core::{RngCore, CryptoRng};
use zeroize::Zeroize;
use group::{
ff::{Field, PrimeField},
GroupEncoding,
};
use multiexp::BatchVerifier;
use ciphersuite::Ciphersuite;
#[cfg(test)]
mod tests;
/// A Schnorr signature of the form (R, s) where s = r + cx.
#[allow(non_snake_case)]
#[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize)]
pub struct SchnorrSignature<C: Ciphersuite> {
pub R: C::G,
pub s: C::F,
}
impl<C: Ciphersuite> SchnorrSignature<C> {
/// Read a SchnorrSignature from something implementing Read.
pub fn read<R: Read>(reader: &mut R) -> io::Result<Self> {
Ok(SchnorrSignature { R: C::read_G(reader)?, s: C::read_F(reader)? })
}
/// Write a SchnorrSignature to something implementing Read.
pub fn write<W: Write>(&self, writer: &mut W) -> io::Result<()> {
writer.write_all(self.R.to_bytes().as_ref())?;
writer.write_all(self.s.to_repr().as_ref())
}
/// Serialize a SchnorrSignature, returning a Vec<u8>.
pub fn serialize(&self) -> Vec<u8> {
let mut buf = vec![];
self.write(&mut buf).unwrap();
buf
}
/// Sign a Schnorr signature with the given nonce for the specified challenge.
pub fn sign(mut private_key: C::F, mut nonce: C::F, challenge: C::F) -> SchnorrSignature<C> {
let res = SchnorrSignature { R: C::generator() * nonce, s: nonce + (private_key * challenge) };
private_key.zeroize();
nonce.zeroize();
res
}
/// Verify a Schnorr signature for the given key with the specified challenge.
#[must_use]
pub fn verify(&self, public_key: C::G, challenge: C::F) -> bool {
(C::generator() * self.s) == (self.R + (public_key * challenge))
}
/// Queue a signature for batch verification.
pub fn batch_verify<R: RngCore + CryptoRng, I: Copy + Zeroize>(
&self,
rng: &mut R,
batch: &mut BatchVerifier<I, C::G>,
id: I,
public_key: C::G,
challenge: C::F,
) {
// s = r + ca
// sG == R + cA
// R + cA - sG == 0
batch.queue(
rng,
id,
[
// R
(C::F::one(), self.R),
// cA
(challenge, public_key),
// -sG
(-self.s, C::generator()),
],
);
}
}

View File

@@ -0,0 +1,72 @@
use rand_core::OsRng;
use group::{ff::Field, Group};
use multiexp::BatchVerifier;
use ciphersuite::{Ciphersuite, Ristretto};
use crate::SchnorrSignature;
pub(crate) fn core_sign<C: Ciphersuite>() {
let private_key = C::random_nonzero_F(&mut OsRng);
let nonce = C::random_nonzero_F(&mut OsRng);
let challenge = C::random_nonzero_F(&mut OsRng); // Doesn't bother to craft an HRAm
assert!(SchnorrSignature::<C>::sign(private_key, nonce, challenge)
.verify(C::generator() * private_key, 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<C: Ciphersuite>() {
assert!(!SchnorrSignature::<C> { R: C::G::identity(), s: C::F::zero() }
.verify(C::generator() * C::random_nonzero_F(&mut OsRng), C::random_nonzero_F(&mut OsRng)));
}
pub(crate) fn core_batch_verify<C: Ciphersuite>() {
// Create 5 signatures
let mut keys = vec![];
let mut challenges = vec![];
let mut sigs = vec![];
for i in 0 .. 5 {
keys.push(C::random_nonzero_F(&mut OsRng));
challenges.push(C::random_nonzero_F(&mut OsRng));
sigs.push(SchnorrSignature::<C>::sign(keys[i], C::random_nonzero_F(&mut OsRng), challenges[i]));
}
// Batch verify
{
let mut batch = BatchVerifier::new(5);
for (i, sig) in sigs.iter().enumerate() {
sig.batch_verify(&mut OsRng, &mut batch, i, C::generator() * keys[i], challenges[i]);
}
batch.verify_with_vartime_blame().unwrap();
}
// Shift 1 from s from one to another and verify it fails
// This test will fail if unique factors aren't used per-signature, hence its inclusion
{
let mut batch = BatchVerifier::new(5);
for (i, mut sig) in sigs.clone().drain(..).enumerate() {
if i == 1 {
sig.s += C::F::one();
}
if i == 2 {
sig.s -= C::F::one();
}
sig.batch_verify(&mut OsRng, &mut batch, i, C::generator() * keys[i], challenges[i]);
}
if let Err(blame) = batch.verify_with_vartime_blame() {
assert!((blame == 1) || (blame == 2));
} else {
panic!("Batch verification considered malleated signatures valid");
}
}
}
#[test]
fn test() {
core_sign::<Ristretto>();
core_verify::<Ristretto>();
core_batch_verify::<Ristretto>();
}