[kmac] Randomly advance the PRNG if its output not used
This commit adds some logic to randomly advance the PRNG in clock
cycles where it's output is not used. This has two advantages:
- The 800-bit wide PRNG can serve as an integrated noise source.
- As KMAC outputs the state in 2 shares it would theoretically be
be possible (although difficult) to predict the PRNG state and exploit
that for attacks. By randomizing how many times the PRNG is updated
we can further aggravate such attacks.
Signed-off-by: Pirmin Vogel <vogelpi@lowrisc.org>
diff --git a/hw/ip/kmac/rtl/kmac_entropy.sv b/hw/ip/kmac/rtl/kmac_entropy.sv
index 1ac5442..c5c307a 100644
--- a/hw/ip/kmac/rtl/kmac_entropy.sv
+++ b/hw/ip/kmac/rtl/kmac_entropy.sv
@@ -203,6 +203,10 @@
logic aux_rand_d, aux_rand_q;
logic aux_update;
+ // Randomness for controlling PRNG updates. This only matters for clock cycles
+ // where the PRNG output is not actually used.
+ logic [3:0] lfsr_en_rand_d, lfsr_en_rand_q;
+
// Entropy valid signal
// FSM set and clear the valid signal, rand_consume signal clear the valid
// signal. Split the set, clear to make entropy valid while FSM is processing
@@ -443,6 +447,21 @@
// Auxiliary randomness -----------------------------------------------------
+ // LFSR enable randomness ===================================================
+ assign lfsr_en_rand_d =
+ aux_update ? lfsr_data_permuted[EntropyLfsrW - 2 -: 4] : // refresh
+ {1'b0, lfsr_en_rand_q[3:1]}; // shift out
+
+ always_ff @(posedge clk_i or negedge rst_ni) begin
+ if (!rst_ni) begin
+ lfsr_en_rand_q <= '0;
+ end else begin
+ lfsr_en_rand_q <= lfsr_en_rand_d;
+ end
+ end
+
+ // LFSR enable randomness ---------------------------------------------------
+
// Randomness outputs =======================================================
assign rand_data_o = lfsr_data_permuted;
assign rand_aux_o = aux_rand_q;
@@ -561,6 +580,8 @@
StRandReady: begin
timer_enable = 1'b 1; // If limit is zero, timer won't work
+ lfsr_en = lfsr_en_rand_q[0];
+
if (rand_consumed_i &&
((fast_process_i && in_keyblock_i) || !fast_process_i)) begin
// If fast_process is set, don't clear the rand valid, even