feat(dec): Decaps D1 - byteDecode_d + Decompress -> u'/v'
K-PKE.Decrypt step 1 (FIPS 203 Alg 15): decode+decompress the ciphertext.
- comp_decomp_sync instance made mode-selectable: Encaps C1/C2 still compress
(mode 0), Decaps ST_DEC_DECOMP decompresses (mode 1) with d=du/dv.
- New ST_DEC_DECOMP state with an inline byteDecode_d walker (reverse of the
C1/C2 bit-packer): walks c_in_bram bytes, accumulates LSB-first into a bit
buffer, extracts d-bit symbols, feeds comp_decomp, writes each decompressed
coeff (mod q) to a bank.
c1 = K polys, d=du -> u'[i] in bank_se rel slot i (0..K-1)
c2 = 1 poly, d=dv -> v' in bank_t rel slot DEC_VSLOT=2 (avoids UPSUM=1)
- dbg_slot_i widened 4->6 bits so the TB can read v' (abs slot 26 at K=4).
- bse/bt write muxes gain the DECOMP writeback paths (dec_u_we / dec_v_we).
Verification: examples/dump_decaps.rs (ml-kem-r worktree) emits per-stage
golden (u'/v'/s_hat/u_hat/w/m') into vectors/decgold/. TB verify_d1 reads back
u'[i] and v' and compares all 256 coeffs each.
Bring-up note: dbg coeff readback latency is bank(1)+dbg_coeff_r(1); the TB's
rdcoeff initially waited 2 cyc and saw data shifted by one index -> fixed to 3.
Verified: dec D1 K=2/3/4 all cases PASS; KeyGen + Encaps unregressed.
This commit is contained in:
@@ -25,7 +25,7 @@ module tb_mlkem_dec_katK_xsim;
|
||||
reg c_in_we=0; reg [10:0] c_in_addr=0; reg [7:0] c_in_byte=0;
|
||||
wire [255:0] ss_o;
|
||||
reg [10:0] dbg_ct_idx_i=0; wire [7:0] dbg_ct_o;
|
||||
reg [3:0] dbg_slot_i=0; reg [7:0] dbg_idx_i=0; wire [11:0] dbg_coeff_o;
|
||||
reg [5:0] dbg_slot_i=0; reg [7:0] dbg_idx_i=0; wire [11:0] dbg_coeff_o;
|
||||
reg dbg_byte_sel_i=0; reg [10:0] dbg_byte_idx_i=0; wire [7:0] dbg_byte_o;
|
||||
reg [11:0] dbg_dk_idx_i=0; wire [7:0] dbg_dk_o;
|
||||
wire [255:0] dbg_rho_o, dbg_sigma_o, dbg_r_o, dbg_hek_o;
|
||||
@@ -88,14 +88,28 @@ 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 D0 done in %0d cyc ===", c);
|
||||
$display("=== Decaps D1 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);
|
||||
$finish;
|
||||
end
|
||||
|
||||
initial begin #120000000; $display("FAIL: global timeout"); $finish; end
|
||||
|
||||
// read one stored coefficient at (slot, idx): present addr, wait for the
|
||||
// bank read (sd_bram, 1 cyc) + dbg_coeff_r register (1 cyc) + settle.
|
||||
task rdcoeff;
|
||||
input [5:0] slot; input [7:0] idx; output [11:0] val;
|
||||
begin
|
||||
dbg_slot_i = slot; dbg_idx_i = idx;
|
||||
@(posedge clk); @(posedge clk); @(posedge clk);
|
||||
val = dbg_coeff_o;
|
||||
end
|
||||
endtask
|
||||
|
||||
// D0: verify dk parse. H(ek)=dk[768K+32:+32], z=dk[768K+64:+32] captured into
|
||||
// hek_r/z_r (dbg_dech_o/dbg_decz_o). ek_pke=dk[384K:768K+32] in ek_bram
|
||||
// (dbg_byte sel=0), dk_pke=dk[0:384K] in dkp_bram (sel=1).
|
||||
@@ -145,9 +159,52 @@ module tb_mlkem_dec_katK_xsim;
|
||||
if (be == 0) $display(" PASS: dk_pke round-trip (BRAM) == dk[0 ..]");
|
||||
else $display(" FAIL: dk_pke %0d byte mismatches", be);
|
||||
errors = errors + be;
|
||||
if (errors == 0) $display(" D0 subcheck PASS: dk parse OK");
|
||||
else $display(" D0 subcheck FAIL: %0d errors", errors);
|
||||
end
|
||||
endtask
|
||||
|
||||
if (errors == 0) $display("K=%0d CASE %0d PASS (D0): dk parse OK", KP, casenum);
|
||||
else $display("K=%0d CASE %0d FAIL (D0): %0d total errors", KP, casenum, errors);
|
||||
// D1: verify u'[i] (bank_se rel i, abs slot K*K+i) and v' (bank_t rel
|
||||
// DEC_VSLOT=2, abs slot K*K+2*K+2) against the decode-decompress golden.
|
||||
reg [11:0] up_g [0:255];
|
||||
reg [11:0] vp_g [0:255];
|
||||
task verify_d1;
|
||||
integer i, j, be, ndiff;
|
||||
reg [8*100-1:0] fn;
|
||||
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
|
||||
// v'
|
||||
$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);
|
||||
if (got !== vp_g[j]) begin
|
||||
if (be < 4) $display(" v'[%0d] got=%03x exp=%03x", j, got, vp_g[j]);
|
||||
be = be + 1;
|
||||
end
|
||||
end
|
||||
if (be == 0) $display(" PASS: v' == golden (256 coeffs)");
|
||||
else $display(" FAIL: v' %0d coeff mismatches", be);
|
||||
ndiff = ndiff + be;
|
||||
errors = errors + ndiff;
|
||||
end
|
||||
endtask
|
||||
endmodule
|
||||
|
||||
Reference in New Issue
Block a user