../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: