Skip to content
5 changes: 5 additions & 0 deletions alpha_0.1.2_release_notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@
* Check the crate release checklist and run claude against the style guide (maybe Francis could cross-check me)
* Run Crucible testing
* Add factories for ML-DSA and ML-KEM (if we are keeping factories, see below)
* After merging the Signer/Verifier, Encrypter/Decrypter split, check if the keygen_from_rng() is still on the right
trait.
* Split the Signature trait into a Signer and a Verifier so that, for example, we can implement the verifier for MTC in
a different struct from the signer; or so that you can get FIPS compliance on old algorithms that are currently only
FIPS-allowed for verification of existing signatures but not for creation of new ones.
* Check out Megan's email May 13 about KeyMaterial: "I was wondering if there might be scope for a closure based
approach that could guarantee encapsulation of the state change from safe to hazardous back to safe again."
* Go back to previous algs and apply memory optimization tricks like internal functions. And add a docs section "Memory
Expand Down
95 changes: 95 additions & 0 deletions crypto/core-test-framework/src/fixed_seed_rng.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
//! A deterministic fake [RNG] for reproducible tests.

use bouncycastle_core::errors::{KeyMaterialError, RNGError};
use bouncycastle_core::key_material;
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,
security_strength: SecurityStrength,
}

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, security_strength: SecurityStrength::_256bit }
}

/// 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
}

/// For testing purposes, set the security strength that this RNG will report
pub fn set_security_strength(&mut self, security_strength: SecurityStrength) {
self.security_strength = security_strength;
}
}

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> {
let mut len = 0;
key_material::do_hazardous_operations(out, |out| {
len = self
.next_bytes_out(out.ref_to_bytes_mut()?)
.map_err(|_| KeyMaterialError::GenericError("RNG failed to acquire next bytes."))?;
out.set_key_len(len)?;
out.set_key_type(KeyType::Seed)?;
out.set_security_strength(SecurityStrength::_256bit)
})?;

Ok(len)
}

fn security_strength(&self) -> SecurityStrength {
self.security_strength.clone()
}
}
59 changes: 44 additions & 15 deletions crypto/core-test-framework/src/kem.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use crate::FixedSeedRNG;
use bouncycastle_core::errors::KEMError;
use bouncycastle_core::traits::{KEMDecapsulator, KEMEncapsulator, KEMPrivateKey, KEMPublicKey};
use bouncycastle_core::traits::{
KEMDecapsulator, KEMEncapsulator, KEMPrivateKey, KEMPublicKey, RNG, SecurityStrength,
};

