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