libhydrogen 0.4.6

A modern and easy to use cryptography library
Documentation
use super::ensure_initialized;
use crate::ffi;
use crate::utils;

pub const SEEDBYTES: usize = ffi::hydro_random_SEEDBYTES as usize;

#[derive(Debug, Clone)]
pub struct Seed([u8; SEEDBYTES]);

#[inline]
pub fn u32() -> u32 {
    ensure_initialized();
    unsafe { ffi::hydro_random_u32() }
}

#[inline]
pub fn uniform(upper_bound: u32) -> u32 {
    ensure_initialized();
    unsafe { ffi::hydro_random_uniform(upper_bound) }
}

#[inline]
pub fn buf_into(out: &mut [u8]) {
    ensure_initialized();
    unsafe {
        ffi::hydro_random_buf(out.as_mut_ptr() as *mut _, out.len());
    }
}

pub fn buf(out_len: usize) -> Vec<u8> {
    let mut out = vec![0u8; out_len];
    buf_into(&mut out);
    out
}

#[inline]
pub fn buf_deterministic_into(out: &mut [u8], seed: &Seed) {
    ensure_initialized();
    unsafe {
        ffi::hydro_random_buf_deterministic(out.as_mut_ptr() as *mut _, out.len(), seed.0.as_ptr())
    }
}

#[inline]
pub fn buf_deterministic(out_len: usize, seed: &Seed) -> Vec<u8> {
    let mut out = vec![0u8; out_len];
    buf_deterministic_into(&mut out, seed);
    out
}

#[inline]
pub fn ratchet() {
    ensure_initialized();
    unsafe {
        ffi::hydro_random_ratchet();
    }
}

#[inline]
pub fn reseed() {
    ensure_initialized();
    unsafe {
        ffi::hydro_random_reseed();
    }
}

impl Drop for Seed {
    fn drop(&mut self) {
        utils::memzero(self)
    }
}

impl From<[u8; SEEDBYTES]> for Seed {
    #[inline]
    fn from(seed: [u8; SEEDBYTES]) -> Seed {
        Seed(seed)
    }
}

impl From<Seed> for [u8; SEEDBYTES] {
    #[inline]
    fn from(val: Seed) -> Self {
        val.0
    }
}

impl AsRef<[u8]> for Seed {
    fn as_ref(&self) -> &[u8] {
        &self.0 as &[u8]
    }
}

impl PartialEq for Seed {
    fn eq(&self, other: &Self) -> bool {
        utils::equal(self, other)
    }
}

impl Eq for Seed {}

impl Seed {
    pub fn gen() -> Seed {
        let mut seed_inner = [0u8; SEEDBYTES];
        buf_into(&mut seed_inner);
        Seed(seed_inner)
    }
}

#[cfg(test)]
mod tests {
    use crate::*;

    #[test]
    fn test_randombytes() {
        init().unwrap();
        assert_ne!(random::u32() | random::u32() | random::u32(), 0);

        for _ in 0..100 {
            let max = random::u32();
            assert!(random::uniform(max) < max)
        }

        let len = random::uniform(100) as usize + 1;
        let mut buf = random::buf(len);
        random::buf_into(&mut buf);

        let seed = random::Seed::gen();
        let buf = random::buf_deterministic(len, &seed);
        let mut buf2 = vec![0u8; len];
        random::buf_deterministic_into(&mut buf2, &seed);
        assert_eq!(buf, buf2);

        let seedx: [u8; random::SEEDBYTES] = seed.clone().into();
        let seedy: random::Seed = seedx.into();
        assert_eq!(seed, seedy);

        random::ratchet();

        random::reseed();
    }
}