feat: finish S-Box substitution

This commit is contained in:
Kristofers Solo 2025-10-02 11:26:48 +03:00
parent b95c294a11
commit e777444583
Signed by: kristoferssolo
GPG Key ID: 74FF8144483D82C8
2 changed files with 39 additions and 30 deletions

View File

@ -30,7 +30,7 @@ pub const PC2_TABLE: [u8; 48] = [
pub const ROUND_ROTATIONS: [u8; 16] = [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1]; pub const ROUND_ROTATIONS: [u8; 16] = [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1];
/// Expansion permutation (32 to 48 bits). /// Expansion permutation (32 to 48 bits).
pub const EXPANSION_TABLE: [u8; 48] = [ pub const E_BOX: [u8; 48] = [
32, 1, 2, 3, 4, 5, 4, 5, 6, 7, 8, 9, 8, 9, 10, 11, 12, 13, 12, 13, 14, 15, 16, 17, 16, 17, 18, 32, 1, 2, 3, 4, 5, 4, 5, 6, 7, 8, 9, 8, 9, 10, 11, 12, 13, 12, 13, 14, 15, 16, 17, 16, 17, 18,
19, 20, 21, 20, 21, 22, 23, 24, 25, 24, 25, 26, 27, 28, 29, 28, 29, 30, 31, 32, 1, 19, 20, 21, 20, 21, 22, 23, 24, 25, 24, 25, 26, 27, 28, 29, 28, 29, 30, 31, 32, 1,
]; ];

View File

@ -1,6 +1,6 @@
mod constants; mod constants;
use crate::constants::{EXPANSION_TABLE, IP, PC1_TABLE, PC2_TABLE, ROUND_ROTATIONS}; use crate::constants::{E_BOX, IP, PC1_TABLE, PC2_TABLE, ROUND_ROTATIONS, S_BOXES};
#[derive(Debug)] #[derive(Debug)]
pub struct Des { pub struct Des {
@ -160,14 +160,25 @@ fn ip(message: u64) -> u64 {
/// Expand the right side of the data from 32 bits to 48. /// Expand the right side of the data from 32 bits to 48.
#[must_use] #[must_use]
fn expansion_permutation(right: u32) -> u64 { fn expansion_permutation(right: u32) -> u64 {
permutate(u64::from(right), 32, 48, &EXPANSION_TABLE) permutate(u64::from(right), 32, 48, &E_BOX)
} }
/// Implementation for testing S-boxes in isolation.
/// Applies all 8 DES S-boxes to a 48-bit input, returning 32-bit result.
#[must_use] #[must_use]
fn s_box_permutation(input: u64) -> u32 { fn s_box_substitution(block: u64) -> u32 {
// Implementation for testing S-boxes in isolation S_BOXES.iter().enumerate().fold(0, |acc, (idx, s_box)| {
// Return 32-bit result after 8 S-boxes let start_bit = 42 - idx * 6; // 42 = 48 - 6
todo!() let shift_amount = (7 - idx) * 4;
let mask = 63 << start_bit; // 63 == 0b11_111
let sbox_bits = u8::try_from((block & mask) >> start_bit).expect("8-bit value");
let row = (sbox_bits >> 5) << 1 | (sbox_bits & 1);
let col = (sbox_bits >> 1) & 15; // 15 == 0b1111
let sbox_value = s_box[row as usize][col as usize];
acc | (u32::from(sbox_value) << shift_amount)
})
} }
#[must_use] #[must_use]
@ -205,7 +216,7 @@ fn feistel(left: u32, right: u32, subkey: u64) -> (u32, u32) {
fn f_function(right: u32, subkey: u64) -> u32 { fn f_function(right: u32, subkey: u64) -> u32 {
let expanded = expansion_permutation(right); let expanded = expansion_permutation(right);
let xored = expanded ^ subkey; let xored = expanded ^ subkey;
let sboxed = s_box_permutation(xored); let sboxed = s_box_substitution(xored);
p_box_permutation(sboxed) p_box_permutation(sboxed)
} }
@ -422,28 +433,26 @@ mod tests {
assert_eq!(expanded >> 48, 0, "Expansion exceeds 48 bits"); assert_eq!(expanded >> 48, 0, "Expansion exceeds 48 bits");
} }
// #[test] #[rstest]
fn sbox_subsitution() { #[case(0x6117_BA86_6527, 0x5C82_B597)] // Round 1
let sbox_tests = [ #[case(0x0C44_8DEB_63EC, 0xF8D0_3AAE)] // Round 2
// (box_idx, 6-bit input, expected 4-bit output) #[case(0xB07C_88F8_27CA, 0x2710_E16F)] // Round 3
(0, 0b000000, 14), // S1: 00 0000 -> row 0, col 0 -> 14 #[case(0x22EF_2EDE_4AB4, 0x21ED_9F3A)] // Round 4
(0, 0b011111, 9), // S1: 01 1111 -> row 1, col 15 -> 9 #[case(0xC605_03EB_51A2, 0x50C8_31EB)] // Round 5
(1, 0b100000, 0), // S2: 10 0000 -> row 2, col 0 -> 0 #[case(0xA6E7_6180_BA80, 0x41F3_4C3D)] // Round 6
(2, 0b001010, 2), // S3: 00 1010 -> row 0, col 10 -> 2 #[case(0x19AF_B813_B3EF, 0x1075_40AD)] // Round 7
]; #[case(0xF748_6F9E_7B5B, 0x6C18_7CAE)] // Round 8
#[case(0x8A70_B948_9B20, 0x110C_5777)] // Round 9
for (box_idx, input, expected) in sbox_tests { #[case(0xA170_BEDA_85BB, 0xDA04_5275)] // Round 10
let row = (input & 1) | ((input >> 4) & 0x2); #[case(0x7BA1_7834_2E23, 0x7305_D101)] // Round 11
let col = (input >> 1) & 0xF; #[case(0x15DA_058B_E418, 0x7B8B_2635)] // Round 12
let val = S_BOXES[box_idx][row as usize][col as usize]; #[case(0xAD78_2B75_B8B1, 0x9AD1_8B4F)] // Round 13
#[case(0x5055_B178_4DCE, 0x6479_9AF1)] // Round 14
assert_eq!( #[case(0x5FC5_D477_FF51, 0xB2E8_8D3C)] // Round 15
val, #[case(0xEB57_8F14_565D, 0xA783_2429)] // Round 16
expected as u8, fn sbox_subsitution(#[case] block: u64, #[case] output: u32) {
"S{} failed: input {input:06b} (row {row}, col {col}) expected {expected}, got {val}", let result = s_box_substitution(block);
box_idx + 1 assert_eq!(result, output, "Expected {output:08X}, got {result:08X}");
);
}
} }
// #[test] // #[test]