feistelnet 0.1.0-alpha.2

Symetric block split Feistel Network
Documentation
// Feistel network framework for Rust
//
// Written by Radim Kolar <hsn@sendmail.cz> 2025
//
// SPDX-License-Identifier: CC0-1.0 OR Unlicense


/**
  Key schedule function for Feistel network.

  Purpose of this function is to derive round keys
  from master key.

  Function have its internal state. It can be simple
  such as simple round counter or more complex
  such as linear shift register.
*/
pub trait KeySchedule<H, K> {
   type State;

   /**
     Ininialize internal state for key schedule function.
   */
   fn new_state(&self, master_key: &K) -> Self::State;

   /**
     Generate key for next round and updates internal state
   */
   fn next_key(&self, master_key: &K, state: &mut Self::State) -> H;
}

/**
  Round function F.
*/
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>,
{
   /// Stav obsahuje predem vygenerovane klice a aktualni index.
   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);

      // Generate forward sequence for all keys
      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;

/// Main structure of the Feistel network.
/// H: Type of the halfblock (e.g., u32)
/// K: Type of the master key (e.g., [u8; 32])
/// KS: KeySchedule implementation
/// RF: RoundFunction implementation
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>,
{
   /// Creates a new instance of the network with the given number of rounds.
   pub fn new(key_schedule: KS, round_function: RF, rounds: usize) -> Self {
      Self {
         key_schedule,
         round_function,
         rounds,
         _marker: PhantomData,
      }
   }

   /// Performs encryption (or decryption, if KS generates keys in reverse order).
   pub fn process(&self, left: H, right: H, master_key: &K) -> (H, H) {
      let mut l: H = left;
      let mut r: H = right;

      // Initialize the internal state of the key scheduler
      let mut ks_state = self.key_schedule.new_state(master_key);

      for _ in 0..self.rounds {
         // 1. Obtain the round key (the state is modified internally)
         let round_key = self.key_schedule.next_key(master_key, &mut ks_state);

         // 2. Perform the Feistel transformation
         // New R = L ^ F(R, K)
         // New L = old R
         let next_r: H = l ^ self.round_function.f(&r, &round_key);
         let next_l: H = r;

         l = next_l;
         r = next_r;
      }

      // After the final round, (R, L) is usually returned,
      // which corresponds to swapping sides in each step.
      (r, l)
   }
}

#[cfg(test)]
mod lib_test;

pub mod magma;