Skip to content

Commit

Permalink
elliptic-curve: adds Scalar::try_from_rng method (#1774)
Browse files Browse the repository at this point in the history
Depends:
 - zkcrypto/ff#126
 - zkcrypto/ff#127
 
This is to provide an `ecdsa::SigningKey::try_from_rng` API
(RustCrypto/signatures#915)
  • Loading branch information
baloo authored Mar 4, 2025
1 parent 67c5bf8 commit 27835aa
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 8 deletions.
1 change: 0 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ hmac = { git = "https://github.com/RustCrypto/MACs.git" }
crypto-bigint = { git = "https://github.com/RustCrypto/crypto-bigint.git" }

# https://github.com/zkcrypto/ff/pull/122
ff = { git = "https://github.com/pinkforest/ff.git", branch = "bump-rand-core" }
# https://github.com/zkcrypto/ff/pull/126
# https://github.com/zkcrypto/ff/pull/127
ff = { git = "https://github.com/baloo/ff.git", branch = "baloo/try_from_rng" }

# https://github.com/zkcrypto/group/pull/56
group = { git = "https://github.com/pinkforest/group.git", branch = "bump-rand-0.9" }
15 changes: 13 additions & 2 deletions elliptic-curve/src/dev.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::{
error::{Error, Result},
ops::{Invert, LinearCombination, MulByGenerator, Reduce, ShrAssign},
point::AffineCoordinates,
rand_core::RngCore,
rand_core::{RngCore, TryRngCore},
scalar::{FromUintUnchecked, IsHigh},
sec1::{CompressedPoint, FromEncodedPoint, ToEncodedPoint},
subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption},
Expand Down Expand Up @@ -99,7 +99,7 @@ impl Field for Scalar {
const ZERO: Self = Self(ScalarPrimitive::ZERO);
const ONE: Self = Self(ScalarPrimitive::ONE);

fn random(mut rng: impl RngCore) -> Self {
fn random<R: RngCore + ?Sized>(rng: &mut R) -> Self {
let mut bytes = FieldBytes::default();

loop {
Expand All @@ -110,6 +110,17 @@ impl Field for Scalar {
}
}

fn try_from_rng<R: TryRngCore + ?Sized>(rng: &mut R) -> core::result::Result<Self, R::Error> {
let mut bytes = FieldBytes::default();

loop {
rng.try_fill_bytes(&mut bytes)?;
if let Some(scalar) = Self::from_repr(bytes).into() {
return Ok(scalar);
}
}
}

fn is_zero(&self) -> Choice {
self.0.is_zero()
}
Expand Down
20 changes: 16 additions & 4 deletions elliptic-curve/src/scalar/nonzero.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use core::{
};
use crypto_bigint::{ArrayEncoding, Integer};
use ff::{Field, PrimeField};
use rand_core::CryptoRng;
use rand_core::{CryptoRng, TryCryptoRng};
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
use zeroize::Zeroize;

Expand Down Expand Up @@ -47,19 +47,31 @@ where
C: CurveArithmetic,
{
/// Generate a random `NonZeroScalar`.
pub fn random<R: CryptoRng + ?Sized>(mut rng: &mut R) -> Self {
pub fn random<R: CryptoRng + ?Sized>(rng: &mut R) -> Self {
// Use rejection sampling to eliminate zero values.
// While this method isn't constant-time, the attacker shouldn't learn
// anything about unrelated outputs so long as `rng` is a secure `CryptoRng`.
loop {
// TODO: remove after `Field::random` switches to `&mut impl RngCore`
#[allow(clippy::needless_borrows_for_generic_args)]
if let Some(result) = Self::new(Field::random(&mut rng)).into() {
if let Some(result) = Self::new(Field::random(rng)).into() {
break result;
}
}
}

/// Generate a random `NonZeroScalar`.
pub fn try_from_rng<R: TryCryptoRng + ?Sized>(rng: &mut R) -> Result<Self, R::Error> {
// Use rejection sampling to eliminate zero values.
// While this method isn't constant-time, the attacker shouldn't learn
// anything about unrelated outputs so long as `rng` is a secure `CryptoRng`.
loop {
// TODO: remove after `Field::random` switches to `&mut impl RngCore`
if let Some(result) = Self::new(Scalar::<C>::try_from_rng(rng)?).into() {
break Ok(result);
}
}
}

/// Create a [`NonZeroScalar`] from a scalar.
pub fn new(scalar: Scalar<C>) -> CtOption<Self> {
CtOption::new(Self { scalar }, !scalar.is_zero())
Expand Down

0 comments on commit 27835aa

Please sign in to comment.