Update rand to 0.10 with a rand_core 0.6 compatibility shim

Bump the `rand` dev-dependency to the latest (0.10), which exposes rand_core
0.10, while the latest `rsa` (0.9) still requires an rand_core 0.6 RNG for key
generation. Bridge the skew with a small, test-only adapter instead of pinning
rand back.

* Add `rand_core_06 = { package = "rand_core", version = "0.6" }` so the shim
  can implement the old traits (cargo unifies it with the rand_core 0.6 that
  rsa already uses).
* `RandCompat<R>` wraps a modern RNG and re-implements rand_core 0.6's RngCore
  + CryptoRng over it, delegating to rand_core 0.10's infallible methods.
  Implementing both satisfies rand_core 0.6's blanket CryptoRngCore impl, which
  is exactly the bound rsa keygen requires.
* The CryptoRng bound is preserved (only wraps RNGs still marked
  cryptographically secure), so the randomness is not weakened — it is purely a
  trait-version shim. Tests now use `RandCompat(rand::rng())`.

46 tests pass (incl. the RSA-based EPUB roundtrips that exercise the shim);
clippy + rustfmt clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-24 20:44:22 -05:00
co-authored by Claude Opus 4.8
parent 259bb4d6fa
commit 2cdefbe45c
3 changed files with 79 additions and 13 deletions
Generated
+36 -7
View File
@@ -141,6 +141,17 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]]
name = "chacha20"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d524456ba66e72eb8b115ff89e01e497f8e6d11d78b70b1aa13c0fbd97540a81"
dependencies = [
"cfg-if",
"cpufeatures",
"rand_core 0.10.1",
]
[[package]]
name = "cipher"
version = "0.5.2"
@@ -305,7 +316,8 @@ dependencies = [
"hex",
"md-5",
"quick-xml",
"rand",
"rand 0.10.1",
"rand_core 0.6.4",
"rsa",
"serde",
"sha1",
@@ -382,6 +394,7 @@ dependencies = [
"cfg-if",
"libc",
"r-efi",
"rand_core 0.10.1",
]
[[package]]
@@ -525,7 +538,7 @@ dependencies = [
"num-integer",
"num-iter",
"num-traits",
"rand",
"rand 0.8.6",
"smallvec",
"zeroize",
]
@@ -656,9 +669,19 @@ version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a"
dependencies = [
"libc",
"rand_chacha",
"rand_core",
"rand_core 0.6.4",
]
[[package]]
name = "rand"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207"
dependencies = [
"chacha20",
"getrandom 0.4.3",
"rand_core 0.10.1",
]
[[package]]
@@ -668,7 +691,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core",
"rand_core 0.6.4",
]
[[package]]
@@ -680,6 +703,12 @@ dependencies = [
"getrandom 0.2.17",
]
[[package]]
name = "rand_core"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69"
[[package]]
name = "regex-automata"
version = "0.4.14"
@@ -710,7 +739,7 @@ dependencies = [
"num-traits",
"pkcs1",
"pkcs8",
"rand_core",
"rand_core 0.6.4",
"signature",
"spki",
"subtle",
@@ -807,7 +836,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
dependencies = [
"digest 0.10.7",
"rand_core",
"rand_core 0.6.4",
]
[[package]]
+6 -3
View File
@@ -39,6 +39,9 @@ winreg = "0.56"
[dev-dependencies]
tempfile = "3"
# Held at 0.8: the latest `rsa` (0.9) requires an `rand_core` 0.6 RNG for keygen,
# which rand 0.9+ no longer provides; bumping breaks the RSA-based EPUB tests.
rand = "0.8"
rand = "0.10"
# Escape hatch: the latest `rsa` (0.9) still requires an `rand_core` 0.6 RNG for
# key generation, while `rand` 0.10 provides `rand_core` 0.10. We depend on
# `rand_core` 0.6 directly (package-renamed to avoid the name clash) so the
# test-only `RandCompat` shim can re-implement its traits over a modern RNG.
rand_core_06 = { package = "rand_core", version = "0.6" }
+37 -3
View File
@@ -269,9 +269,43 @@ mod tests {
Some(buf)
}
/// Test-only escape hatch for the `rand_core` version skew: `rsa` 0.9 still
/// requires an `rand_core` 0.6 RNG for key generation, while `rand` 0.10
/// exposes `rand_core` 0.10. `RandCompat` wraps a modern RNG and
/// re-implements `rand_core` 0.6's `RngCore`/`CryptoRng` over it, delegating
/// to the new (infallible) methods. Implementing both satisfies `rand_core`
/// 0.6's blanket `CryptoRngCore` impl — exactly what `rsa` keygen wants.
///
/// The `CryptoRng` bound is preserved (we only wrap RNGs the new crate still
/// marks cryptographically secure), so this is a pure trait-version shim that
/// does not weaken the randomness.
struct RandCompat<R>(R);
impl<R: rand::Rng> rand_core_06::RngCore for RandCompat<R> {
fn next_u32(&mut self) -> u32 {
rand::Rng::next_u32(&mut self.0)
}
fn next_u64(&mut self) -> u64 {
rand::Rng::next_u64(&mut self.0)
}
fn fill_bytes(&mut self, dest: &mut [u8]) {
rand::Rng::fill_bytes(&mut self.0, dest)
}
fn try_fill_bytes(
&mut self,
dest: &mut [u8],
) -> std::result::Result<(), rand_core_06::Error> {
// `fill_bytes` is infallible in rand_core 0.10.
rand::Rng::fill_bytes(&mut self.0, dest);
Ok(())
}
}
impl<R: rand::CryptoRng> rand_core_06::CryptoRng for RandCompat<R> {}
fn make_rsa() -> (Vec<u8>, rsa::RsaPublicKey) {
use rsa::pkcs8::EncodePrivateKey;
let mut rng = rand::thread_rng();
let mut rng = RandCompat(rand::rng());
let priv_key = rsa::RsaPrivateKey::new(&mut rng, 1024).unwrap();
let der = priv_key.to_pkcs8_der().unwrap().as_bytes().to_vec();
let pub_key = rsa::RsaPublicKey::from(&priv_key);
@@ -286,7 +320,7 @@ mod tests {
let (der, pub_key) = make_rsa();
let bookkey = [0x5Au8; 16];
let mut rng = rand::thread_rng();
let mut rng = RandCompat(rand::rng());
let enc_key = pub_key
.encrypt(&mut rng, rsa::Pkcs1v15Encrypt, &bookkey)
.unwrap();
@@ -323,7 +357,7 @@ mod tests {
let (_der, pub_key) = make_rsa();
let (other_der, _other_pub) = make_rsa();
let bookkey = [0x5Au8; 16];
let mut rng = rand::thread_rng();
let mut rng = RandCompat(rand::rng());
let enc_key = pub_key
.encrypt(&mut rng, rsa::Pkcs1v15Encrypt, &bookkey)
.unwrap();