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