blob: 742c9253631804ea7dfcbfc95cbee5336a26fb1e [file] [log] [blame]
// 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