Skip to content

Commit 697c06a

Browse files
etterlivogelpi
authored andcommitted
[otbn,rtl] Harden acc_qw_sel in bignum MAC against FI attack
This commits predecodes the acc_qw_sel signal to avoid a tricky SW mitigation against FI attacks, see detailed problem description below. It is predecoded by refactoring it into a 4 bit signal which controls the MUXing of the ACC merging for each quad word (64 bits) separately. The problem when acc_qw_sel is not predecoded: The acc_qw_sel signal controls which quarter word of the ACC is overwritten with multiplication results during a vectorized multiplication. These instructions process 64 bits at a time and thus have 4 updates to the ACC WSR. This signal did not have a redundand signal. Therefore, an attack on this signal is an issue for the bn.mulv(m) instructions because: 1) A stuck at fault is induced into the bits such that acc_qw_sel = '0. Yes this requires in theory two attacks as acc_qw_sel is 2 bit wide. But I think it is reasonable that both gates can be FIed with only one attack as the signals are quite related. A multiplication thus will write all 4 results into the same QW of ACC. The other 3 QW keep the original value. This allows that QW0 has the wrong result and the other 3 QW have a deterministic value (the value before the instruction). This could be bad, especially if we perform a multiplication where not all vector elements contain actual data. If only, e.g., 7 out of 8 elements contain data and element 8 is all-zero, this would allow to set a QW to zero (a deterministic value). A SW solution solving this would be to ensure that the ACC register is cleared with a random value before executing a instruction. This is actually supported as the bn.mulv(m) instructions clear ACC in their last cycle and the ACC could also be cleared by using a bn.wsrw instruction. However, with this mitigation we would still not directly detect the attack (we would only have a wrong result). The same randomization would also be needed for unused input vector elements. This adds considerable burdens to the programmer and is also a great source of vulnerabilities. 2) The acc_qw_sel signal is faulted transiently. In this case only one result is written to the wrong QW and therefore one QW would keep its value. Otherwise there are the same problems and the same SW solution could be used. As the SW solution is cumbersome and easy to do wrong, this commit predecodes the acc_qw_sel signal by refactoring it to a single bit MUX per QW. Signed-off-by: Pascal Etterli <pascal.etterli@lowrisc.org>
1 parent 856b98b commit 697c06a

File tree

5 files changed

+39
-34
lines changed

5 files changed

+39
-34
lines changed

hw/ip/otbn/rtl/otbn_instruction_fetch.sv

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ module otbn_instruction_fetch
202202
mac_bignum_predec_to_fsm.mul_add_en,
203203
mac_bignum_predec_to_fsm.c_add_en,
204204
mac_bignum_predec_to_fsm.add_mod_en,
205+
mac_bignum_predec_to_fsm.acc_qw_sel,
205206
mac_bignum_predec_to_fsm.acc_merger_en,
206207
mac_bignum_predec_to_fsm.mul_shift_en,
207208
mac_bignum_predec_to_fsm.mul_merger_en,

hw/ip/otbn/rtl/otbn_mac_bignum.sv

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -505,7 +505,6 @@ module otbn_mac_bignum
505505
///////////////////////////////////////////
506506
// ACC merging for vectorized operations //
507507
///////////////////////////////////////////
508-
logic [1:0] acc_qw_sel;
509508
logic [QWLEN-1:0] acc_new_qw;
510509
logic [WLEN-1:0] acc_blanked;
511510
logic [WLEN-1:0] acc_merged;
@@ -526,14 +525,10 @@ module otbn_mac_bignum
526525
);
527526

