mod fhe;
mod plain;
#[cfg(test)]
mod test;
use super::shift_register::ShiftRegister;
pub use fhe::{KreyviumFheKey, KreyviumFheState};
pub use plain::{KreyviumIV, KreyviumPlainKey, KreyviumPlainState};
use rayon::prelude::*;
fn collect_boxed_array<T: std::fmt::Debug, const N: usize>(
iter: impl IntoIterator<Item = T>,
) -> Result<Box<[T; N]>, ()> {
iter.into_iter()
.collect::<Vec<_>>()
.into_boxed_slice()
.try_into()
.map_err(|_| ())
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct KreyviumState<T> {
a: ShiftRegister<93, T>,
b: ShiftRegister<84, T>,
c: ShiftRegister<111, T>,
k: ShiftRegister<128, T>,
iv: ShiftRegister<128, T>,
counter: u64,
}
impl<T> KreyviumState<T> {
fn round_input(&self, n: usize) -> KreyviumRoundInput<'_, T> {
assert!(n <= 65);
let (k, iv) = (&self.k[127 - n], &self.iv[127 - n]);
let a = (
&self.a[65 - n], &self.a[92 - n], &self.a[91 - n], &self.a[90 - n], &self.a[68 - n], );
let b = (
&self.b[68 - n], &self.b[83 - n], &self.b[82 - n], &self.b[81 - n], &self.b[77 - n], );
let c = (
&self.c[65 - n], &self.c[110 - n], &self.c[109 - n], &self.c[108 - n], &self.c[86 - n], );
KreyviumRoundInput { a, b, c, k, iv }
}
fn backward_round_input(&self) -> KreyviumRoundInput<'_, T> {
let (k, iv) = (&self.k[0], &self.iv[0]);
let a = (
&self.a[0], &self.a[66], &self.a[92], &self.a[91], &self.a[69], );
let b = (
&self.b[0], &self.b[69], &self.b[83], &self.b[82], &self.b[78], );
let c = (
&self.c[0], &self.c[66], &self.c[110], &self.c[109], &self.c[87], );
KreyviumRoundInput { a, b, c, k, iv }
}
fn update(&mut self, values: impl ExactSizeIterator<Item = [T; 3]>) {
let n_rounds = values.len();
for [a, b, c] in values {
self.a.push(a);
self.b.push(b);
self.c.push(c);
}
self.k.n_shifts(n_rounds);
self.iv.n_shifts(n_rounds);
self.counter = self.counter.checked_add(n_rounds as u64).unwrap();
}
fn rewind(&mut self, values: impl ExactSizeIterator<Item = [T; 3]>) {
let n_rounds = values.len();
for [a, b, c] in values {
self.a.push_back(a);
self.b.push_back(b);
self.c.push_back(c);
}
self.k.n_unshifts(n_rounds);
self.iv.n_unshifts(n_rounds);
self.counter = self.counter.checked_sub(n_rounds as u64).unwrap();
}
}
#[allow(
private_bounds,
reason = "All methods in this impl block are private, so the private bounds won't be visible on user side"
)]
impl<T, A> KreyviumState<T>
where
for<'a> KreyviumRoundInput<'a, T>: KreyviumRound<Bit = T, AuxData = A>,
{
fn next(&mut self, aux: &A) -> T {
let round_input = self.round_input(0);
let KreyviumRoundOutput { output, a, b, c } = round_input.round(aux);
self.update(std::iter::once([a, b, c]));
output
}
fn prev(&mut self, aux: &A) {
let backward_input = self.backward_round_input();
let KreyviumBackwardRoundOutput { a, b, c } = backward_input.backward_round(aux);
self.rewind(std::iter::once([a, b, c]));
}
}
#[allow(
private_bounds,
reason = "All methods in this impl block are private, so the private bounds won't be visible on user side"
)]
impl<T, A> KreyviumState<T>
where
for<'a> KreyviumRoundInput<'a, T>: KreyviumRound<Bit = T, AuxData = A>,
T: Send + Sync,
A: Sync,
{
fn next_64(&mut self, aux: &A) -> Vec<T> {
let values = (0..64).into_par_iter().map(|x| {
let round_input = self.round_input(x);
let KreyviumRoundOutput { output, a, b, c } = round_input.round(aux);
(output, [a, b, c])
});
let (res, updates): (Vec<_>, Vec<_>) = values.unzip();
self.update(updates.into_iter());
res
}
fn next_n(&mut self, aux: &A, n_bits: usize) -> Vec<T> {
let mut result = Vec::with_capacity(n_bits);
for _ in 0..n_bits / 64 {
result.extend(self.next_64(aux));
}
for _ in 0..n_bits % 64 {
result.push(self.next(aux));
}
result
}
fn skip_n(&mut self, aux: &A, n_bits: usize) {
for _ in 0..n_bits / 64 {
let _ = self.next_64(aux);
}
for _ in 0..n_bits % 64 {
self.next(aux);
}
}
fn prev_n(&mut self, aux: &A, n_bits: usize) {
for _ in 0..n_bits {
self.prev(aux);
}
}
fn seek_to(&mut self, aux: &A, target: u64) {
match target.cmp(&self.counter) {
std::cmp::Ordering::Greater => {
let n = (target - self.counter) as usize;
self.skip_n(aux, n);
}
std::cmp::Ordering::Less => {
let n = (self.counter - target) as usize;
self.prev_n(aux, n);
}
std::cmp::Ordering::Equal => {}
}
}
fn warmup(&mut self, aux: &A) {
for _ in 0..18 {
self.next_64(aux);
}
self.counter = 0;
}
}
struct KreyviumRoundInput<'a, T> {
a: (&'a T, &'a T, &'a T, &'a T, &'a T),
b: (&'a T, &'a T, &'a T, &'a T, &'a T),
c: (&'a T, &'a T, &'a T, &'a T, &'a T),
k: &'a T,
iv: &'a T,
}
struct KreyviumRoundOutput<T> {
output: T,
a: T,
b: T,
c: T,
}
struct KreyviumBackwardRoundOutput<T> {
a: T,
b: T,
c: T,
}
trait KreyviumRound {
type AuxData;
type Bit;
fn round(self, aux: &Self::AuxData) -> KreyviumRoundOutput<Self::Bit>;
fn backward_round(self, aux: &Self::AuxData) -> KreyviumBackwardRoundOutput<Self::Bit>;
}