kyber_rs/util/random/
random_stream.rs

1use std::io::{Read, Write};
2
3use core::cmp::Ordering;
4
5use num_bigint::BigInt;
6use num_bigint_dig as num_bigint;
7use rand::{rngs::StdRng, RngCore, SeedableRng};
8use sha2::{Digest, Sha256};
9
10use crate::{
11    cipher::{stream::Stream, StreamError},
12    xof::blake3::Xof,
13};
14
15/// [`bits()`] chooses a uniform random [`BigInt`] with a given maximum `bit_len`.
16/// If `exact` is `true`, choose a [`BigInt`] with _exactly_ that `bit_len`, not less
17pub fn bits(bit_len: u64, exact: bool, rand: &mut impl Stream) -> Vec<u8> {
18    let mut b: Vec<u8> = vec![0; ((bit_len + 7) / 8) as usize];
19    let b_clone = b.clone();
20    _ = rand.xor_key_stream(&mut b, &b_clone);
21    let highbits = bit_len & 7;
22    if highbits != 0 {
23        b[0] &= !(0xff << highbits);
24    }
25    if exact {
26        if highbits != 0 {
27            b[0] |= 1 << (highbits - 1)
28        } else {
29            b[0] |= 0x80
30        }
31    }
32    b
33}
34
35/// [`random_int()`] chooses a uniform random [`BigInt`] less than a given modulus
36pub fn random_int(modulus: &BigInt, rand: &mut impl Stream) -> BigInt {
37    let bitlen = modulus.bits();
38
39    loop {
40        let bits = bits(bitlen as u64, false, rand);
41        let i = BigInt::from_bytes_be(num_bigint::Sign::Plus, bits.as_ref());
42        if i.sign() == num_bigint::Sign::Plus && i.cmp(modulus) == Ordering::Less {
43            return i;
44        }
45    }
46}
47
48/// [`bytes()`] fills a slice with random bytes from [`rand`].
49pub fn bytes(b: &mut [u8], rand: &mut impl Stream) -> Result<(), StreamError> {
50    let src_buff = vec![0u8; b.len()];
51    rand.xor_key_stream(b, &src_buff)?;
52    Ok(())
53}
54
55pub struct RandStream {
56    readers: Vec<Box<dyn Read>>,
57}
58
59impl Default for RandStream {
60    fn default() -> Self {
61        let rng_core = Box::new(StdRng::from_entropy()) as Box<dyn RngCore>;
62        let default: Box<dyn Read> = Box::new(rng_core) as Box<dyn Read>;
63        RandStream {
64            readers: vec![default],
65        }
66    }
67}
68
69impl RandStream {
70    /// [`new()`] returns a new [`RandStream`] whih implements [`Stream`] that gets random data from the given
71    /// [`readers`](Read). If no [`reader`](Read) was provided, a default [`RngCore`] is used.
72    /// Otherwise, for each source, 32 bytes are read. They are concatenated and
73    /// then hashed, and the resulting hash is used as a seed to a PRNG.
74    /// The resulting [`RandStream`] can be used in multiple threads.
75    pub fn new(readers: Vec<Box<dyn Read>>) -> RandStream {
76        if readers.is_empty() {
77            return RandStream::default();
78        }
79        RandStream {
80            readers: readers
81                .into_iter()
82                .map(|r| Box::new(r) as Box<dyn Read>)
83                .collect(),
84        }
85    }
86}
87
88impl Stream for RandStream {
89    fn xor_key_stream(&mut self, dst: &mut [u8], src: &[u8]) -> Result<(), StreamError> {
90        let l = dst.len();
91        if src.len() != l {
92            return Err(StreamError::WrongBufferLengths);
93        }
94
95        // readerBytes is how many bytes we expect from each source
96        let reader_bytes = 32;
97
98        // try to read readerBytes bytes from all readers and write them in a buffer
99        let mut b = vec![];
100        let mut nerr = 0_usize;
101        let mut buff = vec![0_u8; reader_bytes];
102        for reader in &mut self.readers {
103            let result = reader.read_exact(&mut buff);
104            if result.is_err() {
105                nerr += 1;
106                continue;
107            }
108            b.write_all(&buff[..buff.len()])?;
109        }
110
111        // we are ok with few sources being insecure (i.e., providing less than
112        // readerBytes bytes), but not all of them
113        if nerr == self.readers.len() {
114            return Err(StreamError::ReadersFailure);
115        }
116
117        // create the XOF output, with hash of collected data as seed
118        let mut h: Sha256 = Sha256::new();
119        h.update(b);
120        let seed = h.finalize();
121
122        let mut blake = Xof::new(Some(&seed));
123        blake.xor_key_stream(dst, src)
124    }
125}