pub trait KeySchedule<H, K> {
type State;
fn new_state(&self, master_key: &K) -> Self::State;
fn next_key(&self, master_key: &K, state: &mut Self::State) -> H;
}
pub trait RoundFunction<H> {
fn f(&self, right: &H, round_key: &H) -> H;
}
pub struct ReverseKeySchedule<H, K, KS>
where
KS: KeySchedule<H, K>,
{
inner: KS,
rounds: usize,
_marker: std::marker::PhantomData<(H, K)>,
}
impl<H, K, KS> ReverseKeySchedule<H, K, KS>
where
KS: KeySchedule<H, K>,
{
pub fn from(schedule: KS, rounds: usize) -> Self {
Self {
inner: schedule,
rounds,
_marker: std::marker::PhantomData,
}
}
}
impl<H, K, KS> KeySchedule<H, K> for ReverseKeySchedule<H, K, KS>
where
KS: KeySchedule<H, K>,
{
type State = Vec<H>;
fn new_state(&self, master_key: &K) -> Self::State {
let mut inner_state = self.inner.new_state(master_key);
let mut keys = Vec::with_capacity(self.rounds);
for _ in 0..self.rounds {
keys.push(self.inner.next_key(master_key, &mut inner_state));
}
keys
}
fn next_key(&self, _unused_master_key: &K, state: &mut Self::State) -> H {
state
.pop()
.expect("KeySchedule state exhausted: next_key called more times than rounds available")
}
}
use std::marker::PhantomData;
use std::ops::BitXor;
pub struct FeistelNetwork<H, K, KS, RF>
where
H: BitXor<Output = H>,
KS: KeySchedule<H, K>,
RF: RoundFunction<H>,
{
key_schedule: KS,
round_function: RF,
rounds: usize,
_marker: PhantomData<(H, K)>,
}
impl<H, K, KS, RF> FeistelNetwork<H, K, KS, RF>
where
H: BitXor<Output = H>,
KS: KeySchedule<H, K>,
RF: RoundFunction<H>,
{
pub fn new(key_schedule: KS, round_function: RF, rounds: usize) -> Self {
Self {
key_schedule,
round_function,
rounds,
_marker: PhantomData,
}
}
pub fn process(&self, left: H, right: H, master_key: &K) -> (H, H) {
let mut l: H = left;
let mut r: H = right;
let mut ks_state = self.key_schedule.new_state(master_key);
for _ in 0..self.rounds {
let round_key = self.key_schedule.next_key(master_key, &mut ks_state);
let next_r: H = l ^ self.round_function.f(&r, &round_key);
let next_l: H = r;
l = next_l;
r = next_r;
}
(r, l)
}
}
#[cfg(test)]
mod lib_test;
pub mod magma;