mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-10 05:09:22 +00:00
Update to FROST v8
This commit is contained in:
@@ -16,13 +16,18 @@ macro_rules! dalek_curve {
|
||||
|
||||
$ID: literal,
|
||||
$CONTEXT: literal,
|
||||
$chal: literal,
|
||||
$digest: literal,
|
||||
$chal: literal,
|
||||
) => {
|
||||
use dalek_ff_group::{$Point, $POINT};
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize)]
|
||||
pub struct $Curve;
|
||||
impl $Curve {
|
||||
fn hash(dst: &[u8], data: &[u8]) -> Sha512 {
|
||||
Sha512::new().chain_update(&[$CONTEXT.as_ref(), dst, data].concat())
|
||||
}
|
||||
}
|
||||
|
||||
impl Curve for $Curve {
|
||||
type F = Scalar;
|
||||
type G = $Point;
|
||||
@@ -33,21 +38,12 @@ macro_rules! dalek_curve {
|
||||
$POINT
|
||||
}
|
||||
|
||||
fn hash_msg(msg: &[u8]) -> Vec<u8> {
|
||||
Sha512::new()
|
||||
.chain_update($CONTEXT)
|
||||
.chain_update($digest)
|
||||
.chain_update(msg)
|
||||
.finalize()
|
||||
.to_vec()
|
||||
fn hash_to_vec(dst: &[u8], data: &[u8]) -> Vec<u8> {
|
||||
Self::hash(dst, data).finalize().to_vec()
|
||||
}
|
||||
|
||||
fn hash_binding_factor(binding: &[u8]) -> Self::F {
|
||||
Self::hash_to_F(b"rho", binding)
|
||||
}
|
||||
|
||||
fn hash_to_F(dst: &[u8], msg: &[u8]) -> Self::F {
|
||||
Scalar::from_hash(Sha512::new().chain_update($CONTEXT).chain_update(dst).chain_update(msg))
|
||||
fn hash_to_F(dst: &[u8], data: &[u8]) -> Self::F {
|
||||
Scalar::from_hash(Self::hash(dst, data))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +52,13 @@ macro_rules! dalek_curve {
|
||||
impl Hram<$Curve> for $Hram {
|
||||
#[allow(non_snake_case)]
|
||||
fn hram(R: &$Point, A: &$Point, m: &[u8]) -> Scalar {
|
||||
$Curve::hash_to_F($chal, &[&R.compress().to_bytes(), &A.compress().to_bytes(), m].concat())
|
||||
let mut hash = Sha512::new();
|
||||
if $chal.len() != 0 {
|
||||
hash.update(&[$CONTEXT.as_ref(), $chal].concat());
|
||||
}
|
||||
Scalar::from_hash(
|
||||
hash.chain_update(&[&R.compress().to_bytes(), &A.compress().to_bytes(), m].concat()),
|
||||
)
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -69,9 +71,8 @@ dalek_curve!(
|
||||
RistrettoPoint,
|
||||
RISTRETTO_BASEPOINT_POINT,
|
||||
b"ristretto",
|
||||
b"FROST-RISTRETTO255-SHA512-v5",
|
||||
b"FROST-RISTRETTO255-SHA512-v8",
|
||||
b"chal",
|
||||
b"digest",
|
||||
);
|
||||
|
||||
#[cfg(feature = "ed25519")]
|
||||
@@ -81,7 +82,6 @@ dalek_curve!(
|
||||
EdwardsPoint,
|
||||
ED25519_BASEPOINT_POINT,
|
||||
b"edwards25519",
|
||||
b"",
|
||||
b"",
|
||||
b"FROST-ED25519-SHA512-v8",
|
||||
b"",
|
||||
);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use zeroize::Zeroize;
|
||||
|
||||
use sha2::{digest::Update, Digest, Sha256};
|
||||
use sha2::{Digest, Sha256};
|
||||
|
||||
use group::{
|
||||
ff::{Field, PrimeField},
|
||||
@@ -26,6 +26,12 @@ macro_rules! kp_curve {
|
||||
) => {
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize)]
|
||||
pub struct $Curve;
|
||||
impl $Curve {
|
||||
fn hash(dst: &[u8], data: &[u8]) -> Sha256 {
|
||||
Sha256::new().chain_update(&[$CONTEXT.as_ref(), dst, data].concat())
|
||||
}
|
||||
}
|
||||
|
||||
impl Curve for $Curve {
|
||||
type F = $lib::Scalar;
|
||||
type G = $lib::ProjectivePoint;
|
||||
@@ -36,17 +42,13 @@ macro_rules! kp_curve {
|
||||
$lib::ProjectivePoint::GENERATOR
|
||||
}
|
||||
|
||||
fn hash_msg(msg: &[u8]) -> Vec<u8> {
|
||||
(&Sha256::new().chain($CONTEXT).chain(b"digest").chain(msg).finalize()).to_vec()
|
||||
}
|
||||
|
||||
fn hash_binding_factor(binding: &[u8]) -> Self::F {
|
||||
Self::hash_to_F(&[$CONTEXT as &[u8], b"rho"].concat(), binding)
|
||||
fn hash_to_vec(dst: &[u8], data: &[u8]) -> Vec<u8> {
|
||||
Self::hash(dst, data).finalize().to_vec()
|
||||
}
|
||||
|
||||
fn hash_to_F(dst: &[u8], msg: &[u8]) -> Self::F {
|
||||
let mut dst = dst;
|
||||
let oversize = Sha256::digest([b"H2C-OVERSIZE-DST-", dst].concat());
|
||||
let mut dst = &[$CONTEXT, dst].concat();
|
||||
let oversize = Sha256::digest([b"H2C-OVERSIZE-DST-".as_ref(), dst].concat()).to_vec();
|
||||
if dst.len() > 255 {
|
||||
dst = &oversize;
|
||||
}
|
||||
@@ -79,17 +81,14 @@ macro_rules! kp_curve {
|
||||
impl Hram<$Curve> for $Hram {
|
||||
#[allow(non_snake_case)]
|
||||
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(),
|
||||
)
|
||||
$Curve::hash_to_F(b"chal", &[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-v8");
|
||||
|
||||
#[cfg(feature = "secp256k1")]
|
||||
kp_curve!(k256, Secp256k1, NonIetfSecp256k1Hram, b"secp256k1", b"FROST-secp256k1-SHA256-v7");
|
||||
kp_curve!(k256, Secp256k1, IetfSecp256k1Hram, b"secp256k1", b"FROST-secp256k1-SHA256-v8");
|
||||
|
||||
@@ -20,7 +20,7 @@ pub use dalek::{Ed25519, IetfEd25519Hram};
|
||||
#[cfg(feature = "kp256")]
|
||||
mod kp256;
|
||||
#[cfg(feature = "secp256k1")]
|
||||
pub use kp256::{Secp256k1, NonIetfSecp256k1Hram};
|
||||
pub use kp256::{Secp256k1, IetfSecp256k1Hram};
|
||||
#[cfg(feature = "p256")]
|
||||
pub use kp256::{P256, IetfP256Hram};
|
||||
|
||||
@@ -53,20 +53,30 @@ pub trait Curve: Clone + Copy + PartialEq + Eq + Debug + Zeroize {
|
||||
// While group does provide this in its API, privacy coins may want to use a custom basepoint
|
||||
fn generator() -> Self::G;
|
||||
|
||||
/// 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 also solely relates to FROST and with a proper Algorithm/HRAM, all projects using
|
||||
// aggregatable signatures over this curve will work without issue
|
||||
// It is kept here as Curve + H{1, 2, 3, 4} is effectively a ciphersuite according to the IETF
|
||||
// draft and moving it to Schnorr would force all of them into being ciphersuite-specific
|
||||
// H2 is left to the Schnorr Algorithm as H2 is the H used in HRAM, which Schnorr further
|
||||
// modularizes
|
||||
fn hash_msg(msg: &[u8]) -> Vec<u8>;
|
||||
/// Hash the given dst and data to a byte vector. Used to instantiate H4 and H5.
|
||||
fn hash_to_vec(dst: &[u8], data: &[u8]) -> Vec<u8>;
|
||||
|
||||
/// Field element from hash. Used during key gen and by other crates under Serai as a general
|
||||
/// utility. Used to instantiate H1 and H3.
|
||||
#[allow(non_snake_case)]
|
||||
fn hash_to_F(dst: &[u8], msg: &[u8]) -> Self::F;
|
||||
|
||||
/// Hash the message for the binding factor. H4 from the IETF draft
|
||||
fn hash_msg(msg: &[u8]) -> Vec<u8> {
|
||||
Self::hash_to_vec(b"msg", msg)
|
||||
}
|
||||
|
||||
/// Hash the commitments for the binding factor. H5 from the IETF draft
|
||||
fn hash_commitments(commitments: &[u8]) -> Vec<u8> {
|
||||
Self::hash_to_vec(b"com", commitments)
|
||||
}
|
||||
|
||||
/// Hash the commitments and message to calculate the binding factor. H1 from the IETF draft
|
||||
fn hash_binding_factor(binding: &[u8]) -> Self::F;
|
||||
fn hash_binding_factor(binding: &[u8]) -> Self::F {
|
||||
Self::hash_to_F(b"rho", binding)
|
||||
}
|
||||
|
||||
/// Securely generate a random nonce. H4 from the IETF draft
|
||||
/// 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);
|
||||
@@ -84,13 +94,6 @@ pub trait Curve: Clone + Copy + PartialEq + Eq + Debug + Zeroize {
|
||||
res
|
||||
}
|
||||
|
||||
/// Field element from hash. Used during key gen and by other crates under Serai as a general
|
||||
/// utility
|
||||
// Not parameterized by Digest as it's fine for it to use its own hash function as relevant to
|
||||
// hash_msg and hash_binding_factor
|
||||
#[allow(non_snake_case)]
|
||||
fn hash_to_F(dst: &[u8], msg: &[u8]) -> Self::F;
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
fn F_len() -> usize {
|
||||
<Self::F as PrimeField>::Repr::default().as_ref().len()
|
||||
|
||||
Reference in New Issue
Block a user