docs(des): document Feistel network and cipher operations

Add doc comments to LR struct and DES helper functions explaining the
Feistel network structure: IP -> 16 rounds -> FP, with each round using
expansion, S-box substitution, and P-box permutation.
This commit is contained in:
Kristofers Solo 2025-12-31 00:16:14 +02:00
parent 9e013352a5
commit 54b3d8716d
Signed by: kristoferssolo
GPG Key ID: 8687F2D3EEE6F0ED
2 changed files with 16 additions and 0 deletions

View File

@ -1,6 +1,10 @@
use crate::block::{block32::Block32, block64::Block64};
use std::mem::swap;
/// Left-Right pair representing DES state during Feistel rounds.
///
/// DES splits a 64-bit block into two 32-bit halves (L and R) for
/// processing through 16 Feistel rounds.
#[derive(Debug, Clone, Copy)]
pub struct LR {
pub(crate) left: Block32,
@ -8,6 +12,7 @@ pub struct LR {
}
impl LR {
/// Creates a new L-R pair from two 32-bit blocks.
#[must_use]
pub fn new(left: impl Into<Block32>, right: impl Into<Block32>) -> Self {
Self {
@ -16,17 +21,20 @@ impl LR {
}
}
/// Swaps the left and right halves in place.
#[inline]
pub const fn swap(&mut self) {
swap(&mut self.left, &mut self.right);
}
/// Returns the left 32-bit half.
#[inline]
#[must_use]
pub const fn left(self) -> Block32 {
self.left
}
/// Returns the right 32-bit half.
#[inline]
#[must_use]
pub const fn right(self) -> Block32 {

View File

@ -68,12 +68,14 @@ impl BlockCipher for Des {
}
}
/// Initial Permutation - rearranges input bits according to IP table.
#[inline]
#[must_use]
fn ip(block: Block64) -> Block64 {
permutate(block.as_u64(), 64, 64, &IP).into()
}
/// Executes 16 Feistel rounds with the given subkeys.
#[must_use]
fn feistel_rounds<'a, I>(block: Block64, subkeys: I) -> Block64
where
@ -88,12 +90,14 @@ where
lr.into()
}
/// Single Feistel round: L' = R, R' = L XOR f(R, K).
fn feistel(lr: &mut LR, subkey: Subkey) {
let tmp = lr.right;
lr.right = lr.left ^ f_function(lr.right, subkey);
lr.left = tmp;
}
/// The f-function: expansion -> XOR with key -> S-box -> P-box.
#[must_use]
fn f_function(right: Block32, subkey: Subkey) -> Block32 {
let expanded = expansion_permutation(right);
@ -102,12 +106,14 @@ fn f_function(right: Block32, subkey: Subkey) -> Block32 {
p_box_permutation(sboxed)
}
/// Expands 32 bits to 48 bits using the E-box permutation.
#[inline]
#[must_use]
fn expansion_permutation(right: Block32) -> Block48 {
permutate(right.as_u64(), 32, 48, &E_BOX).into()
}
/// Substitutes 48 bits through 8 S-boxes, producing 32 bits.
#[must_use]
fn s_box_substitution(block: Block48) -> Block32 {
let six_bit_blocks = block.as_block6_array();
@ -127,12 +133,14 @@ fn s_box_substitution(block: Block48) -> Block32 {
.into()
}
/// Permutes 32 bits according to the P-box table.
#[inline]
#[must_use]
fn p_box_permutation(block: Block32) -> Block32 {
permutate(block.as_u64(), 32, 32, &P_BOX).into()
}
/// Final Permutation - inverse of IP, produces the ciphertext.
#[inline]
#[must_use]
fn fp(result: Block64) -> Block64 {