use super::generichash_blake2b::*;
use crate::blake2b;
use crate::constants::CRYPTO_GENERICHASH_KEYBYTES;
use crate::error::Error;
#[inline]
pub fn crypto_generichash(
output: &mut [u8],
input: &[u8],
key: Option<&[u8]>,
) -> Result<(), Error> {
crypto_generichash_blake2b(output, input, key)
}
pub struct GenericHashState {
state: blake2b::State,
}
#[inline]
pub fn crypto_generichash_init(
key: Option<&[u8]>,
outlen: usize,
) -> Result<GenericHashState, Error> {
let state = crypto_generichash_blake2b_init(key, outlen, None, None)?;
Ok(GenericHashState { state })
}
#[inline]
pub fn crypto_generichash_update(state: &mut GenericHashState, input: &[u8]) {
crypto_generichash_blake2b_update(&mut state.state, input)
}
#[inline]
pub fn crypto_generichash_final(state: GenericHashState, output: &mut [u8]) -> Result<(), Error> {
crypto_generichash_blake2b_final(state.state, output)
}
pub fn crypto_generichash_keygen() -> [u8; CRYPTO_GENERICHASH_KEYBYTES] {
let mut key = [0u8; CRYPTO_GENERICHASH_KEYBYTES];
crate::rng::copy_randombytes(&mut key);
key
}
#[cfg(test)]
mod tests {
use rand::TryRngCore;
use super::*;
#[test]
fn test_generichash() {
use libsodium_sys::crypto_generichash as so_crypto_generichash;
use rand_core::OsRng;
use crate::constants::{CRYPTO_GENERICHASH_BYTES_MAX, CRYPTO_GENERICHASH_BYTES_MIN};
use crate::rng::copy_randombytes;
for _ in 0..20 {
let outlen = CRYPTO_GENERICHASH_BYTES_MIN
+ (OsRng.try_next_u32().unwrap() as usize
% (CRYPTO_GENERICHASH_BYTES_MAX - CRYPTO_GENERICHASH_BYTES_MIN));
let mut output = vec![0u8; outlen];
let mut input = vec![0u8; (OsRng.try_next_u32().unwrap() % 5000) as usize];
copy_randombytes(&mut input);
let mut so_output = output.clone();
crypto_generichash(&mut output, &input, None).ok();
unsafe {
so_crypto_generichash(
so_output.as_mut_ptr(),
so_output.len(),
input.as_ptr(),
input.len() as u64,
std::ptr::null(),
0,
);
}
assert_eq!(output, so_output);
}
}
#[test]
fn test_generichash_key() {
use libsodium_sys::crypto_generichash as so_crypto_generichash;
use rand_core::OsRng;
use crate::constants::{
CRYPTO_GENERICHASH_BYTES_MAX, CRYPTO_GENERICHASH_BYTES_MIN,
CRYPTO_GENERICHASH_KEYBYTES_MAX, CRYPTO_GENERICHASH_KEYBYTES_MIN,
};
use crate::rng::copy_randombytes;
for _ in 0..20 {
let outlen = CRYPTO_GENERICHASH_BYTES_MIN
+ (OsRng.try_next_u32().unwrap() as usize
% (CRYPTO_GENERICHASH_BYTES_MAX - CRYPTO_GENERICHASH_BYTES_MIN));
let mut output = vec![0u8; outlen];
let mut input = vec![0u8; (OsRng.try_next_u32().unwrap() % 5000) as usize];
let keylen = CRYPTO_GENERICHASH_KEYBYTES_MIN
+ (OsRng.try_next_u32().unwrap() as usize
% (CRYPTO_GENERICHASH_KEYBYTES_MAX - CRYPTO_GENERICHASH_KEYBYTES_MIN));
let mut key = vec![0u8; keylen];
copy_randombytes(&mut input);
copy_randombytes(&mut key);
let mut so_output = output.clone();
crypto_generichash(&mut output, &input, Some(&key)).ok();
unsafe {
so_crypto_generichash(
so_output.as_mut_ptr(),
so_output.len(),
input.as_ptr(),
input.len() as u64,
key.as_ptr(),
key.len(),
);
}
assert_eq!(output, so_output);
}
}
}