use crate::{
crypto::Hasher,
utils::usize_to_le_varint_bytes,
word::{Shape, Word, on_all_words},
};
use alloc::{vec, vec::Vec};
use core::ops::{BitAnd, BitOr, BitXor, Not};
use serde::{Deserialize, Serialize};
use zeroize::Zeroize;
#[derive(Clone, Debug, PartialEq, Eq, Zeroize, Serialize, Deserialize)]
pub struct Words {
pub u8: Vec<u8>,
#[cfg(feature = "u16")]
pub u16: Vec<u16>,
#[cfg(feature = "u32")]
pub u32: Vec<u32>,
#[cfg(feature = "u64")]
pub u64: Vec<u64>,
#[cfg(feature = "u128")]
pub u128: Vec<u128>,
}
impl Words {
pub fn feature_flags(&self) -> u8 {
let mut feature_flags = 0u8; on_all_words!(W, {
if self.as_vec::<W>().len() > 0 {
feature_flags |= 1 << (W::WIDTH / 8).trailing_zeros();
}
});
return feature_flags;
}
pub fn as_vec<W: Word>(&self) -> &Vec<W> {
return W::vec_from_words(self);
}
pub fn as_vec_mut<W: Word>(&mut self) -> &mut Vec<W> {
return W::vec_mut_from_words(self);
}
pub const fn new() -> Self {
return Self {
u8: Vec::new(),
#[cfg(feature = "u16")]
u16: Vec::new(),
#[cfg(feature = "u32")]
u32: Vec::new(),
#[cfg(feature = "u64")]
u64: Vec::new(),
#[cfg(feature = "u128")]
u128: Vec::new(),
};
}
pub fn with_capacity(capacities: Shape) -> Self {
return Self {
u8: Vec::with_capacity(capacities.u8),
#[cfg(feature = "u16")]
u16: Vec::with_capacity(capacities.u16),
#[cfg(feature = "u32")]
u32: Vec::with_capacity(capacities.u32),
#[cfg(feature = "u64")]
u64: Vec::with_capacity(capacities.u64),
#[cfg(feature = "u128")]
u128: Vec::with_capacity(capacities.u128),
};
}
pub fn zeros(shape: Shape) -> Self {
return Self {
u8: vec![0u8; shape.u8],
#[cfg(feature = "u16")]
u16: vec![0u16; shape.u16],
#[cfg(feature = "u32")]
u32: vec![0u32; shape.u32],
#[cfg(feature = "u64")]
u64: vec![0u64; shape.u64],
#[cfg(feature = "u128")]
u128: vec![0u128; shape.u128],
};
}
pub fn shape(&self) -> Shape {
let mut shape = Shape::zero();
on_all_words!(W, {
*shape.as_value_mut::<W>() = self.as_vec::<W>().len();
});
return shape;
}
pub fn capacity(&self) -> Shape {
let mut shape = Shape::zero();
on_all_words!(W, {
*shape.as_value_mut::<W>() = self.as_vec::<W>().capacity();
});
return shape;
}
pub fn clear(&mut self) {
on_all_words!(W, {
self.as_vec_mut::<W>().clear();
});
}
pub fn update_hasher<H: Hasher>(&self, hasher: &mut H) {
hasher.update(&[self.feature_flags()]);
on_all_words!(W, {
let words = self.as_vec::<W>();
let mut buf: Vec<u8> = Vec::with_capacity(H::DIGEST_SIZE);
buf.append(&mut usize_to_le_varint_bytes(words.len()));
for &w in words {
let w_bytes = w.to_le_bytes();
if buf.len() + w_bytes.as_ref().len() > H::DIGEST_SIZE {
hasher.update(&buf);
buf.clear();
}
buf.extend_from_slice(w_bytes.as_ref());
}
if buf.len() > 0 {
hasher.update(&buf);
}
});
}
pub fn append_bytes(&self, bytes: &mut Vec<u8>) {
bytes.push(self.feature_flags());
on_all_words!(W, {
let word_vec = self.as_vec::<W>();
bytes.append(&mut usize_to_le_varint_bytes(word_vec.len()));
bytes.extend(word_vec.iter().flat_map(|&w| W::to_le_bytes(w)));
});
}
pub fn as_bytes(&self) -> Vec<u8> {
let mut bytes: Vec<u8> = Vec::new();
self.append_bytes(&mut bytes);
return bytes;
}
}
#[derive(Debug)]
pub struct ShapeError {
expected: Shape,
actual: Shape,
}
impl ShapeError {
pub fn new(expected: Shape, actual: Shape) -> Self {
return Self { expected, actual };
}
pub fn expected(&self) -> Shape {
return self.expected;
}
pub fn actual(&self) -> Shape {
return self.actual;
}
}
macro_rules! impl_words_unop {
($opname: ident, $func: expr) => {
fn $opname(self) -> Words {
let mut result = Words::new();
result.u8 = self.u8.iter().map($func).collect();
#[cfg(feature = "u16")]
{
result.u16 = self.u16.iter().map($func).collect();
}
#[cfg(feature = "u32")]
{
result.u32 = self.u32.iter().map($func).collect();
}
#[cfg(feature = "u64")]
{
result.u64 = self.u64.iter().map($func).collect();
}
#[cfg(feature = "u128")]
{
result.u128 = self.u128.iter().map($func).collect();
}
return result;
}
};
}
macro_rules! impl_words_binop {
($opname: ident, $func: expr) => {
fn $opname(self, rhs: Self) -> Result<Words, ShapeError> {
if self.shape() != rhs.shape() {
return Err(ShapeError::new(self.shape(), rhs.shape()));
}
let mut result = Words::new();
result.u8 = self.u8.iter().zip(rhs.u8.iter()).map($func).collect();
#[cfg(feature = "u16")]
{
result.u16 = self.u16.iter().zip(rhs.u16.iter()).map($func).collect();
}
#[cfg(feature = "u32")]
{
result.u32 = self.u32.iter().zip(rhs.u32.iter()).map($func).collect();
}
#[cfg(feature = "u64")]
{
result.u64 = self.u64.iter().zip(rhs.u64.iter()).map($func).collect();
}
#[cfg(feature = "u128")]
{
result.u128 = self.u128.iter().zip(rhs.u128.iter()).map($func).collect();
}
return Ok(result);
}
};
}
impl Not for &Words {
type Output = Words;
impl_words_unop!(not, |w| !w);
}
impl BitXor for &Words {
type Output = Result<Words, ShapeError>;
impl_words_binop!(bitxor, |(a, b)| a ^ b);
}
impl BitAnd for &Words {
type Output = Result<Words, ShapeError>;
impl_words_binop!(bitand, |(a, b)| a & b);
}
impl BitOr for &Words {
type Output = Result<Words, ShapeError>;
impl_words_binop!(bitor, |(a, b)| a | b);
}