../src/lowrisc_ip_aes_0.6/rtl/aes_sbox_canright_masked.sv Cov: 100%

   1: // Copyright lowRISC contributors.
   2: // Licensed under the Apache License, Version 2.0, see LICENSE for details.
   3: // SPDX-License-Identifier: Apache-2.0
   4: //
   5: // AES Masked Canright SBox with Mask Re-Use
   6: //
   7: // For details, see the following paper:
   8: // Canright, "A very compact 'perfectly masked' S-box for AES (corrected)"
   9: // available at https://eprint.iacr.org/2009/011.pdf
  10: //
  11: // Note: This module implements the masked inversion algorithm with re-using masks.
  12: // For details, see Section 2.3 of the paper. Re-using masks may make the implementation more
  13: // vulnerable to higher-order differential side-channel analysis, but it remains secure against
  14: // first-order attacks. This implementation is commonly referred to as THE Canright Masked SBox.
  15: 
  16: ///////////////////////////////////////////////////////////////////////////////////////////////////
  17: // IMPORTANT NOTE:                                                                               //
  18: //                            DO NOT USE THIS FOR SYNTHESIS BLINDLY!                             //
  19: //                                                                                               //
  20: // This is a high-level implementation targeting primarily RTL simulation. Synthesis tools might //
  21: // heavily optimize the design. The result is likely insecure. Use with care.                    //
  22: ///////////////////////////////////////////////////////////////////////////////////////////////////
  23: 
  24: module aes_sbox_canright_masked (
  25:   input  aes_pkg::ciph_op_e op_i,
  26:   input  logic [7:0]        data_i,     // masked, the actual input data is data_i ^ in_mask_i
  27:   input  logic [7:0]        in_mask_i,  // input mask, independent from actual input data
  28:   input  logic [7:0]        out_mask_i, // output mask, independent from input mask
  29:   output logic [7:0]        data_o      // masked, the actual output data is data_o ^ out_mask_i
  30: );
  31: 
  32:   import aes_pkg::*;
  33:   import aes_sbox_canright_pkg::*;
  34: 
  35:   ///////////////
  36:   // Functions //
  37:   ///////////////
  38: 
  39:   // Masked inverse in GF(2^4), using normal basis [z^4, z]
  40:   // (see Formulas 6, 13, 14, 15, 21, 22, 23, 24 in the paper)
  41:   function automatic logic [3:0] aes_masked_inverse_gf2p4(logic [3:0] b,
  42:                                                           logic [3:0] q,
  43:                                                           logic [1:0] r,
  44:                                                           logic [3:0] m1);
  45:     logic [3:0] b_inv;
  46:     logic [1:0] b1, b0, q1, q0, c, c_inv, c2_inv, r_sq, m11, m10, b1_inv, b0_inv;
  47:     logic [1:0] mul_b0_q1, mul_b1_q0, mul_q0_q1;
  48:     b1  = b[3:2];
  49:     b0  = b[1:0];
  50:     q1  = q[3:2];
  51:     q0  = q[1:0];
  52:     m11 = m1[3:2];
  53:     m10 = m1[1:0];
  54: 
  55:     // Get re-usable intermediate results.
  56:     mul_b0_q1 = aes_mul_gf2p2(b0, q1);
  57:     mul_b1_q0 = aes_mul_gf2p2(b1, q0);
  58:     mul_q0_q1 = aes_mul_gf2p2(q0, q1);
  59: 
  60:     // Formula 13
  61:     // IMPORTANT: The following ops must be executed in order (left to right):
  62:     c = r ^ aes_scale_omega2_gf2p2(aes_square_gf2p2(b1 ^ b0))
  63:           ^ aes_scale_omega2_gf2p2(aes_square_gf2p2(q1 ^ q0))
  64:           ^ aes_mul_gf2p2(b1, b0)
  65:           ^ aes_mul_gf2p2(b1, q0) ^ mul_b0_q1 ^ mul_q0_q1;
  66:     //
  67: 
  68:     // Formulas 14 and 15
  69:     c_inv = aes_square_gf2p2(c);
  70:     r_sq  = aes_square_gf2p2(r);
  71: 
  72:     // Re-masking c_inv
  73:     // Formulas 21 and 23
  74:     // IMPORTANT: First combine the masks (ops in parens) then apply to c_inv:
  75:     c_inv  = c_inv ^ (q1 ^ r_sq);
  76:     c2_inv = c_inv ^ (q0 ^ q1);
  77:     //
  78: 
  79:     // Formulas 22 and 24
  80:     // IMPORTANT: The following ops must be executed in order (left to right):
  81:     b1_inv = m11 ^ aes_mul_gf2p2(b0, c_inv)
  82:                  ^ mul_b0_q1 ^ aes_mul_gf2p2(q0, c_inv)  ^ mul_q0_q1;
  83:     b0_inv = m10 ^ aes_mul_gf2p2(b1, c2_inv)
  84:                  ^ mul_b1_q0 ^ aes_mul_gf2p2(q1, c2_inv) ^ mul_q0_q1;
  85:     //
  86: 
  87:     // Note: b_inv is masked by m1, b was masked by q.
  88:     b_inv = {b1_inv, b0_inv};
  89: 
  90:     return b_inv;
  91:   endfunction
  92: 
  93:   // Masked inverse in GF(2^8), using normal basis [y^16, y]
  94:   // (see Formulas 3, 12, 25, 26 and 27 in the paper)
  95:   function automatic logic [7:0] aes_masked_inverse_gf2p8(logic [7:0] a,
  96:                                                           logic [7:0] m,
  97:                                                           logic [7:0] n);
  98:     logic [7:0] a_inv;
  99:     logic [3:0] a1, a0, m1, m0, b, b_inv, b2_inv, q, s1, s0, a1_inv, a0_inv;
 100:     logic [3:0] mul_a0_m1, mul_a1_m0, mul_m0_m1;
 101:     logic [1:0] r;
 102:     a1 = a[7:4];
 103:     a0 = a[3:0];
 104:     m1 = m[7:4];
 105:     m0 = m[3:0];
 106: 
 107:     // Get re-usable intermediate results.
 108:     mul_a0_m1 = aes_mul_gf2p4(a0, m1);
 109:     mul_a1_m0 = aes_mul_gf2p4(a1, m0);
 110:     mul_m0_m1 = aes_mul_gf2p4(m0, m1);
 111: 
 112:     // q must be independent of m.
 113:     q = n[7:4];
 114: 
 115:     // Formula 12
 116:     // IMPORTANT: The following ops must be executed in order (left to right):
 117:     b = q ^ aes_square_scale_gf2p4_gf2p2(a1 ^ a0)
 118:           ^ aes_square_scale_gf2p4_gf2p2(m1 ^ m0)
 119:           ^ aes_mul_gf2p4(a1, a0)
 120:           ^ mul_a1_m0 ^ mul_a0_m1 ^ mul_m0_m1;
 121:     //
 122: 
 123:     // r must be independent of q.
 124:     r = m1[3:2];
 125: 
 126:     // b is masked by q, b_inv is masked by m1.
 127:     b_inv = aes_masked_inverse_gf2p4(b, q, r, m1);
 128: 
 129:     // Formula 26
 130:     // IMPORTANT: First combine the masks (ops in parens) then apply to b_inv:
 131:     b2_inv = b_inv ^ (m1 ^ m0);
 132:     //
 133: 
 134:     // s is the specified output mask n.
 135:     s1 = n[7:4];
 136:     s0 = n[3:0];
 137: 
 138:     // Formulas 25 and 27
 139:     // IMPORTANT: The following ops must be executed in order (left to right):
 140:     a1_inv = s1 ^ aes_mul_gf2p4(a0, b_inv)
 141:                 ^ mul_a0_m1 ^ aes_mul_gf2p4(m0, b_inv)  ^ mul_m0_m1;
 142:     a0_inv = s0 ^ aes_mul_gf2p4(a1, b2_inv)
 143:                 ^ mul_a1_m0 ^ aes_mul_gf2p4(m1, b2_inv) ^ mul_m0_m1;
 144:     //
 145: 
 146:     // Note: a_inv is now masked by s = n, a was masked by m.
 147:     a_inv = {a1_inv, a0_inv};
 148: 
 149:     return a_inv;
 150:   endfunction
 151: 
 152:   //////////////////////////
 153:   // Masked Canright SBox //
 154:   //////////////////////////
 155: 
 156:   logic [7:0] data_basis_x, data_inverse;
 157:   logic [7:0] in_mask_basis_x;
 158:   logic [7:0] out_mask_basis_x;
 159: 
 160:   // Convert data to normal basis X.
 161:   assign data_basis_x = (op_i == CIPH_FWD) ? aes_mvm(data_i, A2X) :
 162:                                              aes_mvm(data_i ^ 8'h63, S2X);
 163: 
 164:   // Convert masks to normal basis X.
 165:   // The addition of constant 8'h63 following the affine transformation is skipped.
 166:   assign in_mask_basis_x  = (op_i == CIPH_FWD) ? aes_mvm(in_mask_i, A2X) :
 167:                                                  aes_mvm(in_mask_i, S2X);
 168: 
 169:   // The output mask is converted in the opposite direction.
 170:   assign out_mask_basis_x = (op_i == CIPH_INV) ? aes_mvm(out_mask_i, A2X) :
 171:                                                  aes_mvm(out_mask_i, S2X);
 172: 
 173:   // Do the inversion in normal basis X.
 174:   assign data_inverse = aes_masked_inverse_gf2p8(data_basis_x, in_mask_basis_x, out_mask_basis_x);
 175: 
 176:   // Convert to basis S or A.
 177:   assign data_o = (op_i == CIPH_FWD) ? (aes_mvm(data_inverse, X2S) ^ 8'h63) :
 178:                                        (aes_mvm(data_inverse, X2A));
 179: 
 180: endmodule
 181: