Skip to content

Commit 935c5c0

Browse files
Add missing tests from PR #43
1 parent 6ee1bf7 commit 935c5c0

22 files changed

Lines changed: 854 additions & 115 deletions

File tree

alpha_0.1.2_release_notes.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@
66
* Check the crate release checklist and run claude against the style guide (maybe Francis could cross-check me)
77
* Run Crucible testing
88
* Add factories for ML-DSA and ML-KEM (if we are keeping factories, see below)
9+
* After merging the Signer/Verifier, Encrypter/Decrypter split, check if the keygen_from_rng() is still on the right
10+
trait.
11+
* Split the Signature trait into a Signer and a Verifier so that, for example, we can implement the verifier for MTC in
12+
a different struct from the signer; or so that you can get FIPS compliance on old algorithms that are currently only
13+
FIPS-allowed for verification of existing signatures but not for creation of new ones.
914
* Check out Megan's email May 13 about KeyMaterial: "I was wondering if there might be scope for a closure based
1015
approach that could guarantee encapsulation of the state change from safe to hazardous back to safe again."
1116
* Go back to previous algs and apply memory optimization tricks like internal functions. And add a docs section "Memory
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
//! A deterministic fake [RNG] for reproducible tests.
2+
3+
use bouncycastle_core::errors::{KeyMaterialError, RNGError};
4+
use bouncycastle_core::key_material;
5+
use bouncycastle_core::key_material::{KeyMaterialTrait, KeyType};
6+
use bouncycastle_core::traits::{RNG, SecurityStrength};
7+
8+
/// A test-only fake [RNG] that produces a fixed, fully deterministic byte stream.
9+
///
10+
/// The stream is the `SEED_LEN`-byte seed repeated indefinitely. A single internal counter is
11+
/// shared across every [RNG] method, so each byte handed out — whether through
12+
/// [RNG::next_bytes_out], [RNG::next_bytes], [RNG::next_int], or [RNG::fill_keymaterial_out] —
13+
/// advances the same stream. Two instances built from the same seed therefore emit identical
14+
/// streams, which is what makes RNG-driven operations reproducible (and comparable against their
15+
/// seed/`m`-driven internal counterparts) in tests.
16+
///
17+
/// This is a deterministic stub for tests only; it is in no way a secure RNG.
18+
pub struct FixedSeedRNG<const SEED_LEN: usize> {
19+
seed: [u8; SEED_LEN],
20+
counter: usize,
21+
security_strength: SecurityStrength,
22+
}
23+
24+
impl<const SEED_LEN: usize> FixedSeedRNG<SEED_LEN> {
25+
/// Create an instance that emits `seed` repeated indefinitely, starting from its first byte.
26+
pub fn new(seed: [u8; SEED_LEN]) -> Self {
27+
Self { seed, counter: 0, security_strength: SecurityStrength::_256bit }
28+
}
29+
30+
/// Pull the next byte from the deterministic stream and advance the counter.
31+
fn next_byte(&mut self) -> u8 {
32+
let b = self.seed[self.counter % SEED_LEN];
33+
self.counter += 1;
34+
b
35+
}
36+
37+
/// For testing purposes, set the security strength that this RNG will report
38+
pub fn set_security_strength(&mut self, security_strength: SecurityStrength) {
39+
self.security_strength = security_strength;
40+
}
41+
}
42+
43+
impl<const SEED_LEN: usize> RNG for FixedSeedRNG<SEED_LEN> {
44+
/// No-op: this fake RNG ignores reseeding, since its stream is fixed by construction.
45+
fn add_seed_keymaterial(
46+
&mut self,
47+
_additional_seed: &dyn KeyMaterialTrait,
48+
) -> Result<(), RNGError> {
49+
Ok(())
50+
}
51+
52+
fn next_int(&mut self) -> Result<u32, RNGError> {
53+
let mut buf = [0u8; 4];
54+
for slot in buf.iter_mut() {
55+
*slot = self.next_byte();
56+
}
57+
Ok(u32::from_le_bytes(buf))
58+
}
59+
60+
fn next_bytes(&mut self, len: usize) -> Result<Vec<u8>, RNGError> {
61+
let mut out = vec![0u8; len];
62+
for slot in out.iter_mut() {
63+
*slot = self.next_byte();
64+
}
65+
Ok(out)
66+
}
67+
68+
fn next_bytes_out(&mut self, out: &mut [u8]) -> Result<usize, RNGError> {
69+
for slot in out.iter_mut() {
70+
*slot = self.next_byte();
71+
}
72+
Ok(out.len())
73+
}
74+
75+
/// Fill `out` to capacity from the stream and mark it as a full-entropy 256-bit seed,
76+
/// mirroring what a real DRBG's `generate_keymaterial_out` produces. A 256-bit security
77+
/// strength is enough for every ML-KEM / ML-DSA parameter set.
78+
fn fill_keymaterial_out(&mut self, out: &mut dyn KeyMaterialTrait) -> Result<usize, RNGError> {
79+
let mut len = 0;
80+
key_material::do_hazardous_operations(out, |out| {
81+
len = self
82+
.next_bytes_out(out.ref_to_bytes_mut()?)
83+
.map_err(|_| KeyMaterialError::GenericError("RNG failed to acquire next bytes."))?;
84+
out.set_key_len(len)?;
85+
out.set_key_type(KeyType::Seed)?;
86+
out.set_security_strength(SecurityStrength::_256bit)
87+
})?;
88+
89+
Ok(len)
90+
}
91+
92+
fn security_strength(&self) -> SecurityStrength {
93+
self.security_strength.clone()
94+
}
95+
}

