//! GIFT-256 bitsliced S-Box
//! Corresponds to gift256_sbox_bitsliced @ 0x8000394c
//! Pure AND/XOR Boolean network, 32 S-Box instances in parallel
//!
//! Directly transcribed from Ghidra decompilation.
//! WARNING: Variables are reassigned multiple times. Do NOT optimize or merge.

/// Bitsliced S-Box: 8 u32 words processed in parallel.
/// Each bit position across s[0]..s[7] forms one 8-bit S-Box input/output.
///
/// Register mapping (encrypted_mem_read_u32 offsets):
///   s[0]=@0x00, s[1]=@0x04, s[2]=@0x08, s[3]=@0x0c
///   s[4]=@0x10, s[5]=@0x14, s[6]=@0x18, s[7]=@0x1c
pub fn sbox_bitsliced(s: &mut [u32; 8]) {
    // Direct mapping from decompilation variable names:
    // uVar1=@0x1c=s[7], uVar2=@0x04=s[1], uVar3=@0x10=s[4], uVar4=@0x08=s[2]
    // uVar5=@0x0c=s[3], uVar6=@0x18=s[6], uVar7=@0x14=s[5], uVar(last)=@0x00=s[0]
    let (a, b, c, d, e, f, g, h) = (s[7], s[1], s[2], s[3], s[4], s[5], s[6], s[0]);

    let t1 = a ^ b;                            // uVar8 = uVar1 ^ uVar2
    let t2 = e ^ c;                            // uVar14 = uVar3 ^ uVar4
    let t3 = t1 ^ t2;                          // uVar9
    let t4 = d ^ t3 ^ g;                       // uVar10
    let t5 = e ^ a;                            // uVar15 = uVar3 ^ uVar1
    let t6 = t4 ^ t5;                          // uVar11
    let fg = f ^ g;                            // uVar7 = s[5] ^ s[6]
    let t7 = t6 ^ fg;                          // uVar12

    let ag = h ^ fg;                           // uVar25 = s[0] ^ (f^g)
    let bx = b ^ ag;                           // uVar2 updated
    let cd_mix = c ^ d ^ t3;                   // uVar26
    let fg_cd = fg ^ cd_mix;                   // uVar7 subsequent

    // Nonlinear core
    let n1 = (t6 & t5) ^ (t2 & (fg_cd ^ t6)); // uVar16
    let n2 = (t7 & t1) ^ t7 ^ (bx & ag) ^ t1 ^ n1; // uVar5

    let ac = a ^ c;                            // uVar4 updated
    let n1_ext = n1 ^ (cd_mix & t3) ^ t4 ^ ((h ^ cd_mix) & (ac ^ bx)); // uVar16 updated

    let p = n2 & n1_ext;                       // uVar10
    let q = (ac & fg_cd) ^ (t6 & t5);         // uVar22
    let r = (h & (e ^ ag)) ^ ac ^ fg_cd ^ (cd_mix & t3) ^ q; // uVar17
    let qx = q ^ t7 ^ ((a ^ ag) & (h ^ t6)) ^ (t7 & t1) ^ a; // uVar22 updated

    let m = (p ^ r) & (qx ^ n2);              // uVar13
    let n1x = r ^ n1_ext;                     // uVar16 = r ^ n1_ext
    let rx = r ^ ((qx ^ p) & n1x);            // uVar17 updated
    let sx = (p ^ m) & qx;                    // uVar18
    let n1x = (rx & (sx ^ qx ^ p)) ^ n1x;    // uVar16 final
    let sx = sx ^ n2;                          // uVar18 ^= uVar5
    let qx = qx ^ m;                          // uVar22 ^= uVar13

    let u = sx ^ qx;                          // uVar19
    let v = n1x ^ u;                          // uVar5(final) = uVar16 ^ uVar19
    let w = qx ^ rx;                          // uVar20

    // Diffusion outputs
    let o1 = ((v ^ w) & t2) ^ (w & t5);       // uVar10
    let o2 = o1 ^ (u & (ac ^ bx));            // uVar13
    let o3 = o2 ^ (t3 & sx);                  // uVar9

    let o4 = t7 & (rx ^ n1x);                 // uVar12
    let o5 = o4 ^ (n1x & ag);                 // uVar23
    let o6 = ((v ^ w) & (fg_cd ^ t6)) ^ o5;   // uVar21
    let o7 = o6 ^ (w & t6);                   // uVar14

    // Output assignments (encrypted_mem_write_u32):
    s[7] = o3 ^ o7;                            // @0x1c = uVar9 ^ uVar14

    let o8 = (rx ^ n1x) & t1;                 // uVar8
    let o9 = (qx & h) ^ (cd_mix & sx);        // uVar24
    let o6 = o8 ^ o9 ^ (fg_cd & v) ^ o6;     // uVar21 updated
    let o10 = o6 ^ (rx & (a ^ ag));            // uVar1

    s[5] = (ac & v) ^ (w & t5) ^ o7 ^ o10;    // @0x14
    s[6] = o3 ^ o7;                            // @0x18 (same as s[7])

    let o3x = (u & (h ^ cd_mix)) ^ (cd_mix & sx) ^ o5 ^ o3; // uVar9 updated
    s[4] = o3x;                                // @0x10

    s[2] = o2 ^ (qx & (e ^ ag)) ^ o10;        // @0x08

    let o4x = o9 ^ (rx & (h ^ t6)) ^ o4;      // uVar12 updated
    let o11 = o4x ^ o1 ^ (n1x & bx);          // uVar1

    s[1] = o11 ^ o6;                           // @0x04
    s[0] = o11 ^ o8;                           // @0x00
    s[3] = o4x ^ o3x;                          // @0x0c
}
