A Rust implementation of the Subset Counter-Based Deterministic Random Bit Generator (SC_DRBG).
This is a new and experimental function that has not undergone any review or audit. In the absence of cryptanalysis, use at your own risk.
Provides a deterministic random bit generator that maintains an array of seed material in its internal state (rather than a single seed), allowing each output to be generated from a configurable subset of array elements.
SC_DRBG supports 32 and 64 bit unsigned integers for the internal counter and other integer values. The byte order for integer encoding and decoding is configurable via different constructors, and an Endian enum. Supports commitment of elements from an array of seed material to their positions, lengths, and contents, and configurable rounds of mixing for entropy diffusion across elements. Forward secrecy is provided through continuous state evolution.
The Drbg structure representing SC_DRBG implements RngCore for compatibility with the Rust ecosystem as a deterministic random bit generator, and secure memory zeroization on drop. Two generic parameters <D, T> are expected. Generic parameter D is a hashing algorithm implementing the Digest trait, and T is the type for all integer values, including the internal counter, as either u32 or u64.
An instance of Drbg can be initialized via two different constructors, differentiated by endianness:
- new_le: Create a new instance using little-endian byte order.
- new_be: Create a new instance using big-endian byte order.
Both constructors create a new instance from an array of seed material, and an optional context string. A boolean value indicating if the seed material should be processed by an initialization function is also expected. When true, the seed material will undergo initialization1 before the new instance is created, and when false, the seed material will directly be used in the new instance.
The initialization function initialize for arrays of seed material completes two steps to process seed material before creating a new Drbg instance: Committing elements to their properties, and mixing for entropy diffusion. The function expects an array of seed material, optional context string, nonce, number of mixing rounds, and an Endian enum for byte order. In the first step, for each element in the array of seed material, an HMAC is created to commit each element to its position, length, and content. In the second step, the committed elements undergo rounds of mixing to diffuse entropy across elements, using a SHAKE256 sponge "absorb then squeeze" construction.
The Drbg generator methods are used to produce random numbers and random bytes. The generator provides forward secrecy by updating the state after each call. One round of mixing is applied, using the last generated bytes in deriving the mixing key, and a new pseudorandom key for the next round is derived. Two variants of each method are supported, one from the RngCore implementation that uses all elements from the array of seed material to seed the generator, and one using a subset of elements to seed the generator, with the subset clamped to the total array length:
- next_u32: Returns the next random unsigned 32 bit integer, seeded by all elements.
- next_u32_subset: Returns the next random unsigned 32 bit integer, seeded by a subset of elements.
- next_u64: Returns the next random unsigned 64 bit integer, seeded by all elements.
- next_u64_subset: Returns the next random unsigned 64 bit integer, seeded by a subset of elements.
- fill_bytes: Fills a destination buffer with random bytes, seeded by all elements.
- fill_bytes_subset: Fills a destination buffer with random bytes, seeded by a subset of elements.
use hex_literal::hex;
use rand_core::RngCore;
use sc_drbg::Drbg;
use sha3::Sha3_256;
fn main() {
let arr = vec![
hex!("456E64204F662054686520576F726C642053756E").to_vec(),
hex!("556E6D616B65207468652057696C64204C69676874").to_vec(),
hex!("536166652050617373616765").to_vec(),
hex!("747261636B6572706C61747A").to_vec(),
hex!("3635646179736F66737461746963").to_vec(),
];
let context = "some-random-application";
let mut drbg = Drbg::<Sha3_256, u32>::new_le(&arr, Some(context), true)
.expect("Should create new SC_DRBG instance");
let num = drbg.next_u32();
assert_eq!(num, 4076030162);
}Footnotes
-
See the Initialization Function section for more details. When an array of seed material undergoes initialization via one of the constructors, the nonce is derived from a hash of the seed material, and one round of mixing is applied. ↩