feat(dec): Decaps D2 - s_hat=byteDecode12(dk_pke) + u_hat=NTT(u')
K-PKE.Decrypt steps 2-3 (FIPS 203 Alg 15), both by reusing Encaps machines: - ST_DEC_SDEC reuses the Encaps TDEC (byteDecode12) machine: only the byte source changes (td_byte mux -> dkp_rd_data; dkp_rd_addr driven by td_ekaddr in SDEC). Decodes dk_pke -> s_hat[j] into bank_a slot j*K, the same layout t_hat uses, so the D3 MAC can read s_hat[j] with the existing addressing. - ST_DEC_NTT reuses the forward-NTT machine (n_slot_max=k_r) to transform u'[i] in place in bank_se rel slots 0..K-1 -> u_hat[i]. Added ST_DEC_NTT to the bank_se read/write muxes and the NTT load/process/arm blocks alongside ST_N/ST_ENC_N. - FSM: DECOMP -> SDEC -> NTT -> DONE. TB verify_d2 checks s_hat[i] (bank_a slot i*K) and u_hat[i] (bank_se rel i) against golden. verify_d1 narrowed to v' only: D2's in-place NTT overwrites u' in bank_se, so u' correctness is now proven transitively via u_hat==NTT(u'). Verified: dec D2 K=2/3/4 all cases PASS; KeyGen + Encaps unregressed.
This commit is contained in:
@@ -88,12 +88,13 @@ module tb_mlkem_dec_katK_xsim;
|
||||
start_i=1; @(posedge clk); start_i=0;
|
||||
c=0; while(!done_o && c<2000000) begin @(posedge clk); c=c+1; end
|
||||
if(!done_o) begin $display("FAIL K=%0d case %0d: timeout", KP, casenum); $finish; end
|
||||
$display("=== Decaps D1 done in %0d cyc ===", c);
|
||||
$display("=== Decaps D2 done in %0d cyc ===", c);
|
||||
|
||||
verify_d0;
|
||||
verify_d1;
|
||||
if (errors == 0) $display("K=%0d CASE %0d PASS (D1): u'/v' decode-decompress OK", KP, casenum);
|
||||
else $display("K=%0d CASE %0d FAIL (D1): %0d total errors", KP, casenum, errors);
|
||||
verify_d2;
|
||||
if (errors == 0) $display("K=%0d CASE %0d PASS (D2): s_hat + u_hat=NTT(u') OK", KP, casenum);
|
||||
else $display("K=%0d CASE %0d FAIL (D2): %0d total errors", KP, casenum, errors);
|
||||
$finish;
|
||||
end
|
||||
|
||||
@@ -174,22 +175,10 @@ module tb_mlkem_dec_katK_xsim;
|
||||
reg [11:0] got;
|
||||
begin
|
||||
ndiff = 0;
|
||||
// u'[i]
|
||||
for (i = 0; i < KP; i = i + 1) begin
|
||||
$sformat(fn, "sync_rtl/top/TB/vectors/decgold/dc_k%0d_c%0d_up_%0d.hex", KP, casenum, i);
|
||||
$readmemh(fn, up_g);
|
||||
be = 0;
|
||||
for (j = 0; j < 256; j = j + 1) begin
|
||||
rdcoeff(KP*KP + i, j[7:0], got);
|
||||
if (got !== up_g[j]) begin
|
||||
if (be < 4) $display(" u'[%0d][%0d] got=%03x exp=%03x", i, j, got, up_g[j]);
|
||||
be = be + 1;
|
||||
end
|
||||
end
|
||||
if (be == 0) $display(" PASS: u'[%0d] == golden (256 coeffs)", i);
|
||||
else $display(" FAIL: u'[%0d] %0d coeff mismatches", i, be);
|
||||
ndiff = ndiff + be;
|
||||
end
|
||||
// u'[i] is NOT checked here: D2's forward NTT transforms u' in place
|
||||
// in bank_se rel 0..K-1, so by the time the run finishes those slots
|
||||
// hold u_hat. u' correctness is proven transitively in verify_d2
|
||||
// (u_hat == NTT(u') golden). Only v' (bank_t, untouched) is checked.
|
||||
// v'
|
||||
$sformat(fn, "sync_rtl/top/TB/vectors/decgold/dc_k%0d_c%0d_vp.hex", KP, casenum);
|
||||
$readmemh(fn, vp_g);
|
||||
@@ -207,4 +196,48 @@ module tb_mlkem_dec_katK_xsim;
|
||||
errors = errors + ndiff;
|
||||
end
|
||||
endtask
|
||||
|
||||
// D2: verify s_hat[i] (bank_a slot i*K, byteDecode12 dk_pke) and
|
||||
// u_hat[i] (bank_se rel slot i, = NTT(u'[i])) against golden.
|
||||
reg [11:0] sh_g [0:255];
|
||||
reg [11:0] uh_g [0:255];
|
||||
task verify_d2;
|
||||
integer i, j, be, ndiff;
|
||||
reg [8*100-1:0] fn;
|
||||
reg [11:0] got;
|
||||
begin
|
||||
ndiff = 0;
|
||||
for (i = 0; i < KP; i = i + 1) begin
|
||||
// s_hat[i] at bank_a slot i*KP
|
||||
$sformat(fn, "sync_rtl/top/TB/vectors/decgold/dc_k%0d_c%0d_shat_%0d.hex", KP, casenum, i);
|
||||
$readmemh(fn, sh_g);
|
||||
be = 0;
|
||||
for (j = 0; j < 256; j = j + 1) begin
|
||||
rdcoeff(i*KP, j[7:0], got);
|
||||
if (got !== sh_g[j]) begin
|
||||
if (be < 4) $display(" s_hat[%0d][%0d] got=%03x exp=%03x", i, j, got, sh_g[j]);
|
||||
be = be + 1;
|
||||
end
|
||||
end
|
||||
if (be == 0) $display(" PASS: s_hat[%0d] == golden", i);
|
||||
else $display(" FAIL: s_hat[%0d] %0d mismatches", i, be);
|
||||
ndiff = ndiff + be;
|
||||
// u_hat[i] at bank_se rel slot i (abs KP*KP + i)
|
||||
$sformat(fn, "sync_rtl/top/TB/vectors/decgold/dc_k%0d_c%0d_uhat_%0d.hex", KP, casenum, i);
|
||||
$readmemh(fn, uh_g);
|
||||
be = 0;
|
||||
for (j = 0; j < 256; j = j + 1) begin
|
||||
rdcoeff(KP*KP + i, j[7:0], got);
|
||||
if (got !== uh_g[j]) begin
|
||||
if (be < 4) $display(" u_hat[%0d][%0d] got=%03x exp=%03x", i, j, got, uh_g[j]);
|
||||
be = be + 1;
|
||||
end
|
||||
end
|
||||
if (be == 0) $display(" PASS: u_hat[%0d] == golden", i);
|
||||
else $display(" FAIL: u_hat[%0d] %0d mismatches", i, be);
|
||||
ndiff = ndiff + be;
|
||||
end
|
||||
errors = errors + ndiff;
|
||||
end
|
||||
endtask
|
||||
endmodule
|
||||
|
||||
Reference in New Issue
Block a user