fix(sample_ntt): suppress spurious 257th valid_o after last_o
Phase-1 (d1 output) lacked the 'need_more' guard that phase-2 (d2) had, so when the 256th accepted coefficient was a d1 whose group then advanced, the FSM could fire one extra valid_o after last_o for certain seeds (e.g. KAT count=0 rho, seed i=0/j=1 emitted 257 pulses). In mlkem_top KeyGen this trailing pulse leaked into the next poly's index 0, shifting the stream. Fix: gate phase-1 d1 output with 'd1_acc_r && need_more' (mirrors phase-2). Applied to both sample_ntt_sync and sample_ntt_sync_shared. Standalone TB had a coverage blind spot (stopped reading at 256, never checked valid_o stayed low after last_o). Added a regression assertion: counts spurious post-last_o pulses and fails if any. Verified the assertion catches the bug on a reverted-fix copy (3 spurious) and passes on the fix. Verified: - 40-seed audit (sync) + 24-seed audit (shared): all exactly 256 pulses, last_o@256, zero post-last pulses. - Verilator vs hashlib oracle: 1536/1536 (no real coeff dropped). - Full framework regression: 4334/4334. - mlkem_top KeyGen Stage 2c: 2048/2048 A_hat+s+e coeffs exact.
This commit is contained in:
@@ -334,7 +334,7 @@ module sample_ntt_sync #(parameter K = 4) (
|
||||
|
||||
// ----- Phase 1: output d1 -----
|
||||
2'd1: begin
|
||||
if (d1_acc_r) begin
|
||||
if (d1_acc_r && need_more) begin
|
||||
if (!valid_o_r) begin
|
||||
// First cycle: assert output
|
||||
coeff_o_r <= d1_r;
|
||||
@@ -349,7 +349,7 @@ module sample_ntt_sync #(parameter K = 4) (
|
||||
end
|
||||
end
|
||||
end else begin
|
||||
// d1 rejected, skip to phase 2
|
||||
// d1 rejected or no longer needed: skip to phase 2
|
||||
valid_o_r <= 1'b0;
|
||||
sq_phase_r <= 2'd2;
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user