528527
// Place the computed 64-bit chunk at the desired location in the ACC register.
529-
assign acc_merged[0*QWLEN+:QWLEN] = (acc_qw_sel == 2'd0) ? acc_new_qw :
530-
acc_blanked[0*QWLEN+:QWLEN];
531-
assign acc_merged[1*QWLEN+:QWLEN] = (acc_qw_sel == 2'd1) ? acc_new_qw :
532-
acc_blanked[1*QWLEN+:QWLEN];
533-
assign acc_merged[2*QWLEN+:QWLEN] = (acc_qw_sel == 2'd2) ? acc_new_qw :
534-
acc_blanked[2*QWLEN+:QWLEN];
535-
assign acc_merged[3*QWLEN+:QWLEN] = (acc_qw_sel == 2'd3) ? acc_new_qw :
536-
acc_blanked[3*QWLEN+:QWLEN];
528+
for (genvar qw = 0; qw < VLEN/QWLEN; qw++) begin : gen_acc_merged
529+
assign acc_merged[qw * QWLEN +: QWLEN] = predec_i.acc_qw_sel[qw] ?
530+
acc_new_qw : acc_blanked[qw * QWLEN +: QWLEN];
531+
end
537532

538533
//////////////////////////////////////////////////////
539534
// Adder result handling for regular multiplication //
@@ -687,7 +682,6 @@ module otbn_mac_bignum
687682
assign tmp_clear_en = contrl.tmp_clear_en;
688683
assign c_wr_en_raw = contrl.c_wr_en_raw;
689684
assign c_clear_en = contrl.c_clear_en;
690-
assign acc_qw_sel = contrl.acc_qw_sel;
691685
assign acc_wr_en_raw = contrl.acc_wr_en_raw;
692686
assign acc_clear_en = contrl.acc_clear_en;
693687

@@ -745,4 +739,10 @@ module otbn_mac_bignum
745739
assign sec_wipe_err_o = sec_wipe_urnd_i & ~sec_wipe_running_i;
746740

747741
`ASSERT(NoISPRAccWrAndMacEn, ~(ispr_acc_wr_en_i & mac_en_i))
742+
743+
// Only one QWORD must be overwritten at the same time.
744+
`ASSERT(AccQwSelOnehot_A,
745+
predec_i.acc_merger_en |-> $onehot(predec_i.acc_qw_sel),
746+
clk_i, !rst_ni || predec_error_o || state_err_o)
747+
748748
endmodule

hw/ip/otbn/rtl/otbn_mac_bignum_fsm.sv

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ module otbn_mac_bignum_fsm
6060
* | op_a_qw_sel | 0 | 1 | 2 | 3 | yes |
6161
* | op_b_elem0_sel | 0 | 2 | 4 | 6 | yes |
6262
* | op_b_elem1_sel | 1 | 3 | 5 | 7 | yes |
63-
* | acc_qw_sel | 0 | 1 | 2 | 3 | no |
63+
* | acc_qw_sel | 0 | 1 | 2 | 3 | yes |
6464
* | acc_wr_en_raw | 1 | 1 | 1 | 0 | no |
6565
* | acc_clear_en | 0 | 0 | 0 | 1 | no |
6666
* | acc_merger_en | 1 | 1 | 1 | 1 | yes |
@@ -86,7 +86,7 @@ module otbn_mac_bignum_fsm
8686
* | tmp_clear_en | 0 | 0 | 1 || 0 | 0 | 1 || || | 1 | no |
8787
* | c_wr_en_raw | 1 | 0 | 0 || 1 | 0 | 0 || || | 0 | no |
8888
* | c_clear_en | 0 | 0 | 1 || 0 | 0 | 1 || || | 1 | no |
89-
* | acc_qw_sel | 0 | 0 | 0 || 1 | 1 | 1 || || | 3 | no |
89+
* | acc_qw_sel | 0 | 0 | 0 || 1 | 1 | 1 || || | 3 | yes |
9090
* | acc_wr_en_raw | 0 | 0 | 1 || 0 | 0 | 1 || || | 0 | no |
9191
* | acc_clear_en | 0 | 0 | 0 || 0 | 0 | 0 || || | 1 | no |
9292
* | mul_add_en | 0 | 0 | 1 || 0 | 0 | 1 || || | 1 | yes |
@@ -115,19 +115,20 @@ module otbn_mac_bignum_fsm
115115
localparam mac_bignum_contrl_t ControlDefault = '0;
116116

117117
typedef struct packed {
118-
logic [1:0] op_a_qw_sel;
119-
logic [2:0] op_b_elem0_sel;
120-
logic [2:0] op_b_elem1_sel;
121-
logic mul_op_a_tmp_sel;
122-
mac_mul_op_b_sel_e mul_op_b_sel;
123-
logic mul_add_en;
124-
logic c_add_en;
125-
logic add_mod_en;
126-
logic acc_merger_en;
127-
logic mul_shift_en;
128-
logic mul_merger_en;
129-
logic add_res_en;
130-
logic operation_valid_raw;
118+
logic [1:0] op_a_qw_sel;
119+
logic [2:0] op_b_elem0_sel;
120+
logic [2:0] op_b_elem1_sel;
121+
logic mul_op_a_tmp_sel;
122+
mac_mul_op_b_sel_e mul_op_b_sel;
123+
logic mul_add_en;
124+
logic c_add_en;
125+
logic add_mod_en;
126+
logic [VLEN/QWLEN-1:0] acc_qw_sel;
127+
logic acc_merger_en;
128+
logic mul_shift_en;
129+
logic mul_merger_en;
130+
logic add_res_en;
131+
logic operation_valid_raw;
131132
} mac_bignum_predec_dyn_t;
132133

133134
localparam mac_bignum_predec_dyn_t PredecDynDefault = '{
@@ -139,6 +140,7 @@ module otbn_mac_bignum_fsm
139140
mul_add_en: 1'b0,
140141
c_add_en: 1'b0,
141142
add_mod_en: 1'b0,
143+
acc_qw_sel: '0,
142144
acc_merger_en: 1'b0,
143145
mul_shift_en: 1'b0,
144146
mul_merger_en: 1'b0,
@@ -174,11 +176,11 @@ module otbn_mac_bignum_fsm
174176
predec_vec = '{default: PredecDynDefault};
175177

176178
for (int unsigned cycle = 0; cycle < LatencyVec; cycle++) begin
177-
contrl_vec[cycle].acc_qw_sel = 2'(cycle);
178179
contrl_vec[cycle].acc_wr_en_raw = 1'b1;
179180
predec_vec[cycle].op_a_qw_sel = 2'(cycle);
180181
predec_vec[cycle].op_b_elem0_sel = 3'(2 * cycle);
181182
predec_vec[cycle].op_b_elem1_sel = 3'(2 * cycle + 1);
183+
predec_vec[cycle].acc_qw_sel = (VLEN/QWLEN)'(unsigned'(1) << cycle);
182184
predec_vec[cycle].acc_merger_en = 1'b1;
183185
end
184186

@@ -223,11 +225,11 @@ module otbn_mac_bignum_fsm
223225
// Construct the 4 * 3 = 12 cycles and set the correct qword selection
224226
for (int unsigned cycle = 0; cycle < LatencyMod; cycle++) begin
225227
contrl_mod[cycle] = contrl_mod_mul[cycle % LatencyMontgMul];
226-
contrl_mod[cycle].acc_qw_sel = 2'(cycle / LatencyMontgMul);
227228
predec_mod[cycle] = predec_mod_mul[cycle % LatencyMontgMul];
228229
predec_mod[cycle].op_a_qw_sel = 2'(cycle / LatencyMontgMul);
229230
predec_mod[cycle].op_b_elem0_sel = 3'(2 * (cycle / LatencyMontgMul));
230231
predec_mod[cycle].op_b_elem1_sel = 3'(2 * (cycle / LatencyMontgMul) + 1);
232+
predec_mod[cycle].acc_qw_sel = (VLEN/QWLEN)'(unsigned'(1)) << (cycle / LatencyMontgMul);
231233
end
232234

233235
// Clear ACC in the last cycle with randomness
@@ -325,6 +327,7 @@ module otbn_mac_bignum_fsm
325327
mul_add_en: predec_dyn.mul_add_en,
326328
c_add_en: predec_dyn.c_add_en,
327329
add_mod_en: predec_dyn.add_mod_en,
330+
acc_qw_sel: predec_dyn.acc_qw_sel,
328331
acc_merger_en: predec_dyn.acc_merger_en,
329332
mul_shift_en: predec_dyn.mul_shift_en,
330333
mul_merger_en: predec_dyn.mul_merger_en,

hw/ip/otbn/rtl/otbn_pkg.sv

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -616,6 +616,7 @@ package otbn_pkg;
616616
logic mul_add_en;
617617
logic c_add_en;
618618
logic add_mod_en;
619+
logic [VLEN/QWLEN-1:0] acc_qw_sel;
619620
logic acc_merger_en;
620621
logic mul_shift_en;
621622
logic mul_merger_en;
@@ -624,13 +625,12 @@ package otbn_pkg;
624625
} mac_bignum_predec_t;
625626

626627
typedef struct packed {
627-
logic tmp_wr_en_raw;
628-
logic tmp_clear_en;
629-
logic c_wr_en_raw;
630-
logic c_clear_en;
631-
logic [1:0] acc_qw_sel;
632-
logic acc_wr_en_raw;
633-
logic acc_clear_en;
628+
logic tmp_wr_en_raw;
629+
logic tmp_clear_en;
630+
logic c_wr_en_raw;
631+
logic c_clear_en;
632+
logic acc_wr_en_raw;
633+
logic acc_clear_en;
634634
} mac_bignum_contrl_t;
635635

636636
typedef struct packed {

hw/ip/otbn/rtl/otbn_predecode.sv

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -832,6 +832,7 @@ module otbn_predecode
832832
assign mac_bignum_predec_raw_o.mul_add_en = '0;
833833
assign mac_bignum_predec_raw_o.c_add_en = '0;
834834
assign mac_bignum_predec_raw_o.add_mod_en = '0;
835+
assign mac_bignum_predec_raw_o.acc_qw_sel = '0;
835836
assign mac_bignum_predec_raw_o.acc_merger_en = '0;
836837
assign mac_bignum_predec_raw_o.mul_shift_en = '0;
837838
assign mac_bignum_predec_raw_o.mul_merger_en = '0;

0 commit comments

Comments
 (0)