| // 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'hF, 4'hA, 4'h5, 4'h0, |
| 4'hB, 4'h6, 4'h1, 4'hC, |
| 4'h7, 4'h2, 4'hD, 4'h8, |
| 4'h3, 4'hE, 4'h9, 4'h4}; |
| |
| parameter logic [15:0][3:0] PRINCE_SHIFT_ROWS64_INV = '{4'hF, 4'h2, 4'h5, 4'h8, |
| 4'hB, 4'hE, 4'h1, 4'h4, |
| 4'h7, 4'hA, 4'hD, 4'h0, |
| 4'h3, 4'h6, 4'h9, 4'hC}; |
| |
| // 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'h7BDE; |
| parameter logic [15:0] PRINCE_SHIFT_ROWS_CONST1 = 16'hBDE7; |
| parameter logic [15:0] PRINCE_SHIFT_ROWS_CONST2 = 16'hDE7B; |
| parameter logic [15:0] PRINCE_SHIFT_ROWS_CONST3 = 16'hE7BD; |
| |
| // 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_CONST3); |
| state_out[4 +: 4] = prince_nibble_red16(state_in[ 0 +: 16] & PRINCE_SHIFT_ROWS_CONST2); |
| state_out[8 +: 4] = prince_nibble_red16(state_in[ 0 +: 16] & PRINCE_SHIFT_ROWS_CONST1); |
| state_out[12 +: 4] = prince_nibble_red16(state_in[ 0 +: 16] & PRINCE_SHIFT_ROWS_CONST0); |
| // M1 |
| state_out[16 +: 4] = prince_nibble_red16(state_in[16 +: 16] & PRINCE_SHIFT_ROWS_CONST0); |
| state_out[20 +: 4] = prince_nibble_red16(state_in[16 +: 16] & PRINCE_SHIFT_ROWS_CONST3); |
| state_out[24 +: 4] = prince_nibble_red16(state_in[16 +: 16] & PRINCE_SHIFT_ROWS_CONST2); |
| state_out[28 +: 4] = prince_nibble_red16(state_in[16 +: 16] & PRINCE_SHIFT_ROWS_CONST1); |
| 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_CONST3); |
| state_out[4 +: 4] = prince_nibble_red16(state_in[ 0 +: 16] & PRINCE_SHIFT_ROWS_CONST2); |
| state_out[8 +: 4] = prince_nibble_red16(state_in[ 0 +: 16] & PRINCE_SHIFT_ROWS_CONST1); |
| state_out[12 +: 4] = prince_nibble_red16(state_in[ 0 +: 16] & PRINCE_SHIFT_ROWS_CONST0); |
| // M1 |
| state_out[16 +: 4] = prince_nibble_red16(state_in[16 +: 16] & PRINCE_SHIFT_ROWS_CONST0); |
| state_out[20 +: 4] = prince_nibble_red16(state_in[16 +: 16] & PRINCE_SHIFT_ROWS_CONST3); |
| state_out[24 +: 4] = prince_nibble_red16(state_in[16 +: 16] & PRINCE_SHIFT_ROWS_CONST2); |
| state_out[28 +: 4] = prince_nibble_red16(state_in[16 +: 16] & PRINCE_SHIFT_ROWS_CONST1); |
| // M1 |
| state_out[32 +: 4] = prince_nibble_red16(state_in[32 +: 16] & PRINCE_SHIFT_ROWS_CONST0); |
| state_out[36 +: 4] = prince_nibble_red16(state_in[32 +: 16] & PRINCE_SHIFT_ROWS_CONST3); |
| state_out[40 +: 4] = prince_nibble_red16(state_in[32 +: 16] & PRINCE_SHIFT_ROWS_CONST2); |
| state_out[44 +: 4] = prince_nibble_red16(state_in[32 +: 16] & PRINCE_SHIFT_ROWS_CONST1); |
| // M0 |
| state_out[48 +: 4] = prince_nibble_red16(state_in[48 +: 16] & PRINCE_SHIFT_ROWS_CONST3); |
| state_out[52 +: 4] = prince_nibble_red16(state_in[48 +: 16] & PRINCE_SHIFT_ROWS_CONST2); |
| state_out[56 +: 4] = prince_nibble_red16(state_in[48 +: 16] & PRINCE_SHIFT_ROWS_CONST1); |
| state_out[60 +: 4] = prince_nibble_red16(state_in[48 +: 16] & PRINCE_SHIFT_ROWS_CONST0); |
| 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 = {key_in[63-61:0], key_in[63: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 = {key_in[79-61:0], key_in[79: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 = {key_in[127-61:0], key_in[127:128-61]}; |
| // sbox on uppermost 4 bits |
| key_out[127 -: 4] = PRESENT_SBOX4[key_out[127 -: 4]]; |
| // sbox on second nibble from top |
| key_out[123 -: 4] = PRESENT_SBOX4[key_out[123 -: 4]]; |
| // xor in round counter on bits 66 to 62 |
| key_out[66:62] ^= 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); |
| logic [63:0] key_out = key_in; |
| // xor in round counter on bits 19 to 15 |
| key_out[19:15] ^= 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 = {key_out[60:0], key_out[63: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); |
| logic [79:0] key_out = key_in; |
| // xor in round counter on bits 19 to 15 |
| key_out[19:15] ^= 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 = {key_out[60:0], key_out[79: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); |
| logic [127:0] key_out = key_in; |
| // xor in round counter on bits 66 to 62 |
| key_out[66:62] ^= round_idx; |
| // sbox on second highest nibble |
| key_out[123 -: 4] = PRESENT_SBOX4_INV[key_out[123 -: 4]]; |
| // sbox on uppermost 4 bits |
| key_out[127 -: 4] = PRESENT_SBOX4_INV[key_out[127 -: 4]]; |
| // rotate by 61 to the right |
| key_out = {key_out[60:0], key_out[127: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 unsigned 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 unsigned 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 unsigned 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 [7:0] sbox4_8bit(logic [7:0] state_in, logic [15:0][3:0] sbox4); |
| logic [7:0] state_out; |
| // note that if simulation performance becomes an issue, this loop can be unrolled |
| for (int k = 0; k < 8/4; k++) begin |
| state_out[k*4 +: 4] = sbox4[state_in[k*4 +: 4]]; |
| end |
| return state_out; |
| endfunction : sbox4_8bit |
| |
| function automatic logic [15:0] sbox4_16bit(logic [15:0] state_in, logic [15:0][3:0] sbox4); |
| logic [15:0] state_out; |
| // note that if simulation performance becomes an issue, this loop can be unrolled |
| for (int k = 0; k < 2; k++) begin |
| state_out[k*8 +: 8] = sbox4_8bit(state_in[k*8 +: 8], sbox4); |
| end |
| return state_out; |
| endfunction : sbox4_16bit |
| |
| 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 < 4; k++) begin |
| state_out[k*8 +: 8] = sbox4_8bit(state_in[k*8 +: 8], sbox4); |
| 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 < 8; k++) begin |
| state_out[k*8 +: 8] = sbox4_8bit(state_in[k*8 +: 8], sbox4); |
| end |
| return state_out; |
| endfunction : sbox4_64bit |
| |
| function automatic logic [7:0] perm_8bit(logic [7:0] state_in, logic [7:0][2:0] perm); |
| logic [7:0] state_out; |
| // note that if simulation performance becomes an issue, this loop can be unrolled |
| for (int k = 0; k < 8; k++) begin |
| state_out[perm[k]] = state_in[k]; |
| end |
| return state_out; |
| endfunction : perm_8bit |
| |
| function automatic logic [15:0] perm_16bit(logic [15:0] state_in, logic [15:0][3:0] perm); |
| logic [15:0] state_out; |
| // note that if simulation performance becomes an issue, this loop can be unrolled |
| for (int k = 0; k < 16; k++) begin |
| state_out[perm[k]] = state_in[k]; |
| end |
| return state_out; |
| endfunction : perm_16bit |
| |
| 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[perm[k]] = state_in[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[perm[k]] = state_in[k]; |
| end |
| return state_out; |
| endfunction : perm_64bit |
| |
| endpackage : prim_cipher_pkg |