feat(enc): Encaps E5 - c1 = byteEncode_du(Compress_du(u))

ST_ENC_C1: per-coeff Compress_du via comp_decomp_sync (mode 0) then
LSB-first byte packing into ct_bram. 5-phase micro-seq reads u[cp_poly]
from bank_se (rel K+poly), feeds the compressor (1-cyc pipe), appends du
bits to cp_buf, and drains whole bytes. Each poly = 256*du bits (whole
bytes) so the bit buffer empties at every poly boundary.

ST_ENC_U now advances to ST_ENC_C1 (was ST_DONE).

TB: verify_e5 compares ct_bram[0..c1_bytes-1] to the KAT.ct prefix via
the dbg_ct tap. run_enc.sh: encaps TB runner (compiles comp_decomp_sync
which the KeyGen tcl omits).

Verified K=2/3/4 c1 == KAT.ct prefix (640/960/1408 B; K=4 du=11
cross-byte path), K=2 cases 0-2.
This commit is contained in:
2026-06-29 02:59:12 +08:00
parent ee875d2ff7
commit 3bc46f9640
4 changed files with 221 additions and 9 deletions

View File

@@ -10,6 +10,8 @@ module tb_mlkem_enc_katK_xsim;
parameter KP = 2;
localparam EKB = 384*KP + 32; // ek (=pk) bytes
localparam CTB = (KP==4) ? 1568 : (32*(10*KP+4)); // ct bytes: K2 768,K3 1088,K4 1568
localparam DU = (KP==4) ? 11 : 10; // compression du
localparam C1B = 32*DU*KP; // c1 byte count: K2 640,K3 960,K4 1408
reg clk=0, rst_n=0, start_i=0;
reg [2:0] k_i;
@@ -41,8 +43,9 @@ module tb_mlkem_enc_katK_xsim;
reg [7:0] ek_b [0:EKB-1];
reg [7:0] m_b [0:31];
reg [7:0] ss_b [0:31];
reg [7:0] ct_b [0:CTB-1];
integer c, i, errors, casenum, j;
reg [8*80-1:0] tag, ekfile, mfile, ssfile;
reg [8*80-1:0] tag, ekfile, mfile, ssfile, ctfile;
initial begin
if (!$value$plusargs("CASE=%d", casenum)) casenum = 0;
@@ -50,9 +53,11 @@ module tb_mlkem_enc_katK_xsim;
$sformat(ekfile, "sync_rtl/top/TB/vectors/enc_%0s_c%0d_ek.hex", tag, casenum);
$sformat(mfile, "sync_rtl/top/TB/vectors/enc_%0s_c%0d_m.hex", tag, casenum);
$sformat(ssfile, "sync_rtl/top/TB/vectors/enc_%0s_c%0d_ss.hex", tag, casenum);
$sformat(ctfile, "sync_rtl/top/TB/vectors/enc_%0s_c%0d_ct.hex", tag, casenum);
$readmemh(ekfile, ek_b);
$readmemh(mfile, m_b);
$readmemh(ssfile, ss_b);
$readmemh(ctfile, ct_b);
// build m_i: byte i in m_i[8*i +: 8]
m_i = 256'd0;
@@ -102,6 +107,9 @@ module tb_mlkem_enc_katK_xsim;
verify_e3;
verify_e4;
end
// E5: c1 = byteEncode_du(Compress_du(u)) must equal KAT.ct[0..C1B-1].
// Runs for every K/case (ct_b is the full KAT ciphertext).
verify_e5;
$finish;
end
@@ -193,4 +201,24 @@ module tb_mlkem_enc_katK_xsim;
end
endtask
initial begin #120000000; $display("FAIL: global timeout"); $finish; end
// E5: read ct_bram bytes 0..C1B-1 via dbg_ct tap; compare to KAT.ct prefix.
// dbg_ct_idx_i -> ct_rd_addr (1-cyc registered read) -> dbg_ct_o (comb tap):
// wait 3 cycles per byte (same cadence as the coeff readback tasks).
task verify_e5;
integer be;
begin
be = 0;
for (i = 0; i < C1B; i = i + 1) begin
dbg_ct_idx_i = i[10:0];
@(posedge clk); @(posedge clk); @(posedge clk);
if (dbg_ct_o !== ct_b[i]) begin
if (be < 8) $display(" C1[%0d] got=%02x exp=%02x", i, dbg_ct_o, ct_b[i]);
be = be + 1;
end
end
if (be == 0) $display("K=%0d CASE %0d PASS (E5): c1 (%0d B) == KAT.ct prefix", KP, casenum, C1B);
else $display("K=%0d CASE %0d FAIL (E5): %0d c1 byte mismatches", KP, casenum, be);
end
endtask
endmodule