macro_rules! auth_state (($state_name:ident,
$init_name:ident,
$update_name:ident,
$final_name:ident,
$tagbytes:expr) => (
use std::mem;
use ffi;
#[must_use]
pub struct State($state_name);
impl Drop for State {
fn drop(&mut self) {
unsafe {
ffi::sodium_memzero(&mut self.0 as *mut $state_name as *mut _, mem::size_of_val(&self.0));
}
}
}
impl State {
pub fn init(k: &[u8]) -> State {
let mut s = mem::MaybeUninit::uninit();
let state = unsafe {
$init_name(s.as_mut_ptr(), k.as_ptr(), k.len());
s.assume_init() };
State(state)
}
pub fn update(&mut self, in_: &[u8]) {
unsafe {
$update_name(&mut self.0, in_.as_ptr(), in_.len() as c_ulonglong);
}
}
pub fn finalize(mut self) -> Tag {
unsafe {
let mut tag = [0; $tagbytes];
$final_name(&mut self.0, tag.as_mut_ptr());
Tag(tag)
}
}
}
#[cfg(test)]
mod test_s {
use super::*;
#[test]
fn test_auth_eq_auth_state() {
use randombytes::randombytes;
for i in 0..256usize {
let k = gen_key();
let m = randombytes(i);
let tag = authenticate(&m, &k);
let mut state = State::init(k.as_ref());
state.update(&m);
let tag2 = state.finalize();
assert_eq!(tag, tag2);
}
}
#[test]
fn test_auth_eq_auth_state_chunked() {
use randombytes::randombytes;
for i in 0..256usize {
let k = gen_key();
let m = randombytes(i);
let tag = authenticate(&m, &k);
let mut state = State::init(k.as_ref());
for c in m.chunks(1) {
state.update(c);
}
let tag2 = state.finalize();
assert_eq!(tag, tag2);
}
}
}
));