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