../src/lowrisc_prim_all_0.1/rtl/prim_prince.sv Cov: 71.4%
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 module is an implementation of the 64bit PRINCE block cipher. It is a
6: // fully unrolled combinational implementation with configurable number of
7: // rounds. Due to the reflective construction of this cipher, the same circuit
8: // can be used for encryption and decryption, as described below. Further, the
9: // primitive supports a 32bit block cipher flavor which is not specified in the
10: // original paper. It should be noted, however, that the 32bit version is
11: // **not** secure and must not be used in a setting where cryptographic cipher
12: // strength is required. The 32bit variant is only intended to be used as a
13: // lightweight data scrambling device.
14: //
15: // See also: prim_present, prim_cipher_pkg
16: //
17: // References: - https://en.wikipedia.org/wiki/PRESENT
18: // - https://en.wikipedia.org/wiki/Prince_(cipher)
19: // - http://www.lightweightcrypto.org/present/present_ches2007.pdf
20: // - https://csrc.nist.gov/csrc/media/events/lightweight-cryptography-workshop-2015/documents/papers/session7-maene-paper.pdf
21: // - https://eprint.iacr.org/2012/529.pdf
22: // - https://eprint.iacr.org/2015/372.pdf
23: // - https://eprint.iacr.org/2014/656.pdf
24:
25:
26: // TODO: this module has not been verified yet, and has only been used in
27: // synthesis experiments.
28:
29: module prim_prince #(
30: parameter int DataWidth = 64,
31: parameter int KeyWidth = 128,
32: // The construction is reflective. Total number of rounds is 2*NumRoundsHalf + 2
33: parameter int NumRoundsHalf = 5,
34: // This primitive uses the new key schedule proposed in https://eprint.iacr.org/2014/656.pdf
35: // Setting this parameter to 1 falls back to the original key schedule.
36: parameter bit UseOldKeySched = 1'b0
37: ) (
38: input [DataWidth-1:0] data_i,
39: input [KeyWidth-1:0] key_i,
40: input dec_i, // set to 1 for decryption
41: output logic [DataWidth-1:0] data_o
42: );
43:
44: ///////////////////
45: // key expansion //
46: ///////////////////
47:
48: logic [DataWidth-1:0] k0, k0_prime, k1, k0_new;
49:
50: always_comb begin : p_key_expansion
51: k0 = key_i[DataWidth-1:0];
52: k0_prime = {k0[0], k0[DataWidth-1:2], k0[DataWidth-1] ^ k0[1]};
53: k1 = key_i[2*DataWidth-1 : DataWidth];
54:
55: // modify key for decryption
56: if (dec_i) begin
57: k0 = k0_prime;
58: k0_prime = key_i[DataWidth-1:0];
59: k1 ^= prim_cipher_pkg::PRINCE_ALPHA_CONST[DataWidth-1:0];
60: end
61: end
62:
63: if (UseOldKeySched) begin : gen_legacy_keyschedule
64: assign k0_new = k1;
65: end else begin : gen_new_keyschedule
66: // improved keyschedule proposed by https://eprint.iacr.org/2014/656.pdf
67: assign k0_new = k0;
68: end
69:
70: //////////////
71: // datapath //
72: //////////////
73:
74: // state variable for holding the rounds
75: logic [NumRoundsHalf*2+1:0][DataWidth-1:0] data_state;
76:
77: // pre-round XOR
78: always_comb begin : p_pre_round_xor
79: data_state[0] = data_i ^ k0;
80: data_state[0] ^= k1;
81: data_state[0] ^= prim_cipher_pkg::PRINCE_ROUND_CONST[0][DataWidth-1:0];
82: end
83:
84: // forward pass
85: for (genvar k = 1; k <= NumRoundsHalf; k++) begin : gen_fwd_pass
86: logic [DataWidth-1:0] data_state_round;
87: if (DataWidth == 64) begin : gen_fwd_d64
88: always_comb begin : p_fwd_d64
89: data_state_round = prim_cipher_pkg::sbox4_64bit(data_state[k-1],
90: prim_cipher_pkg::PRINCE_SBOX4);
91: data_state_round = prim_cipher_pkg::prince_mult_prime_64bit(data_state_round);
92: data_state_round = prim_cipher_pkg::prince_shiftrows_64bit(data_state_round,
93: prim_cipher_pkg::PRINCE_SHIFT_ROWS64);
94: end
95: end else begin : gen_fwd_d32
96: always_comb begin : p_fwd_d32
97: data_state_round = prim_cipher_pkg::sbox4_32bit(data_state[k-1],
98: prim_cipher_pkg::PRINCE_SBOX4);
99: data_state_round = prim_cipher_pkg::prince_mult_prime_32bit(data_state_round);
100: data_state_round = prim_cipher_pkg::prince_shiftrows_32bit(data_state_round,
101: prim_cipher_pkg::PRINCE_SHIFT_ROWS64);
102: end
103: end
104: logic [DataWidth-1:0] data_state_xor;
105: assign data_state_xor = data_state_round ^
106: prim_cipher_pkg::PRINCE_ROUND_CONST[k][DataWidth-1:0];
107: // improved keyschedule proposed by https://eprint.iacr.org/2014/656.pdf
108: if (k % 2 == 1) assign data_state[k] = data_state_xor ^ k0_new;
109: else assign data_state[k] = data_state_xor ^ k1;
110: end
111:
112: // middle part
113: logic [DataWidth-1:0] data_state_middle;
114: if (DataWidth == 64) begin : gen_middle_d64
115: always_comb begin : p_middle_d64
116: data_state_middle = prim_cipher_pkg::sbox4_64bit(data_state[NumRoundsHalf],
117: prim_cipher_pkg::PRINCE_SBOX4);
118: data_state_middle = prim_cipher_pkg::prince_mult_prime_64bit(data_state_middle);
119: data_state_middle = prim_cipher_pkg::sbox4_64bit(data_state_middle,
120: prim_cipher_pkg::PRINCE_SBOX4_INV);
121: end
122: end else begin : gen_middle_d32
123: always_comb begin : p_middle_d32
124: data_state_middle = prim_cipher_pkg::sbox4_32bit(data_state_middle[NumRoundsHalf],
125: prim_cipher_pkg::PRINCE_SBOX4);
126: data_state_middle = prim_cipher_pkg::prince_mult_prime_32bit(data_state_middle);
127: data_state_middle = prim_cipher_pkg::sbox4_32bit(data_state_middle,
128: prim_cipher_pkg::PRINCE_SBOX4_INV);
129: end
130: end
131:
132: assign data_state[NumRoundsHalf+1] = data_state_middle;
133:
134: // backward pass
135: for (genvar k = 1; k <= NumRoundsHalf; k++) begin : gen_bwd_pass
136: logic [DataWidth-1:0] data_state_xor0, data_state_xor1;
137: // improved keyschedule proposed by https://eprint.iacr.org/2014/656.pdf
138: if (k % 2 == 1) assign data_state_xor0 = data_state[NumRoundsHalf+k] ^ k0_new;
139: else assign data_state_xor0 = data_state[NumRoundsHalf+k] ^ k1;
140: // the construction is reflective, hence the subtraction with NumRoundsHalf
141: assign data_state_xor1 = data_state_xor0 ^
142: prim_cipher_pkg::PRINCE_ROUND_CONST[10-NumRoundsHalf+k][DataWidth-1:0];
143:
144: logic [DataWidth-1:0] data_state_bwd;
145: if (DataWidth == 64) begin : gen_bwd_d64
146: always_comb begin : p_bwd_d64
147: data_state_bwd = prim_cipher_pkg::prince_shiftrows_64bit(data_state_xor1,
148: prim_cipher_pkg::PRINCE_SHIFT_ROWS64_INV);
149: data_state_bwd = prim_cipher_pkg::prince_mult_prime_64bit(data_state_bwd);
150: data_state[NumRoundsHalf+k+1] = prim_cipher_pkg::sbox4_64bit(data_state_bwd,
151: prim_cipher_pkg::PRINCE_SBOX4_INV);
152: end
153: end else begin : gen_bwd_d32
154: always_comb begin : p_bwd_d32
155: data_state_bwd = prim_cipher_pkg::prince_shiftrows_32bit(data_state_xor1,
156: prim_cipher_pkg::PRINCE_SHIFT_ROWS64_INV);
157: data_state_bwd = prim_cipher_pkg::prince_mult_prime_32bit(data_state_bwd);
158: data_state[NumRoundsHalf+k+1] = prim_cipher_pkg::sbox4_32bit(data_state_bwd,
159: prim_cipher_pkg::PRINCE_SBOX4_INV);
160: end
161: end
162: end
163:
164: // post-rounds
165: always_comb begin : p_post_round_xor
166: data_o = data_state[2*NumRoundsHalf+1] ^
167: prim_cipher_pkg::PRINCE_ROUND_CONST[11][DataWidth-1:0];
168: data_o ^= k1;
169: data_o ^= k0_prime;
170: end
171:
172: ////////////////
173: // assertions //
174: ////////////////
175:
176: `ASSERT_INIT(SupportedWidths_A, (DataWidth == 64 && KeyWidth == 128) ||
177: (DataWidth == 32 && KeyWidth == 64))
178: `ASSERT_INIT(SupportedNumRounds_A, NumRoundsHalf > 0 && NumRoundsHalf < 6)
179:
180:
181: endmodule : prim_prince
182: