| // Copyright lowRISC contributors. | 
 | // Licensed under the Apache License, Version 2.0, see LICENSE for details. | 
 | // SPDX-License-Identifier: Apache-2.0 | 
 | // | 
 | // AES Canright SBox #4 | 
 | // | 
 | // For details, see the technical report: Canright, "A very compact Rijndael S-box" | 
 | // available at https://hdl.handle.net/10945/25608 | 
 |  | 
 | module aes_sbox_canright ( | 
 |   input  aes_pkg::ciph_op_e op_i, | 
 |   input  logic [7:0]        data_i, | 
 |   output logic [7:0]        data_o | 
 | ); | 
 |  | 
 |   import aes_pkg::*; | 
 |   import aes_sbox_canright_pkg::*; | 
 |  | 
 |   /////////////// | 
 |   // Functions // | 
 |   /////////////// | 
 |  | 
 |   // Inverse in GF(2^4), using normal basis [alpha^8, alpha^2] | 
 |   // (see Figure 12 in the technical report) | 
 |   function automatic logic [3:0] aes_inverse_gf2p4(logic [3:0] gamma); | 
 |     logic [3:0] delta; | 
 |     logic [1:0] a, b, c, d; | 
 |     a          = gamma[3:2] ^ gamma[1:0]; | 
 |     b          = aes_mul_gf2p2(gamma[3:2], gamma[1:0]); | 
 |     c          = aes_scale_omega2_gf2p2(aes_square_gf2p2(a)); | 
 |     d          = aes_square_gf2p2(c ^ b); | 
 |     delta[3:2] = aes_mul_gf2p2(d, gamma[1:0]); | 
 |     delta[1:0] = aes_mul_gf2p2(d, gamma[3:2]); | 
 |     return delta; | 
 |   endfunction | 
 |  | 
 |   // Inverse in GF(2^8), using normal basis [d^16, d] | 
 |   // (see Figure 11 in the technical report) | 
 |   function automatic logic [7:0] aes_inverse_gf2p8(logic [7:0] gamma); | 
 |     logic [7:0] delta; | 
 |     logic [3:0] a, b, c, d; | 
 |     a          = gamma[7:4] ^ gamma[3:0]; | 
 |     b          = aes_mul_gf2p4(gamma[7:4], gamma[3:0]); | 
 |     c          = aes_square_scale_gf2p4_gf2p2(a); | 
 |     d          = aes_inverse_gf2p4(c ^ b); | 
 |     delta[7:4] = aes_mul_gf2p4(d, gamma[3:0]); | 
 |     delta[3:0] = aes_mul_gf2p4(d, gamma[7:4]); | 
 |     return delta; | 
 |   endfunction | 
 |  | 
 |   /////////////////// | 
 |   // Canright SBox // | 
 |   /////////////////// | 
 |  | 
 |   logic [7:0] data_basis_x, data_inverse; | 
 |  | 
 |   // Convert to normal basis X. | 
 |   assign data_basis_x = (op_i == CIPH_FWD) ? aes_mvm(data_i, A2X) : | 
 |                                              aes_mvm(data_i ^ 8'h63, S2X); | 
 |  | 
 |   // Do the inversion in normal basis X. | 
 |   assign data_inverse = aes_inverse_gf2p8(data_basis_x); | 
 |  | 
 |   // Convert to basis S or A. | 
 |   assign data_o       = (op_i == CIPH_FWD) ? aes_mvm(data_inverse, X2S) ^ 8'h63 : | 
 |                                              aes_mvm(data_inverse, X2A); | 
 |  | 
 | endmodule |