//! GIFT-256 fixsliced bit interleave/deinterleave //! Used to convert between standard and fixsliced representations //! Corresponds to gift256_encrypt_fixsliced State 0 (input) and State 3 (output) /// Pack 8 u32 (standard) into 8 u32 (fixsliced) with initial round key XOR. /// Corresponds to gift256_encrypt_fixsliced State 0. /// /// Input read order (from decompiled offsets): /// input[7]=@0x1c, input[3]=@0x0c, input[6]=@0x18, input[2]=@0x08 /// input[5]=@0x14, input[1]=@0x04, input[4]=@0x10, input[0]=@0x00 pub fn pack_input(input: &[u32; 8], initial_rk: &[u32; 8]) -> [u32; 8] { let (mut a, mut b, mut c, mut d, mut e, mut f, mut g, mut h) = (input[7], input[3], input[6], input[2], input[5], input[1], input[4], input[0]); // Phase 1: 0x55555555 interleave (odd/even bit separation) let t0 = (a ^ (b >> 1)) & 0x55555555; a ^= t0; b ^= t0 << 1; let t1 = (c ^ (d >> 1)) & 0x55555555; c ^= t1; d ^= t1 << 1; let t2 = (e ^ (f >> 1)) & 0x55555555; e ^= t2; f ^= t2 << 1; let t3 = (g ^ (h >> 1)) & 0x55555555; g ^= t3; h ^= t3 << 1; // Phase 2: 0x33333333 interleave (2-bit group separation) let t4 = (a ^ (c >> 2)) & 0x33333333; a ^= t4; c ^= t4 << 2; let t5 = (e ^ (g >> 2)) & 0x33333333; e ^= t5; g ^= t5 << 2; let t6 = (b ^ (d >> 2)) & 0x33333333; b ^= t6; d ^= t6 << 2; let t7 = (f ^ (h >> 2)) & 0x33333333; f ^= t7; h ^= t7 << 2; // Phase 3: 0x0F0F0F0F interleave (nibble separation) + initial round key XOR let t8 = (a ^ (e >> 4)) & 0x0F0F0F0F; let out7 = initial_rk[7] ^ (a ^ t8); let out3 = initial_rk[3] ^ ((t8 << 4) ^ e); let t9 = (c ^ (g >> 4)) & 0x0F0F0F0F; let out5 = initial_rk[5] ^ (c ^ t9); let out1 = initial_rk[1] ^ ((t9 << 4) ^ g); let t10 = (b ^ (f >> 4)) & 0x0F0F0F0F; let out6 = initial_rk[6] ^ (b ^ t10); let out2 = initial_rk[2] ^ ((t10 << 4) ^ f); let t11 = (d ^ (h >> 4)) & 0x0F0F0F0F; let out4 = initial_rk[4] ^ (d ^ t11); let out0 = initial_rk[0] ^ ((t11 << 4) ^ h); [out0, out1, out2, out3, out4, out5, out6, out7] } /// Nibble deinterleave. /// Decompiled: ((uVar4 >> 4 ^ uVar4) & 0xf000f00) * 0x11 ^ uVar4 pub fn nibble_deinterleave(x: u32) -> u32 { (((x >> 4) ^ x) & 0x0F000F00).wrapping_mul(0x11) ^ x } /// Key schedule deinterleave type A (offsets 0x20..0x3C, 0x60..0x7C, 0x1A0..0x1BC) /// x = ((x ^ x>>4) & 0x030F0C00) * 0x11 ^ x; /// x = ((x>>2 ^ x) & 0x33003300) * 5 ^ x; pub fn key_deinterleave_a(x: u32) -> u32 { let x = (((x ^ (x >> 4)) & 0x030F0C00).wrapping_mul(0x11)) ^ x; ((((x >> 2) ^ x) & 0x33003300).wrapping_mul(5)) ^ x } /// Key schedule deinterleave type B (offsets 0x40..0x5C) /// x = ((x>>4 ^ x) & 0x0F000F00) * 0x11 ^ x; pub fn key_deinterleave_b(x: u32) -> u32 { ((((x >> 4) ^ x) & 0x0F000F00).wrapping_mul(0x11)) ^ x } /// Key schedule deinterleave type C (offsets 0x60..0x7C second group) /// x = ((x ^ x>>4) & 0x0C0F0300) * 0x11 ^ x; /// x = ((x>>2 ^ x) & 0x33003300) * 5 ^ x; pub fn key_deinterleave_c(x: u32) -> u32 { let x = (((x ^ (x >> 4)) & 0x0C0F0300).wrapping_mul(0x11)) ^ x; ((((x >> 2) ^ x) & 0x33003300).wrapping_mul(5)) ^ x } /// Interleave a half-key (4 u32 input -> 8 u32 output). /// Same 3-stage butterfly as pack_input but on 4 words. /// Used in key_schedule to interleave the two key halves. pub fn interleave_key_half(input: &[u32], output: &mut [u32]) { let (mut a, mut b) = (input[3], input[1]); let (mut c, mut d) = (input[2], input[0]); // Phase 1: 0x55555555 let t0 = (a ^ (b >> 1)) & 0x55555555; a ^= t0; b ^= t0 << 1; let t1 = (c ^ (d >> 1)) & 0x55555555; c ^= t1; d ^= t1 << 1; // Phase 2: 0x33333333 let t2 = (a ^ (c >> 2)) & 0x33333333; a ^= t2; c ^= t2 << 2; let t3 = (b ^ (d >> 2)) & 0x33333333; b ^= t3; d ^= t3 << 2; // Phase 3: 0x0F0F0F0F let t4 = (a ^ (b >> 4)) & 0x0F0F0F0F; output[7] = a ^ t4; output[3] = (t4 << 4) ^ b; let t5 = (c ^ (d >> 4)) & 0x0F0F0F0F; output[5] = c ^ t5; output[1] = (t5 << 4) ^ d; // For the remaining outputs, use the already-interleaved values let t6 = (a ^ (c >> 4)) & 0x0F0F0F0F; output[6] = a ^ t6; output[2] = (t6 << 4) ^ c; let t7 = (b ^ (d >> 4)) & 0x0F0F0F0F; output[4] = b ^ t7; output[0] = (t7 << 4) ^ d; } /// Unpack output: reverse bit-interleave + final round key XOR. /// Reverse of pack_input: apply masks in reverse order (0x0F -> 0x33 -> 0x55). pub fn unpack_output(s: &[u32; 8], final_rk: &[u32; 8]) -> [u32; 8] { // XOR with final round keys first // Mapping from pack_input output indices: // out7=a, out3=e, out5=c, out1=g, out6=b, out2=f, out4=d, out0=h let mut a = s[7] ^ final_rk[7]; let mut b = s[6] ^ final_rk[6]; let mut c = s[5] ^ final_rk[5]; let mut d = s[4] ^ final_rk[4]; // out4 = d part let mut e = s[3] ^ final_rk[3]; // out3 = e part let mut f = s[2] ^ final_rk[2]; let mut g = s[1] ^ final_rk[1]; let mut h = s[0] ^ final_rk[0]; // Reverse Phase 3: 0x0F0F0F0F let t8 = (a ^ (e >> 4)) & 0x0F0F0F0F; a ^= t8; e ^= t8 << 4; let t9 = (c ^ (g >> 4)) & 0x0F0F0F0F; c ^= t9; g ^= t9 << 4; let t10 = (b ^ (f >> 4)) & 0x0F0F0F0F; b ^= t10; f ^= t10 << 4; let t11 = (d ^ (h >> 4)) & 0x0F0F0F0F; d ^= t11; h ^= t11 << 4; // Reverse Phase 2: 0x33333333 let t4 = (a ^ (c >> 2)) & 0x33333333; a ^= t4; c ^= t4 << 2; let t5 = (e ^ (g >> 2)) & 0x33333333; e ^= t5; g ^= t5 << 2; let t6 = (b ^ (d >> 2)) & 0x33333333; b ^= t6; d ^= t6 << 2; let t7 = (f ^ (h >> 2)) & 0x33333333; f ^= t7; h ^= t7 << 2; // Reverse Phase 1: 0x55555555 let t0 = (a ^ (b >> 1)) & 0x55555555; a ^= t0; b ^= t0 << 1; let t1 = (c ^ (d >> 1)) & 0x55555555; c ^= t1; d ^= t1 << 1; let t2 = (e ^ (f >> 1)) & 0x55555555; e ^= t2; f ^= t2 << 1; let t3 = (g ^ (h >> 1)) & 0x55555555; g ^= t3; h ^= t3 << 1; // Output in original order (reverse of input mapping) [h, f, d, b, g, e, c, a] }