rand_blake3 1.0.1

rand implementations for blake3 types
Documentation
//! rand types backed by a Blake3 hasher.
//!
//! # Examples
//!
//! ```
//! # use rand::{Rng as _, SeedableRng as _};
//! # fn main() {
//! // Hash input and convert the output stream to an rng.
//! let mut hasher = blake3::Hasher::new();
//! hasher.update(b"foo");
//! hasher.update(b"bar");
//! hasher.update(b"baz");
//! let mut rng: rand_blake3::Rng = hasher.into();
//! let output: u64 = rng.gen();
//! assert_eq!(output, 0xfb61f3c9e0fe9ac0u64);
//!
//! // Alternately, seed it as a rand::SeedableRng.
//! let mut rng = rand_blake3::Rng::from_seed(*b"0123456789abcdefghijklmnopqrstuv");
//! let output: u64 = rng.gen();
//! assert_eq!(output, 0x9958c58595366357u64);
//!
//! // In the real world, you will probably not use a static seed, but seed from
//! // OsRng or something of the sort.
//! let mut rng = rand_blake3::Rng::from_rng(rand::rngs::OsRng).unwrap();
//! let _output: u64 = rng.gen();
//!
//! // You can also use this as a backing for a rand ReseedingRng
//! let mut reseeding = rand::rngs::adapter::ReseedingRng::new(
//!     rand_blake3::UnbufferedRng::from_rng(rand::rngs::OsRng).unwrap(),
//!     1024 * 256,
//!     rand::rngs::OsRng,
//! );
//! let _output: u64 = reseeding.gen();
//! # }
//! ```

#![no_std]

use core::convert::Infallible;

use blake3::{Hasher, OutputReader};
use rand_core::{
    block::BlockRngCore,
    impls::{next_u32_via_fill, next_u64_via_fill},
    CryptoRng, Error, RngCore, SeedableRng,
};

use load_buffer::{BufferedLoader, Load};

struct LoadOutputReader {
    reader: OutputReader,
}

impl From<OutputReader> for LoadOutputReader {
    fn from(reader: OutputReader) -> Self {
        Self { reader }
    }
}

impl From<Hasher> for LoadOutputReader {
    fn from(hasher: Hasher) -> Self {
        Self {
            reader: hasher.finalize_xof(),
        }
    }
}

impl Load for LoadOutputReader {
    type Error = Infallible;

    fn load(&mut self, destination: &mut [u8]) -> Result<(), Self::Error> {
        self.reader.fill(destination);
        Ok(())
    }
}

/// The buffered Rng wrapper for [`OutputReader`].  Note that it has From
/// impls for [`OutputReader`] as well as [`Hasher`], and also implements
/// [`SeedableRng`] so you can seed it however you like.
///
/// [`OutputReader`]: https://docs.rs/blake3/latest/blake3/struct.OutputReader.html
/// [`Hasher`]: https://docs.rs/blake3/latest/blake3/struct.Hasher.html
/// [`SeedableRng`]: https://docs.rs/rand/latest/rand/trait.SeedableRng.html
pub struct Rng {
    loader: BufferedLoader<[u8; 64], LoadOutputReader>,
}

impl From<OutputReader> for Rng {
    fn from(reader: OutputReader) -> Self {
        let loader = BufferedLoader::new_static(LoadOutputReader::from(reader));
        Self { loader }
    }
}

impl From<Hasher> for Rng {
    fn from(hasher: Hasher) -> Self {
        let loader = BufferedLoader::new_static(LoadOutputReader::from(hasher));
        Self { loader }
    }
}

impl SeedableRng for Rng {
    type Seed = [u8; 32];

    #[inline]
    fn from_seed(seed: Self::Seed) -> Self {
        Hasher::new_keyed(&seed).finalize_xof().into()
    }
}

impl RngCore for Rng {
    #[inline]
    fn next_u32(&mut self) -> u32 {
        next_u32_via_fill(self)
    }

    #[inline]
    fn next_u64(&mut self) -> u64 {
        next_u64_via_fill(self)
    }

    #[inline]
    fn fill_bytes(&mut self, dest: &mut [u8]) {
        self.loader.load(dest).unwrap();
    }

    #[inline]
    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
        self.loader.load(dest).unwrap();
        Ok(())
    }
}

const BLOCK_COUNT: usize = 16;

impl BlockRngCore for Rng {
    type Item = u32;
    type Results = [u32; BLOCK_COUNT];

    fn generate(&mut self, results: &mut Self::Results) {
        let mut buf = [0u8; BLOCK_COUNT * 4];
        self.loader.load(&mut buf).unwrap();
        for (dest, src) in results.iter_mut().zip(buf.chunks_exact(4)) {
            *dest = u32::from_le_bytes(src.try_into().unwrap());
        }
    }
}

impl CryptoRng for Rng {}

