feat(dec): Decaps D3+D4 - w = v'-INTT(s.u_hat) + m' recovery
Completes K-PKE.Decrypt (FIPS 203 Alg 15) in hardware: m' is recovered. D3 (ST_DEC_W) reuses the Encaps V MAC/INTT machine (u_row tied to 0): - MAC s_hat[j] (bank_a slot j*K) o u_hat[j] (bank_se rel j) -> psum bank_t[UPSUM] -- identical addressing to Encaps V (t_hat[j] o y_hat[j]), so free reuse. - INTT(psum) in place. - SUB: w = v' - psum mod Q (negative -> +Q), written to bank_t[UPSUM]. To read v' and psum in parallel during SUB (one read port per bank), D1's v' write was relocated from bank_t to bank_a slot DEC_VASLOT=1 (always free: s_hat occupies j*K, slot 1 is unused for K>=2). This mirrors V-ADD reading psum (bank_t) + e2 (bank_a) simultaneously. D4 (ST_DEC_MENC): m' = byteEncode_1(Compress_1(w)). Compress_1(w)=1 iff 832 < w <= 2496 (Q=3329); bits packed LSB-first into mprime_r, exposed on dbg_mprime_o (was a placeholder tied to m_r). Added ST_DEC_W to the u_* machine muxes/sub-phases and the FSM chain NTT->W->MENC->DONE. TB verify_d3 checks w (bank_t UPSUM); verify_d4 checks the 32-byte m' against golden (== the KAT-decrypted m == original message). Verified: dec D1-D4 K=2/3/4 all cases PASS; KeyGen + Encaps unregressed.
This commit is contained in:
@@ -88,13 +88,15 @@ 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 D2 done in %0d cyc ===", c);
|
||||
$display("=== Decaps D4 done in %0d cyc ===", c);
|
||||
|
||||
verify_d0;
|
||||
verify_d1;
|
||||
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);
|
||||
verify_d3;
|
||||
verify_d4;
|
||||
if (errors == 0) $display("K=%0d CASE %0d PASS (D4): w + m' recovery OK", KP, casenum);
|
||||
else $display("K=%0d CASE %0d FAIL (D4): %0d total errors", KP, casenum, errors);
|
||||
$finish;
|
||||
end
|
||||
|
||||
@@ -178,13 +180,13 @@ module tb_mlkem_dec_katK_xsim;
|
||||
// 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'
|
||||
// (u_hat == NTT(u') golden). Only v' (bank_a slot 1, untouched) checked.
|
||||
// v' lives in bank_a DEC_VASLOT=1 (abs slot 1).
|
||||
$sformat(fn, "sync_rtl/top/TB/vectors/decgold/dc_k%0d_c%0d_vp.hex", KP, casenum);
|
||||
$readmemh(fn, vp_g);
|
||||
be = 0;
|
||||
for (j = 0; j < 256; j = j + 1) begin
|
||||
rdcoeff(KP*KP + 2*KP + 2, j[7:0], got);
|
||||
rdcoeff(1, j[7:0], got);
|
||||
if (got !== vp_g[j]) begin
|
||||
if (be < 4) $display(" v'[%0d] got=%03x exp=%03x", j, got, vp_g[j]);
|
||||
be = be + 1;
|
||||
@@ -240,4 +242,48 @@ module tb_mlkem_dec_katK_xsim;
|
||||
errors = errors + ndiff;
|
||||
end
|
||||
endtask
|
||||
|
||||
// D3: verify w (bank_t rel UPSUM=1, abs slot K*K+2*K+1) == golden.
|
||||
reg [11:0] w_g [0:255];
|
||||
task verify_d3;
|
||||
integer j, be;
|
||||
reg [8*100-1:0] fn;
|
||||
reg [11:0] got;
|
||||
begin
|
||||
$sformat(fn, "sync_rtl/top/TB/vectors/decgold/dc_k%0d_c%0d_w.hex", KP, casenum);
|
||||
$readmemh(fn, w_g);
|
||||
be = 0;
|
||||
for (j = 0; j < 256; j = j + 1) begin
|
||||
rdcoeff(KP*KP + 2*KP + 1, j[7:0], got);
|
||||
if (got !== w_g[j]) begin
|
||||
if (be < 4) $display(" w[%0d] got=%03x exp=%03x", j, got, w_g[j]);
|
||||
be = be + 1;
|
||||
end
|
||||
end
|
||||
if (be == 0) $display(" PASS: w == golden (256 coeffs)");
|
||||
else $display(" FAIL: w %0d coeff mismatches", be);
|
||||
errors = errors + be;
|
||||
end
|
||||
endtask
|
||||
|
||||
// D4: verify m' = byteEncode_1(Compress_1(w)) == golden (32 bytes via dbg).
|
||||
reg [7:0] mp_g [0:31];
|
||||
task verify_d4;
|
||||
integer j, be;
|
||||
reg [8*100-1:0] fn;
|
||||
begin
|
||||
$sformat(fn, "sync_rtl/top/TB/vectors/decgold/dc_k%0d_c%0d_mprime.hex", KP, casenum);
|
||||
$readmemh(fn, mp_g);
|
||||
be = 0;
|
||||
for (j = 0; j < 32; j = j + 1) begin
|
||||
if (dbg_mprime_o[8*j +: 8] !== mp_g[j]) begin
|
||||
if (be < 4) $display(" m'[%0d] got=%02x exp=%02x", j, dbg_mprime_o[8*j +: 8], mp_g[j]);
|
||||
be = be + 1;
|
||||
end
|
||||
end
|
||||
if (be == 0) $display(" PASS: m' == golden (32 bytes)");
|
||||
else $display(" FAIL: m' %0d byte mismatches", be);
|
||||
errors = errors + be;
|
||||
end
|
||||
endtask
|
||||
endmodule
|
||||
|
||||
Reference in New Issue
Block a user