../src/lowrisc_prim_all_0.1/rtl/prim_present.sv Cov: 45.8%
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 encryption pass of the 64bit PRESENT
6: // block cipher. It is a fully unrolled combinational implementation that
7: // supports both key sizes specified in the paper (80bit and 128bit). Further,
8: // the number of rounds is fully configurable, and the primitive supports a
9: // 32bit block cipher flavor which is not specified in the original paper. It
10: // should be noted, however, that the 32bit version is **not** secure and must
11: // not be used in a setting where cryptographic cipher strength is required. The
12: // 32bit variant is only intended to be used as a lightweight data scrambling
13: // device.
14: //
15: // See also: prim_prince, 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://eprint.iacr.org/2012/529.pdf
21: // - https://csrc.nist.gov/csrc/media/events/lightweight-cryptography-workshop-2015/documents/papers/session7-maene-paper.pdf
22:
23: // TODO: this module has not been verified yet, and has only been used in
24: // synthesis experiments.
25:
26: module prim_present #(
27: parameter int DataWidth = 64, // {32, 64}
28: parameter int KeyWidth = 128, // {64, 80, 128}
29: parameter int NumRounds = 31, // > 0
30: // Note that the decryption pass needs a modified key,
31: // to be calculated by performing NumRounds key updates
32: parameter bit Decrypt = 0 // 0: encrypt, 1: decrypt
33: ) (
34: input [DataWidth-1:0] data_i,
35: input [KeyWidth-1:0] key_i,
36: output logic [DataWidth-1:0] data_o,
37: output logic [KeyWidth-1:0] key_o
38: );
39:
40: //////////////
41: // datapath //
42: //////////////
43:
44: logic [NumRounds:0][DataWidth-1:0] data_state;
45: logic [NumRounds:0][KeyWidth-1:0] round_key;
46:
47: // initialize
48: assign data_state[0] = data_i;
49: assign round_key[0] = key_i;
50:
51: for (genvar k = 0; k < NumRounds; k++) begin : gen_round
52: logic [DataWidth-1:0] data_state_xor, data_state_sbox;
53: // cipher layers
54: assign data_state_xor = data_state[k] ^ round_key[k][KeyWidth-1 : KeyWidth-DataWidth];
55:
56: ////////////////////////////////
57: // decryption pass, performs inverse permutation, sbox and keyschedule
58: if (Decrypt) begin : gen_dec
59: // original 64bit variant
60: if (DataWidth == 64) begin : gen_d64
61: assign data_state_sbox = prim_cipher_pkg::perm_64bit(data_state_xor,
62: prim_cipher_pkg::PRESENT_PERM64_INV);
63: assign data_state[k+1] = prim_cipher_pkg::sbox4_64bit(data_state_sbox,
64: prim_cipher_pkg::PRESENT_SBOX4_INV);
65: // reduced 32bit variant
66: end else begin : gen_d32
67: assign data_state_sbox = prim_cipher_pkg::perm_32bit(data_state_xor,
68: prim_cipher_pkg::PRESENT_PERM32_INV);
69: assign data_state[k+1] = prim_cipher_pkg::sbox4_32bit(data_state_sbox,
70: prim_cipher_pkg::PRESENT_SBOX4_INV);
71: end
72: // update round key, count goes from 1 to 31 (max)
73: // original 128bit key variant
74: if (KeyWidth == 128) begin : gen_k128
75: assign round_key[k+1] = prim_cipher_pkg::present_inv_update_key128(round_key[k],
76: 5'(k + 1),
77: 5'(NumRounds));
78: // original 80bit key variant
79: end else if (KeyWidth == 80) begin : gen_k80
80: assign round_key[k+1] = prim_cipher_pkg::present_inv_update_key80(round_key[k],
81: 5'(k + 1),
82: 5'(NumRounds));
83: // reduced 64bit key variant
84: end else begin : gen_k64
85: assign round_key[k+1] = prim_cipher_pkg::present_inv_update_key64(round_key[k],
86: 5'(k + 1),
87: 5'(NumRounds));
88: end
89: ////////////////////////////////
90: // encryption pass
91: end else begin : gen_enc
92: // original 64bit variant
93: if (DataWidth == 64) begin : gen_d64
94: assign data_state_sbox = prim_cipher_pkg::sbox4_64bit(data_state_xor,
95: prim_cipher_pkg::PRESENT_SBOX4);
96: assign data_state[k+1] = prim_cipher_pkg::perm_64bit(data_state_sbox,
97: prim_cipher_pkg::PRESENT_PERM64);
98: // reduced 32bit variant
99: end else begin : gen_d32
100: assign data_state_sbox = prim_cipher_pkg::sbox4_32bit(data_state_xor,
101: prim_cipher_pkg::PRESENT_SBOX4);
102: assign data_state[k+1] = prim_cipher_pkg::perm_32bit(data_state_sbox,
103: prim_cipher_pkg::PRESENT_PERM32);
104: end
105: // update round key, count goes from 1 to 31 (max)
106: // original 128bit key variant
107: if (KeyWidth == 128) begin : gen_k128
108: assign round_key[k+1] = prim_cipher_pkg::present_update_key128(round_key[k], 5'(k + 1));
109: // original 80bit key variant
110: end else if (KeyWidth == 80) begin : gen_k80
111: assign round_key[k+1] = prim_cipher_pkg::present_update_key80(round_key[k], 5'(k + 1));
112: // reduced 64bit key variant
113: end else begin : gen_k64
114: assign round_key[k+1] = prim_cipher_pkg::present_update_key64(round_key[k], 5'(k + 1));
115: end
116: end // gen_enc
117: ////////////////////////////////
118: end // gen_round
119:
120: // finalize
121: assign data_o = data_state[NumRounds] ^ round_key[NumRounds][KeyWidth-1 : KeyWidth-DataWidth];
122: assign key_o = round_key[NumRounds];
123:
124: ////////////////
125: // assertions //
126: ////////////////
127:
128: `ASSERT_INIT(SupportedWidths_A, (DataWidth == 64 && KeyWidth inside {80, 128}) ||
129: (DataWidth == 32 && KeyWidth == 64))
130: `ASSERT_INIT(SupportedNumRounds_A, NumRounds > 0 && NumRounds <= 31)
131:
132: endmodule : prim_present
133: