Skip to content

Conversation

@mrdomino
Copy link
Contributor

Rejection sampling means that random_mod is inherently variable-time, and the current name violates the contract in the README:

All functions contained in the crate are designed to execute in
constant time unless explicitly specified otherwise (via a *_vartime
name suffix).

This renames random_mod to random_mod_vartime, adding in deprecated aliases at the old names for backwards-compatibility. It preserves the ConstantTimeLess functionality for good measure and to not needlessly increase the amount of timing information leaked.

Of course, random_mod leaks a pretty small amount of timing information; by my reckoning, at worst an average 2 bits per call, and approaching 0 as the modulus approaches 2^n-1. So this is a bit of an edge case; but I think the vartime naming here reduces surprise.

Rejection sampling means that `random_mod` is inherently variable-time,
and the current name violates the contract in the `README`:

> All functions contained in the crate are designed to execute in
> constant time unless explicitly specified otherwise (via a `*_vartime`
> name suffix).

This renames `random_mod` to `random_mod_vartime`, adding in deprecated
aliases at the old names for backwards-compatibility. It preserves the
`ConstantTimeLess` functionality for good measure and to not needlessly
increase the amount of timing information leaked.

Of course, `random_mod` leaks a pretty small amount of timing
information; by my reckoning, at worst an average 2 bits per call, and
approaching 0 as the modulus approaches `2^n-1`. (We would have exactly
0 at `2^n` if we did a check for powers of 2, but this is currently a
worst case for our `random_mod`; if the user knows they have a power of
2, they should use `random_bits` instead.) So this is a bit of an edge
case; but I argue that the `vartime` naming here reduces surprise.
Comment on lines +488 to +517
/// Generate a random number which is less than a given `modulus`.
///
/// This uses rejection sampling.
///
/// As a result, it runs in variable time that depends in part on
/// `modulus`. If the generator `rng` is cryptographically secure (for
/// example, it implements `CryptoRng`), then this is guaranteed not to
/// leak anything about the output value aside from it being less than
/// `modulus`.
#[deprecated(since = "0.7.0", note = "please use `random_mod_vartime` instead")]
fn random_mod<R: RngCore + ?Sized>(rng: &mut R, modulus: &NonZero<Self>) -> Self {
Self::random_mod_vartime(rng, modulus)
}

/// Generate a random number which is less than a given `modulus`.
///
/// This uses rejection sampling.
///
/// As a result, it runs in variable time that depends in part on
/// `modulus`. If the generator `rng` is cryptographically secure (for
/// example, it implements `CryptoRng`), then this is guaranteed not to
/// leak anything about the output value aside from it being less than
/// `modulus`.
#[deprecated(since = "0.7.0", note = "please use `try_random_mod_vartime` instead")]
fn try_random_mod<R: TryRngCore + ?Sized>(
rng: &mut R,
modulus: &NonZero<Self>,
) -> Result<Self, R::Error> {
Self::try_random_mod_vartime(rng, modulus)
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NB. these are the deprecated aliases added (which might otherwise get lost in the noise of the mechanical rename diff.)

@codecov
Copy link

codecov bot commented Dec 12, 2025

Codecov Report

❌ Patch coverage is 70.17544% with 17 lines in your changes missing coverage. Please review.
✅ Project coverage is 79.79%. Comparing base (ba4f0e0) to head (39fe199).
⚠️ Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
src/traits.rs 0.00% 11 Missing ⚠️
src/uint/boxed/rand.rs 71.42% 2 Missing ⚠️
src/uint/rand.rs 81.81% 2 Missing ⚠️
src/limb/rand.rs 0.00% 1 Missing ⚠️
src/modular/const_monty_form.rs 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1030      +/-   ##
==========================================
- Coverage   79.81%   79.79%   -0.03%     
==========================================
  Files         163      163              
  Lines       17750    17759       +9     
==========================================
+ Hits        14168    14170       +2     
- Misses       3582     3589       +7     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@mrdomino
Copy link
Contributor Author

Rereading the argument about cryptographic security of the RNG, the case for the old name being okay seems stronger than I initially thought. I do think it’s a bit of a funny edge case; I could go either way on this change, feel free to reject if it doesn’t seem worthwhile.

Copy link
Member

@tarcieri tarcieri left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be possible to have a fallible version that runs in constant time, takes a select (possibly const generic) number of samples, selects the first one that fits the criteria in constant-time among all of the samples, and returns an error if none of them fit the criteria.

For now though, I agree, this should be named *_vartime.

@tarcieri
Copy link
Member

Not sure what's going on with codecov. I think it's mad you're adding methods which aren't being tested, even if they're deprecated.

@tarcieri tarcieri merged commit e4e1819 into RustCrypto:master Dec 14, 2025
26 of 27 checks passed
@mrdomino mrdomino deleted the rename-random_mod branch December 17, 2025 19:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants