6969// latency = 16 to first result, 23 to last (+1 output register cycle).
7070// Rejection sampling may insert extra input cycles and decrease throughput.
7171//
72- // Rejection sampling (BoolToArith only):
72+ // Rejection sampling (EnRejSampling=1, BoolToArith only):
7373// wready_o is deasserted whenever mask_mod >= mod_i. The caller must hold wvalid_i high until
74- // wready_o rises. Assert sec_wipe_running_i for SCA analysis to avoid trace misalignment.
74+ // wready_o rises. Set EnRejSampling=0 or keep sec_wipe_running_i asserted for SCA analysis to
75+ // avoid trace misalignment.
7576//
7677// Interface:
7778// wvalid_i / wready_o : Input handshake following the 'valid locked-in' principle: once wvalid_i
9192// remask_rand_i : Fresh per-handshake randomness for input re-masking.
9293// sec_wipe_running_i : When asserted, disables rejection sampling so that a wipe can make
9394// forward progress regardless of mask_mod. Has no effect when
94- // Assert for SCA analysis to avoid trace misalignment .
95+ // EnRejSampling=0 .
9596//
9697// Security verification: see hw/ip/otbn/pre_sca for PROLEAD and Alma setups.
9798//
103104module otbn_mask_accelerator
104105 import otbn_pkg:: * ;
105106# (
106- localparam int RandWidth = SecAddRandWidth (SecAddWidth)
107+ localparam int RandWidth = SecAddRandWidth (SecAddWidth),
108+ parameter bit EnRejSampling = 1
107109) (
108110 input logic clk_i,
109111 input logic rst_ni,
@@ -163,6 +165,10 @@ module otbn_mask_accelerator
163165 ma_sharing_t direct_inp1_q;
164166 ma_sharing_t direct_inp2_q;
165167
168+ logic is_b2a;
169+ logic [2 * SecAddWidth- 1 : 0 ] inp2_mux_in [2 ];
170+ logic [2 * SecAddWidth- 1 : 0 ] inp2_mux_out;
171+
166172 // Adder interface: inputs, control, outputs.
167173 ma_sharing_t adder_inp1;
168174 ma_sharing_t adder_inp2;
@@ -271,7 +277,24 @@ module otbn_mask_accelerator
271277 // The register breaks the combinational path to the adder.
272278 // inp1 is always in0_i.
273279 // inp2 is mode-selected between B2A's pre-computed value and the raw in1_i.
274- assign direct_inp2_pre = (mask_op_i == BoolToArith) ? b2a_inp2_pre : in1_i;
280+
281+ // prim_onehot_mux is required here: without it, synthesis merges randomness into the mux
282+ // control signal, which causes SCA verification tools to crash.
283+ assign is_b2a = (mask_op_i == BoolToArith);
284+ assign inp2_mux_in[0 ] = (2 * SecAddWidth)'(b2a_inp2_pre);
285+ assign inp2_mux_in[1 ] = (2 * SecAddWidth)'(in1_i);
286+ assign direct_inp2_pre = ma_sharing_t ' (inp2_mux_out);
287+
288+ prim_onehot_mux # (
289+ .Width (2 * SecAddWidth),
290+ .Inputs (2 )
291+ ) u_direct_inp2_pre_mux (
292+ .clk_i,
293+ .rst_ni,
294+ .in_i (inp2_mux_in),
295+ .sel_i ({~ is_b2a, is_b2a} ),
296+ .out_o (inp2_mux_out)
297+ );
275298
276299 prim_blanker # (
277300 .Width (NumShares* SecAddWidth)
@@ -349,7 +372,7 @@ module otbn_mask_accelerator
349372 .clk_i,
350373 .rst_ni,
351374 .clr_i (1'b0 ),
352- .wvalid_i (inp_valid && (mask_op_i == BoolToArith) ),
375+ .wvalid_i (inp_valid && is_b2a ),
353376 .wready_o (fifo_wready),
354377 .wdata_i (mask_mod),
355378 .rvalid_o (),
@@ -368,7 +391,7 @@ module otbn_mask_accelerator
368391 .Width (NumShares* SecAddWidth)
369392 ) u_prim_blanker_result (
370393 .in_i ({ adder_result[0 ] & mod_smear_mask, adder_result[1 ] & mod_smear_mask} ),
371- .en_i ((mask_op_i == BoolToArith) && adder_rvalid),
394+ .en_i (is_b2a && adder_rvalid),
372395 .out_o (result_b2a)
373396 );
374397
@@ -383,7 +406,7 @@ module otbn_mask_accelerator
383406 );
384407
385408 // Mode-gated: prevents spurious FIFO pops in non-B2A modes.
386- assign rvalid_b2a_d = adder_rvalid && (mask_op_i == BoolToArith) ;
409+ assign rvalid_b2a_d = adder_rvalid && is_b2a ;
387410
388411 always_ff @ (posedge clk_i or negedge rst_ni) begin : proc_rvalid_b2a
389412 if (! rst_ni) begin
@@ -399,7 +422,7 @@ module otbn_mask_accelerator
399422 inp_ready = adder_wready && ! adder_batch_complete;
400423 result_o = adder_result;
401424 rvalid_o = adder_rvalid;
402- if (mask_op_i == BoolToArith ) begin
425+ if (is_b2a ) begin
403426 // B2A mode.
404427 inp_ready = fifo_wready && adder_wready && ! adder_batch_complete;
405428 // result_o[0] = m (arithmetic mask, popped from the FIFO)
@@ -413,8 +436,14 @@ module otbn_mask_accelerator
413436 assign wready = inp_ready;
414437 // sec_wipe_running_i disables rejection sampling so that a wipe can always make forward
415438 // progress regardless of mask_mod.
416- assign wready_o = (mask_op_i == BoolToArith && ! sec_wipe_running_i) ?
417- (mask_mod < mod_i) && wready : wready;
439+ if (EnRejSampling) begin : gen_rej_sampling
440+ assign wready_o = (mask_op_i == BoolToArith && ! sec_wipe_running_i) ?
441+ (mask_mod < mod_i) && wready : wready;
442+ end else begin : gen_no_rej_sampling
443+ logic unused_sec_wipe;
444+ assign unused_sec_wipe = sec_wipe_running_i;
445+ assign wready_o = wready;
446+ end
418447
419448`ifdef INC_ASSERT
420449 // High from the first wvalid_i of a batch until adder_batch_complete fires (all VecSize
0 commit comments