-
Notifications
You must be signed in to change notification settings - Fork 14
dyn RNG #37
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: release/0.1.2alpha
Are you sure you want to change the base?
dyn RNG #37
Changes from all commits
eda7d32
1757233
fa76da7
5a5ac83
e520463
518b9e6
67977bd
0f68121
1897b69
3af4d9c
05b2dfc
ca0a3a5
f37f633
b058773
db7a727
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,92 @@ | ||
| //! A deterministic fake [RNG] for reproducible tests. | ||
|
|
||
| use bouncycastle_core::errors::RNGError; | ||
| use bouncycastle_core::key_material::{KeyMaterialTrait, KeyType}; | ||
| use bouncycastle_core::traits::{RNG, SecurityStrength}; | ||
|
|
||
| /// A test-only fake [RNG] that produces a fixed, fully deterministic byte stream. | ||
| /// | ||
| /// The stream is the `SEED_LEN`-byte seed repeated indefinitely. A single internal counter is | ||
| /// shared across every [RNG] method, so each byte handed out — whether through | ||
| /// [RNG::next_bytes_out], [RNG::next_bytes], [RNG::next_int], or [RNG::fill_keymaterial_out] — | ||
| /// advances the same stream. Two instances built from the same seed therefore emit identical | ||
| /// streams, which is what makes RNG-driven operations reproducible (and comparable against their | ||
| /// seed/`m`-driven internal counterparts) in tests. | ||
| /// | ||
| /// This is a deterministic stub for tests only; it is in no way a secure RNG. | ||
| pub struct FixedSeedRNG<const SEED_LEN: usize> { | ||
| seed: [u8; SEED_LEN], | ||
| counter: usize, | ||
| } | ||
|
|
||
| impl<const SEED_LEN: usize> FixedSeedRNG<SEED_LEN> { | ||
| /// Create an instance that emits `seed` repeated indefinitely, starting from its first byte. | ||
| pub fn new(seed: [u8; SEED_LEN]) -> Self { | ||
| Self { seed, counter: 0 } | ||
| } | ||
|
|
||
| /// Pull the next byte from the deterministic stream and advance the counter. | ||
| fn next_byte(&mut self) -> u8 { | ||
| let b = self.seed[self.counter % SEED_LEN]; | ||
| self.counter += 1; | ||
| b | ||
| } | ||
| } | ||
|
|
||
| impl<const SEED_LEN: usize> RNG for FixedSeedRNG<SEED_LEN> { | ||
| /// No-op: this fake RNG ignores reseeding, since its stream is fixed by construction. | ||
| fn add_seed_keymaterial( | ||
| &mut self, | ||
| _additional_seed: &dyn KeyMaterialTrait, | ||
| ) -> Result<(), RNGError> { | ||
| Ok(()) | ||
| } | ||
|
|
||
| fn next_int(&mut self) -> Result<u32, RNGError> { | ||
| let mut buf = [0u8; 4]; | ||
| for slot in buf.iter_mut() { | ||
| *slot = self.next_byte(); | ||
| } | ||
| Ok(u32::from_le_bytes(buf)) | ||
| } | ||
|
|
||
| fn next_bytes(&mut self, len: usize) -> Result<Vec<u8>, RNGError> { | ||
| let mut out = vec![0u8; len]; | ||
| for slot in out.iter_mut() { | ||
| *slot = self.next_byte(); | ||
| } | ||
| Ok(out) | ||
| } | ||
|
|
||
| fn next_bytes_out(&mut self, out: &mut [u8]) -> Result<usize, RNGError> { | ||
| for slot in out.iter_mut() { | ||
| *slot = self.next_byte(); | ||
| } | ||
| Ok(out.len()) | ||
| } | ||
|
|
||
| /// Fill `out` to capacity from the stream and mark it as a full-entropy 256-bit seed, | ||
| /// mirroring what a real DRBG's `generate_keymaterial_out` produces. A 256-bit security | ||
| /// strength is enough for every ML-KEM / ML-DSA parameter set. | ||
| fn fill_keymaterial_out(&mut self, out: &mut dyn KeyMaterialTrait) -> Result<usize, RNGError> { | ||
| out.allow_hazardous_operations(); | ||
| let len = { | ||
| // mut_ref_to_bytes is infallible here because we just allowed hazardous operations. | ||
| let buf = out.mut_ref_to_bytes().unwrap(); | ||
| for slot in buf.iter_mut() { | ||
| *slot = self.seed[self.counter % SEED_LEN]; | ||
| self.counter += 1; | ||
| } | ||
| buf.len() | ||
| }; | ||
| out.set_key_len(len)?; | ||
| out.set_key_type(KeyType::Seed)?; | ||
| out.set_security_strength(SecurityStrength::_256bit)?; | ||
| out.drop_hazardous_operations(); | ||
| Ok(len) | ||
| } | ||
|
|
||
| fn security_strength(&self) -> SecurityStrength { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unconditionally setting security strength to 256 bit regardless of how many bytes were written. Semes test-only and current callers all use buffers greater than or equal to 32 bytes, but nothing this assumption might come in handy.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I mean, this is in the `core-test-framework, and it's an RNG that's not at all R, so if you try to use this for some non-test purpose, I think you're gonna have bigger problems 😝 |
||
| SecurityStrength::_256bit | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.