#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "alloc")]
use alloc::vec;
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
use crate::error::HqcError;
pub struct Shake256Xof {
pub state: [u64; 25], rate: usize,
pub position: usize,
}
impl Shake256Xof {
pub fn new() -> Self {
Self {
state: [0u64; 25],
rate: 136, position: 0,
}
}
pub fn init(&mut self, input: &[u8]) -> Result<(), HqcError> {
self.state.fill(0);
self.position = 0;
self.absorb(input)?;
self.finalize_absorb()?;
Ok(())
}
pub fn init_with_domain(&mut self, input: &[u8], domain: u8) -> Result<(), HqcError> {
self.state.fill(0);
self.position = 0;
self.absorb(input)?;
self.absorb(&[domain])?;
self.finalize_absorb()?;
Ok(())
}
pub fn squeeze(&mut self, output: &mut [u8]) -> Result<(), HqcError> {
for byte in output.iter_mut() {
if self.position >= self.rate {
self.keccak_f();
self.position = 0;
}
let lane_index = self.position / 8;
let byte_index = self.position % 8;
*byte = ((self.state[lane_index] >> (byte_index * 8)) & 0xFF) as u8;
self.position += 1;
}
Ok(())
}
pub fn squeeze_byte(&mut self) -> Result<u8, HqcError> {
let mut byte = [0u8; 1];
self.squeeze(&mut byte)?;
Ok(byte[0])
}
pub fn squeeze_u32(&mut self) -> Result<u32, HqcError> {
let mut bytes = [0u8; 4];
self.squeeze(&mut bytes)?;
Ok(u32::from_le_bytes(bytes))
}
pub fn squeeze_u64(&mut self) -> Result<u64, HqcError> {
let mut bytes = [0u8; 8];
self.squeeze(&mut bytes)?;
Ok(u64::from_le_bytes(bytes))
}
pub fn absorb(&mut self, input: &[u8]) -> Result<(), HqcError> {
for &byte in input {
if self.position >= self.rate {
self.keccak_f();
self.position = 0;
}
let lane_index = self.position / 8;
let byte_index = self.position % 8;
self.state[lane_index] ^= (byte as u64) << (byte_index * 8);
self.position += 1;
}
Ok(())
}
pub fn finalize_absorb(&mut self) -> Result<(), HqcError> {
if self.position >= self.rate {
self.keccak_f();
self.position = 0;
}
let lane_index = self.position / 8;
let byte_index = self.position % 8;
self.state[lane_index] ^= 0x1F << (byte_index * 8);
let last_byte_position = self.rate - 1; let last_lane_index = last_byte_position / 8;
let last_byte_index = last_byte_position % 8;
self.state[last_lane_index] ^= 0x80 << (last_byte_index * 8);
self.keccak_f();
self.position = 0;
Ok(())
}
fn keccak_f(&mut self) {
lib_q_keccak::f1600(&mut self.state);
}
#[allow(dead_code)] fn keccak_round(&mut self) {
let mut c = [0u64; 5];
for (x, c_val) in c.iter_mut().enumerate() {
*c_val = self.state[x] ^
self.state[x + 5] ^
self.state[x + 10] ^
self.state[x + 15] ^
self.state[x + 20];
}
for x in 0..5 {
let d = c[(x + 4) % 5] ^ c[(x + 1) % 5].rotate_left(1);
for y in 0..5 {
self.state[x + 5 * y] ^= d;
}
}
let mut temp = [0u64; 25];
temp.copy_from_slice(&self.state);
for x in 0..5 {
for y in 0..5 {
let index = x + 5 * y;
let new_index = (y + 5 * x) % 25;
self.state[new_index] = temp[index].rotate_left((x + y) as u32);
}
}
for y in 0..5 {
let mut temp_row = [0u64; 5];
for (x, temp_val) in temp_row.iter_mut().enumerate() {
*temp_val = self.state[x + 5 * y];
}
for x in 0..5 {
self.state[x + 5 * y] =
temp_row[x] ^ (!temp_row[(x + 1) % 5] & temp_row[(x + 2) % 5]);
}
}
self.state[0] ^= 0x0000000000000001;
}
}
impl Default for Shake256Xof {
fn default() -> Self {
Self::new()
}
}
#[cfg(feature = "alloc")]
pub fn shake256_hash(input: &[u8], output_len: usize) -> Result<Vec<u8>, HqcError> {
let mut xof = Shake256Xof::new();
xof.init(input)?;
let mut output = vec![0u8; output_len];
xof.squeeze(&mut output[..output_len])?;
Ok(output)
}
#[cfg(not(feature = "alloc"))]
pub fn shake256_hash(input: &[u8], output_len: usize) -> Result<[u8; 1000], HqcError> {
let mut xof = Shake256Xof::new();
xof.init(input)?;
let mut output = [0u8; 1000];
if output_len > output.len() {
return Err(HqcError::InvalidSize);
}
xof.squeeze(&mut output[..output_len])?;
Ok(output)
}
#[cfg(feature = "alloc")]
pub fn shake256_random(seed: &[u8], output_len: usize) -> Result<Vec<u8>, HqcError> {
shake256_hash(seed, output_len)
}
#[cfg(not(feature = "alloc"))]
pub fn shake256_random(seed: &[u8], output_len: usize) -> Result<[u8; 1000], HqcError> {
shake256_hash(seed, output_len)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_shake256_xof_creation() {
let xof = Shake256Xof::new();
assert_eq!(xof.rate, 136);
assert_eq!(xof.position, 0);
}
#[test]
fn test_xof_kat_compatibility() {
let seed_kem =
hex::decode("9ef877fddbe8891c6e4e79eaf022e563defaca6b152161b9a423e8fe96a403e7")
.unwrap();
let mut xof = Shake256Xof::new();
xof.init_with_domain(&seed_kem, 1).expect("XOF init failed");
let mut seed_pke = [0u8; 32];
let mut sigma = [0u8; 16];
xof.squeeze(&mut seed_pke).expect("XOF squeeze failed");
xof.squeeze(&mut sigma).expect("XOF squeeze failed");
assert!(
seed_pke.iter().any(|&x| x != 0),
"seed_pke should not be all zeros"
);
assert!(
sigma.iter().any(|&x| x != 0),
"sigma should not be all zeros"
);
}
#[test]
fn test_shake256_xof_init() {
let mut xof = Shake256Xof::new();
let input = b"test input";
xof.init(input).unwrap();
assert!(xof.state.iter().any(|&x| x != 0));
}
#[test]
fn test_shake256_xof_squeeze() {
let mut xof = Shake256Xof::new();
let input = b"test input";
xof.init(input).unwrap();
let mut output = [0u8; 32];
xof.squeeze(&mut output).unwrap();
assert!(output.iter().any(|&x| x != 0));
}
#[test]
fn test_shake256_hash() {
let input = b"test input";
let output = shake256_hash(input, 32).unwrap();
assert_eq!(output.len(), 32);
let output2 = shake256_hash(input, 32).unwrap();
assert_eq!(output, output2);
}
#[test]
fn test_shake256_random() {
let seed = b"random seed";
let output = shake256_random(seed, 64).unwrap();
assert_eq!(output.len(), 64);
let output2 = shake256_random(seed, 64).unwrap();
assert_eq!(output, output2);
}
}