From 54b3d8716dc8e6746ead39a140526287c57ab8c0 Mon Sep 17 00:00:00 2001 From: Kristofers Solo Date: Wed, 31 Dec 2025 00:16:14 +0200 Subject: [PATCH] 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. --- des/src/block/lr.rs | 8 ++++++++ des/src/des.rs | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/des/src/block/lr.rs b/des/src/block/lr.rs index 054f626..1efa971 100644 --- a/des/src/block/lr.rs +++ b/des/src/block/lr.rs @@ -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, right: impl Into) -> 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 { diff --git a/des/src/des.rs b/des/src/des.rs index 93834bb..0373fe6 100644 --- a/des/src/des.rs +++ b/des/src/des.rs @@ -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 {