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: // This package holds common constants and functions for PRESENT- and
6: // PRINCE-based scrambling devices.
7: //
8: // See also: prim_present, prim_prince
9: //
10: // References: - https://en.wikipedia.org/wiki/PRESENT
11: // - https://en.wikipedia.org/wiki/Prince_(cipher)
12: // - http://www.lightweightcrypto.org/present/present_ches2007.pdf
13: // - https://eprint.iacr.org/2012/529.pdf
14: // - https://eprint.iacr.org/2015/372.pdf
15: // - https://eprint.iacr.org/2014/656.pdf
16:
17: package prim_cipher_pkg;
18:
19: ///////////////////
20: // PRINCE Cipher //
21: ///////////////////
22:
23: parameter logic [15:0][3:0] PRINCE_SBOX4 = {4'h4, 4'hD, 4'h5, 4'hE,
24: 4'h0, 4'h8, 4'h7, 4'h6,
25: 4'h1, 4'h9, 4'hC, 4'hA,
26: 4'h2, 4'h3, 4'hF, 4'hB};
27:
28: parameter logic [15:0][3:0] PRINCE_SBOX4_INV = {4'h1, 4'hC, 4'hE, 4'h5,
29: 4'h0, 4'h4, 4'h6, 4'hA,
30: 4'h9, 4'h8, 4'hD, 4'hF,
31: 4'h2, 4'h3, 4'h7, 4'hB};
32: // nibble permutations
33: parameter logic [15:0][3:0] PRINCE_SHIFT_ROWS64 = '{4'hB, 4'h6, 4'h1, 4'hC,
34: 4'h7, 4'h2, 4'hD, 4'h8,
35: 4'h3, 4'hE, 4'h9, 4'h4,
36: 4'hF, 4'hA, 4'h5, 4'h0};
37:
38: parameter logic [15:0][3:0] PRINCE_SHIFT_ROWS64_INV = '{4'h3, 4'h6, 4'h9, 4'hC,
39: 4'hF, 4'h2, 4'h5, 4'h8,
40: 4'hB, 4'hE, 4'h1, 4'h4,
41: 4'h7, 4'hA, 4'hD, 4'h0};
42:
43: // these are the round constants
44: parameter logic [11:0][63:0] PRINCE_ROUND_CONST = {64'hC0AC29B7C97C50DD,
45: 64'hD3B5A399CA0C2399,
46: 64'h64A51195E0E3610D,
47: 64'hC882D32F25323C54,
48: 64'h85840851F1AC43AA,
49: 64'h7EF84F78FD955CB1,
50: 64'hBE5466CF34E90C6C,
51: 64'h452821E638D01377,
52: 64'h082EFA98EC4E6C89,
53: 64'hA4093822299F31D0,
54: 64'h13198A2E03707344,
55: 64'h0000000000000000};
56:
57: // tweak constant for key modification between enc/dec modes
58: parameter logic [63:0] PRINCE_ALPHA_CONST = 64'hC0AC29B7C97C50DD;
59:
60: // masking constants for shift rows function below
61: parameter logic [15:0] PRINCE_SHIFT_ROWS_CONST0 = 16'hEDB7;
62: parameter logic [15:0] PRINCE_SHIFT_ROWS_CONST1 = 16'h7EDB;
63: parameter logic [15:0] PRINCE_SHIFT_ROWS_CONST2 = 16'hB7ED;
64: parameter logic [15:0] PRINCE_SHIFT_ROWS_CONST3 = 16'hDB7E;
65:
66: // nibble shifts
67: function automatic logic [31:0] prince_shiftrows_32bit(logic [31:0] state_in,
68: logic [15:0][3:0] shifts );
69: logic [31:0] state_out;
70: // note that if simulation performance becomes an issue, this loop can be unrolled
71: for (int k = 0; k < 32/2; k++) begin
72: // operate on pairs of 2bit instead of nibbles
73: state_out[k*2 +: 2] = state_in[shifts[k]*2 +: 2];
74: end
75: return state_out;
76: endfunction : prince_shiftrows_32bit
77:
78: function automatic logic [63:0] prince_shiftrows_64bit(logic [63:0] state_in,
79: logic [15:0][3:0] shifts );
80: logic [63:0] state_out;
81: // note that if simulation performance becomes an issue, this loop can be unrolled
82: for (int k = 0; k < 64/4; k++) begin
83: state_out[k*4 +: 4] = state_in[shifts[k]*4 +: 4];
84: end
85: return state_out;
86: endfunction : prince_shiftrows_64bit
87:
88: // XOR reduction of four nibbles in a 16bit subvector
89: function automatic logic [3:0] prince_nibble_red16(logic [15:0] vect);
90: return vect[0 +: 4] ^ vect[4 +: 4] ^ vect[8 +: 4] ^ vect[12 +: 4];
91: endfunction : prince_nibble_red16
92:
93: // M prime multiplication
94: function automatic logic [31:0] prince_mult_prime_32bit(logic [31:0] state_in);
95: logic [31:0] state_out;
96: // M0
97: state_out[0 +: 4] = prince_nibble_red16(state_in[ 0 +: 16] & PRINCE_SHIFT_ROWS_CONST0);
98: state_out[4 +: 4] = prince_nibble_red16(state_in[ 0 +: 16] & PRINCE_SHIFT_ROWS_CONST1);
99: state_out[8 +: 4] = prince_nibble_red16(state_in[ 0 +: 16] & PRINCE_SHIFT_ROWS_CONST2);
100: state_out[12 +: 4] = prince_nibble_red16(state_in[ 0 +: 16] & PRINCE_SHIFT_ROWS_CONST3);
101: // M1
102: state_out[16 +: 4] = prince_nibble_red16(state_in[16 +: 16] & PRINCE_SHIFT_ROWS_CONST1);
103: state_out[20 +: 4] = prince_nibble_red16(state_in[16 +: 16] & PRINCE_SHIFT_ROWS_CONST2);
104: state_out[24 +: 4] = prince_nibble_red16(state_in[16 +: 16] & PRINCE_SHIFT_ROWS_CONST3);
105: state_out[28 +: 4] = prince_nibble_red16(state_in[16 +: 16] & PRINCE_SHIFT_ROWS_CONST0);
106: return state_out;
107: endfunction : prince_mult_prime_32bit
108:
109: // M prime multiplication
110: function automatic logic [63:0] prince_mult_prime_64bit(logic [63:0] state_in);
111: logic [63:0] state_out;
112: // M0
113: state_out[0 +: 4] = prince_nibble_red16(state_in[ 0 +: 16] & PRINCE_SHIFT_ROWS_CONST0);
114: state_out[4 +: 4] = prince_nibble_red16(state_in[ 0 +: 16] & PRINCE_SHIFT_ROWS_CONST1);
115: state_out[8 +: 4] = prince_nibble_red16(state_in[ 0 +: 16] & PRINCE_SHIFT_ROWS_CONST2);
116: state_out[12 +: 4] = prince_nibble_red16(state_in[ 0 +: 16] & PRINCE_SHIFT_ROWS_CONST3);
117: // M1
118: state_out[16 +: 4] = prince_nibble_red16(state_in[16 +: 16] & PRINCE_SHIFT_ROWS_CONST1);
119: state_out[20 +: 4] = prince_nibble_red16(state_in[16 +: 16] & PRINCE_SHIFT_ROWS_CONST2);
120: state_out[24 +: 4] = prince_nibble_red16(state_in[16 +: 16] & PRINCE_SHIFT_ROWS_CONST3);
121: state_out[28 +: 4] = prince_nibble_red16(state_in[16 +: 16] & PRINCE_SHIFT_ROWS_CONST0);
122: // M1
123: state_out[32 +: 4] = prince_nibble_red16(state_in[32 +: 16] & PRINCE_SHIFT_ROWS_CONST1);
124: state_out[36 +: 4] = prince_nibble_red16(state_in[32 +: 16] & PRINCE_SHIFT_ROWS_CONST2);
125: state_out[40 +: 4] = prince_nibble_red16(state_in[32 +: 16] & PRINCE_SHIFT_ROWS_CONST3);
126: state_out[44 +: 4] = prince_nibble_red16(state_in[32 +: 16] & PRINCE_SHIFT_ROWS_CONST0);
127: // M0
128: state_out[48 +: 4] = prince_nibble_red16(state_in[48 +: 16] & PRINCE_SHIFT_ROWS_CONST0);
129: state_out[52 +: 4] = prince_nibble_red16(state_in[48 +: 16] & PRINCE_SHIFT_ROWS_CONST1);
130: state_out[56 +: 4] = prince_nibble_red16(state_in[48 +: 16] & PRINCE_SHIFT_ROWS_CONST2);
131: state_out[60 +: 4] = prince_nibble_red16(state_in[48 +: 16] & PRINCE_SHIFT_ROWS_CONST3);
132: return state_out;
133: endfunction : prince_mult_prime_64bit
134:
135:
136: ////////////////////
137: // PRESENT Cipher //
138: ////////////////////
139:
140: // this is the sbox from the present cipher
141: parameter logic [15:0][3:0] PRESENT_SBOX4 = {4'h2, 4'h1, 4'h7, 4'h4,
142: 4'h8, 4'hF, 4'hE, 4'h3,
143: 4'hD, 4'hA, 4'h0, 4'h9,
144: 4'hB, 4'h6, 4'h5, 4'hC};
145:
146: parameter logic [15:0][3:0] PRESENT_SBOX4_INV = {4'hA, 4'h9, 4'h7, 4'h0,
147: 4'h3, 4'h6, 4'h4, 4'hB,
148: 4'hD, 4'h2, 4'h1, 4'hC,
149: 4'h8, 4'hF, 4'hE, 4'h5};
150:
151: // these are modified permutation indices for a 32bit version that
152: // follow the same pattern as for the 64bit version
153: parameter logic [31:0][4:0] PRESENT_PERM32 = {5'd31, 5'd23, 5'd15, 5'd07,
154: 5'd30, 5'd22, 5'd14, 5'd06,
155: 5'd29, 5'd21, 5'd13, 5'd05,
156: 5'd28, 5'd20, 5'd12, 5'd04,
157: 5'd27, 5'd19, 5'd11, 5'd03,
158: 5'd26, 5'd18, 5'd10, 5'd02,
159: 5'd25, 5'd17, 5'd09, 5'd01,
160: 5'd24, 5'd16, 5'd08, 5'd00};
161:
162: parameter logic [31:0][4:0] PRESENT_PERM32_INV = {5'd31, 5'd27, 5'd23, 5'd19,
163: 5'd15, 5'd11, 5'd07, 5'd03,
164: 5'd30, 5'd26, 5'd22, 5'd18,
165: 5'd14, 5'd10, 5'd06, 5'd02,
166: 5'd29, 5'd25, 5'd21, 5'd17,
167: 5'd13, 5'd09, 5'd05, 5'd01,
168: 5'd28, 5'd24, 5'd20, 5'd16,
169: 5'd12, 5'd08, 5'd04, 5'd00};
170:
171: // these are the permutation indices of the present cipher
172: parameter logic [63:0][5:0] PRESENT_PERM64 = {6'd63, 6'd47, 6'd31, 6'd15,
173: 6'd62, 6'd46, 6'd30, 6'd14,
174: 6'd61, 6'd45, 6'd29, 6'd13,
175: 6'd60, 6'd44, 6'd28, 6'd12,
176: 6'd59, 6'd43, 6'd27, 6'd11,
177: 6'd58, 6'd42, 6'd26, 6'd10,
178: 6'd57, 6'd41, 6'd25, 6'd09,
179: 6'd56, 6'd40, 6'd24, 6'd08,
180: 6'd55, 6'd39, 6'd23, 6'd07,
181: 6'd54, 6'd38, 6'd22, 6'd06,
182: 6'd53, 6'd37, 6'd21, 6'd05,
183: 6'd52, 6'd36, 6'd20, 6'd04,
184: 6'd51, 6'd35, 6'd19, 6'd03,
185: 6'd50, 6'd34, 6'd18, 6'd02,
186: 6'd49, 6'd33, 6'd17, 6'd01,
187: 6'd48, 6'd32, 6'd16, 6'd00};
188:
189: parameter logic [63:0][5:0] PRESENT_PERM64_INV = {6'd63, 6'd59, 6'd55, 6'd51,
190: 6'd47, 6'd43, 6'd39, 6'd35,
191: 6'd31, 6'd27, 6'd23, 6'd19,
192: 6'd15, 6'd11, 6'd07, 6'd03,
193: 6'd62, 6'd58, 6'd54, 6'd50,
194: 6'd46, 6'd42, 6'd38, 6'd34,
195: 6'd30, 6'd26, 6'd22, 6'd18,
196: 6'd14, 6'd10, 6'd06, 6'd02,
197: 6'd61, 6'd57, 6'd53, 6'd49,
198: 6'd45, 6'd41, 6'd37, 6'd33,
199: 6'd29, 6'd25, 6'd21, 6'd17,
200: 6'd13, 6'd09, 6'd05, 6'd01,
201: 6'd60, 6'd56, 6'd52, 6'd48,
202: 6'd44, 6'd40, 6'd36, 6'd32,
203: 6'd28, 6'd24, 6'd20, 6'd16,
204: 6'd12, 6'd08, 6'd04, 6'd00};
205:
206: // forward key schedule
207: function automatic logic [63:0] present_update_key64(logic [63:0] key_in,
208: logic [4:0] round_idx);
209: logic [63:0] key_out;
210: // rotate by 61 to the left
211: key_out = 64'(key_in << 61) | 64'(key_in >> (64-61));
212: // sbox on uppermost 4 bits
213: key_out[63 -: 4] = PRESENT_SBOX4[key_out[63 -: 4]];
214: // xor in round counter on bits 19 to 15
215: key_out[19:15] ^= round_idx;
216: return key_out;
217: endfunction : present_update_key64
218:
219: function automatic logic [79:0] present_update_key80(logic [79:0] key_in,
220: logic [4:0] round_idx);
221: logic [79:0] key_out;
222: // rotate by 61 to the left
223: key_out = 80'(key_in << 61) | 80'(key_in >> (80-61));
224: // sbox on uppermost 4 bits
225: key_out[79 -: 4] = PRESENT_SBOX4[key_out[79 -: 4]];
226: // xor in round counter on bits 19 to 15
227: key_out[19:15] ^= round_idx;
228: return key_out;
229: endfunction : present_update_key80
230:
231: function automatic logic [127:0] present_update_key128(logic [127:0] key_in,
232: logic [4:0] round_idx);
233: logic [127:0] key_out;
234: // rotate by 61 to the left
235: key_out = 128'(key_in << 61) | 128'(key_in >> (128-61));
236: // sbox on uppermost 4 bits
237: key_out[127 -: 4] = PRESENT_SBOX4[key_out[127 -: 4]];
238: // xor in round counter on bits 19 to 15
239: key_out[19:15] ^= round_idx;
240: return key_out;
241: endfunction : present_update_key128
242:
243:
244: // inverse key schedule
245: function automatic logic [63:0] present_inv_update_key64(logic [63:0] key_in,
246: logic [4:0] round_idx,
247: // total number of rounds employed
248: logic [4:0] round_cnt);
249: logic [63:0] key_out;
250: // xor in round counter on bits 19 to 15
251: key_out[19:15] ^= 6'(round_cnt) + 1 - round_idx;
252: // sbox on uppermost 4 bits
253: key_out[63 -: 4] = PRESENT_SBOX4_INV[key_out[63 -: 4]];
254: // rotate by 61 to the right
255: key_out = 64'(key_in >> 61) | 64'(key_in << (64-61));
256: return key_out;
257: endfunction : present_inv_update_key64
258:
259: function automatic logic [79:0] present_inv_update_key80(logic [79:0] key_in,
260: logic [4:0] round_idx,
261: // total number of rounds employed
262: logic [4:0] round_cnt);
263: logic [79:0] key_out;
264: // xor in round counter on bits 19 to 15
265: key_out[19:15] ^= 6'(round_cnt) + 1 - round_idx;
266: // sbox on uppermost 4 bits
267: key_out[79 -: 4] = PRESENT_SBOX4_INV[key_out[79 -: 4]];
268: // rotate by 61 to the right
269: key_out = 80'(key_in >> 61) | 80'(key_in << (80-61));
270: return key_out;
271: endfunction : present_inv_update_key80
272:
273: function automatic logic [127:0] present_inv_update_key128(logic [127:0] key_in,
274: logic [4:0] round_idx,
275: // total number of rounds employed
276: logic [4:0] round_cnt);
277: logic [127:0] key_out;
278: // xor in round counter on bits 19 to 15
279: key_out[19:15] ^= 6'(round_cnt) + 1 - round_idx;
280: // sbox on uppermost 4 bits
281: key_out[127 -: 4] = PRESENT_SBOX4_INV[key_out[127 -: 4]];
282: // rotate by 61 to the right
283: key_out = 128'(key_in >> 61) | 128'(key_in << (128-61));
284: return key_out;
285: endfunction : present_inv_update_key128
286:
287:
288: // these functions can be used to derive the DEC key from the ENC key by
289: // stepping the key by the correct number of rounds using the keyschedule functions above.
290: function automatic logic [63:0] present_get_dec_key64(logic [63:0] key_in,
291: // total number of rounds employed
292: logic [4:0] round_cnt);
293: logic [63:0] key_out;
294: key_out = key_in;
295: for (int k = 0; k < round_cnt; k++) begin
296: key_out = present_update_key64(key_out, 5'(k + 1));
297: end
298: return key_out;
299: endfunction : present_get_dec_key64
300:
301: function automatic logic [79:0] present_get_dec_key80(logic [79:0] key_in,
302: // total number of rounds employed
303: logic [4:0] round_cnt);
304: logic [79:0] key_out;
305: key_out = key_in;
306: for (int k = 0; k < round_cnt; k++) begin
307: key_out = present_update_key80(key_out, 5'(k + 1));
308: end
309: return key_out;
310: endfunction : present_get_dec_key80
311:
312: function automatic logic [127:0] present_get_dec_key128(logic [127:0] key_in,
313: // total number of rounds employed
314: logic [4:0] round_cnt);
315: logic [127:0] key_out;
316: key_out = key_in;
317: for (int k = 0; k < round_cnt; k++) begin
318: key_out = present_update_key128(key_out, 5'(k + 1));
319: end
320: return key_out;
321: endfunction : present_get_dec_key128
322:
323: /////////////////////////
324: // Common Subfunctions //
325: /////////////////////////
326:
327: function automatic logic [31:0] sbox4_32bit(logic [31:0] state_in, logic [15:0][3:0] sbox4);
328: logic [31:0] state_out;
329: // note that if simulation performance becomes an issue, this loop can be unrolled
330: for (int k = 0; k < 32/4; k++) begin
331: state_out[k*4 +: 4] = sbox4[state_in[k*4 +: 4]];
332: end
333: return state_out;
334: endfunction : sbox4_32bit
335:
336: function automatic logic [63:0] sbox4_64bit(logic [63:0] state_in, logic [15:0][3:0] sbox4);
337: logic [63:0] state_out;
338: // note that if simulation performance becomes an issue, this loop can be unrolled
339: for (int k = 0; k < 64/4; k++) begin
340: state_out[k*4 +: 4] = sbox4[state_in[k*4 +: 4]];
341: end
342: return state_out;
343: endfunction : sbox4_64bit
344:
345: function automatic logic [31:0] perm_32bit(logic [31:0] state_in, logic [31:0][4:0] perm);
346: logic [31:0] state_out;
347: // note that if simulation performance becomes an issue, this loop can be unrolled
348: for (int k = 0; k < 32; k++) begin
349: state_out[k] = state_in[perm[k]];
350: end
351: return state_out;
352: endfunction : perm_32bit
353:
354: function automatic logic [63:0] perm_64bit(logic [63:0] state_in, logic [63:0][5:0] perm);
355: logic [63:0] state_out;
356: // note that if simulation performance becomes an issue, this loop can be unrolled
357: for (int k = 0; k < 64; k++) begin
358: state_out[k] = state_in[perm[k]];
359: end
360: return state_out;
361: endfunction : perm_64bit
362:
363: endpackage : prim_cipher_pkg
364: