1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
use aead::generic_array::{typenum::Unsigned, GenericArray};
use chacha20::{
cipher::{NewStreamCipher, SyncStreamCipher},
ChaCha20,
};
use rand::{CryptoRng, RngCore};
#[cfg(feature = "alloc")]
use crate::buffer::SecretBytes;
use crate::error::Error;
pub const DETERMINISTIC_SEED_LENGTH: usize = <ChaCha20 as NewStreamCipher>::KeySize::USIZE;
pub trait Rng: CryptoRng + RngCore {}
impl<T: CryptoRng + RngCore> Rng for T {}
#[inline(always)]
pub fn with_rng<O>(f: impl FnOnce(&mut dyn Rng) -> O) -> O {
f(&mut ::rand::rngs::OsRng)
}
#[inline(always)]
pub fn fill_random(value: &mut [u8]) {
with_rng(|rng| rng.fill_bytes(value));
}
pub fn fill_random_deterministic(seed: &[u8], output: &mut [u8]) -> Result<(), Error> {
if seed.len() != DETERMINISTIC_SEED_LENGTH {
return Err(err_msg!(Usage, "Invalid length for seed"));
}
let mut cipher = ChaCha20::new(
GenericArray::from_slice(seed),
GenericArray::from_slice(b"LibsodiumDRG"),
);
cipher.apply_keystream(output);
Ok(())
}
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
#[inline(always)]
pub fn random_secret(len: usize) -> SecretBytes {
SecretBytes::new_with(len, fill_random)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::buffer::HexRepr;
use std::string::ToString;
#[test]
fn fill_random_det_expected() {
let seed = b"testseed000000000000000000000001";
let mut output = [0u8; 32];
fill_random_deterministic(seed, &mut output).unwrap();
assert_eq!(
HexRepr(output).to_string(),
"b1923a011cd1adbe89552db9862470c29512a8f51d184dfd778bfe7f845390d1"
);
}
}