[flash_ctrl] Switch to new keyschedule in PRINCE
This fixes a bug in the improved keyschedule in the PRINCE primitive,
and enables that new keyschedule inside the flash controller.
The comment was outdated, as we have decided to go with PRINCE due to
the lower latency and area with respect to PRESENT.
Signed-off-by: Michael Schaffner <msf@opentitan.org>
diff --git a/hw/ip/flash_ctrl/rtl/flash_phy_scramble.sv b/hw/ip/flash_ctrl/rtl/flash_phy_scramble.sv
index 1796e01..887f84d 100644
--- a/hw/ip/flash_ctrl/rtl/flash_phy_scramble.sv
+++ b/hw/ip/flash_ctrl/rtl/flash_phy_scramble.sv
@@ -54,13 +54,15 @@
assign dec = op_type_i == DeScrambleOp;
- // Previous discussion settled on PRESENT, using PRINCE here for now
- // just to get some area idea
prim_prince # (
.DataWidth(DataWidth),
.KeyWidth(KeySize),
- .UseOldKeySched(1'b1),
- .HalfwayDataReg(1'b1)
+ // Use improved key schedule proposed by https://eprint.iacr.org/2014/656.pdf (see appendix).
+ .UseOldKeySched(1'b0),
+ .HalfwayDataReg(1'b1),
+ // No key register is needed half way, since the data_key_i and operation op_type_i inputs
+ // remain constant until one data block has been processed.
+ .HalfwayKeyReg (1'b0)
) u_cipher (
.clk_i,
.rst_ni,
diff --git a/hw/ip/prim/dv/prim_prince/crypto_dpi_prince/prince_ref.h b/hw/ip/prim/dv/prim_prince/crypto_dpi_prince/prince_ref.h
index 76110c4..bd99e3a 100644
--- a/hw/ip/prim/dv/prim_prince/crypto_dpi_prince/prince_ref.h
+++ b/hw/ip/prim/dv/prim_prince/crypto_dpi_prince/prince_ref.h
@@ -229,12 +229,10 @@
/**
* The core function of the Prince cipher.
*/
-static uint64_t prince_core(const uint64_t core_input, const uint64_t k0,
- const uint64_t k1, int num_half_rounds,
- int old_key_schedule) {
+static uint64_t prince_core(const uint64_t core_input, const uint64_t k0_new,
+ const uint64_t k1, int num_half_rounds) {
PRINCE_PRINT(core_input);
PRINCE_PRINT(k1);
- uint64_t k0_new = (old_key_schedule) ? k1 : k0;
uint64_t round_input = core_input ^ k1 ^ prince_round_constant(0);
for (unsigned int round = 1; round <= num_half_rounds; round++) {
PRINCE_PRINT(round_input);
@@ -257,7 +255,7 @@
PRINCE_PRINT(round_input);
const uint64_t constant_idx = 10 - num_half_rounds + round;
const uint64_t m_inv_in =
- (round % 2 == 1)
+ ((num_half_rounds + round + 1) % 2 == 1)
? round_input ^ k0_new ^ prince_round_constant(constant_idx)
: round_input ^ k1 ^ prince_round_constant(constant_idx);
PRINCE_PRINT(m_inv_in);
@@ -282,6 +280,8 @@
int num_half_rounds, int old_key_schedule) {
const uint64_t prince_alpha = UINT64_C(0xc0ac29b7c97c50dd);
const uint64_t k1 = enc_k1 ^ (decrypt ? prince_alpha : 0);
+ const uint64_t k0_new =
+ (old_key_schedule) ? k1 : enc_k0 ^ (decrypt ? prince_alpha : 0);
const uint64_t enc_k0_prime = prince_k0_to_k0_prime(enc_k0);
const uint64_t k0 = decrypt ? enc_k0_prime : enc_k0;
const uint64_t k0_prime = decrypt ? enc_k0 : enc_k0_prime;
@@ -289,7 +289,7 @@
PRINCE_PRINT(input);
const uint64_t core_input = input ^ k0;
const uint64_t core_output =
- prince_core(core_input, k0, k1, num_half_rounds, old_key_schedule);
+ prince_core(core_input, k0_new, k1, num_half_rounds);
const uint64_t output = core_output ^ k0_prime;
PRINCE_PRINT(k0_prime);
PRINCE_PRINT(output);
diff --git a/hw/ip/prim/rtl/prim_prince.sv b/hw/ip/prim/rtl/prim_prince.sv
index 705e769..b8744a7 100644
--- a/hw/ip/prim/rtl/prim_prince.sv
+++ b/hw/ip/prim/rtl/prim_prince.sv
@@ -65,10 +65,18 @@
end
if (UseOldKeySched) begin : gen_legacy_keyschedule
+ // In this case we constantly use k1.
assign k0_new_d = k1_d;
end else begin : gen_new_keyschedule
- // improved keyschedule proposed by https://eprint.iacr.org/2014/656.pdf
- assign k0_new_d = k0;
+ // Imroved keyschedule proposed by https://eprint.iacr.org/2014/656.pdf
+ // In this case we alternate between k1 and k0.
+ always_comb begin : p_new_keyschedule_k0_alpha
+ k0_new_d = key_i[DataWidth-1:0];
+ // We need to apply the alpha constant here as well, just as for k1 in decryption mode.
+ if (dec_i) begin
+ k0_new_d ^= prim_cipher_pkg::PRINCE_ALPHA_CONST[DataWidth-1:0];
+ end
+ end
end
if (HalfwayKeyReg) begin : gen_key_reg
@@ -130,8 +138,11 @@
assign data_state_xor = data_state_round ^
prim_cipher_pkg::PRINCE_ROUND_CONST[k][DataWidth-1:0];
// improved keyschedule proposed by https://eprint.iacr.org/2014/656.pdf
- if (k % 2 == 1) assign data_state[k] = data_state_xor ^ k0_new_d;
- else assign data_state[k] = data_state_xor ^ k1_d;
+ if (k % 2 == 1) begin : gen_fwd_key_odd
+ assign data_state[k] = data_state_xor ^ k0_new_d;
+ end else begin : gen_fwd_key_even
+ assign data_state[k] = data_state_xor ^ k1_d;
+ end
end
// middle part
@@ -180,8 +191,11 @@
for (genvar k = 1; k <= NumRoundsHalf; k++) begin : gen_bwd_pass
logic [DataWidth-1:0] data_state_xor0, data_state_xor1;
// improved keyschedule proposed by https://eprint.iacr.org/2014/656.pdf
- if (k % 2 == 1) assign data_state_xor0 = data_state[NumRoundsHalf+k] ^ k0_new_q;
- else assign data_state_xor0 = data_state[NumRoundsHalf+k] ^ k1_q;
+ if ((NumRoundsHalf + k + 1) % 2 == 1) begin : gen_bkwd_key_odd
+ assign data_state_xor0 = data_state[NumRoundsHalf+k] ^ k0_new_q;
+ end else begin : gen_bkwd_key_even
+ assign data_state_xor0 = data_state[NumRoundsHalf+k] ^ k1_q;
+ end
// the construction is reflective, hence the subtraction with NumRoundsHalf
assign data_state_xor1 = data_state_xor0 ^
prim_cipher_pkg::PRINCE_ROUND_CONST[10-NumRoundsHalf+k][DataWidth-1:0];