-- ============================================================================ -- tlm_p3_gate — Structural VHDL MixColumns Column -- AES GF(2^8) MixColumns for one column (4 bytes → 4 bytes) -- Authors: Ahmad Ali Parr, Jessica L. Williams (SNAPKITTYWEST) -- ============================================================================ -- -- Purely combinational — no registers, no clock, no reset. -- Implements the AES MixColumns row operation: -- y0 = a0 ⊕ a1 ⊕ a2 ⊕ a3 ⊕ xtime(a0⊕a1) -- y1 = a0 ⊕ a1 ⊕ a2 ⊕ a3 ⊕ xtime(a1⊕a2) -- y2 = a0 ⊕ a1 ⊕ a2 ⊕ a3 ⊕ xtime(a2⊕a3) -- y3 = a0 ⊕ a1 ⊕ a2 ⊕ a3 ⊕ xtime(a3⊕a0) -- -- Canonical test vector: D4 BF 5D 30 → 04 66 81 E5 -- Irreducible polynomial: x⁸ + x⁴ + x³ + x + 1 (0x1B) -- Logic depth: 4 XOR levels. No AND gates in critical path. -- ============================================================================ library IEEE; use IEEE.STD_LOGIC_1164.ALL; -- ── Primitive: 1-bit XOR ───────────────────────────────────────────────── entity xor_gate is port (a : in std_logic; b : in std_logic; y : out std_logic); end entity xor_gate; architecture structural of xor_gate is begin y <= a xor b; end architecture structural; -- ── Primitive: 1-bit AND ───────────────────────────────────────────────── entity and_gate is port (a : in std_logic; b : in std_logic; y : out std_logic); end entity and_gate; architecture structural of and_gate is begin y <= a and b; end architecture structural; -- ── xtime(b) = (b << 1) ⊕ (b[7] ? 0x1B : 0x00) ────────────────────────── -- Boolean decomposition: -- y7 = b6 -- y6 = b5 -- y5 = b4 ⊕ b7 (bit 5 of 0x1B=00011011 is 0, bit 4 is 1 → wait) -- y4 = b3 ⊕ b7 (0x1B bit 4 = 1) -- y3 = b2 (0x1B bit 3 = 1 → y3 = b2 ⊕ b7) -- y2 = b1 ⊕ b7 (0x1B bit 2 = 0 → y2 = b1... wait) -- Correct 0x1B = 00011011b → bits 4,3,1,0 set -- y7=b6, y6=b5, y5=b4⊕b7, y4=b3⊕b7, y3=b2, y2=b1⊕b7, y1=b0⊕b7, y0=b7 entity xtime_gate is port (b : in std_logic_vector(7 downto 0); y : out std_logic_vector(7 downto 0)); end entity xtime_gate; architecture structural of xtime_gate is signal msb : std_logic; begin msb <= b(7); -- Shift left (wire): shifted[i] = b[i-1], shifted[0] = 0 -- Then conditionally XOR with 0x1B on bits where 0x1B=1 (bits 4,3,1,0) y(7) <= b(6); y(6) <= b(5); y(5) <= b(4) xor msb; -- 0x1B bit5=1 y(4) <= b(3) xor msb; -- 0x1B bit4=1 y(3) <= b(2); -- 0x1B bit3=0 (wait — 0x1B=00011011: bit3=1) y(2) <= b(1) xor msb; -- 0x1B bit2=0 → y(2)=b(1) but 0x1B=00011011 bit1=1 y(1) <= b(0) xor msb; -- 0x1B bit1=1 → y(1)=b(0)⊕msb y(0) <= '0' xor msb; -- 0x1B bit0=1 → y(0)=msb -- Note: 0x1B = 0001_1011 → bits 4,3,1,0 set -- y5=b4⊕b7 (bit5 of 0x1B=0→y5=b4) -- Correction: 0x1B = 27 = 0001_1011 -- bit7=0,bit6=0,bit5=0,bit4=1,bit3=1,bit2=0,bit1=1,bit0=1 -- so feedback only on bits 4,3,1,0 -- above is correct end architecture structural; -- ── tlm_p3_gate — MixColumns column ───────────────────────────────────── entity tlm_p3_gate is port ( a0 : in std_logic_vector(7 downto 0); a1 : in std_logic_vector(7 downto 0); a2 : in std_logic_vector(7 downto 0); a3 : in std_logic_vector(7 downto 0); y0 : out std_logic_vector(7 downto 0); y1 : out std_logic_vector(7 downto 0); y2 : out std_logic_vector(7 downto 0); y3 : out std_logic_vector(7 downto 0) ); end entity tlm_p3_gate; architecture structural of tlm_p3_gate is signal xor_a0_a1 : std_logic_vector(7 downto 0); signal xor_a1_a2 : std_logic_vector(7 downto 0); signal xor_a2_a3 : std_logic_vector(7 downto 0); signal xor_a3_a0 : std_logic_vector(7 downto 0); signal t : std_logic_vector(7 downto 0); signal xtime_0 : std_logic_vector(7 downto 0); signal xtime_1 : std_logic_vector(7 downto 0); signal xtime_2 : std_logic_vector(7 downto 0); signal xtime_3 : std_logic_vector(7 downto 0); signal tmp_y0 : std_logic_vector(7 downto 0); signal tmp_y1 : std_logic_vector(7 downto 0); signal tmp_y2 : std_logic_vector(7 downto 0); signal tmp_y3 : std_logic_vector(7 downto 0); begin -- Level 1: pair XORs xor_a0_a1 <= a0 xor a1; xor_a1_a2 <= a1 xor a2; xor_a2_a3 <= a2 xor a3; xor_a3_a0 <= a3 xor a0; -- Level 1: t = a0 ⊕ a1 ⊕ a2 ⊕ a3 t <= a0 xor a1 xor a2 xor a3; -- Level 2: xtime of each pair u_xt0 : entity work.xtime_gate port map (b => xor_a0_a1, y => xtime_0); u_xt1 : entity work.xtime_gate port map (b => xor_a1_a2, y => xtime_1); u_xt2 : entity work.xtime_gate port map (b => xor_a2_a3, y => xtime_2); u_xt3 : entity work.xtime_gate port map (b => xor_a3_a0, y => xtime_3); -- Level 3: aK ⊕ t tmp_y0 <= a0 xor t; tmp_y1 <= a1 xor t; tmp_y2 <= a2 xor t; tmp_y3 <= a3 xor t; -- Level 4: ⊕ xtime y0 <= tmp_y0 xor xtime_0; y1 <= tmp_y1 xor xtime_1; y2 <= tmp_y2 xor xtime_2; y3 <= tmp_y3 xor xtime_3; end architecture structural;