mirror of
https://github.com/serai-dex/serai.git
synced 2025-04-23 14:38:14 +00:00
Update to FROST v8
This commit is contained in:
parent
4881ddae87
commit
a8a00598e4
7 changed files with 96 additions and 98 deletions
|
@ -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()
|
||||
|
|
|
@ -253,7 +253,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_commitments(params.algorithm.transcript().challenge(b"commitments").as_ref()),
|
||||
);
|
||||
|
||||
// Include the offset, if one exists
|
||||
|
|
|
@ -24,20 +24,20 @@ fn ristretto_vectors() {
|
|||
included: &[1, 3],
|
||||
nonces: &[
|
||||
[
|
||||
"eb0dc12ae7b746d36e3f2de46ce3833a05b9d4af5434eeb8cafaefda76906d00",
|
||||
"491e91aa9df514ef598d5e0c7c5cdd088fbde4965b96069d546c0f04f1822b03",
|
||||
"1eaee906e0554a5e533415e971eefa909f3c614c7c75e27f381b0270a9afe308",
|
||||
"16175fc2e7545baf7180e8f5b6e1e73c4f2769323cc76754bdd79fe93ab0bd0b",
|
||||
],
|
||||
[
|
||||
"abd12b8e6f255ee1e540eab029003a6e956567617720f61115f0941615892209",
|
||||
"218e22625f93f262f025bd2d13c46ba722aa29fe585ceed66ff442d98fe4e509",
|
||||
"48d78b8c2de1a515513f9d3fc464a19a72304fac522f17cc647706cb22c21403",
|
||||
"5c0f10966b3f1386660a87de0fafd69decbe9ffae1a152a88b7d83bb4fb1c908",
|
||||
],
|
||||
],
|
||||
sig_shares: &[
|
||||
"efae3a83437fa8cd96194aacc56a7eb841630c280da99e7764a81d1340323306",
|
||||
"96ddc4582e45eabce46f07b9e9375f8b49d35d1510fd34ac02b1e79d6100a602",
|
||||
"5ae13621ebeef844e39454eb3478a50c4531d25939e1065f44f5b04a8535090e",
|
||||
"aa432dcf274a9441c205e76fe43497be99efe374f9853477bd5add2075f6970c",
|
||||
],
|
||||
sig: "7ec584cef9a383afb43883b73bcaa6313afe878bd5fe75a608311b866a76ec67".to_owned() +
|
||||
"858cffdb71c4928a7b895165afa2dd438b366a3d1da6d323675905b1a132d908",
|
||||
sig: "9c407badb8cacf10f306d94e31fb2a71d6a8398039802b4d80a1278472397206".to_owned() +
|
||||
"17516e93f8d57a2ecffd43b83ab35db6de20b6ce32673bd601508e6bfa2ba10a",
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -61,20 +61,20 @@ fn ed25519_vectors() {
|
|||
included: &[1, 3],
|
||||
nonces: &[
|
||||
[
|
||||
"d9aad97e1a1127bb87702ce8d81d8c07c7cbca89e784868d8e3876ff6b459700",
|
||||
"5063be2774520d08a5ccd7f1213fb1179a5fa292bf13bc91cb28e7bd4d4a690c",
|
||||
"1c406170127e33142b8611bc02bf14d5909e49d5cb87150eff3ec9804212920c",
|
||||
"5be4edde8b7acd79528721191626810c94fbc2bcc814b7a67d301fbd7fc16e07",
|
||||
],
|
||||
[
|
||||
"86961f3a429ac0c5696f49e6d796817ff653f83c07f34e9e1f4d4c8c515b7900",
|
||||
"72225ec11c1315d9f1ea0e78b1160ed95800fadd0191d23fd2f2c90ac96cb307",
|
||||
"795f87122f05b7efc4b1a52f435c3d28597411b1a6fec198ce9c818c5451c401",
|
||||
"c9193aaef37bc074ea3286d0361c815f7201bf764cd9e7d8bb4eb5ecca840a09",
|
||||
],
|
||||
],
|
||||
sig_shares: &[
|
||||
"caae171b83bff0c2c6f56a1276892918ba228146f6344b85d2ec6efeb6f16d0d",
|
||||
"ea6fdbf61683cf5f1f742e1b91583f0f667f0369efd2e33399b96d5a3ff0300d",
|
||||
"1f16a3989b4aa2cc3782a503331b9a21d7ba56c9c5455d06981b5425306c9d01",
|
||||
"4c8f33c301c05871b434a686847d5818417a01e50a59e9e7fddaefde7d244207",
|
||||
],
|
||||
sig: "5da10008c13c04dd72328ba8e0f72b63cad43c3bf4b7eaada1c78225afbd977e".to_owned() +
|
||||
"c74afdb47fdfadca0fcda18a28e8891220a284afe5072fb96ba6dc58f6e19e0a",
|
||||
sig: "1aff2259ecb59cfcbb36ae77e02a9b134422abeae47cf7ff56c85fdf90932b18".to_owned() +
|
||||
"6ba5d65b9d0afb3decb64b8ab798f239183558aed09e46ee95f64304ae90df08",
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
@ -4,15 +4,15 @@ use rand_core::OsRng;
|
|||
use crate::tests::vectors::{Vectors, test_with_vectors};
|
||||
|
||||
#[cfg(feature = "secp256k1")]
|
||||
use crate::curve::{Secp256k1, NonIetfSecp256k1Hram};
|
||||
use crate::curve::{Secp256k1, IetfSecp256k1Hram};
|
||||
|
||||
#[cfg(feature = "p256")]
|
||||
use crate::curve::{P256, IetfP256Hram};
|
||||
|
||||
#[cfg(feature = "secp256k1")]
|
||||
#[test]
|
||||
fn secp256k1_non_ietf() {
|
||||
test_with_vectors::<_, Secp256k1, NonIetfSecp256k1Hram>(
|
||||
fn secp256k1_ietf() {
|
||||
test_with_vectors::<_, Secp256k1, IetfSecp256k1Hram>(
|
||||
&mut OsRng,
|
||||
Vectors {
|
||||
threshold: 2,
|
||||
|
@ -28,20 +28,20 @@ fn secp256k1_non_ietf() {
|
|||
included: &[1, 3],
|
||||
nonces: &[
|
||||
[
|
||||
"31c3c1b76b76664569859b9251fbabed9d4d432c6f5aaa03ed41f9c231935798",
|
||||
"206f4ffaeb602ccb57cbe50e146ac690e6d7317d4b93377061d9d1b4caf78a26",
|
||||
"95f352cf568508bce96ef3cb816bf9229eb521ca9c2aff6a4fe8b86bf49ae16f",
|
||||
"c675aea50ff2510ae6b0fcb55432b97ad0b55a28b959bacb0e8b466dbf43dd26",
|
||||
],
|
||||
[
|
||||
"0d3945bc1553676a5dd910cb4f14437d99ed421516b2617357b984820fdca520",
|
||||
"635e0fd90caaf40b5e986d0ee0f58778e4d88731bc6ac70350ef702ffe20a21b",
|
||||
"b5089ebf363630d3477711005173c1419f4f40514f7287b4ca6ff110967a2d70",
|
||||
"5e50ce9975cfc6164e85752f52094b11091fdbca846a9c245fdbfa4bab1ae28c",
|
||||
],
|
||||
],
|
||||
sig_shares: &[
|
||||
"18b71e284c5d008896ed8847b234ec829eda376d6208838ee7faf2ce21b154c1",
|
||||
"a452a49c8116124d0a283f3589a96b704894b43246e47e59d376353bcc638311",
|
||||
"280c44c6c37cd64c7f5a552ae8416a57d21c115cab524dbff5fbcebbf5c0019d",
|
||||
"e372bca35133a80ca140dcac2125c966b763a934678f40e09fb8b0ae9d4aee1b",
|
||||
],
|
||||
sig: "03dafb28ee7ad033fd15ed470d07156617260d74a9d76a15d371d7b613d2b111e".to_owned() +
|
||||
"7bd09c2c4cd7312d5a115c77d3bde57f2e76eeb9fa8ed01e8bb712809ee14d7d2",
|
||||
sig: "0364b02292a4b0e61f849f4d6fac0e67c2f698a21e1cba9e4a5b8fa535f2f9310d".to_owned() +
|
||||
"0b7f016a14b07e59209b31d7096733bfced0ddaa6398ee64d5e220ddc2d4ae77",
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -65,20 +65,20 @@ fn p256_vectors() {
|
|||
included: &[1, 3],
|
||||
nonces: &[
|
||||
[
|
||||
"33a519cf070a166f9ef41a798d03423743f3e7d0b0efd5d0d963773c4c53205e",
|
||||
"307d208d0c5728f323ae374f1ebd7f14a1a49b77d9d4bc1eab222218a17765ff",
|
||||
"e9165dad654fc20a9e31ca6f32ac032ec327b551a50e8ac5cf25f5c4c9e20757",
|
||||
"e9059a232598a0fba0e495a687580e624ab425337c3221246fb2c716905bc9e7",
|
||||
],
|
||||
[
|
||||
"a614eadb972dc37b88aeceb6e899903f3104742d13f379a0e014541decbea4a4",
|
||||
"e509791018504c5bb87edaf0f44761cc840888507c4cd80237971d78e65f70f2",
|
||||
"b9d136e29eb758bd77cb83c317ac4e336cf8cda830c089deddf6d5ec81da9884",
|
||||
"5261e2d00ce227e67bb9b38990294e2c82970f335b2e6d9f1d07a72ba43d01f0",
|
||||
],
|
||||
],
|
||||
sig_shares: &[
|
||||
"61e8b9c474df2e66ad19fd80a6e6cec1c6fe43c0a1cffd2d1c28299e93e1bbdb",
|
||||
"9651d355ca1dea2557ba1f73e38a9f4ff1f1afc565323ef27f88a9d14df8370e",
|
||||
"bdaa275f10ca57e3a3a9a7a0d95aeabb517897d8482873a8f9713d458f94756f",
|
||||
"0e8fd85386939e8974a8748e66641df0fe043323c52487a2b10b8a397897de21",
|
||||
],
|
||||
sig: "02dfba781e17b830229ae4ed22ebe402873683d9dfd945d01762217fb3172c2a7".to_owned() +
|
||||
"1f83a8d1a3efd188c04d41cf48a716e11b8eff38607023c1f9bb0d36fe1d9f2e9",
|
||||
sig: "03c41521412528dce484c35b6b9b7cc8150102ab3e4bdf858d702270c05098e6c6".to_owned() +
|
||||
"cc39ffb2975df66d18521c2f3fbf08ac4f7ccafc0d4cfb4baa7cc77f082c5390",
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
@ -70,16 +70,12 @@ impl<C: Curve> Curve for AltGenerator<C> {
|
|||
C::G::generator() * C::hash_to_F(b"FROST_tests", b"generator")
|
||||
}
|
||||
|
||||
fn hash_msg(msg: &[u8]) -> Vec<u8> {
|
||||
C::hash_msg(msg)
|
||||
fn hash_to_vec(dst: &[u8], data: &[u8]) -> Vec<u8> {
|
||||
C::hash_to_vec(&[b"FROST_tests_alt", dst].concat(), data)
|
||||
}
|
||||
|
||||
fn hash_binding_factor(binding: &[u8]) -> Self::F {
|
||||
C::hash_binding_factor(binding)
|
||||
}
|
||||
|
||||
fn hash_to_F(dst: &[u8], msg: &[u8]) -> Self::F {
|
||||
C::hash_to_F(dst, msg)
|
||||
fn hash_to_F(dst: &[u8], data: &[u8]) -> Self::F {
|
||||
C::hash_to_F(&[b"FROST_tests_alt", dst].concat(), data)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue