Files
hcapReverse/src/gift256/interleave.rs
2026-02-27 08:56:04 +08:00

193 lines
6.0 KiB
Rust

//! 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]
}