use crate::siphash::{SipState, siphash24_ctr};
use arrayvec::ArrayVec;
use std::fmt;
pub(crate) const NUM_REGISTERS: usize = 8;
pub(crate) const R5: RegisterId = RegisterId(5);
#[derive(Clone, Copy, Eq, PartialEq)]
pub(crate) struct RegisterId(u8);
impl fmt::Debug for RegisterId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "R{}", self.0)
}
}
impl RegisterId {
#[inline(always)]
pub(crate) fn as_usize(&self) -> usize {
self.0 as usize
}
#[inline(always)]
#[cfg(feature = "compiler")]
pub(crate) fn as_u8(&self) -> u8 {
self.0
}
#[inline(always)]
pub(crate) fn all() -> impl Iterator<Item = RegisterId> {
(0_u8..(NUM_REGISTERS as u8)).map(RegisterId)
}
}
#[derive(Default, Clone, Eq, PartialEq)]
pub(crate) struct RegisterSet(ArrayVec<RegisterId, NUM_REGISTERS>);
impl fmt::Debug for RegisterSet {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "[")?;
for n in 0..self.len() {
if n != 0 {
write!(f, ",")?;
}
self.index(n).fmt(f)?;
}
write!(f, "]")
}
}
impl RegisterSet {
#[inline(always)]
pub(crate) fn len(&self) -> usize {
self.0.len()
}
#[inline(always)]
pub(crate) fn contains(&self, id: RegisterId) -> bool {
self.0.contains(&id)
}
#[inline(always)]
pub(crate) fn from_filter<P: FnMut(RegisterId) -> bool>(mut predicate: P) -> Self {
let mut result: Self = Default::default();
for r in RegisterId::all() {
if predicate(r) {
result.0.push(r);
}
}
result
}
#[inline(always)]
pub(crate) fn index(&self, index: usize) -> RegisterId {
self.0[index]
}
}
#[derive(Debug, Clone, Eq, PartialEq)]
#[repr(C)]
pub(crate) struct RegisterFile([u64; NUM_REGISTERS]);
impl RegisterFile {
#[inline(always)]
pub(crate) fn load(&self, id: RegisterId) -> u64 {
self.0[id.as_usize()]
}
#[inline(always)]
pub(crate) fn store(&mut self, id: RegisterId, value: u64) {
self.0[id.as_usize()] = value;
}
#[inline(always)]
pub(crate) fn new(key: SipState, input: u64) -> Self {
RegisterFile(siphash24_ctr(key, input))
}
#[inline(always)]
pub(crate) fn digest(&self, key: SipState) -> [u64; 4] {
let mut x = SipState {
v0: self.0[0].wrapping_add(key.v0),
v1: self.0[1].wrapping_add(key.v1),
v2: self.0[2],
v3: self.0[3],
};
let mut y = SipState {
v0: self.0[4],
v1: self.0[5],
v2: self.0[6].wrapping_add(key.v2),
v3: self.0[7].wrapping_add(key.v3),
};
x.sip_round();
y.sip_round();
[x.v0 ^ y.v0, x.v1 ^ y.v1, x.v2 ^ y.v2, x.v3 ^ y.v3]
}
}