diff --git a/aes_128/aes_core.sv b/aes_128/aes_core.sv new file mode 100644 index 0000000..211d7fe --- /dev/null +++ b/aes_128/aes_core.sv @@ -0,0 +1,238 @@ +module aes_core ( + input logic clk +, input logic rst_n +// Command +, input logic start +// AES-128 input +, input logic [127:0] plaintext +, input logic [127:0] key +// AES-128 output +, output logic [127:0] ciphertext +// Status +, output logic busy +, output logic done +); + + // FSM states + typedef enum logic [2:0] { + S_IDLE + , S_INIT + , S_ROUND + , S_FINAL + , S_DONE + } aes_state_t; + + aes_state_t fsm_state; + + // Input registers + logic [127:0] plaintext_reg; + logic [127:0] key_reg; + + // AES working registers + logic [127:0] state_reg; + logic [127:0] round_key_reg; + + logic [3:0] round; + + // Combinational datapath signals + logic [127:0] state_next; + logic [127:0] round_key_next; + + logic final_round; + + // Final-round control + // AES round 10 skips MixColumns. + assign final_round = (fsm_state == S_FINAL); + + aes_key_schedule u_aes_key_schedule ( + .key_in (round_key_reg) + , .round (round) + , .key_out (round_key_next) + ); + + + // AES round datapath + // use round_key_next + + aes_round u_aes_round ( + .state_in (state_reg) + , .round_key (round_key_next) + , .final_round (final_round) + , .state_out (state_next) + ); + +// AES controller FSM +// split into separate always_ff blocks for svlint +// FSM state +always_ff @(posedge clk, negedge rst_n) + if (!rst_n) + fsm_state <= S_IDLE; + else + case (fsm_state) + + S_IDLE: + if (start) + fsm_state <= S_INIT; + + S_INIT: + fsm_state <= S_ROUND; + + S_ROUND: + if (round == 4'd9) + fsm_state <= S_FINAL; + + S_FINAL: + fsm_state <= S_DONE; + + S_DONE: + if (start) + fsm_state <= S_INIT; + + default: + fsm_state <= S_IDLE; + + endcase + + +// Input reg +always_ff @(posedge clk, negedge rst_n) + if (!rst_n) + plaintext_reg <= 128'b0; + else if ((fsm_state == S_IDLE || fsm_state == S_DONE) && start) + plaintext_reg <= plaintext; + + +always_ff @(posedge clk, negedge rst_n) + if (!rst_n) + key_reg <= 128'b0; + else if ((fsm_state == S_IDLE || fsm_state == S_DONE) && start) + key_reg <= key; + + + +// AES state reg +always_ff @(posedge clk, negedge rst_n) + if (!rst_n) + state_reg <= 128'b0; + else + case (fsm_state) + + S_INIT: + state_reg <= plaintext_reg ^ key_reg; + + S_ROUND: + state_reg <= state_next; + + S_FINAL: + state_reg <= state_next; + + default: + state_reg <= state_reg; + + endcase + + + +// Round key reg +always_ff @(posedge clk, negedge rst_n) + if (!rst_n) + round_key_reg <= 128'b0; + else + case (fsm_state) + + S_INIT: + round_key_reg <= key_reg; + + S_ROUND: + round_key_reg <= round_key_next; + + S_FINAL: + round_key_reg <= round_key_next; + + default: + round_key_reg <= round_key_reg; + + endcase + + +// Round counter +always_ff @(posedge clk, negedge rst_n) + if (!rst_n) + round <= 4'b0; + else + case (fsm_state) + + S_INIT: + round <= 4'd1; + + S_ROUND: + if (round == 4'd9) + round <= 4'd10; + else + round <= round + 1'b1; + + default: + round <= round; + + endcase + +// Ciphertext reg +always_ff @(posedge clk, negedge rst_n) + if (!rst_n) + ciphertext <= 128'b0; + else if (fsm_state == S_FINAL) + ciphertext <= state_next; + +// Busy +always_ff @(posedge clk, negedge rst_n) + if (!rst_n) + busy <= 1'b0; + else + case (fsm_state) + + S_IDLE: + if (start) + busy <= 1'b1; + else + busy <= 1'b0; + + S_FINAL: + busy <= 1'b0; + + S_DONE: + if (start) + busy <= 1'b1; + else + busy <= 1'b0; + + default: + busy <= busy; + + endcase + + +// Done +always_ff @(posedge clk, negedge rst_n) + if (!rst_n) + done <= 1'b0; + else + case (fsm_state) + + S_IDLE: + done <= 1'b0; + + S_FINAL: + done <= 1'b1; + + S_DONE: + if (start) + done <= 1'b0; + else + done <= 1'b1; + + default: + done <= done; + + endcase + +endmodule diff --git a/aes_128/aes_core_tb.sv b/aes_128/aes_core_tb.sv new file mode 100644 index 0000000..10fcc1d --- /dev/null +++ b/aes_128/aes_core_tb.sv @@ -0,0 +1,199 @@ +module aes_core_tb; + +logic clk; +logic rst_n; + +logic start; +logic [127:0] plaintext; +logic [127:0] key; + +logic [127:0] ciphertext; +logic busy; +logic done; + +aes_core dut ( + .clk (clk) + , .rst_n (rst_n) + + , .start (start) + , .plaintext (plaintext) + , .key (key) + + , .ciphertext (ciphertext) + + , .busy (busy) + , .done (done) +); + +// 10 ns clock period +always #5 clk = ~clk; + +// Logs of every round +/* +always @(posedge clk) begin + + if (dut.fsm_state == dut.S_ROUND) begin + + $display("ROUND %0d", dut.round); + + $display( + "state_in = %032h" + , dut.u_aes_round.state_in + ); + + $display( + "shifted = %032h" + , dut.u_aes_round.shifted_state + ); + + $display( + "mixed = %032h" + , dut.u_aes_round.mixed_state + ); + + $display( + "round_key = %032h" + , dut.round_key_next + ); + + $display( + "state_out = %032h" + , dut.state_next + ); + + end + +end +*/ + +task automatic run_test( + input logic [127:0] test_plaintext + , input logic [127:0] test_key + , input logic [127:0] expected_ciphertext +); + +begin + + // ----------------------------------------- + // Provide new inputs + // ----------------------------------------- + + plaintext = test_plaintext; + key = test_key; + + // ----------------------------------------- + // Issue one-cycle START pulse + // ----------------------------------------- + + @(negedge clk); + start = 1'b1; + + @(negedge clk); + start = 1'b0; + + // ----------------------------------------- + // Make sure this NEW operation has started + // ----------------------------------------- + + wait (busy == 1'b1); + + // ----------------------------------------- + // Wait for this operation to finish + // ----------------------------------------- + + wait (done == 1'b1); + + #1; + + // ----------------------------------------- + // Check output + // ----------------------------------------- + + if (ciphertext === expected_ciphertext) begin + + $display("PASS"); + $display(" plaintext = %032h", test_plaintext); + $display(" key = %032h", test_key); + $display(" ciphertext = %032h", ciphertext); + + end else begin + + $display("FAIL"); + $display(" plaintext = %032h", test_plaintext); + $display(" key = %032h", test_key); + $display(" expected = %032h", expected_ciphertext); + $display(" actual = %032h", ciphertext); + + $fatal; + + end + +end + +endtask + +initial begin + + clk = 1'b0; + rst_n = 1'b0; + start = 1'b0; + + plaintext = 128'b0; + key = 128'b0; + + // ----------------------------------------- + // Reset + // ----------------------------------------- + + repeat (2) + @(posedge clk); + + rst_n = 1'b1; + + // ========================================= + // FIPS 197 Appendix B + // ========================================= + + run_test( + 128'h3243f6a8885a308d313198a2e0370734 + , 128'h2b7e151628aed2a6abf7158809cf4f3c + , 128'h3925841d02dc09fbdc118597196a0b32 + ); + + // ========================================= + // NIST SP 800-38A AES-128 + // ========================================= + + run_test( + 128'h6bc1bee22e409f96e93d7e117393172a + , 128'h2b7e151628aed2a6abf7158809cf4f3c + , 128'h3ad77bb40d7a3660a89ecaf32466ef97 + ); + + run_test( + 128'hae2d8a571e03ac9c9eb76fac45af8e51 + , 128'h2b7e151628aed2a6abf7158809cf4f3c + , 128'hf5d3d58503b9699de785895a96fdbaaf + ); + + run_test( + 128'h30c81c46a35ce411e5fbc1191a0a52ef + , 128'h2b7e151628aed2a6abf7158809cf4f3c + , 128'h43b1cd7f598ece23881b00e3ed030688 + ); + + run_test( + 128'hf69f2445df4f9b17ad2b417be66c3710 + , 128'h2b7e151628aed2a6abf7158809cf4f3c + , 128'h7b0c785e27e8ad3f8223207104725dd4 + ); + + $display("================================="); + $display("ALL AES TESTS PASSED"); + $display("================================="); + + $finish; + +end + +endmodule diff --git a/aes_128/aes_key_schedule.sv b/aes_128/aes_key_schedule.sv new file mode 100644 index 0000000..e6a5767 --- /dev/null +++ b/aes_128/aes_key_schedule.sv @@ -0,0 +1,48 @@ +module aes_key_schedule( +input wire [127:0] key_in +, input wire [3:0] round +, output wire [127:0] key_out +); + wire [31:0] W0 = key_in[127:96]; + wire [31:0] W1 = key_in[95:64]; + wire [31:0] W2 = key_in[63:32]; + wire [31:0] W3 = key_in[31:0]; + + // RotWord: rotate left by 1 byte: [b3 b2 b1 b0] as bytes -> [b2 b1 b0 b3] + wire [31:0] rot = {W3[23:0], W3[31:24]}; + + // SubWord: apply S-box to each byte of rot + wire [7:0] sw0, sw1, sw2, sw3; + aes_sbox s0(.byte_in(rot[7:0]), .byte_out(sw0)); + aes_sbox s1(.byte_in(rot[15:8]), .byte_out(sw1)); + aes_sbox s2(.byte_in(rot[23:16]), .byte_out(sw2)); + aes_sbox s3(.byte_in(rot[31:24]), .byte_out(sw3)); + wire [31:0] sub = {sw3, sw2, sw1, sw0}; + + // Rcon lookup (AES-128 uses 10 values) + reg [7:0] rcon; + always @(*) begin + case (round) + 4'd1: rcon = 8'h01; + 4'd2: rcon = 8'h02; + 4'd3: rcon = 8'h04; + 4'd4: rcon = 8'h08; + 4'd5: rcon = 8'h10; + 4'd6: rcon = 8'h20; + 4'd7: rcon = 8'h40; + 4'd8: rcon = 8'h80; + 4'd9: rcon = 8'h1B; + 4'd10: rcon = 8'h36; + default: rcon = 8'h00; + endcase + end + + wire [31:0] temp = sub ^ {rcon, 24'h0}; + + wire [31:0] W0n = W0 ^ temp; + wire [31:0] W1n = W1 ^ W0n; + wire [31:0] W2n = W2 ^ W1n; + wire [31:0] W3n = W3 ^ W2n; + + assign key_out = {W0n, W1n, W2n, W3n}; +endmodule diff --git a/aes_128/aes_mixcolumns.sv b/aes_128/aes_mixcolumns.sv new file mode 100644 index 0000000..be3ffee --- /dev/null +++ b/aes_128/aes_mixcolumns.sv @@ -0,0 +1,44 @@ +module aes_mixcolumns ( +input wire [127:0] in_state +, output wire [127:0] out_state +); + function automatic [7:0] xtime(input [7:0] a); + begin + xtime = {a[6:0], 1'b0} ^ (8'h1b & {8{a[7]}}); + end + endfunction + + function automatic [31:0] mix_single_column(input [31:0] c); + reg [7:0] a0, a1, a2, a3; + reg [7:0] r0, r1, r2, r3; + begin + // c packs bytes little-endian: [7:0]=b0, [15:8]=b1, ... + a0 = c[31:24]; + a1 = c[23:16]; + a2 = c[15:8]; + a3 = c[7:0]; + + // AES MixColumns matrix: + // [2 3 1 1] [a0] + // [1 2 3 1] [a1] + // [1 1 2 3] [a2] + // [3 1 1 2] [a3] + r0 = xtime(a0) ^ (xtime(a1) ^ a1) ^ a2 ^ a3; + r1 = a0 ^ xtime(a1) ^ (xtime(a2) ^ a2) ^ a3; + r2 = a0 ^ a1 ^ xtime(a2) ^ (xtime(a3) ^ a3); + r3 = (xtime(a0) ^ a0) ^ a1 ^ a2 ^ xtime(a3); + + mix_single_column = {r0, r1, r2, r3}; + end + endfunction + + wire [31:0] c0 = in_state[127:96]; + wire [31:0] c1 = in_state[95:64]; + wire [31:0] c2 = in_state[63:32]; + wire [31:0] c3 = in_state[31:0]; + + assign out_state[127:96] = mix_single_column(c0); + assign out_state[95:64] = mix_single_column(c1); + assign out_state[63:32] = mix_single_column(c2); + assign out_state[31:0] = mix_single_column(c3); +endmodule diff --git a/aes_128/aes_round.sv b/aes_128/aes_round.sv new file mode 100644 index 0000000..c53c0ae --- /dev/null +++ b/aes_128/aes_round.sv @@ -0,0 +1,68 @@ +module aes_round ( + input wire [127:0] state_in +, input wire [127:0] round_key +, input wire final_round +, output wire [127:0] state_out +); + +// Break into bytes +wire [7:0] b [0:15]; + +for (genvar i = 0; i < 16; i = i + 1) begin: l_byte_split + assign b[i] = state_in[127 - i * 8 -: 8]; +end + +// SubBytes +wire [7:0] sb [0:15]; + +for (genvar i = 0; i < 16; i = i + 1) begin: l_subbytes + aes_sbox u_sbox ( + .byte_in (b[i]) + , .byte_out(sb[i]) + ); +end + +// ShiftRows +wire [7:0] sh [0:15]; + +assign sh[0] = sb[0]; +assign sh[1] = sb[5]; +assign sh[2] = sb[10]; +assign sh[3] = sb[15]; + +assign sh[4] = sb[4]; +assign sh[5] = sb[9]; +assign sh[6] = sb[14]; +assign sh[7] = sb[3]; + +assign sh[8] = sb[8]; +assign sh[9] = sb[13]; +assign sh[10] = sb[2]; +assign sh[11] = sb[7]; + +assign sh[12] = sb[12]; +assign sh[13] = sb[1]; +assign sh[14] = sb[6]; +assign sh[15] = sb[11]; + +// Pack shifted bytes back to 128-bit +wire [127:0] shifted_state; + +for (genvar i = 0; i < 16; i = i + 1) begin: l_pack_shift + assign shifted_state[127 - i * 8 -: 8] = sh[i]; +end + +// MixColumns +wire [127:0] mixed_state; + +aes_mixcolumns u_mix ( + .in_state (shifted_state) + , .out_state(mixed_state) +); + +wire [127:0] pre_xor = final_round ? shifted_state : mixed_state; + +// AddRoundKey +assign state_out = pre_xor ^ round_key; + +endmodule diff --git a/aes_128/aes_sbox.sv b/aes_128/aes_sbox.sv new file mode 100644 index 0000000..35c2f37 --- /dev/null +++ b/aes_128/aes_sbox.sv @@ -0,0 +1,157 @@ +module aes_sbox( +input wire [7:0] byte_in +, output reg [7:0] byte_out +); + +always @(*) begin + case (byte_in) + + 8'h00: byte_out = 8'h63; 8'h01: byte_out = 8'h7c; + 8'h02: byte_out = 8'h77; 8'h03: byte_out = 8'h7b; + 8'h04: byte_out = 8'hf2; 8'h05: byte_out = 8'h6b; + 8'h06: byte_out = 8'h6f; 8'h07: byte_out = 8'hc5; + 8'h08: byte_out = 8'h30; 8'h09: byte_out = 8'h01; + 8'h0a: byte_out = 8'h67; 8'h0b: byte_out = 8'h2b; + 8'h0c: byte_out = 8'hfe; 8'h0d: byte_out = 8'hd7; + 8'h0e: byte_out = 8'hab; 8'h0f: byte_out = 8'h76; + + 8'h10: byte_out = 8'hca; 8'h11: byte_out = 8'h82; + 8'h12: byte_out = 8'hc9; 8'h13: byte_out = 8'h7d; + 8'h14: byte_out = 8'hfa; 8'h15: byte_out = 8'h59; + 8'h16: byte_out = 8'h47; 8'h17: byte_out = 8'hf0; + 8'h18: byte_out = 8'had; 8'h19: byte_out = 8'hd4; + 8'h1a: byte_out = 8'ha2; 8'h1b: byte_out = 8'haf; + 8'h1c: byte_out = 8'h9c; 8'h1d: byte_out = 8'ha4; + 8'h1e: byte_out = 8'h72; 8'h1f: byte_out = 8'hc0; + + 8'h20: byte_out = 8'hb7; 8'h21: byte_out = 8'hfd; + 8'h22: byte_out = 8'h93; 8'h23: byte_out = 8'h26; + 8'h24: byte_out = 8'h36; 8'h25: byte_out = 8'h3f; + 8'h26: byte_out = 8'hf7; 8'h27: byte_out = 8'hcc; + 8'h28: byte_out = 8'h34; 8'h29: byte_out = 8'ha5; + 8'h2a: byte_out = 8'he5; 8'h2b: byte_out = 8'hf1; + 8'h2c: byte_out = 8'h71; 8'h2d: byte_out = 8'hd8; + 8'h2e: byte_out = 8'h31; 8'h2f: byte_out = 8'h15; + + 8'h30: byte_out = 8'h04; 8'h31: byte_out = 8'hc7; + 8'h32: byte_out = 8'h23; 8'h33: byte_out = 8'hc3; + 8'h34: byte_out = 8'h18; 8'h35: byte_out = 8'h96; + 8'h36: byte_out = 8'h05; 8'h37: byte_out = 8'h9a; + 8'h38: byte_out = 8'h07; 8'h39: byte_out = 8'h12; + 8'h3a: byte_out = 8'h80; 8'h3b: byte_out = 8'he2; + 8'h3c: byte_out = 8'heb; 8'h3d: byte_out = 8'h27; + 8'h3e: byte_out = 8'hb2; 8'h3f: byte_out = 8'h75; + + 8'h40: byte_out = 8'h09; 8'h41: byte_out = 8'h83; + 8'h42: byte_out = 8'h2c; 8'h43: byte_out = 8'h1a; + 8'h44: byte_out = 8'h1b; 8'h45: byte_out = 8'h6e; + 8'h46: byte_out = 8'h5a; 8'h47: byte_out = 8'ha0; + 8'h48: byte_out = 8'h52; 8'h49: byte_out = 8'h3b; + 8'h4a: byte_out = 8'hd6; 8'h4b: byte_out = 8'hb3; + 8'h4c: byte_out = 8'h29; 8'h4d: byte_out = 8'he3; + 8'h4e: byte_out = 8'h2f; 8'h4f: byte_out = 8'h84; + + 8'h50: byte_out = 8'h53; 8'h51: byte_out = 8'hd1; + 8'h52: byte_out = 8'h00; 8'h53: byte_out = 8'hed; + 8'h54: byte_out = 8'h20; 8'h55: byte_out = 8'hfc; + 8'h56: byte_out = 8'hb1; 8'h57: byte_out = 8'h5b; + 8'h58: byte_out = 8'h6a; 8'h59: byte_out = 8'hcb; + 8'h5a: byte_out = 8'hbe; 8'h5b: byte_out = 8'h39; + 8'h5c: byte_out = 8'h4a; 8'h5d: byte_out = 8'h4c; + 8'h5e: byte_out = 8'h58; 8'h5f: byte_out = 8'hcf; + + 8'h60: byte_out = 8'hd0; 8'h61: byte_out = 8'hef; + 8'h62: byte_out = 8'haa; 8'h63: byte_out = 8'hfb; + 8'h64: byte_out = 8'h43; 8'h65: byte_out = 8'h4d; + 8'h66: byte_out = 8'h33; 8'h67: byte_out = 8'h85; + 8'h68: byte_out = 8'h45; 8'h69: byte_out = 8'hf9; + 8'h6a: byte_out = 8'h02; 8'h6b: byte_out = 8'h7f; + 8'h6c: byte_out = 8'h50; 8'h6d: byte_out = 8'h3c; + 8'h6e: byte_out = 8'h9f; 8'h6f: byte_out = 8'ha8; + + 8'h70: byte_out = 8'h51; 8'h71: byte_out = 8'ha3; + 8'h72: byte_out = 8'h40; 8'h73: byte_out = 8'h8f; + 8'h74: byte_out = 8'h92; 8'h75: byte_out = 8'h9d; + 8'h76: byte_out = 8'h38; 8'h77: byte_out = 8'hf5; + 8'h78: byte_out = 8'hbc; 8'h79: byte_out = 8'hb6; + 8'h7a: byte_out = 8'hda; 8'h7b: byte_out = 8'h21; + 8'h7c: byte_out = 8'h10; 8'h7d: byte_out = 8'hff; + 8'h7e: byte_out = 8'hf3; 8'h7f: byte_out = 8'hd2; + + 8'h80: byte_out = 8'hcd; 8'h81: byte_out = 8'h0c; + 8'h82: byte_out = 8'h13; 8'h83: byte_out = 8'hec; + 8'h84: byte_out = 8'h5f; 8'h85: byte_out = 8'h97; + 8'h86: byte_out = 8'h44; 8'h87: byte_out = 8'h17; + 8'h88: byte_out = 8'hc4; 8'h89: byte_out = 8'ha7; + 8'h8a: byte_out = 8'h7e; 8'h8b: byte_out = 8'h3d; + 8'h8c: byte_out = 8'h64; 8'h8d: byte_out = 8'h5d; + 8'h8e: byte_out = 8'h19; 8'h8f: byte_out = 8'h73; + + 8'h90: byte_out = 8'h60; 8'h91: byte_out = 8'h81; + 8'h92: byte_out = 8'h4f; 8'h93: byte_out = 8'hdc; + 8'h94: byte_out = 8'h22; 8'h95: byte_out = 8'h2a; + 8'h96: byte_out = 8'h90; 8'h97: byte_out = 8'h88; + 8'h98: byte_out = 8'h46; 8'h99: byte_out = 8'hee; + 8'h9a: byte_out = 8'hb8; 8'h9b: byte_out = 8'h14; + 8'h9c: byte_out = 8'hde; 8'h9d: byte_out = 8'h5e; + 8'h9e: byte_out = 8'h0b; 8'h9f: byte_out = 8'hdb; + + 8'ha0: byte_out = 8'he0; 8'ha1: byte_out = 8'h32; + 8'ha2: byte_out = 8'h3a; 8'ha3: byte_out = 8'h0a; + 8'ha4: byte_out = 8'h49; 8'ha5: byte_out = 8'h06; + 8'ha6: byte_out = 8'h24; 8'ha7: byte_out = 8'h5c; + 8'ha8: byte_out = 8'hc2; 8'ha9: byte_out = 8'hd3; + 8'haa: byte_out = 8'hac; 8'hab: byte_out = 8'h62; + 8'hac: byte_out = 8'h91; 8'had: byte_out = 8'h95; + 8'hae: byte_out = 8'he4; 8'haf: byte_out = 8'h79; + + 8'hb0: byte_out = 8'he7; 8'hb1: byte_out = 8'hc8; + 8'hb2: byte_out = 8'h37; 8'hb3: byte_out = 8'h6d; + 8'hb4: byte_out = 8'h8d; 8'hb5: byte_out = 8'hd5; + 8'hb6: byte_out = 8'h4e; 8'hb7: byte_out = 8'ha9; + 8'hb8: byte_out = 8'h6c; 8'hb9: byte_out = 8'h56; + 8'hba: byte_out = 8'hf4; 8'hbb: byte_out = 8'hea; + 8'hbc: byte_out = 8'h65; 8'hbd: byte_out = 8'h7a; + 8'hbe: byte_out = 8'hae; 8'hbf: byte_out = 8'h08; + + 8'hc0: byte_out = 8'hba; 8'hc1: byte_out = 8'h78; + 8'hc2: byte_out = 8'h25; 8'hc3: byte_out = 8'h2e; + 8'hc4: byte_out = 8'h1c; 8'hc5: byte_out = 8'ha6; + 8'hc6: byte_out = 8'hb4; 8'hc7: byte_out = 8'hc6; + 8'hc8: byte_out = 8'he8; 8'hc9: byte_out = 8'hdd; + 8'hca: byte_out = 8'h74; 8'hcb: byte_out = 8'h1f; + 8'hcc: byte_out = 8'h4b; 8'hcd: byte_out = 8'hbd; + 8'hce: byte_out = 8'h8b; 8'hcf: byte_out = 8'h8a; + + 8'hd0: byte_out = 8'h70; 8'hd1: byte_out = 8'h3e; + 8'hd2: byte_out = 8'hb5; 8'hd3: byte_out = 8'h66; + 8'hd4: byte_out = 8'h48; 8'hd5: byte_out = 8'h03; + 8'hd6: byte_out = 8'hf6; 8'hd7: byte_out = 8'h0e; + 8'hd8: byte_out = 8'h61; 8'hd9: byte_out = 8'h35; + 8'hda: byte_out = 8'h57; 8'hdb: byte_out = 8'hb9; + 8'hdc: byte_out = 8'h86; 8'hdd: byte_out = 8'hc1; + 8'hde: byte_out = 8'h1d; 8'hdf: byte_out = 8'h9e; + + 8'he0: byte_out = 8'he1; 8'he1: byte_out = 8'hf8; + 8'he2: byte_out = 8'h98; 8'he3: byte_out = 8'h11; + 8'he4: byte_out = 8'h69; 8'he5: byte_out = 8'hd9; + 8'he6: byte_out = 8'h8e; 8'he7: byte_out = 8'h94; + 8'he8: byte_out = 8'h9b; 8'he9: byte_out = 8'h1e; + 8'hea: byte_out = 8'h87; 8'heb: byte_out = 8'he9; + 8'hec: byte_out = 8'hce; 8'hed: byte_out = 8'h55; + 8'hee: byte_out = 8'h28; 8'hef: byte_out = 8'hdf; + + 8'hf0: byte_out = 8'h8c; 8'hf1: byte_out = 8'ha1; + 8'hf2: byte_out = 8'h89; 8'hf3: byte_out = 8'h0d; + 8'hf4: byte_out = 8'hbf; 8'hf5: byte_out = 8'he6; + 8'hf6: byte_out = 8'h42; 8'hf7: byte_out = 8'h68; + 8'hf8: byte_out = 8'h41; 8'hf9: byte_out = 8'h99; + 8'hfa: byte_out = 8'h2d; 8'hfb: byte_out = 8'h0f; + 8'hfc: byte_out = 8'hb0; 8'hfd: byte_out = 8'h54; + 8'hfe: byte_out = 8'hbb; 8'hff: byte_out = 8'h16; + + default: byte_out = 8'h00; + endcase +end + +endmodule