pub struct TestFrameworkKEM {
// Put any config options here
Expand All @@ -24,8 +27,7 @@ impl TestFrameworkKEM {
pub fn test_kem<
PK: KEMPublicKey<PK_LEN>,
SK: KEMPrivateKey<SK_LEN>,
ENCAPSULATOR: KEMEncapsulator<PK, PK_LEN, CT_LEN, SS_LEN>,
DECAPSULATOR: KEMDecapsulator<SK, SK_LEN, CT_LEN, SS_LEN>,
KEMAlg: KEMEncapsulator<PK, PK_LEN, CT_LEN, SS_LEN> + KEMDecapsulator<SK, SK_LEN, CT_LEN, SS_LEN>,
const PK_LEN: usize,
const SK_LEN: usize,
const CT_LEN: usize,
Expand All @@ -37,27 +39,45 @@ impl TestFrameworkKEM {
) {
// Basic test
let (pk, sk) = keygen().unwrap();
let (ss, ct) = ENCAPSULATOR::encaps(&pk).unwrap();
let ss1 = DECAPSULATOR::decaps(&sk, &ct).unwrap();
let (ss, ct) = KEMAlg::encaps(&pk).unwrap();
let ss1 = KEMAlg::decaps(&sk, &ct).unwrap();
assert_eq!(ss, ss1);

// Test that encaps_rng is deterministic in its RNG input: two encapsulations against the
// same public key, each fed an RNG that emits identical bytes, must produce the same
// shared secret and ciphertext.
{
let mut rng_a = FixedSeedRNG::new([0x5A; 64]);
let mut rng_b = FixedSeedRNG::new([0x5A; 64]);
let (ss_a, ct_a) = KEMAlg::encaps_rng(&pk, &mut rng_a).unwrap();
let (ss_b, ct_b) = KEMAlg::encaps_rng(&pk, &mut rng_b).unwrap();
assert_eq!(
ss_a, ss_b,
"encaps_rng shared secret must be deterministic given fixed RNG output"
);
assert_eq!(
ct_a, ct_b,
"encaps_rng ciphertext must be deterministic given fixed RNG output"
);
}

// Test non-determinism
if !self.alg_is_deterministic {
let (ss1, ct1) = ENCAPSULATOR::encaps(&pk).unwrap();
let (ss2, ct2) = ENCAPSULATOR::encaps(&pk).unwrap();
let (ss1, ct1) = KEMAlg::encaps(&pk).unwrap();
let (ss2, ct2) = KEMAlg::encaps(&pk).unwrap();
assert_ne!(ss1, ss2);
assert_ne!(ct1, ct2);
}

// Test that decaps fails for broken ct value
let (pk, sk) = keygen().unwrap();
let (ss, mut ct) = ENCAPSULATOR::encaps(&pk).unwrap();
let (ss, mut ct) = KEMAlg::encaps(&pk).unwrap();
ct[17] ^= 0xFF;
if self.is_implicitly_rejecting {
let ss2 = DECAPSULATOR::decaps(&sk, &ct).unwrap();
let ss2 = KEMAlg::decaps(&sk, &ct).unwrap();
assert_ne!(ss, ss2);
} else {
match DECAPSULATOR::decaps(&sk, &ct) {
match KEMAlg::decaps(&sk, &ct) {
Err(KEMError::DecapsulationFailed) =>
/* good */
{
Expand All @@ -76,10 +96,10 @@ impl TestFrameworkKEM {

// should throw an Err
if self.is_implicitly_rejecting {
let ss2 = DECAPSULATOR::decaps(&sk, &ct_copy).unwrap();
let ss2 = KEMAlg::decaps(&sk, &ct_copy).unwrap();
assert_ne!(ss, ss2);
} else {
match DECAPSULATOR::decaps(&sk, &ct) {
match KEMAlg::decaps(&sk, &ct) {
Err(KEMError::DecapsulationFailed) =>
/* good */
{
Expand All @@ -94,20 +114,29 @@ impl TestFrameworkKEM {

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

// too long
let mut long_ct = vec![1u8; CT_LEN + 2];
long_ct.as_mut_slice()[..CT_LEN].copy_from_slice(&ct);
match DECAPSULATOR::decaps(&sk, &long_ct) {
match KEMAlg::decaps(&sk, &long_ct) {
Err(KEMError::LengthError(_)) => { /* good */ }
_ => panic!("This should have thrown an error but it didn't."),
};

// encaps_rng should reject an RNG at a lower security level than the KEM
let mut no_security_rng = FixedSeedRNG::new([0x00; 64]);
no_security_rng.set_security_strength(SecurityStrength::None);
assert_eq!(no_security_rng.security_strength(), SecurityStrength::None);
match KEMAlg::encaps_rng(&pk, &mut no_security_rng) {
Err(KEMError::RNGError(_)) => { /* good */ }
_ => panic!("This should have thrown an error but it didn't."),
}
}
}

Expand Down
3 changes: 3 additions & 0 deletions crypto/core-test-framework/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ pub mod kem;
pub mod mac;
pub mod signature;

mod fixed_seed_rng;
pub use fixed_seed_rng::FixedSeedRNG;

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";

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";
5 changes: 5 additions & 0 deletions crypto/core/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@ pub enum RNGError {
/// Indicates that the RNG cannot produce any more output until it has been reseeded with fresh entropy.
ReseedRequired,

/// Thrown my algorithms attempting to use an RNG instance, for example for key generation or
/// other randomness required by the algorithm, but the provided RNG is at a lower security strength
/// than the algorithm requires.
SecurityStrengthInsufficientForAlgorithm,

KeyMaterialError(KeyMaterialError),
}

Expand Down
19 changes: 16 additions & 3 deletions crypto/core/src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,8 +206,16 @@ pub trait KEMEncapsulator<
>: Sized
{
/// Performs an encapsulation against the given public key.
/// Sources randomness from the library's default OS-backed RNG.
/// Returns the ciphertext and derived shared secret.
fn encaps(pk: &PK) -> Result<(KeyMaterial<SS_LEN>, [u8; CT_LEN]), KEMError>;
/// Performs an encapsulation against the given public key.
/// Sources randomness from the provided RNG.
/// Returns the ciphertext and derived shared secret.
fn encaps_rng(
pk: &PK,
rng: &mut dyn RNG,
) -> Result<(KeyMaterial<SS_LEN>, [u8; CT_LEN]), KEMError>;
}

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

fn add_seed_keymaterial(
&mut self,
additional_seed: impl KeyMaterialTrait,
additional_seed: &dyn KeyMaterialTrait,
) -> Result<(), RNGError>;
fn next_int(&mut self) -> Result<u32, RNGError>;

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

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

/// Returns the Security Strength of this RNG.
fn security_strength(&self) -> SecurityStrength;
Expand Down
4 changes: 2 additions & 2 deletions crypto/factory/src/rng_factory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ impl AlgorithmFactory for RNGFactory {
impl RNG for RNGFactory {
fn add_seed_keymaterial(
&mut self,
additional_seed: impl KeyMaterialTrait,
additional_seed: &dyn KeyMaterialTrait,
) -> Result<(), RNGError> {
match self {
Self::HashDRBG_SHA256(rng) => rng.add_seed_keymaterial(additional_seed),
Expand Down Expand Up @@ -121,7 +121,7 @@ impl RNG for RNGFactory {
}
}

fn fill_keymaterial_out(&mut self, out: &mut impl KeyMaterialTrait) -> Result<usize, RNGError> {
fn fill_keymaterial_out(&mut self, out: &mut dyn KeyMaterialTrait) -> Result<usize, RNGError> {
match self {
Self::HashDRBG_SHA256(rng) => rng.fill_keymaterial_out(out),
Self::HashDRBG_SHA512(rng) => rng.fill_keymaterial_out(out),
Expand Down
2 changes: 1 addition & 1 deletion crypto/mldsa-lowmemory/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@
//! ## Generating Keys
//!
//! ```rust
//! use bouncycastle_mldsa_lowmemory::MLDSA65;
//! use bouncycastle_mldsa_lowmemory::{MLDSA65, MLDSATrait};
//!
//! let (pk, sk) = MLDSA65::keygen().unwrap();
//! ```
Expand Down
Loading
Loading