Skip to content

Commit 07acf8d

Browse files
Rust wrapper: add rand_core trait support
1 parent 7efc962 commit 07acf8d

5 files changed

Lines changed: 97 additions & 5 deletions

File tree

wrapper/rust/wolfssl-wolfcrypt/Cargo.lock

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

wrapper/rust/wolfssl-wolfcrypt/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ readme = "README.md"
1212

1313
[features]
1414
std = []
15+
rand_core = ["dep:rand_core"]
16+
17+
[dependencies]
18+
rand_core = { version = "0.10", optional = true, default-features = false }
1519

1620
[build-dependencies]
1721
bindgen = "0.72.1"

wrapper/rust/wolfssl-wolfcrypt/Makefile

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
1+
FEATURES := rand_core
2+
CARGO_FEATURE_FLAGS := --features $(FEATURES)
3+
14
.PHONY: all
25
all:
3-
cargo build
4-
cargo clippy
5-
cargo doc
6+
cargo build $(CARGO_FEATURE_FLAGS)
7+
cargo clippy $(CARGO_FEATURE_FLAGS)
8+
cargo doc $(CARGO_FEATURE_FLAGS)
69

710
.PHONY: test
811
test:
9-
cargo test -- --test-threads=1
12+
cargo test $(CARGO_FEATURE_FLAGS) -- --test-threads=1
1013

1114
.PHONY: testfips
1215
testfips:
13-
cargo test --lib --bins --tests -- --test-threads=1
16+
cargo test $(CARGO_FEATURE_FLAGS) --lib --bins --tests -- --test-threads=1
1417

1518
.PHONY: clean
1619
clean:

wrapper/rust/wolfssl-wolfcrypt/src/random.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,34 @@ impl RNG {
380380
}
381381
}
382382

383+
/// Implement `rand_core::TryRng` for `RNG`, allowing it to be used anywhere
384+
/// a standard Rust RNG is expected.
385+
///
386+
/// `Error` is set to `Infallible` so that the blanket impls for `Rng` and
387+
/// `CryptoRng` apply automatically. wolfSSL RNG failures cause a panic, which
388+
/// is consistent with the infallible contract.
389+
#[cfg(feature = "rand_core")]
390+
impl rand_core::TryRng for RNG {
391+
type Error = core::convert::Infallible;
392+
393+
fn try_next_u32(&mut self) -> Result<u32, Self::Error> {
394+
rand_core::utils::next_word_via_fill(self)
395+
}
396+
397+
fn try_next_u64(&mut self) -> Result<u64, Self::Error> {
398+
rand_core::utils::next_word_via_fill(self)
399+
}
400+
401+
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Self::Error> {
402+
self.generate_block(dest).expect("RNG failure");
403+
Ok(())
404+
}
405+
}
406+
407+
/// Mark `RNG` as a cryptographically secure random number generator.
408+
#[cfg(feature = "rand_core")]
409+
impl rand_core::TryCryptoRng for RNG {}
410+
383411
impl Drop for RNG {
384412
/// Safely free the underlying wolfSSL RNG context.
385413
///

wrapper/rust/wolfssl-wolfcrypt/tests/test_random.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,3 +97,53 @@ fn test_rng_reseed() {
9797
let seed = [1u8, 2, 3, 4];
9898
rng.reseed(&seed).expect("Error with reseed()");
9999
}
100+
101+
#[test]
102+
#[cfg(feature = "rand_core")]
103+
fn test_rng_rand_core_fill_bytes() {
104+
use rand_core::Rng;
105+
let mut rng = RNG::new().expect("Failed to create RNG");
106+
let mut buf = [0u8; 32];
107+
rng.fill_bytes(&mut buf);
108+
assert_ne!(buf, [0u8; 32]);
109+
}
110+
111+
#[test]
112+
#[cfg(feature = "rand_core")]
113+
fn test_rng_rand_core_try_fill_bytes() {
114+
use rand_core::TryRng;
115+
let mut rng = RNG::new().expect("Failed to create RNG");
116+
let mut buf = [0u8; 32];
117+
rng.try_fill_bytes(&mut buf).expect("Failed to try_fill_bytes");
118+
assert_ne!(buf, [0u8; 32]);
119+
}
120+
121+
#[test]
122+
#[cfg(feature = "rand_core")]
123+
fn test_rng_rand_core_next_u32() {
124+
use rand_core::Rng;
125+
let mut rng = RNG::new().expect("Failed to create RNG");
126+
// Generate several values and verify they aren't all zero
127+
let v: u64 = (0..4).map(|_| rng.next_u32() as u64).sum();
128+
assert_ne!(v, 0);
129+
}
130+
131+
#[test]
132+
#[cfg(feature = "rand_core")]
133+
fn test_rng_rand_core_next_u64() {
134+
use rand_core::Rng;
135+
let mut rng = RNG::new().expect("Failed to create RNG");
136+
// Generate two values and verify they aren't all ones
137+
let v1 = rng.next_u64();
138+
let v2 = rng.next_u64();
139+
assert_ne!(v1 & v2, u64::MAX);
140+
}
141+
142+
#[test]
143+
#[cfg(feature = "rand_core")]
144+
fn test_rng_is_crypto_rng() {
145+
use rand_core::CryptoRng;
146+
fn requires_crypto_rng<R: CryptoRng>(_: &R) {}
147+
let rng = RNG::new().expect("Failed to create RNG");
148+
requires_crypto_rng(&rng);
149+
}

0 commit comments

Comments
 (0)