| // Copyright lowRISC contributors. | 
 | // Licensed under the Apache License, Version 2.0, see LICENSE for details. | 
 | // SPDX-License-Identifier: Apache-2.0 | 
 | // | 
 | // AES MixColumns for one single column of the state matrix | 
 | // | 
 | // For details, see Equations 4-7 of: | 
 | // Satoh et al., "A Compact Rijndael Hardware Architecture with S-Box Optimization" | 
 |  | 
 | module aes_mix_single_column ( | 
 |   input  aes_pkg::ciph_op_e op_i, | 
 |   input  logic [3:0][7:0]   data_i, | 
 |   output logic [3:0][7:0]   data_o | 
 | ); | 
 |  | 
 |   import aes_pkg::*; | 
 |  | 
 |   logic [3:0][7:0] x; | 
 |   logic [1:0][7:0] y; | 
 |   logic [1:0][7:0] z; | 
 |  | 
 |   logic [3:0][7:0] x_mul2; | 
 |   logic [1:0][7:0] y_pre_mul4; | 
 |   logic      [7:0] y2, y2_pre_mul2; | 
 |  | 
 |   logic [1:0][7:0] z_muxed; | 
 |  | 
 |   // Drive x | 
 |   assign x[0] = data_i[0] ^ data_i[3]; | 
 |   assign x[1] = data_i[3] ^ data_i[2]; | 
 |   assign x[2] = data_i[2] ^ data_i[1]; | 
 |   assign x[3] = data_i[1] ^ data_i[0]; | 
 |  | 
 |   // Mul2(x) | 
 |   for (genvar i = 0; i < 4; i++) begin : gen_x_mul2 | 
 |     assign x_mul2[i] = aes_mul2(x[i]); | 
 |   end | 
 |  | 
 |   // Drive y_pre_mul4 | 
 |   assign y_pre_mul4[0] = data_i[3] ^ data_i[1]; | 
 |   assign y_pre_mul4[1] = data_i[2] ^ data_i[0]; | 
 |  | 
 |   // Mul4(y_pre_mul4) | 
 |   for (genvar i = 0; i < 2; i++) begin : gen_mul4 | 
 |     assign y[i] = aes_mul4(y_pre_mul4[i]); | 
 |   end | 
 |  | 
 |   // Drive y2_pre_mul2 | 
 |   assign y2_pre_mul2 = y[0] ^ y[1]; | 
 |  | 
 |   // Mul2(y) | 
 |   assign y2 = aes_mul2(y2_pre_mul2); | 
 |  | 
 |   // Drive z | 
 |   assign z[0] = y2 ^ y[0]; | 
 |   assign z[1] = y2 ^ y[1]; | 
 |  | 
 |   // Mux z | 
 |   assign z_muxed[0] = (op_i == CIPH_FWD) ? 8'b0 : | 
 |                       (op_i == CIPH_INV) ? z[0] : 8'b0; | 
 |   assign z_muxed[1] = (op_i == CIPH_FWD) ? 8'b0 : | 
 |                       (op_i == CIPH_INV) ? z[1] : 8'b0; | 
 |  | 
 |   // Drive outputs | 
 |   assign data_o[0] = data_i[1] ^ x_mul2[3] ^ x[1] ^ z_muxed[1]; | 
 |   assign data_o[1] = data_i[0] ^ x_mul2[2] ^ x[1] ^ z_muxed[0]; | 
 |   assign data_o[2] = data_i[3] ^ x_mul2[1] ^ x[3] ^ z_muxed[1]; | 
 |   assign data_o[3] = data_i[2] ^ x_mul2[0] ^ x[3] ^ z_muxed[0]; | 
 |  | 
 | endmodule |