From 18cb4b76a77aba1d6542ff8a2d7f00a53d576000 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Thu, 22 May 2025 09:53:53 +0200 Subject: [PATCH 1/3] Improve secret scalar generation --- src/lib.rs | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 470bb69..214cd90 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -126,7 +126,7 @@ #![deny(unsafe_code)] use ark_ec::{AffineRepr, CurveGroup}; -use ark_ff::{One, PrimeField, Zero}; +use ark_ff::{PrimeField, Zero}; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use ark_std::vec::Vec; @@ -323,15 +323,31 @@ impl Secret { Self { scalar, public } } - /// Construct a `Secret` from the given seed. + /// Derives a `Secret` scalar deterministically from a seed. /// - /// The `seed` is hashed using the `Suite::hash` to construct the secret scalar. + /// The seed is hashed using `Suite::Hasher`, and the output is reduced + /// modulo the curve's order to produce a valid scalar in the range + /// `[1, n - 1]`. No clamping or multiplication by the cofactor is + /// performed, regardless of the curve. + /// + /// The caller is responsible for ensuring that the resulting scalar is + /// used safely with respect to the target curve's cofactor and subgroup + /// properties. pub fn from_seed(seed: &[u8]) -> Self { - let bytes = utils::hash::(seed); - let mut scalar = ScalarField::::from_le_bytes_mod_order(&bytes[..]); - if scalar.is_zero() { - scalar.set_one(); - } + let mut cnt = 0_u8; + let scalar = loop { + let mut hasher = S::Hasher::new(); + hasher.update(seed); + if cnt > 0 { + hasher.update(&[cnt]); + } + let bytes = hasher.finalize(); + let scalar = ScalarField::::from_le_bytes_mod_order(&bytes[..]); + if !scalar.is_zero() { + break scalar; + } + cnt += 1; + }; Self::from_scalar(scalar) } @@ -425,7 +441,7 @@ macro_rules! suite_types { mod tests { use super::*; use suites::testing::{Input, Secret}; - use testing::{TEST_SEED, random_val}; + use testing::{random_val, TEST_SEED}; #[test] fn vrf_output_check() { From 352ff530c81896eac02e0bbb897dd86012eab685 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Thu, 22 May 2025 09:55:41 +0200 Subject: [PATCH 2/3] Clippy --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 214cd90..2c7df96 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -339,7 +339,7 @@ impl Secret { let mut hasher = S::Hasher::new(); hasher.update(seed); if cnt > 0 { - hasher.update(&[cnt]); + hasher.update([cnt]); } let bytes = hasher.finalize(); let scalar = ScalarField::::from_le_bytes_mod_order(&bytes[..]); From 61b093d1bf5cfb7a70d15b655bcaa3868715e376 Mon Sep 17 00:00:00 2001 From: Davide Galassi Date: Thu, 22 May 2025 09:56:56 +0200 Subject: [PATCH 3/3] Fmt --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 2c7df96..0ecabf4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -441,7 +441,7 @@ macro_rules! suite_types { mod tests { use super::*; use suites::testing::{Input, Secret}; - use testing::{random_val, TEST_SEED}; + use testing::{TEST_SEED, random_val}; #[test] fn vrf_output_check() {