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
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
use libc::size_t;
use nettle_sys::{
    nettle_yarrow256_init, nettle_yarrow256_is_seeded, nettle_yarrow256_random,
    nettle_yarrow256_seed, yarrow256_ctx,
};
use getrandom::getrandom;
use std::mem::{transmute, zeroed};
use std::os::raw::c_void;
use std::ptr;

use super::Random;

/// Yarrow is a secure CRNG developed by Kelsey et.al.
///
/// Default instances are seeded using `OsRng`.
pub struct Yarrow {
    context: yarrow256_ctx,
}

impl Yarrow {
    /// Create a new CRNG instance for `seed`.
    pub fn from_seed(seed: &[u8]) -> Yarrow {
        unsafe {
            let mut ctx = zeroed();

            nettle_yarrow256_init(&mut ctx as *mut _, 0, ptr::null_mut());
            nettle_yarrow256_seed(
                &mut ctx as *mut _,
                seed.len(),
                seed.as_ptr(),
            );

            Yarrow { context: ctx }
        }
    }
}

impl Random for Yarrow {
    unsafe fn context(&mut self) -> *mut c_void {
        transmute(&mut self.context)
    }

    unsafe extern "C" fn random_impl(
        ctx: *mut c_void, length: size_t, dst: *mut u8,
    ) {
        assert_eq!(nettle_yarrow256_is_seeded(ctx as *mut _), 1);
        nettle_yarrow256_random(ctx as *mut _, length, dst);
    }
}

impl Default for Yarrow {
    fn default() -> Self {
        let mut seed = vec![0u8; 64];
        if let Err(e) = getrandom(&mut seed) {
            panic!("Failed to initialize random generator: {}", e);
        }
        Yarrow::from_seed(&seed)
    }
}

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

    #[test]
    fn auto_seeded() {
        let mut rng1 = Yarrow::default();
        let mut rng2 = Yarrow::default();
        let mut buf1 = vec![0u8; 100];
        let mut buf2 = vec![0u8; 100];
        let zero = vec![0u8; 100];

        rng1.random(&mut buf1);
        rng2.random(&mut buf2);

        assert!(buf1 != buf2);
        assert!(buf1 != zero);
        assert!(buf1 != zero);
    }

    #[test]
    fn fixed_seed() {
        let seed =
            &b"aaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbcccccccccccccccccccdddd"[..];
        let mut rng1 = Yarrow::from_seed(seed);
        let mut rng2 = Yarrow::from_seed(seed);
        let mut buf1 = vec![0u8; 100];
        let mut buf2 = vec![0u8; 100];
        let zero = vec![0u8; 100];

        rng1.random(&mut buf1);
        rng2.random(&mut buf2);

        assert_eq!(buf1, buf2);
        assert!(buf1 != zero);
    }

    #[test]
    fn random_inteface() {
        let seed =
            &b"aaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbcccccccccccccccccccdddd"[..];
        let mut rng1 = Yarrow::from_seed(seed);
        let mut rng2 = Yarrow::from_seed(seed);
        let mut buf1 = vec![0u8; 100];
        let mut buf2 = vec![0u8; 100];
        let zero = vec![0u8; 100];

        rng1.random(&mut buf1);

        unsafe {
            let ctx = rng2.context();
            <Yarrow as Random>::random_impl(ctx, buf2.len(), buf2.as_mut_ptr());
        }

        assert_eq!(buf1, buf2);
        assert!(buf1 != zero);
    }
}