use std::num::Wrapping;
use std::ops::{BitXor, BitXorAssign, Index, IndexMut};
#[derive(Clone, Copy, PartialEq, Debug)]
pub struct ZestBlock {
pub data: [u64; 64],
}
impl ZestBlock {
#[inline(always)]
pub fn new() -> ZestBlock {
ZestBlock { data: [0_u64; 64] }
}
#[inline(always)]
pub fn from_u64(least_sig: u64) -> ZestBlock {
let mut data = [0_u64; 64];
data[63] = least_sig;
ZestBlock { data }
}
#[inline(always)]
pub fn increment_block(&mut self) {
let mut carry: u64 = 1;
for elem in self.data.iter_mut().rev() {
*elem = (Wrapping(*elem) + Wrapping(carry)).0;
carry = (*elem < carry) as u64;
}
}
#[inline(always)]
pub fn data_u8(self) -> [u8; 512] {
let mut u8_data = [0_u8; 512];
for (i, chunk) in u8_data.chunks_exact_mut(8).enumerate() {
chunk.copy_from_slice(&self.data[i].to_be_bytes());
}
u8_data
}
}
impl BitXor<ZestBlock> for ZestBlock {
type Output = ZestBlock;
#[inline(always)]
fn bitxor(self, rhs: ZestBlock) -> Self::Output {
let mut xored = self;
for (index, chunk) in xored.data.iter_mut().enumerate() {
*chunk ^= rhs[index];
}
xored
}
}
impl BitXorAssign<ZestBlock> for ZestBlock {
#[inline(always)]
fn bitxor_assign(&mut self, rhs: ZestBlock) {
for (index, chunk) in self.data.iter_mut().enumerate() {
*chunk ^= rhs[index];
}
}
}
impl Index<usize> for ZestBlock {
type Output = u64;
#[inline(always)]
fn index(&self, index: usize) -> &Self::Output {
&self.data[index]
}
}
impl IndexMut<usize> for ZestBlock {
#[inline(always)]
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
&mut self.data[index]
}
}
impl From<[u64; 64]> for ZestBlock {
#[inline(always)]
fn from(data: [u64; 64]) -> Self {
ZestBlock { data }
}
}
impl From<[u8; 512]> for ZestBlock {
#[inline(always)]
fn from(data: [u8; 512]) -> Self {
let mut u64_data = [0_u64; 64];
for (i, chunk) in data.chunks_exact(8).enumerate() {
u64_data[i] = u64::from_be_bytes(chunk.try_into().unwrap());
}
ZestBlock { data: u64_data }
}
}
impl Default for ZestBlock {
#[inline(always)]
fn default() -> Self {
ZestBlock::new()
}
}
#[inline(always)]
pub fn bytes_to_blocks(bytes_input: Vec<u8>) -> Vec<ZestBlock> {
let mut blocks: Vec<ZestBlock> = vec![];
for block in bytes_input.chunks_exact(512) {
let block_arr: [u8; 512] = block.try_into().unwrap();
blocks.push(block_arr.into());
}
blocks
}
#[inline(always)]
pub fn blocks_to_bytes(blocks_input: Vec<ZestBlock>) -> Vec<u8> {
let mut blocks: Vec<u8> = vec![];
for block in blocks_input {
blocks.append(&mut block.data_u8().to_vec())
}
blocks
}