mirror of
https://github.com/serai-dex/serai.git
synced 2025-03-24 08:08:51 +00:00
Finish implementing FROST v5
Identity check for P256 and H4 was all that was needed.
This commit is contained in:
parent
e4fc469e58
commit
b4cd29f49a
4 changed files with 26 additions and 7 deletions
|
@ -11,7 +11,7 @@ use curve25519_dalek::{
|
||||||
edwards::EdwardsPoint as DPoint
|
edwards::EdwardsPoint as DPoint
|
||||||
};
|
};
|
||||||
|
|
||||||
use ff::PrimeField;
|
use ff::{Field, PrimeField};
|
||||||
use group::Group;
|
use group::Group;
|
||||||
|
|
||||||
use transcript::{Transcript as TranscriptTrait, DigestTranscript};
|
use transcript::{Transcript as TranscriptTrait, DigestTranscript};
|
||||||
|
@ -59,6 +59,10 @@ impl Curve for Ed25519 {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn random_nonce<R: RngCore + CryptoRng>(_secret: Self::F, rng: &mut R) -> Self::F {
|
||||||
|
dfg::Scalar::random(rng)
|
||||||
|
}
|
||||||
|
|
||||||
// This will already be a keccak256 hash in the case of CLSAG signing, making it fine to simply
|
// This will already be a keccak256 hash in the case of CLSAG signing, making it fine to simply
|
||||||
// return as-is, yet this ensures it's fixed size (a security requirement) and unique regardless
|
// return as-is, yet this ensures it's fixed size (a security requirement) and unique regardless
|
||||||
// of how it's called/what it's called with
|
// of how it's called/what it's called with
|
||||||
|
|
|
@ -3,6 +3,8 @@ use std::collections::HashMap;
|
||||||
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
use rand_core::{RngCore, CryptoRng};
|
||||||
|
|
||||||
use ff::{Field, PrimeField};
|
use ff::{Field, PrimeField};
|
||||||
use group::{Group, GroupOps};
|
use group::{Group, GroupOps};
|
||||||
|
|
||||||
|
@ -32,7 +34,7 @@ pub enum CurveError {
|
||||||
// It uses GenericArray which will hopefully be deprecated as Rust evolves and doesn't offer enough
|
// It uses GenericArray which will hopefully be deprecated as Rust evolves and doesn't offer enough
|
||||||
// advantages in the modern day to be worth the hassle -- Kayaba
|
// advantages in the modern day to be worth the hassle -- Kayaba
|
||||||
pub trait Curve: Clone + Copy + PartialEq + Eq + Debug {
|
pub trait Curve: Clone + Copy + PartialEq + Eq + Debug {
|
||||||
/// Field element type
|
/// Scalar field element type
|
||||||
// This is available via G::Scalar yet `C::G::Scalar` is ambiguous, forcing horrific accesses
|
// This is available via G::Scalar yet `C::G::Scalar` is ambiguous, forcing horrific accesses
|
||||||
type F: PrimeField;
|
type F: PrimeField;
|
||||||
/// Group element type
|
/// Group element type
|
||||||
|
@ -57,6 +59,9 @@ pub trait Curve: Clone + Copy + PartialEq + Eq + Debug {
|
||||||
/// If little endian is used for the scalar field's Repr
|
/// If little endian is used for the scalar field's Repr
|
||||||
fn little_endian() -> bool;
|
fn little_endian() -> bool;
|
||||||
|
|
||||||
|
/// Securely generate a random nonce. H4 from the IETF draft
|
||||||
|
fn random_nonce<R: RngCore + CryptoRng>(secret: Self::F, rng: &mut R) -> Self::F;
|
||||||
|
|
||||||
/// Hash the message for the binding factor. H3 from the IETF draft
|
/// Hash the message for the binding factor. H3 from the IETF draft
|
||||||
// This doesn't actually need to be part of Curve as it does nothing with the curve
|
// This doesn't actually need to be part of Curve as it does nothing with the curve
|
||||||
// This also solely relates to FROST and with a proper Algorithm/HRAM, all projects using
|
// This also solely relates to FROST and with a proper Algorithm/HRAM, all projects using
|
||||||
|
@ -80,7 +85,7 @@ pub trait Curve: Clone + Copy + PartialEq + Eq + Debug {
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
fn hash_to_F(dst: &[u8], msg: &[u8]) -> Self::F;
|
fn hash_to_F(dst: &[u8], msg: &[u8]) -> Self::F;
|
||||||
|
|
||||||
/// Constant size of a serialized field element
|
/// Constant size of a serialized scalar field element
|
||||||
// The alternative way to grab this would be either serializing a junk element and getting its
|
// The alternative way to grab this would be either serializing a junk element and getting its
|
||||||
// length or doing a naive division of its BITS property by 8 and assuming a lack of padding
|
// length or doing a naive division of its BITS property by 8 and assuming a lack of padding
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
|
|
|
@ -80,7 +80,10 @@ fn preprocess<R: RngCore + CryptoRng, C: Curve, A: Algorithm<C>>(
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
params: &mut Params<C, A>,
|
params: &mut Params<C, A>,
|
||||||
) -> PreprocessPackage<C> {
|
) -> PreprocessPackage<C> {
|
||||||
let nonces = [C::F::random(&mut *rng), C::F::random(&mut *rng)];
|
let nonces = [
|
||||||
|
C::random_nonce(params.view().secret_share(), &mut *rng),
|
||||||
|
C::random_nonce(params.view().secret_share(), &mut *rng)
|
||||||
|
];
|
||||||
let commitments = [C::generator_table() * nonces[0], C::generator_table() * nonces[1]];
|
let commitments = [C::generator_table() * nonces[0], C::generator_table() * nonces[1]];
|
||||||
let mut serialized = C::G_to_bytes(&commitments[0]);
|
let mut serialized = C::G_to_bytes(&commitments[0]);
|
||||||
serialized.extend(&C::G_to_bytes(&commitments[1]));
|
serialized.extend(&C::G_to_bytes(&commitments[1]));
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
use core::convert::TryInto;
|
use core::convert::TryInto;
|
||||||
|
|
||||||
use rand::rngs::OsRng;
|
use rand::{RngCore, CryptoRng, rngs::OsRng};
|
||||||
|
|
||||||
use ff::{Field, PrimeField};
|
use ff::{Field, PrimeField};
|
||||||
use group::GroupEncoding;
|
use group::{Group, GroupEncoding};
|
||||||
|
|
||||||
use sha2::{digest::Update, Digest, Sha256};
|
use sha2::{digest::Update, Digest, Sha256};
|
||||||
|
|
||||||
|
@ -102,6 +102,13 @@ impl Curve for P256 {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn random_nonce<R: RngCore + CryptoRng>(secret: Self::F, rng: &mut R) -> Self::F {
|
||||||
|
let mut seed = vec![0; 32];
|
||||||
|
rng.fill_bytes(&mut seed);
|
||||||
|
seed.extend(&secret.to_repr());
|
||||||
|
Self::hash_to_F(&[CONTEXT_STRING, b"nonce"].concat(), &seed)
|
||||||
|
}
|
||||||
|
|
||||||
fn hash_msg(msg: &[u8]) -> Vec<u8> {
|
fn hash_msg(msg: &[u8]) -> Vec<u8> {
|
||||||
(&Sha256::new()
|
(&Sha256::new()
|
||||||
.chain(CONTEXT_STRING)
|
.chain(CONTEXT_STRING)
|
||||||
|
@ -151,7 +158,7 @@ impl Curve for P256 {
|
||||||
.map_err(|_| CurveError::InvalidLength(33, slice.len()))?;
|
.map_err(|_| CurveError::InvalidLength(33, slice.len()))?;
|
||||||
|
|
||||||
let point = ProjectivePoint::from_bytes(&bytes.into());
|
let point = ProjectivePoint::from_bytes(&bytes.into());
|
||||||
if point.is_none().into() {
|
if point.is_none().into() || point.unwrap().is_identity().into() {
|
||||||
Err(CurveError::InvalidPoint)?;
|
Err(CurveError::InvalidPoint)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue