| // 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::*; |
| |
| /////////////////////////// |
| // Functions & Constants // |
| /////////////////////////// |
| |
| // Multiplication in GF(2^2), using normal basis [Omega^2, Omega] |
| // (see Figure 14 in the technical report) |
| function automatic logic [1:0] aes_mul_gf2p2(logic [1:0] g, logic [1:0] d); |
| logic [1:0] f; |
| logic a, b, c; |
| a = g[1] & d[1]; |
| b = (^g) & (^d); |
| c = g[0] & d[0]; |
| f[1] = a ^ b; |
| f[0] = c ^ b; |
| return f; |
| endfunction |
| |
| // Scale by Omega^2 = N in GF(2^2), using normal basis [Omega^2, Omega] |
| // (see Figure 16 in the technical report) |
| function automatic logic [1:0] aes_scale_omega2_gf2p2(logic [1:0] g); |
| logic [1:0] d; |
| d[1] = g[0]; |
| d[0] = g[1] ^ g[0]; |
| return d; |
| endfunction |
| |
| // Scale by Omega = N^2 in GF(2^2), using normal basis [Omega^2, Omega] |
| // (see Figure 15 in the technical report) |
| function automatic logic [1:0] aes_scale_omega_gf2p2(logic [1:0] g); |
| logic [1:0] d; |
| d[1] = g[1] ^ g[0]; |
| d[0] = g[1]; |
| return d; |
| endfunction |
| |
| // Square in GF(2^2), using normal basis [Omega^2, Omega] |
| // (see Figures 8 and 10 in the technical report) |
| function automatic logic [1:0] aes_square_gf2p2(logic [1:0] g); |
| logic [1:0] d; |
| d[1] = g[0]; |
| d[0] = g[1]; |
| return d; |
| endfunction |
| |
| // Multiplication in GF(2^4), using normal basis [alpha^8, alpha^2] |
| // (see Figure 13 in the technical report) |
| function automatic logic [3:0] aes_mul_gf2p4(logic [3:0] gamma, logic [3:0] delta); |
| logic [3:0] theta; |
| logic [1:0] a, b, c; |
| a = aes_mul_gf2p2(gamma[3:2], delta[3:2]); |
| b = aes_mul_gf2p2(gamma[3:2] ^ gamma[1:0], delta[3:2] ^ delta[1:0]); |
| c = aes_mul_gf2p2(gamma[1:0], delta[1:0]); |
| theta[3:2] = a ^ aes_scale_omega2_gf2p2(b); |
| theta[1:0] = c ^ aes_scale_omega2_gf2p2(b); |
| return theta; |
| endfunction |
| |
| // Square and scale by nu in GF(2^4)/GF(2^2), using normal basis [alpha^8, alpha^2] |
| // (see Figure 19 as well as Appendix A of the technical report) |
| function automatic logic [3:0] aes_square_scale_gf2p4_gf2p2(logic [3:0] gamma); |
| logic [3:0] delta; |
| logic [1:0] a, b; |
| a = gamma[3:2] ^ gamma[1:0]; |
| b = aes_square_gf2p2(gamma[1:0]); |
| delta[3:2] = aes_square_gf2p2(a); |
| delta[1:0] = aes_scale_omega_gf2p2(b); |
| return delta; |
| endfunction |
| |
| // 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 |
| |
| // Basis conversion matrices to convert between polynomial basis A, normal basis X |
| // and basis S incorporating the bit matrix of the SBox. More specifically, |
| // multiplication by x2s performs the transformation from normal basis X into |
| // polynomial basis A, followed by the affine transformation (substep 2). Likewise, |
| // multiplication by s2x performs the inverse affine transformation followed by the |
| // transformation from polynomial basis A to normal basis X. |
| // (see Appendix A of the technical report) |
| const logic [7:0] a2x [8] = '{8'h98, 8'hf3, 8'hf2, 8'h48, 8'h09, 8'h81, 8'ha9, 8'hff}; |
| const logic [7:0] x2a [8] = '{8'h64, 8'h78, 8'h6e, 8'h8c, 8'h68, 8'h29, 8'hde, 8'h60}; |
| const logic [7:0] x2s [8] = '{8'h58, 8'h2d, 8'h9e, 8'h0b, 8'hdc, 8'h04, 8'h03, 8'h24}; |
| const logic [7:0] s2x [8] = '{8'h8c, 8'h79, 8'h05, 8'heb, 8'h12, 8'h04, 8'h51, 8'h53}; |
| |
| /////////////////// |
| // 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 |