crypto/core-test-framework/src/kem.rs

Lines changed: 44 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1+
use crate::FixedSeedRNG;
12
use bouncycastle_core::errors::KEMError;
2-
use bouncycastle_core::traits::{KEMDecapsulator, KEMEncapsulator, KEMPrivateKey, KEMPublicKey};
3+
use bouncycastle_core::traits::{
4+
KEMDecapsulator, KEMEncapsulator, KEMPrivateKey, KEMPublicKey, RNG, SecurityStrength,
5+
};
36

47
pub struct TestFrameworkKEM {
58
// Put any config options here
@@ -24,8 +27,7 @@ impl TestFrameworkKEM {
2427
pub fn test_kem<
2528
PK: KEMPublicKey<PK_LEN>,
2629
SK: KEMPrivateKey<SK_LEN>,
27-
ENCAPSULATOR: KEMEncapsulator<PK, PK_LEN, CT_LEN, SS_LEN>,
28-
DECAPSULATOR: KEMDecapsulator<SK, SK_LEN, CT_LEN, SS_LEN>,
30+
KEMAlg: KEMEncapsulator<PK, PK_LEN, CT_LEN, SS_LEN> + KEMDecapsulator<SK, SK_LEN, CT_LEN, SS_LEN>,
2931
const PK_LEN: usize,
3032
const SK_LEN: usize,
3133
const CT_LEN: usize,
@@ -37,27 +39,45 @@ impl TestFrameworkKEM {
3739
) {
3840
// Basic test
3941
let (pk, sk) = keygen().unwrap();
40-
let (ss, ct) = ENCAPSULATOR::encaps(&pk).unwrap();
41-
let ss1 = DECAPSULATOR::decaps(&sk, &ct).unwrap();
42+
let (ss, ct) = KEMAlg::encaps(&pk).unwrap();
43+
let ss1 = KEMAlg::decaps(&sk, &ct).unwrap();
4244
assert_eq!(ss, ss1);
4345

46+
// Test that encaps_rng is deterministic in its RNG input: two encapsulations against the
47+
// same public key, each fed an RNG that emits identical bytes, must produce the same
48+
// shared secret and ciphertext.
49+
{
50+
let mut rng_a = FixedSeedRNG::new([0x5A; 64]);
51+
let mut rng_b = FixedSeedRNG::new([0x5A; 64]);
52+
let (ss_a, ct_a) = KEMAlg::encaps_rng(&pk, &mut rng_a).unwrap();
53+
let (ss_b, ct_b) = KEMAlg::encaps_rng(&pk, &mut rng_b).unwrap();
54+
assert_eq!(
55+
ss_a, ss_b,
56+
"encaps_rng shared secret must be deterministic given fixed RNG output"
57+
);
58+
assert_eq!(
59+
ct_a, ct_b,
60+
"encaps_rng ciphertext must be deterministic given fixed RNG output"
61+
);
62+
}
63+
4464
// Test non-determinism
4565
if !self.alg_is_deterministic {
46-
let (ss1, ct1) = ENCAPSULATOR::encaps(&pk).unwrap();
47-
let (ss2, ct2) = ENCAPSULATOR::encaps(&pk).unwrap();
66+
let (ss1, ct1) = KEMAlg::encaps(&pk).unwrap();
67+
let (ss2, ct2) = KEMAlg::encaps(&pk).unwrap();
4868
assert_ne!(ss1, ss2);
4969
assert_ne!(ct1, ct2);
5070
}
5171

5272
// Test that decaps fails for broken ct value
5373
let (pk, sk) = keygen().unwrap();
54-
let (ss, mut ct) = ENCAPSULATOR::encaps(&pk).unwrap();
74+
let (ss, mut ct) = KEMAlg::encaps(&pk).unwrap();
5575
ct[17] ^= 0xFF;
5676
if self.is_implicitly_rejecting {
57-
let ss2 = DECAPSULATOR::decaps(&sk, &ct).unwrap();
77+
let ss2 = KEMAlg::decaps(&sk, &ct).unwrap();
5878
assert_ne!(ss, ss2);
5979
} else {
60-
match DECAPSULATOR::decaps(&sk, &ct) {
80+
match KEMAlg::decaps(&sk, &ct) {
6181
Err(KEMError::DecapsulationFailed) =>
6282
/* good */
6383
{
@@ -76,10 +96,10 @@ impl TestFrameworkKEM {
7696

7797
// should throw an Err
7898
if self.is_implicitly_rejecting {
79-
let ss2 = DECAPSULATOR::decaps(&sk, &ct_copy).unwrap();
99+
let ss2 = KEMAlg::decaps(&sk, &ct_copy).unwrap();
80100
assert_ne!(ss, ss2);
81101
} else {
82-
match DECAPSULATOR::decaps(&sk, &ct) {
102+
match KEMAlg::decaps(&sk, &ct) {
83103
Err(KEMError::DecapsulationFailed) =>
84104
/* good */
85105
{
@@ -94,20 +114,29 @@ impl TestFrameworkKEM {
94114

95115
// test ct the wrong length
96116
let (pk, sk) = keygen().unwrap();
97-
let (_ss, ct) = ENCAPSULATOR::encaps(&pk).unwrap();
117+
let (_ss, ct) = KEMAlg::encaps(&pk).unwrap();
98118
// too short
99-
match DECAPSULATOR::decaps(&sk, &ct[..CT_LEN - 1]) {
119+
match KEMAlg::decaps(&sk, &ct[..CT_LEN - 1]) {
100120
Err(KEMError::LengthError(_)) => { /* good */ }
101121
_ => panic!("This should have thrown an error but it didn't."),
102122
};
103123

104124
// too long
105125
let mut long_ct = vec![1u8; CT_LEN + 2];
106126
long_ct.as_mut_slice()[..CT_LEN].copy_from_slice(&ct);
107-
match DECAPSULATOR::decaps(&sk, &long_ct) {
127+
match KEMAlg::decaps(&sk, &long_ct) {
108128
Err(KEMError::LengthError(_)) => { /* good */ }
109129
_ => panic!("This should have thrown an error but it didn't."),
110130
};
131+
132+
// encaps_rng should reject an RNG at a lower security level than the KEM
133+
let mut no_security_rng = FixedSeedRNG::new([0x00; 64]);
134+
no_security_rng.set_security_strength(SecurityStrength::None);
135+
assert_eq!(no_security_rng.security_strength(), SecurityStrength::None);
136+
match KEMAlg::encaps_rng(&pk, &mut no_security_rng) {
137+
Err(KEMError::RNGError(_)) => { /* good */ }
138+
_ => panic!("This should have thrown an error but it didn't."),
139+
}
111140
}
112141
}
113142

crypto/core-test-framework/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ pub mod kem;
1515
pub mod mac;
1616
pub mod signature;
1717

18+
mod fixed_seed_rng;
19+
pub use fixed_seed_rng::FixedSeedRNG;
20+
1821
pub const DUMMY_SEED_512: &[u8; 512] = b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff";
1922

2023
pub const DUMMY_SEED_1024: &[u8; 1024] = b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff";

crypto/core/src/errors.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,11 @@ pub enum RNGError {
6464
/// Indicates that the RNG cannot produce any more output until it has been reseeded with fresh entropy.
6565
ReseedRequired,
6666

67+
/// Thrown my algorithms attempting to use an RNG instance, for example for key generation or
68+
/// other randomness required by the algorithm, but the provided RNG is at a lower security strength
69+
/// than the algorithm requires.
70+
SecurityStrengthInsufficientForAlgorithm,
71+
6772
KeyMaterialError(KeyMaterialError),
6873
}
6974

crypto/core/src/traits.rs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -206,8 +206,16 @@ pub trait KEMEncapsulator<
206206
>: Sized
207207
{
208208
/// Performs an encapsulation against the given public key.
209+
/// Sources randomness from the library's default OS-backed RNG.
209210
/// Returns the ciphertext and derived shared secret.
210211
fn encaps(pk: &PK) -> Result<(KeyMaterial<SS_LEN>, [u8; CT_LEN]), KEMError>;
212+
/// Performs an encapsulation against the given public key.
213+
/// Sources randomness from the provided RNG.
214+
/// Returns the ciphertext and derived shared secret.
215+
fn encaps_rng(
216+
pk: &PK,
217+
rng: &mut dyn RNG,
218+
) -> Result<(KeyMaterial<SS_LEN>, [u8; CT_LEN]), KEMError>;
211219
}
212220

213221
/// A Key Encapsulation Mechanism (KEM) is defined as a set of three operations:
@@ -426,13 +434,18 @@ impl SecurityStrength {
426434
/// be used by applications that intend to submit to FIPS certification as it more closely aligns with the
427435
/// requirements of SP 800-90A.
428436
/// Note: this interface produces bytes. If you want a [KeyMaterialTrait], then use [KeyMaterial::from_rng].
429-
pub trait RNG: Default {
437+
///
438+
/// Implementors are expected to also implement [Default] (default-construction should produce a
439+
/// securely OS-seeded instance), but this is intentionally *not* a supertrait bound: requiring
440+
/// `Default` would make `RNG` not dyn-compatible, and `&mut dyn RNG` is needed so RNG instances
441+
/// can be handed around as trait objects.
442+
pub trait RNG {
430443
// TODO: add back once we figure out streaming interaction with entropy sources.
431444
// fn add_seed_bytes(&mut self, additional_seed: &[u8]) -> Result<(), RNGError>;
432445

433446
fn add_seed_keymaterial(
434447
&mut self,
435-
additional_seed: impl KeyMaterialTrait,
448+
additional_seed: &dyn KeyMaterialTrait,
436449
) -> Result<(), RNGError>;
437450
fn next_int(&mut self) -> Result<u32, RNGError>;
438451

@@ -443,7 +456,7 @@ pub trait RNG: Default {
443456
/// The entire output buffer is zeroized before the random bytes are written.
444457
fn next_bytes_out(&mut self, out: &mut [u8]) -> Result<usize, RNGError>;
445458

446-
fn fill_keymaterial_out(&mut self, out: &mut impl KeyMaterialTrait) -> Result<usize, RNGError>;
459+
fn fill_keymaterial_out(&mut self, out: &mut dyn KeyMaterialTrait) -> Result<usize, RNGError>;
447460

448461
/// Returns the Security Strength of this RNG.
449462
fn security_strength(&self) -> SecurityStrength;

crypto/factory/src/rng_factory.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ impl AlgorithmFactory for RNGFactory {
9090
impl RNG for RNGFactory {
9191
fn add_seed_keymaterial(
9292
&mut self,
93-
additional_seed: impl KeyMaterialTrait,
93+
additional_seed: &dyn KeyMaterialTrait,
9494
) -> Result<(), RNGError> {
9595
match self {
9696
Self::HashDRBG_SHA256(rng) => rng.add_seed_keymaterial(additional_seed),
@@ -121,7 +121,7 @@ impl RNG for RNGFactory {
121121
}
122122
}
123123

124-
fn fill_keymaterial_out(&mut self, out: &mut impl KeyMaterialTrait) -> Result<usize, RNGError> {
124+
fn fill_keymaterial_out(&mut self, out: &mut dyn KeyMaterialTrait) -> Result<usize, RNGError> {
125125
match self {
126126
Self::HashDRBG_SHA256(rng) => rng.fill_keymaterial_out(out),
127127
Self::HashDRBG_SHA512(rng) => rng.fill_keymaterial_out(out),

crypto/mldsa-lowmemory/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@
128128
//! ## Generating Keys
129129
//!
130130
//! ```rust
131-
//! use bouncycastle_mldsa_lowmemory::MLDSA65;
131+
//! use bouncycastle_mldsa_lowmemory::{MLDSA65, MLDSATrait};
132132
//!
133133
//! let (pk, sk) = MLDSA65::keygen().unwrap();
134134
//! ```

0 commit comments

Comments
 (0)