diff --git a/sync_rtl/top/TB/tb_mlkem_kg_kat_xsim.v b/sync_rtl/top/TB/tb_mlkem_kg_kat_xsim.v new file mode 100644 index 0000000..5062723 --- /dev/null +++ b/sync_rtl/top/TB/tb_mlkem_kg_kat_xsim.v @@ -0,0 +1,68 @@ +// tb_mlkem_kg_kat_xsim.v - Stage 4 end-to-end: full ML-KEM-512 KeyGen vs NIST KAT. +// Drives d/z (KAT count=0), runs KeyGen, verifies: +// ek (800B, sel=0) == KAT pk +// dk (1632B, dk tap) == KAT sk (= dk_pke || ek || H(ek) || z) +// No force/release — pure valid/ready via start_i/done_o. +`timescale 1ns/1ps +module tb_mlkem_kg_kat_xsim; + reg clk=0, rst_n=0, start_i=0; + reg [255:0] d_i, z_i; + wire busy_o, done_o; + reg [3: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 [9: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; + + mlkem_top #(.K(2)) dut ( + .clk(clk), .rst_n(rst_n), .d_i(d_i), .z_i(z_i), .start_i(start_i), + .busy_o(busy_o), .done_o(done_o), + .dbg_slot_i(dbg_slot_i), .dbg_idx_i(dbg_idx_i), .dbg_coeff_o(dbg_coeff_o), + .dbg_byte_sel_i(dbg_byte_sel_i), .dbg_byte_idx_i(dbg_byte_idx_i), .dbg_byte_o(dbg_byte_o), + .dbg_dk_idx_i(dbg_dk_idx_i), .dbg_dk_o(dbg_dk_o), + .dbg_rho_o(dbg_rho_o), .dbg_sigma_o(dbg_sigma_o) + ); + always #5 clk = ~clk; + + // KAT count=0 (byte0-low literals) + localparam [255:0] D_LIT = 256'h2426f1941779574d3f1b163bd57f7e173e229e630ec7f7073bdf365137c4bb6d; + localparam [255:0] Z_LIT = 256'h687acf9406694974d383032f7579378f449c75d0560af56cf921ec48404896f6; + + reg [7:0] ek_gold [0:799]; + reg [7:0] dk_gold [0:1631]; + integer c, i, errors; + + initial begin + $readmemh("sync_rtl/top/TB/vectors/c000_ek_bytes.hex", ek_gold); + $readmemh("sync_rtl/top/TB/vectors/c000_dk_full_bytes.hex", dk_gold); + + d_i = D_LIT; z_i = Z_LIT; + rst_n=0; repeat(4) @(posedge clk); rst_n=1; @(posedge clk); + start_i=1; @(posedge clk); start_i=0; + c=0; while(!done_o && c<600000) begin @(posedge clk); c=c+1; end + if(!done_o) begin $display("FAIL: timeout after %0d cyc", c); $finish; end + $display("=== Stage 4: ML-KEM-512 KeyGen end-to-end vs NIST KAT === done in %0d cyc", c); + + errors = 0; + // ek == KAT pk (800B) + dbg_byte_sel_i = 1'b0; + for (i = 0; i < 800; i = i + 1) begin + dbg_byte_idx_i = i[9:0]; @(posedge clk); @(posedge clk); + if (dbg_byte_o !== ek_gold[i]) begin + if (errors < 8) $display(" EK[%0d] got=%02x exp=%02x", i, dbg_byte_o, ek_gold[i]); + errors = errors + 1; + end + end + // dk == KAT sk (1632B) + for (i = 0; i < 1632; i = i + 1) begin + dbg_dk_idx_i = i[11:0]; @(posedge clk); @(posedge clk); + if (dbg_dk_o !== dk_gold[i]) begin + if (errors < 8) $display(" DK[%0d] got=%02x exp=%02x", i, dbg_dk_o, dk_gold[i]); + errors = errors + 1; + end + end + if (errors == 0) $display("ALL TESTS PASSED: ek==KAT.pk (800B), dk==KAT.sk (1632B)"); + else $display("TESTS FAILED: %0d byte mismatches", errors); + $finish; + end + initial begin #40000000; $display("FAIL: global timeout"); $finish; end +endmodule diff --git a/sync_rtl/top/TB/vectors/c000_dk_full_bytes.hex b/sync_rtl/top/TB/vectors/c000_dk_full_bytes.hex new file mode 100644 index 0000000..0c16c2c --- /dev/null +++ b/sync_rtl/top/TB/vectors/c000_dk_full_bytes.hex @@ -0,0 +1,1632 @@ +fa +da +6a +79 +a3 +79 +d2 +cb +36 +c8 +56 +45 +0c +44 +6f +44 +84 +b8 +6a +56 +0c +61 +70 +56 +4d +00 +2e +4b +74 +07 +3f +66 +a6 +fb +6a +57 +bc +e1 +be +92 +a1 +a1 +b5 +31 +c6 +1f +50 +88 +2a +00 +84 +50 +85 +42 +a1 +e1 +c3 +b3 +a9 +50 +f2 +07 +2e +9a +16 +54 +4e +46 +ca +20 +28 +4b +60 +12 +a6 +2c +69 +7a +c8 +58 +61 +5e +18 +1e +1e +a0 +b5 +5b +00 +21 +19 +09 +0b +7b +87 +19 +20 +e9 +b8 +94 +b0 +7a +28 +12 +69 +dc +a1 +5f +af +4a +09 +b0 +00 +4c +ac +61 +a2 +ce +a7 +3f +28 +05 +7d +bf +12 +19 +d0 +77 +47 +b3 +81 +cf +0d +e5 +2a +ba +d3 +0c +a0 +f5 +78 +73 +b2 +bf +a0 +12 +bd +5b +c2 +48 +05 +f3 +65 +7a +d0 +ba +6b +c4 +98 +8c +d9 +c6 +de +49 +2c +0d +43 +3c +e5 +aa +32 +8b +d6 +c6 +cb +50 +24 +63 +34 +0d +c5 +e0 +29 +d2 +c8 +71 +3d +78 +0f +31 +f4 +41 +c2 +4c +40 +00 +e5 +67 +99 +a6 +bc +66 +b4 +a1 +93 +c7 +3c +ed +56 +0f +8a +e4 +3f +9b +20 +75 +ce +b7 +78 +97 +6b +7f +11 +1a +cb +38 +a3 +06 +f2 +b7 +0a +2b +d8 +75 +2e +82 +80 +86 +ba +0f +3e +81 +1a +8c +3b +0d +5f +8b +90 +72 +15 +9e +56 +ba +1e +10 +08 +00 +91 +95 +af +58 +a8 +5a +3e +27 +1f +00 +ac +25 +cc +f3 +23 +3c +b8 +71 +67 +68 +ad +98 +e7 +b1 +f2 +89 +0d +b6 +17 +0f +2b +61 +4f +56 +c1 +93 +38 +71 +ae +1a +41 +30 +24 +ca +9a +21 +37 +79 +5c +8a +2e +9e +15 +28 +0f +f1 +08 +ae +e3 +28 +23 +57 +51 +e5 +69 +ca +63 +a7 +82 +1f +29 +ad +26 +70 +6b +23 +12 +24 +d9 +51 +60 +bd +75 +22 +dd +e0 +bf +e6 +e0 +a8 +26 +19 +74 +88 +5a +2f +df +21 +7f +8c +16 +c4 +f6 +7c +0e +9f +b2 +a2 +f7 +03 +0c +af +88 +1d +2c +8b +2e +6a +68 +63 +90 +61 +92 +10 +8b +00 +42 +60 +b0 +ad +ea +07 +c0 +b3 +49 +d5 +88 +11 +0a +9c +bb +69 +9b +39 +52 +bb +11 +2c +c7 +c8 +d9 +a7 +59 +b9 +55 +4c +1f +99 +1e +a1 +f5 +1f +4c +61 +78 +e4 +38 +27 +c5 +14 +9b +da +07 +7f +bd +76 +9a +3b +81 +8d +f7 +1a +42 +86 +07 +83 +fd +23 +3d +1b +26 +a9 +6a +57 +3e +99 +eb +91 +5f +6b +c1 +8d +81 +3d +ed +14 +a3 +04 +c1 +35 +8e +47 +05 +70 +d2 +54 +78 +a6 +b6 +ba +2a +c5 +61 +28 +90 +b5 +a5 +69 +e5 +26 +33 +42 +45 +9c +b9 +ca +76 +74 +f2 +28 +39 +69 +54 +af +74 +8d +9d +50 +13 +53 +42 +71 +39 +04 +cc +59 +10 +6e +0b +b2 +19 +42 +b4 +06 +6f +86 +bf +5d +9c +3c +f1 +b6 +c0 +86 +92 +c5 +b9 +88 +1b +29 +97 +10 +88 +a8 +b4 +15 +e2 +6c +4a +25 +67 +58 +8b +2d +df +b6 +8d +11 +14 +6f +cf +f0 +b4 +cb +79 +c5 +74 +87 +01 +8c +25 +54 +1d +32 +67 +a1 +06 +40 +e4 +30 +bf +eb +bb +4f +45 +a7 +99 +c9 +f5 +54 +d1 +b6 +9d +70 +c7 +9d +17 +12 +4f +9c +01 +cf +3a +d6 +56 +9e +77 +a4 +e1 +b6 +57 +04 +70 +10 +06 +45 +2f +45 +a7 +2f +32 +98 +c6 +60 +82 +0f +1c +20 +6a +f7 +00 +c9 +a6 +21 +92 +3c +39 +11 +cd +51 +8e +02 +24 +04 +c8 +70 +c3 +d3 +b3 +b6 +83 +1a +82 +53 +6a +31 +70 +33 +4e +31 +59 +b0 +c9 +59 +03 +6c +43 +2c +f5 +b4 +84 +b1 +2c +75 +cc +c3 +c9 +6c +e3 +28 +fb +ba +79 +e2 +f7 +24 +78 +9a +8d +27 +f7 +af +8b +b0 +86 +45 +d2 +c9 +a3 +e8 +7f +80 +42 +c3 +62 +27 +19 +4a +3c +0e +14 +d0 +91 +29 +d0 +69 +d5 +37 +9d +bd +60 +65 +65 +d9 +15 +a3 +bc +98 +82 +e8 +74 +23 +a0 +62 +00 +0a +5f +4c +55 +23 +ec +94 +47 +ce +a1 +64 +3a +97 +ad +33 +c1 +98 +62 +46 +ad +91 +e2 +73 +ce +32 +ac +af +f4 +53 +35 +99 +65 +37 +07 +21 +80 +b7 +01 +00 +83 +1d +7e +e1 +68 +f4 +73 +92 +48 +31 +19 +f9 +38 +63 +ec +b0 +bc +60 +53 +12 +d3 +57 +28 +87 +6b +00 +f5 +f5 +7a +f4 +c8 +5e +da +97 +28 +1d +57 +43 +90 +bc +72 +56 +19 +36 +68 +dc +98 +62 +53 +54 +ab +52 +b9 +bc +e7 +81 +c5 +77 +1c +c2 +60 +99 +f6 +fb +ac +be +e1 +78 +4d +19 +48 +87 +73 +1f +09 +7c +87 +e0 +82 +cb +ea +c5 +7d +30 +b7 +b9 +a2 +93 +87 +2c +84 +14 +66 +f2 +24 +4c +c6 +5f +f4 +ba +65 +3d +67 +51 +df +a2 +20 +51 +d5 +53 +36 +99 +42 +c3 +1c +29 +f9 +13 +07 +af +57 +32 +92 +d6 +97 +a8 +c3 +16 +12 +e0 +7b +53 +35 +cf +08 +32 +9f +d2 +46 +bf +2a +32 +20 +0a +8c +b0 +c4 +b0 +3b +9d +09 +c5 +ba +1c +39 +19 +53 +9e +92 +29 +c6 +96 +92 +43 +48 +28 +2f +69 +6b +15 +25 +e5 +60 +38 +06 +b4 +db +61 +8b +3d +c8 +63 +0c +b2 +86 +e4 +31 +17 +21 +bc +50 +31 +f2 +57 +aa +92 +5b +f8 +09 +60 +44 +5a +a8 +d8 +e6 +97 +88 +e9 +9d +a9 +5c +1d +10 +cc +3b +e8 +58 +52 +8d +b0 +cf +ea +00 +3c +74 +69 +37 +80 +a6 +5a +36 +e6 +28 +43 +b3 +be +15 +40 +65 +43 +d2 +2d +83 +50 +7c +87 +b2 +78 +67 +92 +c8 +0f +a5 +62 +84 +54 +a3 +10 +39 +4d +da +4c +2a +b5 +94 +93 +85 +02 +57 +d6 +d3 +bc +10 +71 +86 +d9 +06 +27 +07 +f3 +54 +e8 +1a +1a +10 +fc +b7 +63 +d3 +1a +4e +c4 +09 +aa +24 +3e +d2 +e5 +9b +b1 +89 +85 +5e +b1 +65 +62 +66 +bb +37 +50 +07 +85 +ea +08 +cd +88 +c2 +22 +a8 +c5 +3a +87 +77 +ca +b4 +2c +9c +23 +8a +00 +d5 +93 +69 +42 +50 +26 +e9 +9d +2a +e6 +04 +0a +f6 +70 +90 +29 +ca +87 +89 +c8 +97 +b3 +29 +fb +a7 +48 +d6 +9c +8a +71 +48 +c9 +5a +bb +0c +71 +78 +7c +58 +f1 +2f +21 +f2 +21 +3e +38 +92 +42 +aa +7f +bd +32 +0c +12 +ac +42 +c6 +11 +60 +6c +b8 +c1 +d1 +b4 +62 +58 +86 +a1 +45 +a5 +35 +bd +65 +bd +0d +99 +6b +33 +0c +16 +57 +d6 +1a +87 +e9 +04 +17 +00 +32 +25 +75 +98 +20 +a3 +bb +ec +50 +5c +da +f1 +11 +93 +22 +9a +ae +17 +3c +d1 +2b +ad +22 +a7 +a3 +0a +76 +a9 +fa +76 +36 +c3 +d5 +aa +48 +e1 +78 +40 +12 +a0 +12 +f1 +41 +68 +b7 +85 +3d +2a +16 +f9 +0c +a0 +2c +c3 +3b +20 +06 +c0 +8f +26 +c1 +5f +ca +29 +61 +2c +c7 +92 +e1 +cf +02 +e1 +32 +1a +75 +a8 +10 +89 +19 +86 +66 +7d +41 +48 +af +36 +e6 +5e +1a +59 +25 +89 +02 +96 +17 +73 +4c +31 +5c +0e +39 +b7 +51 +8c +86 +60 +cd +c2 +65 +d0 +c8 +13 +ef +20 +a0 +43 +31 +7f +ae +5b +8e +40 +54 +6e +ec +f7 +1d +6c +05 +4f +a6 +6b +49 +40 +13 +09 +be +f3 +0f +d5 +1a +55 +19 +75 +5d +a9 +10 +46 +89 +b2 +6f +08 +39 +15 +4c +84 +7b +ef +23 +65 +94 +3c +02 +49 +48 +3a +ad +9a +73 +67 +c9 +80 +a3 +d1 +ce +46 +d2 +00 +8a +15 +27 +5c +a3 +bc +a4 +83 +4e +6f +9a +30 +36 +c0 +cd +80 +ba +22 +8d +34 +b9 +78 +02 +44 +d5 +c0 +cb +e9 +07 +c6 +fb +43 +82 +4a +9c +07 +46 +47 +16 +39 +cb +86 +18 +8c +60 +c3 +b2 +53 +21 +5c +c9 +16 +92 +bc +d1 +49 +3d +6a +44 +4d +53 +64 +46 +e0 +29 +68 +13 +80 +01 +cc +28 +7e +0e +51 +8f +3a +a2 +5d +8c +3b +95 +b3 +c3 +5c +59 +f4 +81 +9d +48 +49 +76 +02 +9a +f0 +5a +26 +3c +35 +33 +6b +26 +1f +77 +b2 +cd +c2 +93 +89 +f0 +84 +c0 +4c +bb +37 +0c +48 +56 +2b +5b +50 +77 +1c +0f +b8 +16 +90 +8e +19 +8d +d6 +d5 +3f +76 +e4 +8b +f0 +42 +c2 +b1 +f8 +2a +3a +40 +b8 +da +f5 +1f +46 +d7 +6f +a4 +bc +c9 +d3 +c8 +94 +ff +85 +0c +0f +aa +32 +e0 +ac +33 +90 +1a +4c +79 +13 +9f +5f +20 +41 +7e +c1 +a1 +90 +60 +70 +44 +f1 +8b +b8 +24 +cf +35 +0c +78 +ab +3d +df +3c +2c +86 +ca +55 +43 +f7 +15 +ca +87 +5d +7c +7e +85 +01 +25 +60 +71 +ea +51 +8d +2f +18 +5b +05 +62 +6a +a3 +d1 +c3 +8c +db +c2 +d0 +06 +ed +00 +51 +aa +c6 +f6 +96 +48 +40 +48 +ec +21 +f9 +6c +f5 +0a +56 +d0 +75 +9c +44 +8f +37 +79 +75 +2f +03 +83 +d3 +74 +49 +69 +06 +94 +cf +7a +68 diff --git a/sync_rtl/top/mlkem_top.v b/sync_rtl/top/mlkem_top.v index 50a7a7e..5b59669 100644 --- a/sync_rtl/top/mlkem_top.v +++ b/sync_rtl/top/mlkem_top.v @@ -40,6 +40,10 @@ module mlkem_top #( input dbg_byte_sel_i, input [9:0] dbg_byte_idx_i, output [7:0] dbg_byte_o, + // Debug full-dk readback: dk = dk_pke(768) || ek(800) || H(ek)(32) || z(32) + // = 1632 bytes. Index 0..1631. + input [11:0] dbg_dk_idx_i, + output [7:0] dbg_dk_o, // Debug taps for hash outputs output [255:0] dbg_rho_o, output [255:0] dbg_sigma_o @@ -80,6 +84,20 @@ module mlkem_top #( dbg_byte_r <= dbg_byte_sel_i ? dkp_mem[dbg_byte_idx_i] : ek_mem[dbg_byte_idx_i]; assign dbg_byte_o = dbg_byte_r; + // full dk = dk_pke(0..767) || ek(768..1567) || H(ek)(1568..1599) || z(1600..1631) + reg [7:0] dbg_dk_r; + always @(posedge clk) begin + if (dbg_dk_idx_i < 12'd768) + dbg_dk_r <= dkp_mem[dbg_dk_idx_i]; + else if (dbg_dk_idx_i < 12'd1568) + dbg_dk_r <= ek_mem[dbg_dk_idx_i - 12'd768]; + else if (dbg_dk_idx_i < 12'd1600) + dbg_dk_r <= hek_r[(dbg_dk_idx_i - 12'd1568)*8 +: 8]; + else + dbg_dk_r <= z_i[(dbg_dk_idx_i - 12'd1600)*8 +: 8]; + end + assign dbg_dk_o = dbg_dk_r; + // ================================================================ // Top-level FSM (built incrementally). Stage 2a: G only. // ================================================================ @@ -90,6 +108,7 @@ module mlkem_top #( localparam ST_N = 4'd4; // forward NTT of s[i],e[i] in place localparam ST_M = 4'd5; // matrix accumulate t_hat = e_hat + sum A o s_hat localparam ST_E = 4'd6; // byteEncode12 -> ek_mem, dkp_mem + localparam ST_H = 4'd7; // H(ek) via multi-block SHA3-256 localparam ST_DONE = 4'd15; reg [3:0] st, st_next; @@ -139,6 +158,49 @@ module mlkem_top #( .mb_last_i(1'b0), .mb_ready_o() ); + // ---- second sha3_top dedicated to multi-block H(ek) (SHA3-256, 800B->6 blk) ---- + reg [1087:0] h_block_r; // current pre-padded rate block + reg h_mbvalid; + reg h_mblast; + wire h_mbready; + wire [511:0] h_hash; + wire h_vo; + reg h_ack; + reg [255:0] hek_r; // captured H(ek) + reg [2:0] h_blk; // 0..5 block index + reg [7:0] h_byte; // 0..135 byte within block being assembled + reg [1:0] h_phase; // 0=assemble 1=feed 2=wait-perm 3=done + + sha3_top u_sha3_h ( + .clk(clk), .rst_n(rst_n), + .mode(2'b01), // unused in mb mode + .data_i(512'b0), + .valid_i(1'b0), + .ready_o(), + .hash_o(h_hash), + .valid_o(h_vo), + .ready_i(h_ack), + .mb_en(1'b1), + .mb_block_i(h_block_r), + .mb_valid_i(h_mbvalid), + .mb_last_i(h_mblast), + .mb_ready_o(h_mbready) + ); + + // byte b (0..135) of block blk for SHA3-256 over 800-byte ek: + // global byte g = blk*136 + b; ek_mem[g] if g<800; + // g==800 -> 0x06 (domain+first pad bit); g==815 -> |0x80 (last block); else 0 + function [7:0] h_padbyte(input [2:0] blk, input [7:0] b); + integer g; + begin + g = blk*136 + b; + if (g < 800) h_padbyte = ek_mem[g]; + else if (g == 800) h_padbyte = (g == 815) ? 8'h86 : 8'h06; + else if (g == 815) h_padbyte = 8'h80; // 6th block (815 = 5*136+135) + else h_padbyte = 8'h00; + end + endfunction + // ---- sample_ntt_sync: Â[i][j] = SampleNTT(rho || j || i) ---- reg snt_valid; wire snt_ready; @@ -284,7 +346,8 @@ module mlkem_top #( ST_C: if (c_poly >= 2*K) st_next = ST_N; ST_N: if (n_slot >= 2*K) st_next = ST_M; ST_M: if (m_i >= K) st_next = ST_E; - ST_E: if (e_done) st_next = ST_DONE; + ST_E: if (e_done) st_next = ST_H; + ST_H: if (h_phase == 2'd3) st_next = ST_DONE; ST_DONE: st_next = ST_IDLE; default: st_next = ST_IDLE; endcase @@ -323,6 +386,14 @@ module mlkem_top #( e_pair <= 8'd0; e_rho <= 10'd0; e_done <= 1'b0; + h_block_r <= 1088'd0; + h_mbvalid <= 1'b0; + h_mblast <= 1'b0; + h_ack <= 1'b0; + hek_r <= 256'd0; + h_blk <= 3'd0; + h_byte <= 8'd0; + h_phase <= 2'd0; end else begin st <= st_next; @@ -532,6 +603,53 @@ module mlkem_top #( else e_rho <= e_rho + 10'd1; end end + + // Arm H stage when E finishes + if (st == ST_E && st_next == ST_H) begin + h_blk <= 3'd0; + h_byte <= 8'd0; + h_phase <= 2'd0; // assemble + h_mbvalid<= 1'b0; + h_mblast <= 1'b0; + h_ack <= 1'b1; // ready to consume final digest + end + + // ---- ST_H: H(ek) via multi-block SHA3-256 (6 pre-padded blocks) ---- + if (st == ST_H) begin + case (h_phase) + // assemble 136 bytes of block h_blk into h_block_r + 2'd0: begin + h_block_r[h_byte*8 +: 8] <= h_padbyte(h_blk, h_byte); + if (h_byte == 8'd135) begin + h_byte <= 8'd0; + h_mbvalid <= 1'b1; + h_mblast <= (h_blk == 3'd5); + h_phase <= 2'd1; // feed + end else begin + h_byte <= h_byte + 8'd1; + end + end + // feed: hold valid until accepted (mb_ready drops) + 2'd1: begin + if (h_mbvalid && !h_mbready) begin + h_mbvalid <= 1'b0; + h_mblast <= 1'b0; + h_phase <= 2'd2; // wait permute + end + end + // wait permute done: ready again (more blocks) or digest valid (last) + 2'd2: begin + if (h_vo) begin + hek_r <= h_hash[255:0]; + h_phase <= 2'd3; // done + end else if (h_mbready) begin + h_blk <= h_blk + 3'd1; + h_phase <= 2'd0; // assemble next block + end + end + default: ; // 2'd3 done: hold + endcase + end end end