|  | // Copyright lowRISC contributors. | 
|  | // Licensed under the Apache License, Version 2.0, see LICENSE for details. | 
|  | // SPDX-License-Identifier: Apache-2.0 | 
|  | // | 
|  | // This package holds common constants and functions for PRESENT- and | 
|  | // PRINCE-based scrambling devices. | 
|  | // | 
|  | // See also: prim_present, prim_prince | 
|  | // | 
|  | // References: - https://en.wikipedia.org/wiki/PRESENT | 
|  | //             - https://en.wikipedia.org/wiki/Prince_(cipher) | 
|  | //             - http://www.lightweightcrypto.org/present/present_ches2007.pdf | 
|  | //             - https://eprint.iacr.org/2012/529.pdf | 
|  | //             - https://eprint.iacr.org/2015/372.pdf | 
|  | //             - https://eprint.iacr.org/2014/656.pdf | 
|  |  | 
|  | package prim_cipher_pkg; | 
|  |  | 
|  | /////////////////// | 
|  | // PRINCE Cipher // | 
|  | /////////////////// | 
|  |  | 
|  | parameter logic [15:0][3:0] PRINCE_SBOX4 = {4'h4, 4'hD, 4'h5, 4'hE, | 
|  | 4'h0, 4'h8, 4'h7, 4'h6, | 
|  | 4'h1, 4'h9, 4'hC, 4'hA, | 
|  | 4'h2, 4'h3, 4'hF, 4'hB}; | 
|  |  | 
|  | parameter logic [15:0][3:0] PRINCE_SBOX4_INV = {4'h1, 4'hC, 4'hE, 4'h5, | 
|  | 4'h0, 4'h4, 4'h6, 4'hA, | 
|  | 4'h9, 4'h8, 4'hD, 4'hF, | 
|  | 4'h2, 4'h3, 4'h7, 4'hB}; | 
|  | // nibble permutations | 
|  | parameter logic [15:0][3:0] PRINCE_SHIFT_ROWS64  = '{4'hB, 4'h6, 4'h1, 4'hC, | 
|  | 4'h7, 4'h2, 4'hD, 4'h8, | 
|  | 4'h3, 4'hE, 4'h9, 4'h4, | 
|  | 4'hF, 4'hA, 4'h5, 4'h0}; | 
|  |  | 
|  | parameter logic [15:0][3:0] PRINCE_SHIFT_ROWS64_INV = '{4'h3, 4'h6, 4'h9, 4'hC, | 
|  | 4'hF, 4'h2, 4'h5, 4'h8, | 
|  | 4'hB, 4'hE, 4'h1, 4'h4, | 
|  | 4'h7, 4'hA, 4'hD, 4'h0}; | 
|  |  | 
|  | // these are the round constants | 
|  | parameter logic [11:0][63:0] PRINCE_ROUND_CONST = {64'hC0AC29B7C97C50DD, | 
|  | 64'hD3B5A399CA0C2399, | 
|  | 64'h64A51195E0E3610D, | 
|  | 64'hC882D32F25323C54, | 
|  | 64'h85840851F1AC43AA, | 
|  | 64'h7EF84F78FD955CB1, | 
|  | 64'hBE5466CF34E90C6C, | 
|  | 64'h452821E638D01377, | 
|  | 64'h082EFA98EC4E6C89, | 
|  | 64'hA4093822299F31D0, | 
|  | 64'h13198A2E03707344, | 
|  | 64'h0000000000000000}; | 
|  |  | 
|  | // tweak constant for key modification between enc/dec modes | 
|  | parameter logic [63:0] PRINCE_ALPHA_CONST = 64'hC0AC29B7C97C50DD; | 
|  |  | 
|  | // masking constants for shift rows function below | 
|  | parameter logic [15:0] PRINCE_SHIFT_ROWS_CONST0 = 16'hEDB7; | 
|  | parameter logic [15:0] PRINCE_SHIFT_ROWS_CONST1 = 16'h7EDB; | 
|  | parameter logic [15:0] PRINCE_SHIFT_ROWS_CONST2 = 16'hB7ED; | 
|  | parameter logic [15:0] PRINCE_SHIFT_ROWS_CONST3 = 16'hDB7E; | 
|  |  | 
|  | // nibble shifts | 
|  | function automatic logic [31:0] prince_shiftrows_32bit(logic [31:0]      state_in, | 
|  | logic [15:0][3:0] shifts ); | 
|  | logic [31:0] state_out; | 
|  | // note that if simulation performance becomes an issue, this loop can be unrolled | 
|  | for (int k = 0; k < 32/2; k++) begin | 
|  | // operate on pairs of 2bit instead of nibbles | 
|  | state_out[k*2  +: 2] = state_in[shifts[k]*2  +: 2]; | 
|  | end | 
|  | return state_out; | 
|  | endfunction : prince_shiftrows_32bit | 
|  |  | 
|  | function automatic logic [63:0] prince_shiftrows_64bit(logic [63:0]      state_in, | 
|  | logic [15:0][3:0] shifts ); | 
|  | logic [63:0] state_out; | 
|  | // note that if simulation performance becomes an issue, this loop can be unrolled | 
|  | for (int k = 0; k < 64/4; k++) begin | 
|  | state_out[k*4  +: 4] = state_in[shifts[k]*4  +: 4]; | 
|  | end | 
|  | return state_out; | 
|  | endfunction : prince_shiftrows_64bit | 
|  |  | 
|  | // XOR reduction of four nibbles in a 16bit subvector | 
|  | function automatic logic [3:0] prince_nibble_red16(logic [15:0] vect); | 
|  | return vect[0 +: 4] ^ vect[4 +: 4] ^ vect[8 +: 4] ^ vect[12 +: 4]; | 
|  | endfunction : prince_nibble_red16 | 
|  |  | 
|  | // M prime multiplication | 
|  | function automatic logic [31:0] prince_mult_prime_32bit(logic [31:0] state_in); | 
|  | logic [31:0] state_out; | 
|  | // M0 | 
|  | state_out[0  +: 4] = prince_nibble_red16(state_in[ 0 +: 16] & PRINCE_SHIFT_ROWS_CONST0); | 
|  | state_out[4  +: 4] = prince_nibble_red16(state_in[ 0 +: 16] & PRINCE_SHIFT_ROWS_CONST1); | 
|  | state_out[8  +: 4] = prince_nibble_red16(state_in[ 0 +: 16] & PRINCE_SHIFT_ROWS_CONST2); | 
|  | state_out[12 +: 4] = prince_nibble_red16(state_in[ 0 +: 16] & PRINCE_SHIFT_ROWS_CONST3); | 
|  | // M1 | 
|  | state_out[16 +: 4] = prince_nibble_red16(state_in[16 +: 16] & PRINCE_SHIFT_ROWS_CONST1); | 
|  | state_out[20 +: 4] = prince_nibble_red16(state_in[16 +: 16] & PRINCE_SHIFT_ROWS_CONST2); | 
|  | state_out[24 +: 4] = prince_nibble_red16(state_in[16 +: 16] & PRINCE_SHIFT_ROWS_CONST3); | 
|  | state_out[28 +: 4] = prince_nibble_red16(state_in[16 +: 16] & PRINCE_SHIFT_ROWS_CONST0); | 
|  | return state_out; | 
|  | endfunction : prince_mult_prime_32bit | 
|  |  | 
|  | // M prime multiplication | 
|  | function automatic logic [63:0] prince_mult_prime_64bit(logic [63:0] state_in); | 
|  | logic [63:0] state_out; | 
|  | // M0 | 
|  | state_out[0  +: 4] = prince_nibble_red16(state_in[ 0 +: 16] & PRINCE_SHIFT_ROWS_CONST0); | 
|  | state_out[4  +: 4] = prince_nibble_red16(state_in[ 0 +: 16] & PRINCE_SHIFT_ROWS_CONST1); | 
|  | state_out[8  +: 4] = prince_nibble_red16(state_in[ 0 +: 16] & PRINCE_SHIFT_ROWS_CONST2); | 
|  | state_out[12 +: 4] = prince_nibble_red16(state_in[ 0 +: 16] & PRINCE_SHIFT_ROWS_CONST3); | 
|  | // M1 | 
|  | state_out[16 +: 4] = prince_nibble_red16(state_in[16 +: 16] & PRINCE_SHIFT_ROWS_CONST1); | 
|  | state_out[20 +: 4] = prince_nibble_red16(state_in[16 +: 16] & PRINCE_SHIFT_ROWS_CONST2); | 
|  | state_out[24 +: 4] = prince_nibble_red16(state_in[16 +: 16] & PRINCE_SHIFT_ROWS_CONST3); | 
|  | state_out[28 +: 4] = prince_nibble_red16(state_in[16 +: 16] & PRINCE_SHIFT_ROWS_CONST0); | 
|  | // M1 | 
|  | state_out[32 +: 4] = prince_nibble_red16(state_in[32 +: 16] & PRINCE_SHIFT_ROWS_CONST1); | 
|  | state_out[36 +: 4] = prince_nibble_red16(state_in[32 +: 16] & PRINCE_SHIFT_ROWS_CONST2); | 
|  | state_out[40 +: 4] = prince_nibble_red16(state_in[32 +: 16] & PRINCE_SHIFT_ROWS_CONST3); | 
|  | state_out[44 +: 4] = prince_nibble_red16(state_in[32 +: 16] & PRINCE_SHIFT_ROWS_CONST0); | 
|  | // M0 | 
|  | state_out[48 +: 4] = prince_nibble_red16(state_in[48 +: 16] & PRINCE_SHIFT_ROWS_CONST0); | 
|  | state_out[52 +: 4] = prince_nibble_red16(state_in[48 +: 16] & PRINCE_SHIFT_ROWS_CONST1); | 
|  | state_out[56 +: 4] = prince_nibble_red16(state_in[48 +: 16] & PRINCE_SHIFT_ROWS_CONST2); | 
|  | state_out[60 +: 4] = prince_nibble_red16(state_in[48 +: 16] & PRINCE_SHIFT_ROWS_CONST3); | 
|  | return state_out; | 
|  | endfunction : prince_mult_prime_64bit | 
|  |  | 
|  |  | 
|  | //////////////////// | 
|  | // PRESENT Cipher // | 
|  | //////////////////// | 
|  |  | 
|  | // this is the sbox from the present cipher | 
|  | parameter logic [15:0][3:0] PRESENT_SBOX4 = {4'h2, 4'h1, 4'h7, 4'h4, | 
|  | 4'h8, 4'hF, 4'hE, 4'h3, | 
|  | 4'hD, 4'hA, 4'h0, 4'h9, | 
|  | 4'hB, 4'h6, 4'h5, 4'hC}; | 
|  |  | 
|  | parameter logic [15:0][3:0] PRESENT_SBOX4_INV = {4'hA, 4'h9, 4'h7, 4'h0, | 
|  | 4'h3, 4'h6, 4'h4, 4'hB, | 
|  | 4'hD, 4'h2, 4'h1, 4'hC, | 
|  | 4'h8, 4'hF, 4'hE, 4'h5}; | 
|  |  | 
|  | // these are modified permutation indices for a 32bit version that | 
|  | // follow the same pattern as for the 64bit version | 
|  | parameter logic [31:0][4:0] PRESENT_PERM32 = {5'd31, 5'd23, 5'd15, 5'd07, | 
|  | 5'd30, 5'd22, 5'd14, 5'd06, | 
|  | 5'd29, 5'd21, 5'd13, 5'd05, | 
|  | 5'd28, 5'd20, 5'd12, 5'd04, | 
|  | 5'd27, 5'd19, 5'd11, 5'd03, | 
|  | 5'd26, 5'd18, 5'd10, 5'd02, | 
|  | 5'd25, 5'd17, 5'd09, 5'd01, | 
|  | 5'd24, 5'd16, 5'd08, 5'd00}; | 
|  |  | 
|  | parameter logic [31:0][4:0] PRESENT_PERM32_INV = {5'd31, 5'd27, 5'd23, 5'd19, | 
|  | 5'd15, 5'd11, 5'd07, 5'd03, | 
|  | 5'd30, 5'd26, 5'd22, 5'd18, | 
|  | 5'd14, 5'd10, 5'd06, 5'd02, | 
|  | 5'd29, 5'd25, 5'd21, 5'd17, | 
|  | 5'd13, 5'd09, 5'd05, 5'd01, | 
|  | 5'd28, 5'd24, 5'd20, 5'd16, | 
|  | 5'd12, 5'd08, 5'd04, 5'd00}; | 
|  |  | 
|  | // these are the permutation indices of the present cipher | 
|  | parameter logic [63:0][5:0] PRESENT_PERM64 = {6'd63, 6'd47, 6'd31, 6'd15, | 
|  | 6'd62, 6'd46, 6'd30, 6'd14, | 
|  | 6'd61, 6'd45, 6'd29, 6'd13, | 
|  | 6'd60, 6'd44, 6'd28, 6'd12, | 
|  | 6'd59, 6'd43, 6'd27, 6'd11, | 
|  | 6'd58, 6'd42, 6'd26, 6'd10, | 
|  | 6'd57, 6'd41, 6'd25, 6'd09, | 
|  | 6'd56, 6'd40, 6'd24, 6'd08, | 
|  | 6'd55, 6'd39, 6'd23, 6'd07, | 
|  | 6'd54, 6'd38, 6'd22, 6'd06, | 
|  | 6'd53, 6'd37, 6'd21, 6'd05, | 
|  | 6'd52, 6'd36, 6'd20, 6'd04, | 
|  | 6'd51, 6'd35, 6'd19, 6'd03, | 
|  | 6'd50, 6'd34, 6'd18, 6'd02, | 
|  | 6'd49, 6'd33, 6'd17, 6'd01, | 
|  | 6'd48, 6'd32, 6'd16, 6'd00}; | 
|  |  | 
|  | parameter logic [63:0][5:0] PRESENT_PERM64_INV = {6'd63, 6'd59, 6'd55, 6'd51, | 
|  | 6'd47, 6'd43, 6'd39, 6'd35, | 
|  | 6'd31, 6'd27, 6'd23, 6'd19, | 
|  | 6'd15, 6'd11, 6'd07, 6'd03, | 
|  | 6'd62, 6'd58, 6'd54, 6'd50, | 
|  | 6'd46, 6'd42, 6'd38, 6'd34, | 
|  | 6'd30, 6'd26, 6'd22, 6'd18, | 
|  | 6'd14, 6'd10, 6'd06, 6'd02, | 
|  | 6'd61, 6'd57, 6'd53, 6'd49, | 
|  | 6'd45, 6'd41, 6'd37, 6'd33, | 
|  | 6'd29, 6'd25, 6'd21, 6'd17, | 
|  | 6'd13, 6'd09, 6'd05, 6'd01, | 
|  | 6'd60, 6'd56, 6'd52, 6'd48, | 
|  | 6'd44, 6'd40, 6'd36, 6'd32, | 
|  | 6'd28, 6'd24, 6'd20, 6'd16, | 
|  | 6'd12, 6'd08, 6'd04, 6'd00}; | 
|  |  | 
|  | // forward key schedule | 
|  | function automatic logic [63:0] present_update_key64(logic [63:0] key_in, | 
|  | logic [4:0]  round_idx); | 
|  | logic [63:0] key_out; | 
|  | // rotate by 61 to the left | 
|  | key_out = 64'(key_in << 61) | 64'(key_in >> (64-61)); | 
|  | // sbox on uppermost 4 bits | 
|  | key_out[63 -: 4] = PRESENT_SBOX4[key_out[63 -: 4]]; | 
|  | // xor in round counter on bits 19 to 15 | 
|  | key_out[19:15] ^= round_idx; | 
|  | return key_out; | 
|  | endfunction : present_update_key64 | 
|  |  | 
|  | function automatic logic [79:0] present_update_key80(logic [79:0] key_in, | 
|  | logic [4:0]  round_idx); | 
|  | logic [79:0] key_out; | 
|  | // rotate by 61 to the left | 
|  | key_out = 80'(key_in << 61) | 80'(key_in >> (80-61)); | 
|  | // sbox on uppermost 4 bits | 
|  | key_out[79 -: 4] = PRESENT_SBOX4[key_out[79 -: 4]]; | 
|  | // xor in round counter on bits 19 to 15 | 
|  | key_out[19:15] ^= round_idx; | 
|  | return key_out; | 
|  | endfunction : present_update_key80 | 
|  |  | 
|  | function automatic logic [127:0] present_update_key128(logic [127:0] key_in, | 
|  | logic [4:0]   round_idx); | 
|  | logic [127:0] key_out; | 
|  | // rotate by 61 to the left | 
|  | key_out = 128'(key_in << 61) | 128'(key_in >> (128-61)); | 
|  | // sbox on uppermost 4 bits | 
|  | key_out[127 -: 4] = PRESENT_SBOX4[key_out[127 -: 4]]; | 
|  | // xor in round counter on bits 19 to 15 | 
|  | key_out[19:15] ^= round_idx; | 
|  | return key_out; | 
|  | endfunction : present_update_key128 | 
|  |  | 
|  |  | 
|  | // inverse key schedule | 
|  | function automatic logic [63:0] present_inv_update_key64(logic [63:0] key_in, | 
|  | logic [4:0]  round_idx, | 
|  | // total number of rounds employed | 
|  | logic [4:0]  round_cnt); | 
|  | logic [63:0] key_out; | 
|  | // xor in round counter on bits 19 to 15 | 
|  | key_out[19:15] ^= 6'(round_cnt) + 1 - round_idx; | 
|  | // sbox on uppermost 4 bits | 
|  | key_out[63 -: 4] = PRESENT_SBOX4_INV[key_out[63 -: 4]]; | 
|  | // rotate by 61 to the right | 
|  | key_out = 64'(key_in >> 61) | 64'(key_in << (64-61)); | 
|  | return key_out; | 
|  | endfunction : present_inv_update_key64 | 
|  |  | 
|  | function automatic logic [79:0] present_inv_update_key80(logic [79:0] key_in, | 
|  | logic [4:0]  round_idx, | 
|  | // total number of rounds employed | 
|  | logic [4:0]  round_cnt); | 
|  | logic [79:0] key_out; | 
|  | // xor in round counter on bits 19 to 15 | 
|  | key_out[19:15] ^= 6'(round_cnt) + 1 - round_idx; | 
|  | // sbox on uppermost 4 bits | 
|  | key_out[79 -: 4] = PRESENT_SBOX4_INV[key_out[79 -: 4]]; | 
|  | // rotate by 61 to the right | 
|  | key_out = 80'(key_in >> 61) | 80'(key_in << (80-61)); | 
|  | return key_out; | 
|  | endfunction : present_inv_update_key80 | 
|  |  | 
|  | function automatic logic [127:0] present_inv_update_key128(logic [127:0] key_in, | 
|  | logic [4:0]   round_idx, | 
|  | // total number of rounds employed | 
|  | logic [4:0]   round_cnt); | 
|  | logic [127:0] key_out; | 
|  | // xor in round counter on bits 19 to 15 | 
|  | key_out[19:15] ^= 6'(round_cnt) + 1 - round_idx; | 
|  | // sbox on uppermost 4 bits | 
|  | key_out[127 -: 4] = PRESENT_SBOX4_INV[key_out[127 -: 4]]; | 
|  | // rotate by 61 to the right | 
|  | key_out = 128'(key_in >> 61) | 128'(key_in << (128-61)); | 
|  | return key_out; | 
|  | endfunction : present_inv_update_key128 | 
|  |  | 
|  |  | 
|  | // these functions can be used to derive the DEC key from the ENC key by | 
|  | // stepping the key by the correct number of rounds using the keyschedule functions above. | 
|  | function automatic logic [63:0] present_get_dec_key64(logic [63:0] key_in, | 
|  | // total number of rounds employed | 
|  | logic [4:0]  round_cnt); | 
|  | logic [63:0] key_out; | 
|  | key_out = key_in; | 
|  | for (int k = 0; k < round_cnt; k++) begin | 
|  | key_out = present_update_key64(key_out, 5'(k + 1)); | 
|  | end | 
|  | return key_out; | 
|  | endfunction : present_get_dec_key64 | 
|  |  | 
|  | function automatic logic [79:0] present_get_dec_key80(logic [79:0] key_in, | 
|  | // total number of rounds employed | 
|  | logic [4:0]  round_cnt); | 
|  | logic [79:0] key_out; | 
|  | key_out = key_in; | 
|  | for (int k = 0; k < round_cnt; k++) begin | 
|  | key_out = present_update_key80(key_out, 5'(k + 1)); | 
|  | end | 
|  | return key_out; | 
|  | endfunction : present_get_dec_key80 | 
|  |  | 
|  | function automatic logic [127:0] present_get_dec_key128(logic [127:0] key_in, | 
|  | // total number of rounds employed | 
|  | logic [4:0]   round_cnt); | 
|  | logic [127:0] key_out; | 
|  | key_out = key_in; | 
|  | for (int k = 0; k < round_cnt; k++) begin | 
|  | key_out = present_update_key128(key_out, 5'(k + 1)); | 
|  | end | 
|  | return key_out; | 
|  | endfunction : present_get_dec_key128 | 
|  |  | 
|  | ///////////////////////// | 
|  | // Common Subfunctions // | 
|  | ///////////////////////// | 
|  |  | 
|  | function automatic logic [31:0] sbox4_32bit(logic [31:0] state_in, logic [15:0][3:0] sbox4); | 
|  | logic [31:0] state_out; | 
|  | // note that if simulation performance becomes an issue, this loop can be unrolled | 
|  | for (int k = 0; k < 32/4; k++) begin | 
|  | state_out[k*4  +: 4] = sbox4[state_in[k*4  +: 4]]; | 
|  | end | 
|  | return state_out; | 
|  | endfunction : sbox4_32bit | 
|  |  | 
|  | function automatic logic [63:0] sbox4_64bit(logic [63:0] state_in, logic [15:0][3:0] sbox4); | 
|  | logic [63:0] state_out; | 
|  | // note that if simulation performance becomes an issue, this loop can be unrolled | 
|  | for (int k = 0; k < 64/4; k++) begin | 
|  | state_out[k*4  +: 4] = sbox4[state_in[k*4  +: 4]]; | 
|  | end | 
|  | return state_out; | 
|  | endfunction : sbox4_64bit | 
|  |  | 
|  | function automatic logic [31:0] perm_32bit(logic [31:0] state_in, logic [31:0][4:0] perm); | 
|  | logic [31:0] state_out; | 
|  | // note that if simulation performance becomes an issue, this loop can be unrolled | 
|  | for (int k = 0; k < 32; k++) begin | 
|  | state_out[k] = state_in[perm[k]]; | 
|  | end | 
|  | return state_out; | 
|  | endfunction : perm_32bit | 
|  |  | 
|  | function automatic logic [63:0] perm_64bit(logic [63:0] state_in, logic [63:0][5:0] perm); | 
|  | logic [63:0] state_out; | 
|  | // note that if simulation performance becomes an issue, this loop can be unrolled | 
|  | for (int k = 0; k < 64; k++) begin | 
|  | state_out[k] = state_in[perm[k]]; | 
|  | end | 
|  | return state_out; | 
|  | endfunction : perm_64bit | 
|  |  | 
|  | endpackage : prim_cipher_pkg |