feat(enc): Encaps E3 - y_hat = NTT(y) in place

ST_ENC_N reuses the ST_N forward-NTT datapath (mode=0, read-ahead load,
in-place writeback to bank_se). Slot count parameterized: KeyGen 2K (s,e),
Encaps K (y only; e1/e2 stay time-domain) via n_slot_max. bse rd/wr muxes
and the C->N arming extended for ST_ENC_N.

Verified (K=2 c0) y_hat[0..1] == ml-kem-r golden; E0/E1/E2 still pass
(E2 y check dropped since NTT overwrites y in place -> covered by E3);
K=3/4 run through E3 without timeout.
This commit is contained in:
2026-06-29 02:01:37 +08:00
parent cdc5ce25b1
commit 8ed4d59546
2 changed files with 44 additions and 23 deletions

View File

@@ -99,6 +99,7 @@ module tb_mlkem_enc_katK_xsim;
if (KP == 2 && casenum == 0) begin
verify_e1;
verify_e2;
verify_e3;
end
$finish;
end
@@ -134,19 +135,18 @@ module tb_mlkem_enc_katK_xsim;
// e2 lives in bank_t rel slot 0 -> dbg slot = slot_t_rt = 8.
task verify_e2;
begin
$readmemh("sync_rtl/top/TB/vectors/encgold/ec_k2_c0_y_0.hex", gy, 0, 255);
$readmemh("sync_rtl/top/TB/vectors/encgold/ec_k2_c0_y_1.hex", gy, 256, 511);
$readmemh("sync_rtl/top/TB/vectors/encgold/ec_k2_c0_e1_0.hex", gy, 512, 767);
$readmemh("sync_rtl/top/TB/vectors/encgold/ec_k2_c0_e1_1.hex", gy, 768, 1023);
$readmemh("sync_rtl/top/TB/vectors/encgold/ec_k2_c0_e2.hex", ge2);
ce = 0;
// y0,y1,e1_0,e1_1 at bank_se dbg slots 4..7
for (slot = 0; slot < 4; slot = slot + 1)
// e1_0,e1_1 at bank_se dbg slots 6,7 (time-domain, untouched by NTT).
// (y at slots 4,5 is overwritten in place by y_hat -> checked in E3.)
for (slot = 2; slot < 4; slot = slot + 1)
for (idx = 0; idx < 256; idx = idx + 1) begin
dbg_slot_i = (4+slot); dbg_idx_i = idx[7:0];
@(posedge clk); @(posedge clk); @(posedge clk);
if (dbg_coeff_o !== gy[slot*256+idx]) begin
if (ce < 8) $display(" Y[s%0d,%0d] got=%03x exp=%03x", slot, idx, dbg_coeff_o, gy[slot*256+idx]);
if (ce < 8) $display(" E1[s%0d,%0d] got=%03x exp=%03x", slot-2, idx, dbg_coeff_o, gy[slot*256+idx]);
ce = ce + 1;
end
end
@@ -159,9 +159,29 @@ module tb_mlkem_enc_katK_xsim;
ce = ce + 1;
end
end
if (ce == 0) $display("K=2 CASE 0 PASS (E2): y[0..1],e1[0..1],e2 == ml-kem-r golden");
if (ce == 0) $display("K=2 CASE 0 PASS (E2): e1[0..1],e2 == ml-kem-r golden");
else $display("K=2 CASE 0 FAIL (E2): %0d coeff mismatches", ce);
end
endtask
// y_hat[i] = NTT(y[i]) in place at bank_se rel slots 0..K-1 -> dbg slots 4..5 (K=2).
reg [11:0] gyh [0:2*256-1];
task verify_e3;
begin
$readmemh("sync_rtl/top/TB/vectors/encgold/ec_k2_c0_yhat_0.hex", gyh, 0, 255);
$readmemh("sync_rtl/top/TB/vectors/encgold/ec_k2_c0_yhat_1.hex", gyh, 256, 511);
ce = 0;
for (slot = 0; slot < 2; slot = slot + 1)
for (idx = 0; idx < 256; idx = idx + 1) begin
dbg_slot_i = (4+slot); dbg_idx_i = idx[7:0];
@(posedge clk); @(posedge clk); @(posedge clk);
if (dbg_coeff_o !== gyh[slot*256+idx]) begin
if (ce < 8) $display(" YH[s%0d,%0d] got=%03x exp=%03x", slot, idx, dbg_coeff_o, gyh[slot*256+idx]);
ce = ce + 1;
end
end
if (ce == 0) $display("K=2 CASE 0 PASS (E3): y_hat[0..1] == ml-kem-r golden");
else $display("K=2 CASE 0 FAIL (E3): %0d coeff mismatches", ce);
end
endtask
initial begin #120000000; $display("FAIL: global timeout"); $finish; end
endmodule