/// The unbuffered counterpart to [`Rng`].
///
/// Use this instead of Rng if you know bytes will only be read in blocks of 64
/// bytes, such as what would be done for a [`ReseedingRng`], or anything else
/// that uses a [`BlockRng`].
///
/// [`Rng`]: struct.Rng.html
/// [`ReseedingRng`]: https://docs.rs/rand/latest/rand/rngs/adapter/struct.ReseedingRng.html
/// [`BlockRng`]: https://docs.rs/rand_core/latest/rand_core/block/struct.BlockRng.html
pub struct UnbufferedRng {
    loader: LoadOutputReader,
}

impl From<OutputReader> for UnbufferedRng {
    fn from(reader: OutputReader) -> Self {
        let loader = LoadOutputReader::from(reader);
        Self { loader }
    }
}

impl From<Hasher> for UnbufferedRng {
    fn from(hasher: Hasher) -> Self {
        let loader = LoadOutputReader::from(hasher);
        Self { loader }
    }
}

impl SeedableRng for UnbufferedRng {
    type Seed = [u8; 32];

    #[inline]
    fn from_seed(seed: Self::Seed) -> Self {
        Hasher::new_keyed(&seed).finalize_xof().into()
    }
}

impl RngCore for UnbufferedRng {
    #[inline]
    fn next_u32(&mut self) -> u32 {
        next_u32_via_fill(self)
    }

    #[inline]
    fn next_u64(&mut self) -> u64 {
        next_u64_via_fill(self)
    }

    #[inline]
    fn fill_bytes(&mut self, dest: &mut [u8]) {
        self.loader.load(dest).unwrap();
    }

    #[inline]
    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
        self.loader.load(dest).unwrap();
        Ok(())
    }
}

impl BlockRngCore for UnbufferedRng {
    type Item = u32;
    type Results = [u32; BLOCK_COUNT];

    fn generate(&mut self, results: &mut Self::Results) {
        let mut buf = [0u8; BLOCK_COUNT * 4];
        self.loader.load(&mut buf).unwrap();
        for (dest, src) in results.iter_mut().zip(buf.chunks_exact(4)) {
            *dest = u32::from_le_bytes(src.try_into().unwrap());
        }
    }
}

impl CryptoRng for UnbufferedRng {}

#[cfg(test)]
mod test {
    use super::*;
    use rand::rngs::adapter::ReseedingRng;
    use rand::rngs::OsRng;
    use rand::Rng as _;

    #[test]
    fn test_rand_core() {
        let mut seeded = crate::Rng::from_seed(*b"0123456789abcdefghijklmnopqrstuv");
        let mut buf = [0u8; 64];
        seeded.fill_bytes(&mut buf);
        // Verified using: printf 0123456789abcdefghijklmnopqrstuv | b3sum -l 76 --keyed <(true)
        assert_eq!(
            &buf,
            b"\
            \x57\x63\x36\x95\x85\xc5\x58\x99\x4a\x3e\xe0\x27\x78\x87\x94\x1f\
            \xf0\xf8\xbd\x3a\xca\x96\xfa\x00\xdb\xb8\x25\x07\x2c\x47\x67\xf1\
            \x69\xd0\xf2\x11\x68\xff\x75\x74\x4c\x1c\x48\x8f\xee\x7a\x01\x78\
            \x52\xcf\x04\x5d\xc2\x9e\xa1\x0e\x09\x63\x76\x18\xc3\x5f\xf6\x10\
            ",
        );

        // defers to rand_core::impls, which interpret bytes little-endian.
        assert_eq!(seeded.gen::<u32>(), 0xc6a18732);
        assert_eq!(seeded.gen::<u64>(), 0x705c00977b0d7be0);

        // Test partial consumption, to be sure buffering doesn't cause problems

        let mut seeded = crate::Rng::from_seed(*b"0123456789abcdefghijklmnopqrstuv");
        let mut buf = [0u8; 63];
        seeded.fill_bytes(&mut buf);
        // Verified using: printf 0123456789abcdefghijklmnopqrstuv | b3sum -l 76 --keyed <(true)
        assert_eq!(
            &buf,
            b"\
            \x57\x63\x36\x95\x85\xc5\x58\x99\x4a\x3e\xe0\x27\x78\x87\x94\x1f\
            \xf0\xf8\xbd\x3a\xca\x96\xfa\x00\xdb\xb8\x25\x07\x2c\x47\x67\xf1\
            \x69\xd0\xf2\x11\x68\xff\x75\x74\x4c\x1c\x48\x8f\xee\x7a\x01\x78\
            \x52\xcf\x04\x5d\xc2\x9e\xa1\x0e\x09\x63\x76\x18\xc3\x5f\xf6\
            ",
        );

        // defers to rand_core::impls, which interpret bytes little-endian.
        assert_eq!(seeded.gen::<u32>(), 0xa1873210);
        assert_eq!(seeded.gen::<u64>(), 0x5c00977b0d7be0c6);
    }

    #[test]
    fn test_reseeding_rng() {
        let mut reseeding = ReseedingRng::new(Rng::from_rng(OsRng).unwrap(), 1024 * 256, OsRng);

        let _out: u32 = reseeding.gen();
    }
}