use std::{slice, ptr};
use libc::{uint8_t, uint16_t, c_void};
use types::{Error, TernPoly};
use super::ffi;
#[repr(C)]
pub struct RandContext {
pub rand_gen: *const RandGen,
pub seed: *const uint8_t,
pub seed_len: uint16_t,
pub state: *const c_void,
}
impl Default for RandContext {
fn default() -> RandContext {
RandContext {
rand_gen: &mut RNG_DEFAULT,
seed: ptr::null(),
seed_len: 0,
state: ptr::null(),
}
}
}
impl Drop for RandContext {
fn drop(&mut self) {
let result = unsafe { ffi::ntru_rand_release(self) };
if result != 0 {
panic!()
}
}
}
impl RandContext {
pub fn get_seed(&self) -> &[u8] {
unsafe { slice::from_raw_parts(self.seed, self.seed_len as usize) }
}
pub fn get_rng(&self) -> &RandGen {
unsafe { &*self.rand_gen }
}
}
#[repr(C)]
pub struct RandGen {
init_fn: unsafe extern "C" fn(rand_ctx: *mut RandContext, rand_gen: *const RandGen)
-> uint8_t,
generate_fn: unsafe extern "C" fn(rand_data: *mut uint8_t,
len: uint16_t,
rand_ctx: *const RandContext)
-> uint8_t,
release_fn: unsafe extern "C" fn(rand_ctx: *mut RandContext) -> uint8_t,
}
impl RandGen {
pub fn init(&self, rand_gen: &RandGen) -> Result<RandContext, Error> {
let mut rand_ctx: RandContext = Default::default();
let result = unsafe { (self.init_fn)(&mut rand_ctx, rand_gen) };
if result == 1 {
Ok(rand_ctx)
} else {
Err(Error::Prng)
}
}
pub fn generate(&self, length: u16, rand_ctx: &RandContext) -> Result<Box<[u8]>, Error> {
let mut plain = vec![0u8; length as usize];
let result = unsafe { (self.generate_fn)(&mut plain[0], length, rand_ctx) };
if result == 1 {
Ok(plain.into_boxed_slice())
} else {
Err(Error::Prng)
}
}
}
#[cfg(target_os = "windows")]
pub const RNG_WINCRYPT: RandGen = RandGen {
init_fn: ffi::ntru_rand_wincrypt_init,
generate_fn: ffi::ntru_rand_wincrypt_generate,
release_fn: ffi::ntru_rand_wincrypt_release,
};
#[cfg(not(target_os = "windows"))]
pub const RNG_DEVURANDOM: RandGen = RandGen {
init_fn: ffi::ntru_rand_devurandom_init,
generate_fn: ffi::ntru_rand_devurandom_generate,
release_fn: ffi::ntru_rand_devurandom_release,
};
#[cfg(not(target_os = "windows"))]
pub const RNG_DEVRANDOM: RandGen = RandGen {
init_fn: ffi::ntru_rand_devrandom_init,
generate_fn: ffi::ntru_rand_devrandom_generate,
release_fn: ffi::ntru_rand_devrandom_release,
};
pub const RNG_DEFAULT: RandGen = RandGen {
init_fn: ffi::ntru_rand_default_init,
generate_fn: ffi::ntru_rand_default_generate,
release_fn: ffi::ntru_rand_default_release,
};
pub const RNG_CTR_DRBG: RandGen = RandGen {
init_fn: ffi::ntru_rand_ctr_drbg_init,
generate_fn: ffi::ntru_rand_ctr_drbg_generate,
release_fn: ffi::ntru_rand_ctr_drbg_release,
};
pub fn init(rand_gen: &RandGen) -> Result<RandContext, Error> {
let mut rand_ctx: RandContext = Default::default();
let result = unsafe { ffi::ntru_rand_init(&mut rand_ctx, rand_gen) };
if result == 0 {
Ok(rand_ctx)
} else {
Err(Error::from(result))
}
}
pub fn init_det(rand_gen: &RandGen, seed: &[u8]) -> Result<RandContext, Error> {
let mut rand_ctx: RandContext = Default::default();
let result = unsafe {
ffi::ntru_rand_init_det(&mut rand_ctx, rand_gen, &seed[0], seed.len() as uint16_t)
};
if result == 0 {
Ok(rand_ctx)
} else {
Err(Error::from(result))
}
}
pub fn generate(length: u16, rand_ctx: &RandContext) -> Result<Box<[u8]>, Error> {
let mut plain = vec![0u8; length as usize];
let result = unsafe { ffi::ntru_rand_generate(&mut plain[0], length, rand_ctx) };
if result == 0 {
Ok(plain.into_boxed_slice())
} else {
Err(Error::from(result))
}
}
impl TernPoly {
pub fn rand(n: u16,
num_ones: u16,
num_neg_ones: u16,
rand_ctx: &RandContext)
-> Option<TernPoly> {
let mut poly: TernPoly = Default::default();
let result = unsafe { ffi::ntru_rand_tern(n, num_ones, num_neg_ones, &mut poly, rand_ctx) };
if result == 0 { None } else { Some(poly) }
}
}