refactor: create permutation table applying function

This commit is contained in:
Kristofers Solo 2025-10-01 18:15:47 +03:00
parent 5468d90a17
commit a452149b33
Signed by: kristoferssolo
GPG Key ID: 8687F2D3EEE6F0ED

View File

@ -1,6 +1,6 @@
mod constants; mod constants;
use crate::constants::{PC1_TABLE, PC2_TABLE, PERMUTATION, ROUND_ROTATIONS}; use crate::constants::{IP, PC1_TABLE, PC2_TABLE, PERMUTATION, ROUND_ROTATIONS};
#[derive(Debug)] #[derive(Debug)]
pub struct Des { pub struct Des {
@ -54,8 +54,8 @@ impl Des {
} }
#[must_use] #[must_use]
fn ip(&self, input: u64) -> u64 { fn ip(&self, message: u64) -> u64 {
todo!() apply_permutaion(message, 64, 64, &IP)
} }
#[must_use] #[must_use]
@ -75,23 +75,7 @@ impl Des {
/// versus Rust u64's little-endian bit numbering (0-63, LSB first). /// versus Rust u64's little-endian bit numbering (0-63, LSB first).
#[must_use] #[must_use]
pub fn pc1(key: u64) -> u64 { pub fn pc1(key: u64) -> u64 {
PC1_TABLE apply_permutaion(key, 64, 56, &PC1_TABLE)
.iter()
.enumerate()
.fold(0, |mut acc, (idx, &pos)| {
// pos is 1-based DES bit position (1-64, big-endian MSB first)
let des_bit_1based = u64::from(pos);
let des_bit_0based = des_bit_1based.saturating_sub(1); // 0-63
// Map DES big-endian position to u64 little-endian position
let bit_pos = 63u64.saturating_sub(des_bit_0based);
// Extract bit from u64 at the correct position
let bit = ((key >> bit_pos) & 1) << (55usize.saturating_sub(idx));
acc |= bit;
acc
})
} }
/// Compression permuation /// Compression permuation
@ -100,23 +84,7 @@ pub fn pc1(key: u64) -> u64 {
pub fn pc2(key: u64) -> u64 { pub fn pc2(key: u64) -> u64 {
let key_56 = key & 0x00FF_FFFF_FFFF_FFFF; let key_56 = key & 0x00FF_FFFF_FFFF_FFFF;
PC2_TABLE apply_permutaion(key_56, 56, 48, &PC2_TABLE)
.iter()
.enumerate()
.fold(0, |mut acc, (idx, &pos)| {
// pos is 1-based DES position in the 56-bit input (1-56)
let des_bit_1based = u64::from(pos);
let des_bit_0based = des_bit_1based.saturating_sub(1); // 0-55
// Map DES big-endian position to u64 little-endian position within 56 bits
let bit_pos = 55u64.saturating_sub(des_bit_0based);
// Extract bit from the 56-bit combined value
let bit = ((key_56 >> bit_pos) & 1) << (47usize.saturating_sub(idx));
acc |= bit;
acc
})
} }
#[must_use] #[must_use]
@ -177,6 +145,38 @@ fn generate_subkeys(key: u64) -> [u64; 16] {
.expect("Exactly 16 subkeys expected") .expect("Exactly 16 subkeys expected")
} }
/// Generic bit permutation for arbitrary input/output sizes.
///
/// # Arguments
/// - `input` - The input value (treated as a bitfield of `input_bits` size)
/// - `input_bits` - Number of meaningful bits in the input (1-64)
/// - `output_bits` - Number of bits in the output (1-64)
/// - `position_table` - 1-based positions (1 to `input_bits`) where each output bit comes from
#[must_use]
fn apply_permutaion(input: u64, input_bits: u32, output_bits: u32, position_table: &[u8]) -> u64 {
position_table
.iter()
.enumerate()
.fold(0, |acc, (idx, &pos)| {
// Convert 1-based DES position to 0-based input position (MSB first)
let pos_0based = u64::from(pos.saturating_sub(1));
let input_bit_pos = u64::from(input_bits)
.saturating_sub(1)
.saturating_sub(pos_0based);
// Extract bit from input
let bit_value = (input >> input_bit_pos) & 1;
// Extract bit from u64 at the correct position
let output_bit_pos = u64::from(output_bits)
.saturating_sub(1)
.saturating_sub(idx as u64);
let shifted_bit = bit_value << output_bit_pos;
acc | shifted_bit
})
}
/// Encrypts data using ECB mode. /// Encrypts data using ECB mode.
/// ///
/// # Arguments /// # Arguments
@ -287,11 +287,14 @@ mod tests {
} }
} }
// #[test] #[test]
fn initial_permutation() { fn initial_permutation() {
let expected_ip = 0xC2B093C7A3A7C24A; let expected_ip = 0xCC00_CCFF_F0AA_F0AA;
let result = des_instance().ip(TEST_KEY); let result = des_instance().ip(TEST_PLAINTEXT);
assert_eq!(result, expected_ip, "Initial permulation failed"); assert_eq!(
result, expected_ip,
"Initial permulation failed {result:016X} != {expected_ip:016X}"
);
} }
#[test] #[test]