From 1cace51649c06831bfa40d5910c8fd5f09361649 Mon Sep 17 00:00:00 2001 From: FallenSigh Date: Sat, 27 Jun 2026 03:20:52 +0800 Subject: [PATCH] delete mlkem_top --- sync_rtl/de/TB/tb_de_xsim.v | 223 --- sync_rtl/de/TB/xsim_run.tcl | 132 -- sync_rtl/en/TB/tb_en_xsim.v | 238 --- sync_rtl/en/TB/xsim_run.tcl | 132 -- sync_rtl/kg/TB/tb_kg_xsim.v | 238 --- sync_rtl/kg/TB/xsim_run.tcl | 132 -- sync_rtl/sha3_chain/TB/gen_vectors.py | 85 - sync_rtl/sha3_chain/TB/tb_sha3_chain.cpp | 179 -- sync_rtl/sha3_chain/TB/tb_sha3_chain_xsim.v | 287 --- .../TB/vectors/sha3_chain_input.hex | 8 - sync_rtl/sha3_chain/TB/xsim_run.tcl | 68 - sync_rtl/sha3_chain/sha3_chain_top.v | 93 - sync_rtl/sha3_chain/sha3_chain_top_shared.v | 115 -- sync_rtl/top/TB/tb_mlkem_top_xsim.v | 491 ----- sync_rtl/top/TB/xsim_run.tcl | 187 -- sync_rtl/top/keccak_arbiter.v | 143 -- sync_rtl/top/mlkem_top.v | 1658 ----------------- 17 files changed, 4409 deletions(-) delete mode 100644 sync_rtl/de/TB/tb_de_xsim.v delete mode 100644 sync_rtl/de/TB/xsim_run.tcl delete mode 100644 sync_rtl/en/TB/tb_en_xsim.v delete mode 100644 sync_rtl/en/TB/xsim_run.tcl delete mode 100644 sync_rtl/kg/TB/tb_kg_xsim.v delete mode 100644 sync_rtl/kg/TB/xsim_run.tcl delete mode 100644 sync_rtl/sha3_chain/TB/gen_vectors.py delete mode 100644 sync_rtl/sha3_chain/TB/tb_sha3_chain.cpp delete mode 100644 sync_rtl/sha3_chain/TB/tb_sha3_chain_xsim.v delete mode 100644 sync_rtl/sha3_chain/TB/vectors/sha3_chain_input.hex delete mode 100644 sync_rtl/sha3_chain/TB/xsim_run.tcl delete mode 100644 sync_rtl/sha3_chain/sha3_chain_top.v delete mode 100644 sync_rtl/sha3_chain/sha3_chain_top_shared.v delete mode 100644 sync_rtl/top/TB/tb_mlkem_top_xsim.v delete mode 100644 sync_rtl/top/TB/xsim_run.tcl delete mode 100644 sync_rtl/top/keccak_arbiter.v delete mode 100644 sync_rtl/top/mlkem_top.v diff --git a/sync_rtl/de/TB/tb_de_xsim.v b/sync_rtl/de/TB/tb_de_xsim.v deleted file mode 100644 index 9b7dae8..0000000 --- a/sync_rtl/de/TB/tb_de_xsim.v +++ /dev/null @@ -1,223 +0,0 @@ -// tb_de_xsim.v - Decaps-only KAT testbench for mlkem_top -// -// Runs full ML-KEM flow (kg→en→de) but only CHECKS Decaps results. -// Uses existing vector files from sync_rtl/top/TB/vectors/. -// -// Usage: -// xvlog -sv -i . .v sync_rtl/de/TB/tb_de_xsim.v -// xelab tb_de_xsim -s tb_de_xsim --timescale 1ns/1ps -// xsim tb_de_xsim -R - -`timescale 1ns / 1ps - -module tb_de_xsim; - - parameter VECTOR_FILE = "sync_rtl/top/TB/vectors/mlkem_top_input.hex"; - parameter EXPECTED_FILE = "sync_rtl/top/TB/vectors/mlkem_top_expected.hex"; - parameter MAX_VECTORS = 16; - parameter TIMEOUT_CYCLES = 10000000; - parameter K_PARAM = 4; - localparam PK_WIDTH = 12 * K_PARAM * 256; - localparam SK_WIDTH = 12 * K_PARAM * 256; - localparam EXP_PK_WIDTH = 6400; - localparam EXP_SK_WIDTH = 13056; - localparam EXP_CT_WIDTH = 6144; - localparam EXP_SS_WIDTH = 256; - - // DUT signals - reg clk; - reg rst_n; - reg [1:0] mode; - reg [2:0] i_k; - reg valid_i; - wire ready_o; - wire [PK_WIDTH-1:0] pk_o; - wire [SK_WIDTH-1:0] sk_o; - wire pk_valid; - wire sk_valid; - wire [EXP_CT_WIDTH*K_PARAM/2-1:0] ct_o; - wire [255:0] K_o; - wire ct_valid; - wire K_valid; - wire [255:0] K_o_dec; - wire K_valid_dec; - wire done_o; - - // DUT instantiation - mlkem_top #(.K(K_PARAM)) u_dut ( - .clk(clk), .rst_n(rst_n), .mode(mode), .i_k(i_k), - .valid_i(valid_i), .ready_o(ready_o), - .pk_o(pk_o), .sk_o(sk_o), .pk_valid(pk_valid), .sk_valid(sk_valid), - .ct_o(ct_o), .K_o(K_o), .ct_valid(ct_valid), .K_valid(K_valid), - .K_o_dec(K_o_dec), .K_valid_dec(K_valid_dec), .done_o(done_o) - ); - - initial clk = 1'b0; - always #5 clk = ~clk; - - reg [767:0] input_mem [0:MAX_VECTORS-1]; - reg [25855:0] expected_mem [0:MAX_VECTORS-1]; - - integer vec_count, idx, dc_pass, dc_fail; - - function [7:0] nibble_to_ascii; - input [3:0] nibble; - nibble_to_ascii = (nibble < 4'd10) ? (8'h30 + {4'd0, nibble}) : (8'h41 + ({4'd0, nibble} - 4'd10)); - endfunction - - task print_hex256; - input [255:0] val; - input [256*8:1] label; - integer bi; - begin - $write("%s: ", label); - for (bi = 63; bi >= 0; bi = bi - 1) - $write("%c", nibble_to_ascii(val[(bi*4)+:4])); - $write("\n"); - end - endtask - - integer wfd_result; - task wait_for_done; - input [256*8:1] op_name; - integer cyc; - begin - cyc = 0; - while (!done_o && cyc < TIMEOUT_CYCLES) begin @(posedge clk); cyc = cyc + 1; end - if (cyc >= TIMEOUT_CYCLES) begin - $display("ERROR: %s timeout after %0d cycles", op_name, TIMEOUT_CYCLES); - wfd_result = 0; - end else begin - $display("INFO: %s done after %0d cycles", op_name, cyc); - wfd_result = 1; - end - end - endtask - - initial begin - vec_count = 0; - $readmemh(VECTOR_FILE, input_mem); - $readmemh(EXPECTED_FILE, expected_mem); - - begin - integer found_end = 0; - for (idx = 0; idx < MAX_VECTORS; idx = idx + 1) begin - if (!found_end && (input_mem[idx] === 768'hx || input_mem[idx] === 768'hz)) - found_end = 1; - else if (!found_end) - vec_count = vec_count + 1; - end - end - - if (vec_count == 0) begin - $display("ERROR: No vectors loaded from %s", VECTOR_FILE); - $finish; - end - - $display("===================================================="); - $display("MLKEM_TOP Decaps-ONLY KAT TESTBENCH"); - $display(" Vectors loaded: %0d", vec_count); - $display("===================================================="); - - mode <= 2'd0; - i_k <= 3'd2; - valid_i <= 1'b0; - rst_n <= 1'b0; - repeat (5) @(posedge clk); - rst_n <= 1'b1; - @(posedge clk); - - force u_dut.chain_kc_ready_o = 1'b1; - force u_dut.ntt_valid_o = 1'b1; - - dc_pass = 0; dc_fail = 0; - - for (idx = 0; idx < vec_count; idx = idx + 1) begin - reg [255:0] d_val, msg_val, z_val; - - d_val = input_mem[idx][767:512]; - msg_val = input_mem[idx][511:256]; - z_val = input_mem[idx][255:0]; - - // KeyGen (run but don't check) - force u_dut.d_reg = d_val; - mode <= 2'b00; - i_k <= 3'd2; - valid_i <= 1'b1; - @(posedge clk); - valid_i <= 1'b0; - wait_for_done("KeyGen"); - if (wfd_result) release u_dut.d_reg; - else begin - release u_dut.d_reg; - rst_n <= 1'b0; repeat (5) @(posedge clk); rst_n <= 1'b1; - force u_dut.chain_kc_ready_o = 1'b1; force u_dut.ntt_valid_o = 1'b1; - @(posedge clk); - end - repeat (2) @(posedge clk); - - // Encaps (run but don't check) - force u_dut.m_reg = msg_val; - mode <= 2'b01; - i_k <= 3'd2; - valid_i <= 1'b1; - @(posedge clk); - valid_i <= 1'b0; - wait_for_done("Encaps"); - if (wfd_result) release u_dut.m_reg; - else begin - release u_dut.m_reg; - rst_n <= 1'b0; repeat (5) @(posedge clk); rst_n <= 1'b1; - force u_dut.chain_kc_ready_o = 1'b1; force u_dut.ntt_valid_o = 1'b1; - @(posedge clk); - end - repeat (2) @(posedge clk); - - // Decaps (check this) - $display("--- Vector %0d: Decaps ---", idx); - print_hex256(z_val, " z "); - - force u_dut.z_reg = z_val; - mode <= 2'b10; - i_k <= 3'd2; - valid_i <= 1'b1; - @(posedge clk); - valid_i <= 1'b0; - wait_for_done("Decaps"); - if (wfd_result) begin - release u_dut.z_reg; - if (K_valid_dec) begin - $display(" PASS: Decaps completed (K_valid_dec asserted)"); - dc_pass = dc_pass + 1; - end else begin - $display(" FAIL: Decaps K_valid_dec not asserted"); - dc_fail = dc_fail + 1; - end - end else begin - release u_dut.z_reg; - $display(" FAIL: Decaps timeout (placeholder states — expected)"); - dc_fail = dc_fail + 1; - rst_n <= 1'b0; repeat (5) @(posedge clk); rst_n <= 1'b1; - force u_dut.chain_kc_ready_o = 1'b1; force u_dut.ntt_valid_o = 1'b1; - @(posedge clk); - end - repeat (2) @(posedge clk); - end - - release u_dut.chain_kc_ready_o; - release u_dut.ntt_valid_o; - - $display("===================================================="); - $display("DECAPS TEST COMPLETE"); - $display(" PASS: %0d FAIL: %0d", dc_pass, dc_fail); - $display("===================================================="); - $finish; - end - - initial begin - #(TIMEOUT_CYCLES * 10 * 100); - $display("FATAL: Global simulation timeout"); - $finish; - end - -endmodule diff --git a/sync_rtl/de/TB/xsim_run.tcl b/sync_rtl/de/TB/xsim_run.tcl deleted file mode 100644 index 7be0c2f..0000000 --- a/sync_rtl/de/TB/xsim_run.tcl +++ /dev/null @@ -1,132 +0,0 @@ -# NOTE: On some systems, you may need: -# export LD_PRELOAD=/usr/lib64/libtinfo.so.5 -# before running this script. - -# xsim_run.tcl - Vivado xsim compilation and simulation for Decaps-only testbench -# -# Compiles ALL RTL dependencies for mlkem_top plus the Decaps-only testbench. -# Run from the project root: ~/Dev/mlkem/ -# -# Prerequisites: -# source /opt/Xilinx/Vivado/2019.2/settings64.sh -# -# Usage: -# vivado -mode batch -source sync_rtl/de/TB/xsim_run.tcl - -# ================================================================ -# Configuration -# ================================================================ -set COMMON_DIR sync_rtl/common -set SHA3_DIR sync_rtl/sha3 -set SHA3C_DIR sync_rtl/sha3_chain -set RNG_DIR sync_rtl/rng -set NTT_DIR sync_rtl/ntt -set PA_DIR sync_rtl/poly_arith -set PM_DIR sync_rtl/poly_mul -set CBD_DIR sync_rtl/sample_cbd -set SNT_DIR sync_rtl/sample_ntt -set CD_DIR sync_rtl/comp_decomp -set MA_DIR sync_rtl/mod_add -set STOR_DIR sync_rtl/storage -set TOP_DIR sync_rtl/top -set TB_DIR sync_rtl/de/TB - -# ================================================================ -# Step 1: Compile common infrastructure -# ================================================================ -puts "=== Compiling common infrastructure ===" -xvlog -sv -i . ${COMMON_DIR}/pipeline_reg.v -xvlog -sv -i . ${COMMON_DIR}/skid_buffer.v - -# ================================================================ -# Step 2: Compile SHA3 / Keccak core -# ================================================================ -puts "=== Compiling SHA3/Keccak core ===" -xvlog -sv ${SHA3_DIR}/keccak_round.v -xvlog -sv ${SHA3_DIR}/keccak_core.v -xvlog -sv -i . ${SHA3_DIR}/sha3_top.v - -# ================================================================ -# Step 3: Compile SHA3 chain (G function) -# ================================================================ -puts "=== Compiling SHA3 chain ===" -xvlog -sv -i . ${SHA3C_DIR}/sha3_chain_top_shared.v - -# ================================================================ -# Step 4: Compile RNG -# ================================================================ -puts "=== Compiling RNG ===" -xvlog -sv ${RNG_DIR}/rng_sync.v - -# ================================================================ -# Step 5: Compile NTT core and dependencies -# ================================================================ -puts "=== Compiling NTT core ===" -xvlog -sv ${NTT_DIR}/zeta_rom.v -xvlog -sv ${NTT_DIR}/barrett_mul.v -xvlog -sv ${NTT_DIR}/butterfly_unit.v -xvlog -sv -i . ${NTT_DIR}/ntt_core.v - -# ================================================================ -# Step 6: Compile polynomial arithmetic -# ================================================================ -puts "=== Compiling polynomial arithmetic ===" -xvlog -sv ${PA_DIR}/poly_arith_sync.v - -# ================================================================ -# Step 7: Compile polynomial multiplication -# ================================================================ -puts "=== Compiling polynomial multiplication ===" -xvlog -sv ${PM_DIR}/poly_mul_zeta_rom.v -xvlog -sv ${PM_DIR}/basecase_mul.v -xvlog -sv -i . ${PM_DIR}/poly_mul_sync.v - -# ================================================================ -# Step 8: Compile sampling modules -# ================================================================ -puts "=== Compiling sampling modules ===" -xvlog -sv -i . ${CBD_DIR}/sample_cbd_sync_shared.v -xvlog -sv -i . ${SNT_DIR}/sample_ntt_sync_shared.v - -# ================================================================ -# Step 9: Compile compression and modular arithmetic -# ================================================================ -puts "=== Compiling compression and modular arithmetic ===" -xvlog -sv ${CD_DIR}/comp_decomp_sync.v -xvlog -sv ${MA_DIR}/mod_add_sync.v - -# ================================================================ -# Step 10: Compile storage (BRAM) -# ================================================================ -puts "=== Compiling storage BRAMs ===" -xvlog -sv ${STOR_DIR}/s_bram.v -xvlog -sv ${STOR_DIR}/sd_bram.v - -# ================================================================ -# Step 11: Compile top-level integration -# ================================================================ -puts "=== Compiling top-level integration ===" -xvlog -sv -i . ${TOP_DIR}/keccak_arbiter.v -xvlog -sv -i . ${TOP_DIR}/mlkem_top.v - -# ================================================================ -# Step 12: Compile testbench -# ================================================================ -puts "=== Compiling Decaps-only testbench ===" -xvlog -sv ${TB_DIR}/tb_de_xsim.v - -# ================================================================ -# Step 13: Elaborate snapshot (xelab) -# ================================================================ -puts "=== Elaborating snapshot ===" -xelab tb_de_xsim -s tb_de_xsim --timescale 1ns/1ps - -# ================================================================ -# Step 14: Run simulation -# ================================================================ -puts "" -puts "=== Running Decaps-only simulation ===" -xsim tb_de_xsim -R - -puts "" -puts "=== Decaps simulation complete ===" diff --git a/sync_rtl/en/TB/tb_en_xsim.v b/sync_rtl/en/TB/tb_en_xsim.v deleted file mode 100644 index 9908dad..0000000 --- a/sync_rtl/en/TB/tb_en_xsim.v +++ /dev/null @@ -1,238 +0,0 @@ -// tb_en_xsim.v - Encaps-only KAT testbench for mlkem_top -// -// Runs full ML-KEM flow (kg→en→de) but only CHECKS Encaps results. -// Uses existing vector files from sync_rtl/top/TB/vectors/. -// -// Usage: -// xvlog -sv -i . .v sync_rtl/en/TB/tb_en_xsim.v -// xelab tb_en_xsim -s tb_en_xsim --timescale 1ns/1ps -// xsim tb_en_xsim -R - -`timescale 1ns / 1ps - -module tb_en_xsim; - - parameter VECTOR_FILE = "sync_rtl/top/TB/vectors/mlkem_top_input.hex"; - parameter EXPECTED_FILE = "sync_rtl/top/TB/vectors/mlkem_top_expected.hex"; - parameter MAX_VECTORS = 16; - parameter TIMEOUT_CYCLES = 10000000; - parameter K_PARAM = 4; - localparam PK_WIDTH = 12 * K_PARAM * 256; - localparam SK_WIDTH = 12 * K_PARAM * 256; - localparam EXP_PK_WIDTH = 6400; - localparam EXP_SK_WIDTH = 13056; - localparam EXP_CT_WIDTH = 6144; - localparam EXP_SS_WIDTH = 256; - - // DUT signals - reg clk; - reg rst_n; - reg [1:0] mode; - reg [2:0] i_k; - reg valid_i; - wire ready_o; - wire [PK_WIDTH-1:0] pk_o; - wire [SK_WIDTH-1:0] sk_o; - wire pk_valid; - wire sk_valid; - wire [EXP_CT_WIDTH*K_PARAM/2-1:0] ct_o; - wire [255:0] K_o; - wire ct_valid; - wire K_valid; - wire [255:0] K_o_dec; - wire K_valid_dec; - wire done_o; - - // DUT instantiation - mlkem_top #(.K(K_PARAM)) u_dut ( - .clk(clk), .rst_n(rst_n), .mode(mode), .i_k(i_k), - .valid_i(valid_i), .ready_o(ready_o), - .pk_o(pk_o), .sk_o(sk_o), .pk_valid(pk_valid), .sk_valid(sk_valid), - .ct_o(ct_o), .K_o(K_o), .ct_valid(ct_valid), .K_valid(K_valid), - .K_o_dec(K_o_dec), .K_valid_dec(K_valid_dec), .done_o(done_o) - ); - - initial clk = 1'b0; - always #5 clk = ~clk; - - reg [767:0] input_mem [0:MAX_VECTORS-1]; - reg [25855:0] expected_mem [0:MAX_VECTORS-1]; - - integer vec_count, idx, en_pass, en_fail; - - function [7:0] nibble_to_ascii; - input [3:0] nibble; - nibble_to_ascii = (nibble < 4'd10) ? (8'h30 + {4'd0, nibble}) : (8'h41 + ({4'd0, nibble} - 4'd10)); - endfunction - - task print_hex256; - input [255:0] val; - input [256*8:1] label; - integer bi; - begin - $write("%s: ", label); - for (bi = 63; bi >= 0; bi = bi - 1) - $write("%c", nibble_to_ascii(val[(bi*4)+:4])); - $write("\n"); - end - endtask - - integer wfd_result; - task wait_for_done; - input [256*8:1] op_name; - integer cyc; - begin - cyc = 0; - while (!done_o && cyc < TIMEOUT_CYCLES) begin @(posedge clk); cyc = cyc + 1; end - if (cyc >= TIMEOUT_CYCLES) begin - $display("ERROR: %s timeout after %0d cycles", op_name, TIMEOUT_CYCLES); - wfd_result = 0; - end else begin - $display("INFO: %s done after %0d cycles", op_name, cyc); - wfd_result = 1; - end - end - endtask - - initial begin - vec_count = 0; - $readmemh(VECTOR_FILE, input_mem); - $readmemh(EXPECTED_FILE, expected_mem); - - begin - integer found_end = 0; - for (idx = 0; idx < MAX_VECTORS; idx = idx + 1) begin - if (!found_end && (input_mem[idx] === 768'hx || input_mem[idx] === 768'hz)) - found_end = 1; - else if (!found_end) - vec_count = vec_count + 1; - end - end - - if (vec_count == 0) begin - $display("ERROR: No vectors loaded from %s", VECTOR_FILE); - $finish; - end - - $display("===================================================="); - $display("MLKEM_TOP Encaps-ONLY KAT TESTBENCH"); - $display(" Vectors loaded: %0d", vec_count); - $display("===================================================="); - - mode <= 2'd0; - i_k <= 3'd2; - valid_i <= 1'b0; - rst_n <= 1'b0; - repeat (5) @(posedge clk); - rst_n <= 1'b1; - @(posedge clk); - - force u_dut.chain_kc_ready_o = 1'b1; - force u_dut.ntt_valid_o = 1'b1; - - en_pass = 0; en_fail = 0; - - for (idx = 0; idx < vec_count; idx = idx + 1) begin - reg [255:0] d_val, msg_val, z_val; - reg [EXP_CT_WIDTH-1:0] exp_ct; - reg [EXP_SS_WIDTH-1:0] exp_ss; - - d_val = input_mem[idx][767:512]; - msg_val = input_mem[idx][511:256]; - z_val = input_mem[idx][255:0]; - exp_ss = expected_mem[idx][0 +: EXP_SS_WIDTH]; - exp_ct = expected_mem[idx][EXP_SS_WIDTH +: EXP_CT_WIDTH]; - - // KeyGen (run but don't check) - force u_dut.d_reg = d_val; - mode <= 2'b00; - i_k <= 3'd2; - valid_i <= 1'b1; - @(posedge clk); - valid_i <= 1'b0; - wait_for_done("KeyGen"); - if (wfd_result) release u_dut.d_reg; - else begin - release u_dut.d_reg; - rst_n <= 1'b0; repeat (5) @(posedge clk); rst_n <= 1'b1; - force u_dut.chain_kc_ready_o = 1'b1; force u_dut.ntt_valid_o = 1'b1; - @(posedge clk); - end - repeat (2) @(posedge clk); - - // Encaps (check this) - $display("--- Vector %0d: Encaps ---", idx); - print_hex256(msg_val, " msg"); - - force u_dut.m_reg = msg_val; - mode <= 2'b01; - i_k <= 3'd2; - valid_i <= 1'b1; - @(posedge clk); - valid_i <= 1'b0; - wait_for_done("Encaps"); - if (wfd_result) begin - release u_dut.m_reg; - if (ct_valid && K_valid) begin - if (ct_o[EXP_CT_WIDTH-1:0] == exp_ct) begin - $display(" PASS: ct matches expected"); - en_pass = en_pass + 1; - end else begin - $display(" FAIL: ct mismatch"); - en_fail = en_fail + 1; - end - if (K_o == exp_ss) - $display(" PASS: K matches expected ss"); - else begin - $display(" FAIL: K mismatch"); - en_fail = en_fail + 1; - end - end else begin - $display(" FAIL: ct_valid=%b K_valid=%b", ct_valid, K_valid); - en_fail = en_fail + 1; - end - end else begin - release u_dut.m_reg; - $display(" FAIL: Encaps timeout"); - en_fail = en_fail + 1; - rst_n <= 1'b0; repeat (5) @(posedge clk); rst_n <= 1'b1; - force u_dut.chain_kc_ready_o = 1'b1; force u_dut.ntt_valid_o = 1'b1; - @(posedge clk); - end - repeat (2) @(posedge clk); - - // Decaps (run but don't check) - force u_dut.z_reg = z_val; - mode <= 2'b10; - i_k <= 3'd2; - valid_i <= 1'b1; - @(posedge clk); - valid_i <= 1'b0; - wait_for_done("Decaps"); - if (wfd_result) release u_dut.z_reg; - else begin - release u_dut.z_reg; - rst_n <= 1'b0; repeat (5) @(posedge clk); rst_n <= 1'b1; - force u_dut.chain_kc_ready_o = 1'b1; force u_dut.ntt_valid_o = 1'b1; - @(posedge clk); - end - repeat (2) @(posedge clk); - end - - release u_dut.chain_kc_ready_o; - release u_dut.ntt_valid_o; - - $display("===================================================="); - $display("ENCAPS TEST COMPLETE"); - $display(" PASS: %0d FAIL: %0d", en_pass, en_fail); - $display("===================================================="); - $finish; - end - - initial begin - #(TIMEOUT_CYCLES * 10 * 100); - $display("FATAL: Global simulation timeout"); - $finish; - end - -endmodule diff --git a/sync_rtl/en/TB/xsim_run.tcl b/sync_rtl/en/TB/xsim_run.tcl deleted file mode 100644 index 830d566..0000000 --- a/sync_rtl/en/TB/xsim_run.tcl +++ /dev/null @@ -1,132 +0,0 @@ -# NOTE: On some systems, you may need: -# export LD_PRELOAD=/usr/lib64/libtinfo.so.5 -# before running this script. - -# xsim_run.tcl - Vivado xsim compilation and simulation for Encaps-only testbench -# -# Compiles ALL RTL dependencies for mlkem_top plus the Encaps-only testbench. -# Run from the project root: ~/Dev/mlkem/ -# -# Prerequisites: -# source /opt/Xilinx/Vivado/2019.2/settings64.sh -# -# Usage: -# vivado -mode batch -source sync_rtl/en/TB/xsim_run.tcl - -# ================================================================ -# Configuration -# ================================================================ -set COMMON_DIR sync_rtl/common -set SHA3_DIR sync_rtl/sha3 -set SHA3C_DIR sync_rtl/sha3_chain -set RNG_DIR sync_rtl/rng -set NTT_DIR sync_rtl/ntt -set PA_DIR sync_rtl/poly_arith -set PM_DIR sync_rtl/poly_mul -set CBD_DIR sync_rtl/sample_cbd -set SNT_DIR sync_rtl/sample_ntt -set CD_DIR sync_rtl/comp_decomp -set MA_DIR sync_rtl/mod_add -set STOR_DIR sync_rtl/storage -set TOP_DIR sync_rtl/top -set TB_DIR sync_rtl/en/TB - -# ================================================================ -# Step 1: Compile common infrastructure -# ================================================================ -puts "=== Compiling common infrastructure ===" -xvlog -sv -i . ${COMMON_DIR}/pipeline_reg.v -xvlog -sv -i . ${COMMON_DIR}/skid_buffer.v - -# ================================================================ -# Step 2: Compile SHA3 / Keccak core -# ================================================================ -puts "=== Compiling SHA3/Keccak core ===" -xvlog -sv ${SHA3_DIR}/keccak_round.v -xvlog -sv ${SHA3_DIR}/keccak_core.v -xvlog -sv -i . ${SHA3_DIR}/sha3_top.v - -# ================================================================ -# Step 3: Compile SHA3 chain (G function) -# ================================================================ -puts "=== Compiling SHA3 chain ===" -xvlog -sv -i . ${SHA3C_DIR}/sha3_chain_top_shared.v - -# ================================================================ -# Step 4: Compile RNG -# ================================================================ -puts "=== Compiling RNG ===" -xvlog -sv ${RNG_DIR}/rng_sync.v - -# ================================================================ -# Step 5: Compile NTT core and dependencies -# ================================================================ -puts "=== Compiling NTT core ===" -xvlog -sv ${NTT_DIR}/zeta_rom.v -xvlog -sv ${NTT_DIR}/barrett_mul.v -xvlog -sv ${NTT_DIR}/butterfly_unit.v -xvlog -sv -i . ${NTT_DIR}/ntt_core.v - -# ================================================================ -# Step 6: Compile polynomial arithmetic -# ================================================================ -puts "=== Compiling polynomial arithmetic ===" -xvlog -sv ${PA_DIR}/poly_arith_sync.v - -# ================================================================ -# Step 7: Compile polynomial multiplication -# ================================================================ -puts "=== Compiling polynomial multiplication ===" -xvlog -sv ${PM_DIR}/poly_mul_zeta_rom.v -xvlog -sv ${PM_DIR}/basecase_mul.v -xvlog -sv -i . ${PM_DIR}/poly_mul_sync.v - -# ================================================================ -# Step 8: Compile sampling modules -# ================================================================ -puts "=== Compiling sampling modules ===" -xvlog -sv -i . ${CBD_DIR}/sample_cbd_sync_shared.v -xvlog -sv -i . ${SNT_DIR}/sample_ntt_sync_shared.v - -# ================================================================ -# Step 9: Compile compression and modular arithmetic -# ================================================================ -puts "=== Compiling compression and modular arithmetic ===" -xvlog -sv ${CD_DIR}/comp_decomp_sync.v -xvlog -sv ${MA_DIR}/mod_add_sync.v - -# ================================================================ -# Step 10: Compile storage (BRAM) -# ================================================================ -puts "=== Compiling storage BRAMs ===" -xvlog -sv ${STOR_DIR}/s_bram.v -xvlog -sv ${STOR_DIR}/sd_bram.v - -# ================================================================ -# Step 11: Compile top-level integration -# ================================================================ -puts "=== Compiling top-level integration ===" -xvlog -sv -i . ${TOP_DIR}/keccak_arbiter.v -xvlog -sv -i . ${TOP_DIR}/mlkem_top.v - -# ================================================================ -# Step 12: Compile testbench -# ================================================================ -puts "=== Compiling Encaps-only testbench ===" -xvlog -sv ${TB_DIR}/tb_en_xsim.v - -# ================================================================ -# Step 13: Elaborate snapshot (xelab) -# ================================================================ -puts "=== Elaborating snapshot ===" -xelab tb_en_xsim -s tb_en_xsim --timescale 1ns/1ps - -# ================================================================ -# Step 14: Run simulation -# ================================================================ -puts "" -puts "=== Running Encaps-only simulation ===" -xsim tb_en_xsim -R - -puts "" -puts "=== Encaps simulation complete ===" diff --git a/sync_rtl/kg/TB/tb_kg_xsim.v b/sync_rtl/kg/TB/tb_kg_xsim.v deleted file mode 100644 index 505a41c..0000000 --- a/sync_rtl/kg/TB/tb_kg_xsim.v +++ /dev/null @@ -1,238 +0,0 @@ -// tb_kg_xsim.v - KeyGen-only KAT testbench for mlkem_top -// -// Runs full ML-KEM flow (kg→en→de) but only CHECKS KeyGen results. -// Uses existing vector files from sync_rtl/top/TB/vectors/. -// -// Usage: -// xvlog -sv -i . .v sync_rtl/kg/TB/tb_kg_xsim.v -// xelab tb_kg_xsim -s tb_kg_xsim --timescale 1ns/1ps -// xsim tb_kg_xsim -R - -`timescale 1ns / 1ps - -module tb_kg_xsim; - - parameter VECTOR_FILE = "sync_rtl/top/TB/vectors/mlkem_top_input.hex"; - parameter EXPECTED_FILE = "sync_rtl/top/TB/vectors/mlkem_top_expected.hex"; - parameter MAX_VECTORS = 16; - parameter TIMEOUT_CYCLES = 10000000; - parameter K_PARAM = 4; - localparam PK_WIDTH = 12 * K_PARAM * 256; - localparam SK_WIDTH = 12 * K_PARAM * 256; - localparam EXP_PK_WIDTH = 6400; - localparam EXP_SK_WIDTH = 13056; - localparam EXP_CT_WIDTH = 6144; - localparam EXP_SS_WIDTH = 256; - - // DUT signals - reg clk; - reg rst_n; - reg [1:0] mode; - reg [2:0] i_k; - reg valid_i; - wire ready_o; - wire [PK_WIDTH-1:0] pk_o; - wire [SK_WIDTH-1:0] sk_o; - wire pk_valid; - wire sk_valid; - wire [EXP_CT_WIDTH*K_PARAM/2-1:0] ct_o; - wire [255:0] K_o; - wire ct_valid; - wire K_valid; - wire [255:0] K_o_dec; - wire K_valid_dec; - wire done_o; - - // DUT instantiation - mlkem_top #(.K(K_PARAM)) u_dut ( - .clk(clk), .rst_n(rst_n), .mode(mode), .i_k(i_k), - .valid_i(valid_i), .ready_o(ready_o), - .pk_o(pk_o), .sk_o(sk_o), .pk_valid(pk_valid), .sk_valid(sk_valid), - .ct_o(ct_o), .K_o(K_o), .ct_valid(ct_valid), .K_valid(K_valid), - .K_o_dec(K_o_dec), .K_valid_dec(K_valid_dec), .done_o(done_o) - ); - - initial clk = 1'b0; - always #5 clk = ~clk; - - reg [767:0] input_mem [0:MAX_VECTORS-1]; - reg [25855:0] expected_mem [0:MAX_VECTORS-1]; - - integer vec_count, idx, kg_pass, kg_fail; - - function [7:0] nibble_to_ascii; - input [3:0] nibble; - nibble_to_ascii = (nibble < 4'd10) ? (8'h30 + {4'd0, nibble}) : (8'h41 + ({4'd0, nibble} - 4'd10)); - endfunction - - task print_hex256; - input [255:0] val; - input [256*8:1] label; - integer bi; - begin - $write("%s: ", label); - for (bi = 63; bi >= 0; bi = bi - 1) - $write("%c", nibble_to_ascii(val[(bi*4)+:4])); - $write("\n"); - end - endtask - - integer wfd_result; - task wait_for_done; - input [256*8:1] op_name; - integer cyc; - begin - cyc = 0; - while (!done_o && cyc < TIMEOUT_CYCLES) begin @(posedge clk); cyc = cyc + 1; end - if (cyc >= TIMEOUT_CYCLES) begin - $display("ERROR: %s timeout after %0d cycles", op_name, TIMEOUT_CYCLES); - wfd_result = 0; - end else begin - $display("INFO: %s done after %0d cycles", op_name, cyc); - wfd_result = 1; - end - end - endtask - - initial begin - vec_count = 0; - $readmemh(VECTOR_FILE, input_mem); - $readmemh(EXPECTED_FILE, expected_mem); - - begin - integer found_end = 0; - for (idx = 0; idx < MAX_VECTORS; idx = idx + 1) begin - if (!found_end && (input_mem[idx] === 768'hx || input_mem[idx] === 768'hz)) - found_end = 1; - else if (!found_end) - vec_count = vec_count + 1; - end - end - - if (vec_count == 0) begin - $display("ERROR: No vectors loaded from %s", VECTOR_FILE); - $finish; - end - - $display("===================================================="); - $display("MLKEM_TOP KeyGen-ONLY KAT TESTBENCH"); - $display(" Vectors loaded: %0d", vec_count); - $display("===================================================="); - - mode <= 2'd0; - i_k <= 3'd2; - valid_i <= 1'b0; - rst_n <= 1'b0; - repeat (5) @(posedge clk); - rst_n <= 1'b1; - @(posedge clk); - - force u_dut.chain_kc_ready_o = 1'b1; - force u_dut.ntt_valid_o = 1'b1; - - kg_pass = 0; kg_fail = 0; - - for (idx = 0; idx < vec_count; idx = idx + 1) begin - reg [255:0] d_val, msg_val, z_val; - reg [EXP_PK_WIDTH-1:0] exp_pk; - reg [EXP_SK_WIDTH-1:0] exp_sk; - - d_val = input_mem[idx][767:512]; - msg_val = input_mem[idx][511:256]; - z_val = input_mem[idx][255:0]; - exp_sk = expected_mem[idx][EXP_SS_WIDTH + EXP_CT_WIDTH +: EXP_SK_WIDTH]; - exp_pk = expected_mem[idx][EXP_SS_WIDTH + EXP_CT_WIDTH + EXP_SK_WIDTH +: EXP_PK_WIDTH]; - - $display("--- Vector %0d: KeyGen ---", idx); - print_hex256(d_val, " d "); - - // KeyGen - force u_dut.d_reg = d_val; - mode <= 2'b00; - i_k <= 3'd2; - valid_i <= 1'b1; - @(posedge clk); - valid_i <= 1'b0; - wait_for_done("KeyGen"); - if (wfd_result) begin - release u_dut.d_reg; - if (pk_valid && sk_valid) begin - if (pk_o[EXP_PK_WIDTH-1:0] == exp_pk) begin - $display(" PASS: pk matches expected"); - kg_pass = kg_pass + 1; - end else begin - $display(" FAIL: pk mismatch"); - kg_fail = kg_fail + 1; - end - if (sk_o[SK_WIDTH-1:0] == exp_sk[SK_WIDTH-1:0]) - $display(" PASS: sk matches expected"); - else begin - $display(" FAIL: sk mismatch"); - kg_fail = kg_fail + 1; - end - end else begin - $display(" FAIL: pk_valid=%b sk_valid=%b", pk_valid, sk_valid); - kg_fail = kg_fail + 1; - end - end else begin - release u_dut.d_reg; - $display(" FAIL: KeyGen timeout"); - kg_fail = kg_fail + 1; - rst_n <= 1'b0; repeat (5) @(posedge clk); rst_n <= 1'b1; - force u_dut.chain_kc_ready_o = 1'b1; force u_dut.ntt_valid_o = 1'b1; - @(posedge clk); - end - repeat (2) @(posedge clk); - - // Encaps (run but don't check) - force u_dut.m_reg = msg_val; - mode <= 2'b01; - i_k <= 3'd2; - valid_i <= 1'b1; - @(posedge clk); - valid_i <= 1'b0; - wait_for_done("Encaps"); - if (wfd_result) release u_dut.m_reg; - else begin - release u_dut.m_reg; - rst_n <= 1'b0; repeat (5) @(posedge clk); rst_n <= 1'b1; - force u_dut.chain_kc_ready_o = 1'b1; force u_dut.ntt_valid_o = 1'b1; - @(posedge clk); - end - repeat (2) @(posedge clk); - - // Decaps (run but don't check) - force u_dut.z_reg = z_val; - mode <= 2'b10; - i_k <= 3'd2; - valid_i <= 1'b1; - @(posedge clk); - valid_i <= 1'b0; - wait_for_done("Decaps"); - if (wfd_result) release u_dut.z_reg; - else begin - release u_dut.z_reg; - rst_n <= 1'b0; repeat (5) @(posedge clk); rst_n <= 1'b1; - force u_dut.chain_kc_ready_o = 1'b1; force u_dut.ntt_valid_o = 1'b1; - @(posedge clk); - end - repeat (2) @(posedge clk); - end - - release u_dut.chain_kc_ready_o; - release u_dut.ntt_valid_o; - - $display("===================================================="); - $display("KEYGEN TEST COMPLETE"); - $display(" PASS: %0d FAIL: %0d", kg_pass, kg_fail); - $display("===================================================="); - $finish; - end - - initial begin - #(TIMEOUT_CYCLES * 10 * 100); - $display("FATAL: Global simulation timeout"); - $finish; - end - -endmodule diff --git a/sync_rtl/kg/TB/xsim_run.tcl b/sync_rtl/kg/TB/xsim_run.tcl deleted file mode 100644 index d780989..0000000 --- a/sync_rtl/kg/TB/xsim_run.tcl +++ /dev/null @@ -1,132 +0,0 @@ -# NOTE: On some systems, you may need: -# export LD_PRELOAD=/usr/lib64/libtinfo.so.5 -# before running this script. - -# xsim_run.tcl - Vivado xsim compilation and simulation for KeyGen-only testbench -# -# Compiles ALL RTL dependencies for mlkem_top plus the KeyGen-only testbench. -# Run from the project root: ~/Dev/mlkem/ -# -# Prerequisites: -# source /opt/Xilinx/Vivado/2019.2/settings64.sh -# -# Usage: -# vivado -mode batch -source sync_rtl/kg/TB/xsim_run.tcl - -# ================================================================ -# Configuration -# ================================================================ -set COMMON_DIR sync_rtl/common -set SHA3_DIR sync_rtl/sha3 -set SHA3C_DIR sync_rtl/sha3_chain -set RNG_DIR sync_rtl/rng -set NTT_DIR sync_rtl/ntt -set PA_DIR sync_rtl/poly_arith -set PM_DIR sync_rtl/poly_mul -set CBD_DIR sync_rtl/sample_cbd -set SNT_DIR sync_rtl/sample_ntt -set CD_DIR sync_rtl/comp_decomp -set MA_DIR sync_rtl/mod_add -set STOR_DIR sync_rtl/storage -set TOP_DIR sync_rtl/top -set TB_DIR sync_rtl/kg/TB - -# ================================================================ -# Step 1: Compile common infrastructure -# ================================================================ -puts "=== Compiling common infrastructure ===" -xvlog -sv -i . ${COMMON_DIR}/pipeline_reg.v -xvlog -sv -i . ${COMMON_DIR}/skid_buffer.v - -# ================================================================ -# Step 2: Compile SHA3 / Keccak core -# ================================================================ -puts "=== Compiling SHA3/Keccak core ===" -xvlog -sv ${SHA3_DIR}/keccak_round.v -xvlog -sv ${SHA3_DIR}/keccak_core.v -xvlog -sv -i . ${SHA3_DIR}/sha3_top.v - -# ================================================================ -# Step 3: Compile SHA3 chain (G function) -# ================================================================ -puts "=== Compiling SHA3 chain ===" -xvlog -sv -i . ${SHA3C_DIR}/sha3_chain_top_shared.v - -# ================================================================ -# Step 4: Compile RNG -# ================================================================ -puts "=== Compiling RNG ===" -xvlog -sv ${RNG_DIR}/rng_sync.v - -# ================================================================ -# Step 5: Compile NTT core and dependencies -# ================================================================ -puts "=== Compiling NTT core ===" -xvlog -sv ${NTT_DIR}/zeta_rom.v -xvlog -sv ${NTT_DIR}/barrett_mul.v -xvlog -sv ${NTT_DIR}/butterfly_unit.v -xvlog -sv -i . ${NTT_DIR}/ntt_core.v - -# ================================================================ -# Step 6: Compile polynomial arithmetic -# ================================================================ -puts "=== Compiling polynomial arithmetic ===" -xvlog -sv ${PA_DIR}/poly_arith_sync.v - -# ================================================================ -# Step 7: Compile polynomial multiplication -# ================================================================ -puts "=== Compiling polynomial multiplication ===" -xvlog -sv ${PM_DIR}/poly_mul_zeta_rom.v -xvlog -sv ${PM_DIR}/basecase_mul.v -xvlog -sv -i . ${PM_DIR}/poly_mul_sync.v - -# ================================================================ -# Step 8: Compile sampling modules -# ================================================================ -puts "=== Compiling sampling modules ===" -xvlog -sv -i . ${CBD_DIR}/sample_cbd_sync_shared.v -xvlog -sv -i . ${SNT_DIR}/sample_ntt_sync_shared.v - -# ================================================================ -# Step 9: Compile compression and modular arithmetic -# ================================================================ -puts "=== Compiling compression and modular arithmetic ===" -xvlog -sv ${CD_DIR}/comp_decomp_sync.v -xvlog -sv ${MA_DIR}/mod_add_sync.v - -# ================================================================ -# Step 10: Compile storage (BRAM) -# ================================================================ -puts "=== Compiling storage BRAMs ===" -xvlog -sv ${STOR_DIR}/s_bram.v -xvlog -sv ${STOR_DIR}/sd_bram.v - -# ================================================================ -# Step 11: Compile top-level integration -# ================================================================ -puts "=== Compiling top-level integration ===" -xvlog -sv -i . ${TOP_DIR}/keccak_arbiter.v -xvlog -sv -i . ${TOP_DIR}/mlkem_top.v - -# ================================================================ -# Step 12: Compile testbench -# ================================================================ -puts "=== Compiling KeyGen-only testbench ===" -xvlog -sv ${TB_DIR}/tb_kg_xsim.v - -# ================================================================ -# Step 13: Elaborate snapshot (xelab) -# ================================================================ -puts "=== Elaborating snapshot ===" -xelab tb_kg_xsim -s tb_kg_xsim --timescale 1ns/1ps - -# ================================================================ -# Step 14: Run simulation -# ================================================================ -puts "" -puts "=== Running KeyGen-only simulation ===" -xsim tb_kg_xsim -R - -puts "" -puts "=== KeyGen simulation complete ===" diff --git a/sync_rtl/sha3_chain/TB/gen_vectors.py b/sync_rtl/sha3_chain/TB/gen_vectors.py deleted file mode 100644 index d659ed5..0000000 --- a/sync_rtl/sha3_chain/TB/gen_vectors.py +++ /dev/null @@ -1,85 +0,0 @@ -#!/usr/bin/env python3 -"""gen_vectors.py — Generate SHA3-512 test vectors for tb_sha3_chain_xsim.v - -Computes expected rho and sigma values for sha3_chain_top (ML-KEM G function). - -The RTL computes: SHA3-512(d_in || 0x02) - - d_in: 256-bit input (32 bytes, big-endian) - - 0x02: single byte appended (k=2 parameter for ML-KEM) - - G(d || 0x02) uses SHA3-512 mode (rate=576, suffix=01) - - rho = hash[255:0] (first 256 bits of hash) - - sigma = hash[511:256] (next 256 bits of hash) - -Output: - vectors/sha3_chain_input.hex — 256-bit d_in values (64 hex chars per line) - -Usage: - python3 gen_vectors.py -""" - -import hashlib -import os - -VECTORS_DIR = os.path.join(os.path.dirname(__file__), "vectors") -OUTPUT_FILE = os.path.join(VECTORS_DIR, "sha3_chain_input.hex") - -# Test vectors: (label, d_in value) -TEST_VECTORS = [ - ("all-zeros", 0x0000000000000000000000000000000000000000000000000000000000000000), - ("all-ones", 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF), - ("lsb-one", 0x0000000000000000000000000000000000000000000000000000000000000001), - ("msb-one", 0x8000000000000000000000000000000000000000000000000000000000000000), - ("pattern-aa", 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA), - ("pattern-55", 0x5555555555555555555555555555555555555555555555555555555555555555), - ("random-1", 0x1A2B3C4D5E6F708192A3B4C5D6E7F8091A2B3C4D5E6F708192A3B4C5D6E7F80), - ("random-2", 0xF0E1D2C3B4A5968778695A4B3C2D1E0FF0E1D2C3B4A5968778695A4B3C2D1E0F), -] - - -def sha3_512_g(d_in: int) -> tuple: - """Compute rho, sigma = G(d_in || 0x02) using SHA3-512. - - Returns (rho, sigma) as 256-bit integers. - """ - # d_in as 32 bytes, big-endian (MSB first) - d_bytes = d_in.to_bytes(32, "big") - # Append k=2 as single byte 0x02 - message = d_bytes + b"\x02" - # SHA3-512 hash → 64 bytes - h = hashlib.sha3_512(message).digest() - # rho = first 256 bits, sigma = next 256 bits - rho = int.from_bytes(h[0:32], "big") - sigma = int.from_bytes(h[32:64], "big") - return rho, sigma - - -def main(): - os.makedirs(VECTORS_DIR, exist_ok=True) - - d_in_values = [] - print("// Expected values computed by gen_vectors.py") - print("// SHA3-512(d_in || 0x02)") - print("//" + "=" * 72) - - with open(OUTPUT_FILE, "w") as f: - for label, d_in in TEST_VECTORS: - # Write d_in to hex file (256 bits = 64 hex chars) - f.write(f"{d_in:064X}\n") - d_in_values.append(d_in) - - # Compute expected values - rho, sigma = sha3_512_g(d_in) - print(f"// {label}") - print(f"// d_in = 0x{d_in:064x}") - print(f"// rho = 0x{rho:064x}") - print(f"// sigma = 0x{sigma:064x}") - print() - - print(f"Generated {len(TEST_VECTORS)} vectors → {OUTPUT_FILE}") - print() - print("// Copy the expected values above into tb_sha3_chain_xsim.v") - print("// as hardcoded parameters/initial blocks.") - - -if __name__ == "__main__": - main() diff --git a/sync_rtl/sha3_chain/TB/tb_sha3_chain.cpp b/sync_rtl/sha3_chain/TB/tb_sha3_chain.cpp deleted file mode 100644 index 2cf626f..0000000 --- a/sync_rtl/sha3_chain/TB/tb_sha3_chain.cpp +++ /dev/null @@ -1,179 +0,0 @@ -// tb_sha3_chain.cpp - Verilator C++ testbench for sha3_chain_top -// -// Reads test vectors from +VECTOR_FILE= plusarg. -// Format: one 64-char hex string per line (256-bit d). -// -// Drives d_in, asserts start_i, waits for done_o, -// prints "RESULT: RHO_HEX SIGMA_HEX\n" to stdout. -// -// Clock: 10ns period. Reset: 2 cycles. - -#include -#include -#include -#include -#include -#include "Vsha3_chain_top.h" -#include "verilated.h" - -#define CLK_PERIOD_NS 10.0 -#define TIMEOUT_CYCLES 500000 - -static vluint64_t main_time = 0; - -double sc_time_stamp() { - return main_time; -} - -// One full clock cycle (both edges + eval) -static void posedge(Vsha3_chain_top* dut) { - dut->clk = !dut->clk; - main_time += (vluint64_t)(CLK_PERIOD_NS / 2.0); - dut->eval(); - dut->clk = !dut->clk; - main_time += (vluint64_t)(CLK_PERIOD_NS / 2.0); - dut->eval(); -} - -static int hex_char_to_nibble(char c) { - if (c >= '0' && c <= '9') return c - '0'; - if (c >= 'A' && c <= 'F') return c - 'A' + 10; - if (c >= 'a' && c <= 'f') return c - 'a' + 10; - return 0; -} - -// Parse 64-char hex string into 8 x 32-bit WData words (256 bits). -// Hex is MSB-first (leftmost = bits [255:252]). -// data[0] = bits[31:0], data[7] = bits[255:224]. -static void hex_to_256(const std::string& hex, uint32_t data_words[8]) { - for (int w = 0; w < 8; w++) data_words[w] = 0; - - int nibble_idx = 0; - for (int i = (int)hex.length() - 1; i >= 0; i--) { - char c = hex[i]; - if (c == ' ' || c == '\t') continue; - int nib = hex_char_to_nibble(c); - int word_idx = nibble_idx / 8; - int shift = (nibble_idx % 8) * 4; - if (word_idx < 8) { - data_words[word_idx] |= ((uint32_t)nib << shift); - } - nibble_idx++; - } -} - -// Print rho_out and sigma_out as hex (MSB-first), space-separated. -// rho[0]=bits[31:0], rho[7]=bits[255:224] -// sigma[0]=bits[31:0], sigma[7]=bits[255:224] -static void print_256_hex(uint32_t data_words[8]) { - for (int w = 7; w >= 0; w--) { - uint32_t val = data_words[w]; - for (int j = 28; j >= 0; j -= 4) { - printf("%01X", (int)((val >> j) & 0xF)); - } - } -} - -int main(int argc, char** argv) { - Verilated::commandArgs(argc, argv); - - // Parse +VECTOR_FILE= plusarg - const char* vector_file = NULL; - for (int i = 1; i < argc; i++) { - std::string arg(argv[i]); - if (arg.rfind("+VECTOR_FILE=", 0) == 0) { - vector_file = argv[i] + 13; - } - } - - if (!vector_file) { - std::cerr << "ERROR: +VECTOR_FILE= not specified" << std::endl; - return 1; - } - - std::ifstream infile(vector_file); - if (!infile.is_open()) { - std::cerr << "ERROR: Cannot open vector file: " << vector_file << std::endl; - return 1; - } - - // Instantiate DUT - Vsha3_chain_top* dut = new Vsha3_chain_top; - - // Initialize - dut->clk = 0; - dut->rst_n = 0; - for (int w = 0; w < 8; w++) dut->d_in[w] = 0; - dut->start_i = 0; - - // Reset: 2 full cycles - for (int i = 0; i < 2; i++) posedge(dut); - dut->rst_n = 1; - - std::string line; - vluint64_t cycle = 0; - int vec_count = 0; - - while (std::getline(infile, line)) { - if (line.empty() || line[0] == '#') continue; - - std::string d_hex = line; - // Trim trailing whitespace - while (!d_hex.empty() && (d_hex.back() == ' ' || d_hex.back() == '\t' || d_hex.back() == '\r')) - d_hex.pop_back(); - - // Parse d - uint32_t d_words[8]; - hex_to_256(d_hex, d_words); - for (int w = 0; w < 8; w++) dut->d_in[w] = d_words[w]; - - // Assert start_i - dut->start_i = 1; - - // One cycle with start_i=1 - cycle++; - posedge(dut); - - // De-assert start_i - dut->start_i = 0; - - // Wait for done_o - while (!dut->done_o) { - posedge(dut); - cycle++; - if (cycle > TIMEOUT_CYCLES) { - std::cerr << "ERROR: Timeout waiting for done_o (vec " << vec_count << ")" << std::endl; - goto done; - } - } - - // Read outputs - uint32_t rho_words[8], sigma_words[8]; - for (int w = 0; w < 8; w++) { - rho_words[w] = dut->rho_out[w]; - sigma_words[w] = dut->sigma_out[w]; - } - - printf("RESULT: "); - print_256_hex(rho_words); - printf(" "); - print_256_hex(sigma_words); - printf("\n"); - - // One cycle with done_o high, then start_i must be low to return to IDLE - posedge(dut); - cycle++; - vec_count++; - } - -done: - infile.close(); - delete dut; - - if (vec_count == 0) { - std::cerr << "ERROR: No vectors processed" << std::endl; - return 1; - } - - return 0; -} diff --git a/sync_rtl/sha3_chain/TB/tb_sha3_chain_xsim.v b/sync_rtl/sha3_chain/TB/tb_sha3_chain_xsim.v deleted file mode 100644 index b12137b..0000000 --- a/sync_rtl/sha3_chain/TB/tb_sha3_chain_xsim.v +++ /dev/null @@ -1,287 +0,0 @@ -// tb_sha3_chain_xsim.v - Vivado xsim testbench for sha3_chain_top -// -// Tests the ML-KEM G function: SHA3-512(d_in || 0x02) → {rho, sigma}. -// Uses $readmemh file-based test vectors for d_in values. -// -// Vector format (256 bits = 64 hex chars per line): -// Each line is a 256-bit d_in value (MSB-first hex). -// -// Expected rho/sigma values are hardcoded (computed by gen_vectors.py -// using hashlib.sha3_512). -// -// Protocol: start_i / done_o handshake -// 1. Drive d_in, assert start_i=1 -// 2. Wait for done_o=1 (with timeout watchdog) -// 3. Capture rho_out, sigma_out -// 4. Compare with expected values -// 5. Deassert start_i (FSM returns to IDLE) - -`timescale 1ns / 1ps - -module tb_sha3_chain_xsim; - - // ================================================================ - // Parameters - // ================================================================ - parameter VECTOR_FILE = "sync_rtl/sha3_chain/TB/vectors/sha3_chain_input.hex"; - parameter RESULT_FILE = "sync_rtl/sha3_chain/TB/vectors/sha3_chain_result.hex"; - parameter MAX_VECTORS = 256; - parameter TIMEOUT_CYCLES = 2000; - - // ================================================================ - // DUT signals - // ================================================================ - reg clk; - reg rst_n; - reg [255:0] d_in; - reg start_i; - wire done_o; - wire [255:0] rho_out; - wire [255:0] sigma_out; - - // ================================================================ - // Expected values (computed by gen_vectors.py) - // 8 test vectors total - // ================================================================ - reg [255:0] expected_rho [0:7]; - reg [255:0] expected_sigma [0:7]; - - initial begin - // all-zeros - expected_rho[0] = 256'h6a0af64a85e909df8e2816605d20b4e382b30bbb61bf3a5f821a0b5dba9ad3e7; - expected_sigma[0] = 256'he367d3e9ab3b86b64230aa8bf8815d408ef819f9e9d956ce22bbc2f68eaa9e3a; - // all-ones - expected_rho[1] = 256'hf393670510fe33b5df9efb515bf1515c84bdf625e3c53154c10c7d2c92b7f234; - expected_sigma[1] = 256'h9fac853f1e61e8389a04fc710845963c18e48fbec11c66d7d6567f8e168160cc; - // lsb-one - expected_rho[2] = 256'h90ad3aafcc6bde61dc5014cf6cdee8065504733fc0caa8bddf3e1689a7b7b302; - expected_sigma[2] = 256'h3c8686e00e96619b07c7d56fa1effce7ec5597f94a9109ec40c2a6314f6e4ada; - // msb-one - expected_rho[3] = 256'h6c914803c353f4f3b4d8cc541b67019dd2d04cd0fb2ba51b8ebaba973d8f5cbe; - expected_sigma[3] = 256'h33d64b904e1afa541dbe72162021b54c7aef182125da38d88dd7d076636af6cf; - // pattern-aa - expected_rho[4] = 256'h561a98ff76434dc201ca8152cf2b97342090157a522354e299db35fec29690aa; - expected_sigma[4] = 256'hed57f5826ed6e77c756cf821244b350e6b34eb05f9639e227f9a5e130eca649f; - // pattern-55 - expected_rho[5] = 256'hff31fe4fc62849226d9197992b1a2d0429c2c325011d2c7bb48860920c04636c; - expected_sigma[5] = 256'hdb5f9599ae43d39fa182896d0ab1d1af663f19355dfeb951fed7b1c8c94eb0d3; - // random-1 - expected_rho[6] = 256'h4538916fc357ba9fe24033fa8c1e18cbfb14faf7e1771e0d7521c80cb0d4379f; - expected_sigma[6] = 256'h78565d212000aabb8086e3373ad82d45c07589bcca35409a3f5d9fd30623340e; - // random-2 - expected_rho[7] = 256'h176c0b7e91b90ae50757b14bbec130a9e328d09d020466565829de47f6b387cd; - expected_sigma[7] = 256'h413f41c838828e079d5e06b06de61eed6b5bd5005b334e516be6e3b900da7938; - end - - // ================================================================ - // DUT instantiation - // ================================================================ - sha3_chain_top u_dut ( - .clk (clk), - .rst_n (rst_n), - .d_in (d_in), - .start_i (start_i), - .done_o (done_o), - .rho_out (rho_out), - .sigma_out(sigma_out) - ); - - // ================================================================ - // Clock generation: 100 MHz (10 ns period) - // ================================================================ - initial clk = 1'b0; - always #5 clk = ~clk; - - // ================================================================ - // Vector memory (loaded by $readmemh) - // ================================================================ - reg [255:0] vector_mem [0:MAX_VECTORS-1]; - integer vec_count; - integer idx; - integer cycle_count; - integer result_fd; - integer pass_count; - integer fail_count; - - // ================================================================ - // Hex-to-ASCII conversion helper - // ================================================================ - function [7:0] nibble_to_ascii; - input [3:0] nibble; - begin - if (nibble < 4'd10) - nibble_to_ascii = 8'h30 + {4'd0, nibble}; - else - nibble_to_ascii = 8'h41 + ({4'd0, nibble} - 4'd10); - end - endfunction - - // ================================================================ - // Main test sequence - // ================================================================ - initial begin - vec_count = 0; - $readmemh(VECTOR_FILE, vector_mem); - - // Count non-X entries - begin - integer found_end; - found_end = 0; - for (idx = 0; idx < MAX_VECTORS; idx = idx + 1) begin - if (!found_end && (vector_mem[idx] === 256'hx || vector_mem[idx] === 256'hz)) - found_end = 1; - else if (!found_end) - vec_count = vec_count + 1; - end - end - - if (vec_count == 0) begin - $display("ERROR: No vectors loaded from %s", VECTOR_FILE); - $display(" Check that the file exists."); - $display(" Format: 64 hex chars per line (256-bit d_in)"); - $finish; - end - - $display("INFO: Loaded %0d test vectors from %s", vec_count, VECTOR_FILE); - - // Open result file - result_fd = $fopen(RESULT_FILE, "w"); - if (result_fd == 0) begin - $display("ERROR: Cannot open result file: %s", RESULT_FILE); - $finish; - end - - // Initialize DUT inputs - d_in <= 256'd0; - start_i <= 1'b0; - - // Reset sequence: rst_n low for 3 cycles, then high - rst_n <= 1'b0; - repeat (3) @(posedge clk); - rst_n <= 1'b1; - @(posedge clk); - - pass_count = 0; - fail_count = 0; - - // ============================================================ - // Process each vector - // ============================================================ - for (idx = 0; idx < vec_count; idx = idx + 1) begin - begin - reg [255:0] vec_d_in; - reg [255:0] captured_rho; - reg [255:0] captured_sigma; - integer bit_idx; - reg [3:0] nib; - - vec_d_in = vector_mem[idx]; - - $display("INFO: Vector %0d - d_in=0x%064h", idx, vec_d_in); - - // Drive d_in and assert start_i - d_in <= vec_d_in; - start_i <= 1'b1; - @(posedge clk); - - // Wait for done_o (with timeout) - cycle_count = 0; - while (!done_o && cycle_count < TIMEOUT_CYCLES) begin - @(posedge clk); - cycle_count = cycle_count + 1; - end - - if (cycle_count >= TIMEOUT_CYCLES) begin - $display("ERROR: Timeout waiting for done_o on vector %0d", idx); - $fwrite(result_fd, "TIMEOUT: vector %0d d_in=0x%064h\n", idx, vec_d_in); - fail_count = fail_count + 1; - // Force reset the FSM - start_i <= 1'b0; - @(posedge clk); - end else begin - // Capture outputs (valid on cycle done_o=1) - captured_rho = rho_out; - captured_sigma = sigma_out; - - // Deassert start_i (FSM returns to IDLE on next cycle) - start_i <= 1'b0; - - // Check rho - if (captured_rho !== expected_rho[idx]) begin - $display("FAIL: Vector %0d RHO mismatch", idx); - $display(" expected = 0x%064h", expected_rho[idx]); - $display(" got = 0x%064h", captured_rho); - $fwrite(result_fd, "FAIL: vector %0d RHO expected=0x%064h got=0x%064h\n", - idx, expected_rho[idx], captured_rho); - fail_count = fail_count + 1; - end else begin - pass_count = pass_count + 1; - end - - // Check sigma - if (captured_sigma !== expected_sigma[idx]) begin - $display("FAIL: Vector %0d SIGMA mismatch", idx); - $display(" expected = 0x%064h", expected_sigma[idx]); - $display(" got = 0x%064h", captured_sigma); - $fwrite(result_fd, "FAIL: vector %0d SIGMA expected=0x%064h got=0x%064h\n", - idx, expected_sigma[idx], captured_sigma); - fail_count = fail_count + 1; - end else begin - pass_count = pass_count + 1; - end - - // Write results to output file - $fwrite(result_fd, "RESULT: %0d ", idx); - $fwrite(result_fd, "d_in=0x"); - for (bit_idx = 63; bit_idx >= 0; bit_idx = bit_idx - 1) begin - nib = vec_d_in[(bit_idx*4)+:4]; - $fwrite(result_fd, "%c", nibble_to_ascii(nib)); - end - $fwrite(result_fd, " rho=0x"); - for (bit_idx = 63; bit_idx >= 0; bit_idx = bit_idx - 1) begin - nib = captured_rho[(bit_idx*4)+:4]; - $fwrite(result_fd, "%c", nibble_to_ascii(nib)); - end - $fwrite(result_fd, " sigma=0x"); - for (bit_idx = 63; bit_idx >= 0; bit_idx = bit_idx - 1) begin - nib = captured_sigma[(bit_idx*4)+:4]; - $fwrite(result_fd, "%c", nibble_to_ascii(nib)); - end - $fwrite(result_fd, "\n"); - - @(posedge clk); - end - end // inner begin block - end - - // ============================================================ - // Summary - // ============================================================ - $fclose(result_fd); - - $display("========================================"); - $display("SHA3 CHAIN TEST COMPLETE"); - $display(" Total vectors: %0d", vec_count); - $display(" Checks (rho+sigma): %0d", vec_count * 2); - $display(" Passed: %0d", pass_count); - $display(" Failed: %0d", fail_count); - $display(" Results written to: %s", RESULT_FILE); - if (fail_count == 0) - $display(" RESULT: ALL TESTS PASSED"); - else - $display(" RESULT: SOME TESTS FAILED"); - $display("========================================"); - - $finish; - end - - // ================================================================ - // Timeout watchdog - // ================================================================ - initial begin - #(TIMEOUT_CYCLES * 10 * 100); - $display("FATAL: Global simulation timeout reached"); - $finish; - end - -endmodule diff --git a/sync_rtl/sha3_chain/TB/vectors/sha3_chain_input.hex b/sync_rtl/sha3_chain/TB/vectors/sha3_chain_input.hex deleted file mode 100644 index e0c0bac..0000000 --- a/sync_rtl/sha3_chain/TB/vectors/sha3_chain_input.hex +++ /dev/null @@ -1,8 +0,0 @@ -0000000000000000000000000000000000000000000000000000000000000000 -FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF -0000000000000000000000000000000000000000000000000000000000000001 -8000000000000000000000000000000000000000000000000000000000000000 -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -5555555555555555555555555555555555555555555555555555555555555555 -01A2B3C4D5E6F708192A3B4C5D6E7F8091A2B3C4D5E6F708192A3B4C5D6E7F80 -F0E1D2C3B4A5968778695A4B3C2D1E0FF0E1D2C3B4A5968778695A4B3C2D1E0F diff --git a/sync_rtl/sha3_chain/TB/xsim_run.tcl b/sync_rtl/sha3_chain/TB/xsim_run.tcl deleted file mode 100644 index 3f0ad1f..0000000 --- a/sync_rtl/sha3_chain/TB/xsim_run.tcl +++ /dev/null @@ -1,68 +0,0 @@ -# NOTE: On some systems, you may need: -# export LD_PRELOAD=/usr/lib64/libtinfo.so.5 -# before running this script. - -# xsim_run.tcl - Vivado xsim compilation and simulation script -# -# Compiles sha3_chain_top with all SHA3 dependencies plus testbench. -# Run from the project root: ~/Dev/mlkem/ -# -# Dependencies: -# sync_rtl/sha3/keccak_round.v (combinational Keccak round) -# sync_rtl/sha3/keccak_core.v (24-round Keccak core) -# sync_rtl/sha3/sha3_top.v (SHA3 G/H/J top wrapper) -# sync_rtl/sha3_chain/sha3_chain_top.v (ML-KEM G function) -# -# Prerequisites: -# source /opt/Xilinx/Vivado/2019.2/settings64.sh -# -# Usage: -# xsim -runall xsim_run.tcl -# vivado -mode batch -source xsim_run.tcl - -# ================================================================ -# Configuration -# ================================================================ -set SHA3_DIR sync_rtl/sha3 -set SHA3_CHAIN_DIR sync_rtl/sha3_chain -set TB_DIR sync_rtl/sha3_chain/TB - -# ================================================================ -# Step 1: Compile RTL sources (xvlog) -# ================================================================ -puts "=== Compiling SHA3 RTL sources ===" - -# Core Keccak module (combinational round) -xvlog -sv --relax -i . sync_rtl/sha3/keccak_round.v - -# Keccak core (24-round sequential core) -xvlog -sv --relax -i . sync_rtl/sha3/keccak_core.v - -# SHA3 top wrapper (G/H/J modes) -xvlog -sv --relax -i . sync_rtl/sha3/sha3_top.v - -# sha3_chain_top (ML-KEM G function) -xvlog -sv --relax -i . sync_rtl/sha3_chain/sha3_chain_top.v - -# ================================================================ -# Step 2: Compile testbench -# ================================================================ -puts "=== Compiling testbench ===" - -xvlog -sv --relax sync_rtl/sha3_chain/TB/tb_sha3_chain_xsim.v - -# ================================================================ -# Step 3: Elaborate snapshot (xelab) -# ================================================================ -puts "=== Elaborating snapshot ===" - -xelab tb_sha3_chain_xsim -s tb_sha3_chain_xsim --timescale 1ns/1ps - -# ================================================================ -# Step 4: Run simulation -# ================================================================ -puts "=== Running sha3_chain test ===" -xsim tb_sha3_chain_xsim -R - -puts "" -puts "=== sha3_chain simulation complete ===" diff --git a/sync_rtl/sha3_chain/sha3_chain_top.v b/sync_rtl/sha3_chain/sha3_chain_top.v deleted file mode 100644 index e391d64..0000000 --- a/sync_rtl/sha3_chain/sha3_chain_top.v +++ /dev/null @@ -1,93 +0,0 @@ -// sha3_chain_top.v - Simple integration module: d → SHA3_G(d||k=2) -// -// Feeds external 256-bit d to sha3_top in G mode with k=2, captures -// rho (first 256 bits) and sigma (next 256 bits) from the hash output. -// -// 3-state FSM: IDLE → BUSY → DONE -// -// Interface: -// clk, rst_n - clock, active-low reset -// d_in[255:0] - 256-bit d input (external, NOT from RNG) -// start_i - start computation -// done_o - computation complete -// rho_out - G output first 256 bits -// sigma_out - G output next 256 bits - -module sha3_chain_top ( - input clk, - input rst_n, - input [255:0] d_in, - input start_i, - output done_o, - output [255:0] rho_out, - output [255:0] sigma_out -); - - localparam ST_IDLE = 2'd0; - localparam ST_BUSY = 2'd1; - localparam ST_DONE = 2'd2; - - reg [1:0] state_r, state_next; - - // ── sha3_top signals ── - wire [511:0] sha3_data_i; - wire sha3_valid_i; - wire sha3_ready_o; - wire [511:0] sha3_hash_o; - wire sha3_valid_o; - - // data_i = {248'b0, k=8'd2, d_in} - assign sha3_data_i = {248'b0, 8'd2, d_in}; - - sha3_top u_sha3 ( - .clk (clk), - .rst_n (rst_n), - .mode (2'b00), // G mode (SHA3-512) - .data_i (sha3_data_i), - .valid_i (sha3_valid_i), - .ready_o (sha3_ready_o), - .hash_o (sha3_hash_o), - .valid_o (sha3_valid_o), - .ready_i (1'b1) // always accept output - ); - - // valid_i: assert when IDLE + start_i + sha3 ready - assign sha3_valid_i = (state_r == ST_IDLE) && start_i && sha3_ready_o; - - // done_o - assign done_o = (state_r == ST_DONE); - - // ── output registers ── - reg [255:0] rho_out_r, sigma_out_r; - assign rho_out = rho_out_r; - assign sigma_out = sigma_out_r; - - // ── FSM combinational next-state ── - always @(*) begin - state_next = state_r; - case (state_r) - ST_IDLE: if (start_i && sha3_ready_o) state_next = ST_BUSY; - ST_BUSY: if (sha3_valid_o) state_next = ST_DONE; - ST_DONE: if (!start_i) state_next = ST_IDLE; - default: state_next = ST_IDLE; - endcase - end - - // ── sequential logic ── - always @(posedge clk or negedge rst_n) begin - if (!rst_n) begin - state_r <= ST_IDLE; - rho_out_r <= 256'd0; - sigma_out_r <= 256'd0; - end else begin - state_r <= state_next; - - // Capture output when BUSY → DONE - if (state_r == ST_BUSY && sha3_valid_o) begin - rho_out_r <= sha3_hash_o[255:0]; - sigma_out_r <= sha3_hash_o[511:256]; - end - end - end - -endmodule diff --git a/sync_rtl/sha3_chain/sha3_chain_top_shared.v b/sync_rtl/sha3_chain/sha3_chain_top_shared.v deleted file mode 100644 index e5b5978..0000000 --- a/sync_rtl/sha3_chain/sha3_chain_top_shared.v +++ /dev/null @@ -1,115 +0,0 @@ -// sha3_chain_top_shared.v - SHA3-512 chain: G(d||k=2) → rho, sigma -// -// Refactored version that accepts an external keccak_core interface instead -// of instantiating sha3_top internally. Designed for shared-keccak top-level -// integration where a single keccak_core is time-multiplexed via an arbiter. -// -// The internal logic replicates sha3_top's G-mode absorb-state construction -// and keccak sequencing, but exposes keccak_core signals through the port -// list so the arbiter can route them. -// -// 3-state FSM: IDLE → BUSY → DONE -// -// Interface: -// clk, rst_n - clock, active-low reset -// d_in[255:0] - 256-bit d input (external, NOT from RNG) -// start_i - start computation -// done_o - computation complete (pulsed for duration of DONE) -// rho_out[255:0] - G output first 256 bits -// sigma_out[255:0] - G output next 256 bits -// kc_state_o[1599:0]- from keccak_core output (post-permutation state) -// kc_valid_o - from keccak_core (permutation complete) -// kc_ready_i - to keccak_core (always accept output = 1'b1) -// kc_state_i[1599:0]- to keccak_core input (pre-permutation state) -// kc_valid_i - to keccak_core (start permutation pulse) -// kc_ready_o - from keccak_core (core is idle / can accept) - -module sha3_chain_top_shared ( - input clk, - input rst_n, - input [255:0] d_in, - input start_i, - output done_o, - output [255:0] rho_out, - output [255:0] sigma_out, - // keccak_core interface (connect to shared arbiter) - input [1599:0] kc_state_o, - input kc_valid_o, - output kc_ready_i, - output [1599:0] kc_state_i, - output kc_valid_i, - input kc_ready_o -); - - localparam ST_IDLE = 2'd0; - localparam ST_BUSY = 2'd1; - localparam ST_DONE = 2'd2; - - reg [1:0] state_r, state_next; - - // ================================================================ - // Absorb state: message || suffix || pad10*1 into rate bits - // - // Replicates sha3_top G-mode absorb_state construction: - // data_i = {248'b0, k=8'd2, d_in} - // G: padded_block = {1'b1, {308{1'b0}}, 1'b1, 2'b10, data_i[263:0]} - // absorb_state = {1024'b0, padded_block_576} - // ================================================================ - wire [511:0] sha3_data_i; - wire [575:0] g_pad; - wire [1599:0] absorb_state; - - assign sha3_data_i = {248'b0, 8'd2, d_in}; - assign g_pad = {1'b1, {308{1'b0}}, 1'b1, 2'b10, sha3_data_i[263:0]}; - assign absorb_state = {{(1600-576){1'b0}}, g_pad}; - - // ================================================================ - // keccak_core interface connections - // ================================================================ - assign kc_ready_i = 1'b1; // always accept output - assign kc_state_i = absorb_state; // feed absorb state combinationally - assign kc_valid_i = (state_next == ST_BUSY); // start keccak on IDLE → BUSY - - // done_o: asserted for duration of DONE state - assign done_o = (state_r == ST_DONE); - - // ================================================================ - // Output registers - // ================================================================ - reg [255:0] rho_out_r, sigma_out_r; - assign rho_out = rho_out_r; - assign sigma_out = sigma_out_r; - - // ================================================================ - // FSM combinational next-state - // ================================================================ - always @(*) begin - state_next = state_r; - case (state_r) - ST_IDLE: if (start_i && kc_ready_o) state_next = ST_BUSY; - ST_BUSY: if (kc_valid_o) state_next = ST_DONE; - ST_DONE: if (!start_i) state_next = ST_IDLE; - default: state_next = ST_IDLE; - endcase - end - - // ================================================================ - // Sequential logic - // ================================================================ - always @(posedge clk or negedge rst_n) begin - if (!rst_n) begin - state_r <= ST_IDLE; - rho_out_r <= 256'd0; - sigma_out_r <= 256'd0; - end else begin - state_r <= state_next; - - // Capture squeezed output when BUSY → DONE - if (state_r == ST_BUSY && kc_valid_o) begin - rho_out_r <= kc_state_o[255:0]; - sigma_out_r <= kc_state_o[511:256]; - end - end - end - -endmodule diff --git a/sync_rtl/top/TB/tb_mlkem_top_xsim.v b/sync_rtl/top/TB/tb_mlkem_top_xsim.v deleted file mode 100644 index 9e63949..0000000 --- a/sync_rtl/top/TB/tb_mlkem_top_xsim.v +++ /dev/null @@ -1,491 +0,0 @@ -// tb_mlkem_top_xsim.v - KAT (Known Answer Test) testbench for mlkem_top -// -// Reads FIPS 203 test vectors from hex files using $readmemh. -// Uses Verilog `force` to inject known d/z/m values into the DUT's -// internal registers, overriding the internal RNG output for deterministic -// KAT verification. -// -// IMPORTANT: The mlkem_top module has a known design deadlock: -// sha3_chain_top_shared requires kc_ready_o to transition IDLE→BUSY, -// but keccak_arbiter requires cons_valid_i[0]=1 before granting it. -// Workaround: force chain_kc_ready_o wire to 1 during all tests. -// -// Input vector format (192 hex chars = 768 bits per line): -// bits [767:512] = d (256 bits) -// bits [511:256] = msg (256 bits) -// bits [255:0] = z (256 bits) -// -// Expected output format (6464 hex chars = 25856 bits per line): -// bits [25855:19456] = pk (800 bytes = 6400 bits) -// bits [19455:6400] = sk (1632 bytes = 13056 bits) -// bits [6399:256] = ct (768 bytes = 6144 bits) -// bits [255:0] = ss (32 bytes = 256 bits) -// -// Test flow per vector: -// 1. Force d_reg and run KeyGen → verify done_o, capture pk/sk -// 2. Force m_reg and run Encaps → verify done_o, capture ct/K -// 3. Force z_reg and run Decaps → verify done_o, capture K_dec -// -// Usage: -// xvlog -sv -i . .v tb_mlkem_top_xsim.v -// xelab tb_mlkem_top_xsim -s tb_mlkem_top_xsim --timescale 1ns/1ps -// xsim tb_mlkem_top_xsim -R - -`timescale 1ns / 1ps - -module tb_mlkem_top_xsim; - - // ================================================================ - // Parameters - // ================================================================ - parameter VECTOR_FILE = "sync_rtl/top/TB/vectors/mlkem_top_input.hex"; - parameter EXPECTED_FILE = "sync_rtl/top/TB/vectors/mlkem_top_expected.hex"; - parameter MAX_VECTORS = 16; - parameter TIMEOUT_CYCLES = 10000000; // mlkem_top is SLOW (millions of cycles) - parameter K_PARAM = 4; // matches DUT K=4 - localparam PK_WIDTH = 12 * K_PARAM * 256; // 12288 - localparam SK_WIDTH = 12 * K_PARAM * 256; // 12288 - localparam CT_WIDTH = 12 * K_PARAM * 256; // 12288 - // Expected widths for ML-KEM-512 (k=2): - localparam EXP_PK_WIDTH = 6400; // 800 bytes - localparam EXP_SK_WIDTH = 13056; // 1632 bytes - localparam EXP_CT_WIDTH = 6144; // 768 bytes - localparam EXP_SS_WIDTH = 256; // 32 bytes - - // ================================================================ - // DUT signals - // ================================================================ - reg clk; - reg rst_n; - reg [1:0] mode; - reg [2:0] i_k; - reg valid_i; - wire ready_o; - - wire [PK_WIDTH-1:0] pk_o; - wire [SK_WIDTH-1:0] sk_o; - wire pk_valid; - wire sk_valid; - - wire [CT_WIDTH-1:0] ct_o; - wire [255:0] K_o; - wire ct_valid; - wire K_valid; - - wire [255:0] K_o_dec; - wire K_valid_dec; - wire done_o; - - // ================================================================ - // DUT instantiation - // ================================================================ - mlkem_top #(.K(K_PARAM)) u_dut ( - .clk (clk), - .rst_n (rst_n), - .mode (mode), - .i_k (i_k), - .valid_i (valid_i), - .ready_o (ready_o), - .pk_o (pk_o), - .sk_o (sk_o), - .pk_valid (pk_valid), - .sk_valid (sk_valid), - .ct_o (ct_o), - .K_o (K_o), - .ct_valid (ct_valid), - .K_valid (K_valid), - .K_o_dec (K_o_dec), - .K_valid_dec (K_valid_dec), - .done_o (done_o) - ); - - // ================================================================ - // Clock generation: 100 MHz (10 ns period) - // ================================================================ - initial clk = 1'b0; - always #5 clk = ~clk; - - // ================================================================ - // Vector memories (loaded by $readmemh) - // ================================================================ - reg [767:0] input_mem [0:MAX_VECTORS-1]; - reg [25855:0] expected_mem [0:MAX_VECTORS-1]; - - // ================================================================ - // Test variables - // ================================================================ - integer vec_count; - integer idx; - integer cycle_count; - integer pass_count; - integer fail_count; - integer kg_pass, kg_fail; - integer en_pass, en_fail; - integer dc_pass, dc_fail; - - // ================================================================ - // Hex-to-ASCII conversion helper - // ================================================================ - function [7:0] nibble_to_ascii; - input [3:0] nibble; - begin - if (nibble < 4'd10) - nibble_to_ascii = 8'h30 + {4'd0, nibble}; - else - nibble_to_ascii = 8'h41 + ({4'd0, nibble} - 4'd10); - end - endfunction - - // ================================================================ - // Print 256-bit value as hex - // ================================================================ - task print_hex256; - input [255:0] val; - input [256*8:1] label; - integer bit_idx; - reg [3:0] nib; - begin - $write("%s: ", label); - for (bit_idx = 63; bit_idx >= 0; bit_idx = bit_idx - 1) begin - nib = val[(bit_idx*4)+:4]; - $write("%c", nibble_to_ascii(nib)); - end - $write("\n"); - end - endtask - - // ================================================================ - // Wait for done_o with timeout - // Sets result_var: 0 = timeout, 1 = got done - // ================================================================ - integer wfd_result; - task wait_for_done; - input [256*8:1] op_name; - integer cyc; - begin - cyc = 0; - while (!done_o && cyc < TIMEOUT_CYCLES) begin - @(posedge clk); - cyc = cyc + 1; - end - if (cyc >= TIMEOUT_CYCLES) begin - $display("ERROR: %s timeout after %0d cycles", op_name, TIMEOUT_CYCLES); - wfd_result = 0; - end else begin - $display("INFO: %s done after %0d cycles", op_name, cyc); - wfd_result = 1; - end - end - endtask - - // ================================================================ - // Main test sequence - // ================================================================ - initial begin - // ------------------------------------------------------------ - // Count loaded vectors - // ------------------------------------------------------------ - vec_count = 0; - - // Load vectors from hex files - $readmemh(VECTOR_FILE, input_mem); - $readmemh(EXPECTED_FILE, expected_mem); - - // Count non-X entries to determine actual vector count - begin - integer found_end; - found_end = 0; - for (idx = 0; idx < MAX_VECTORS; idx = idx + 1) begin - if (!found_end && (input_mem[idx] === 768'hx || input_mem[idx] === 768'hz)) - found_end = 1; - else if (!found_end) - vec_count = vec_count + 1; - end - end - - if (vec_count == 0) begin - $display("ERROR: No vectors loaded from %s", VECTOR_FILE); - $display(" Check that the file exists and is in the correct format."); - $display(" Each line: <192 hex chars> = d(64) + msg(64) + z(64)"); - $finish; - end - - $display("===================================================="); - $display("MLKEM_TOP KAT TESTBENCH"); - $display(" Vectors loaded: %0d", vec_count); - $display(" Input file: %s", VECTOR_FILE); - $display(" Expected file: %s", EXPECTED_FILE); - $display(" Timeout: %0d cycles (~%0d ms)", - TIMEOUT_CYCLES, TIMEOUT_CYCLES * 10 / 1000); - $display("===================================================="); - - // ------------------------------------------------------------ - // Initialize signals - // ------------------------------------------------------------ - mode <= 2'd0; - i_k <= 3'd2; // ML-KEM-512 - valid_i <= 1'b0; - - // Reset sequence: rst_n low for 3 cycles, then high - rst_n <= 1'b0; - repeat (5) @(posedge clk); - rst_n <= 1'b1; - @(posedge clk); - - // ------------------------------------------------------------ - // WORKAROUND: Force chain_kc_ready_o to break arbiter deadlock - // The sha3_chain_top_shared module requires kc_ready_o=1 in its - // ST_IDLE→ST_BUSY transition, but the keccak_arbiter won't - // assert cons_ready_o[0] until cons_valid_i[0]=1 (which the - // chain doesn't assert until it reaches ST_BUSY). Deadlock. - // Forcing chain_kc_ready_o=1 breaks this cycle. - // - // WORKAROUND: Force ntt_valid_o to 1 to fix done_o timing issue - // The mlkem_top FSM uses ntt_done_o to enter the output-read - // state, but ntt_core asserts done_o AFTER S_OUTPUT completes. - // Forcing ntt_valid_o=1 lets the FSM complete its output phase. - // ------------------------------------------------------------ - force u_dut.chain_kc_ready_o = 1'b1; - force u_dut.ntt_valid_o = 1'b1; - $display("INFO: Forced chain_kc_ready_o=1 (arbiter deadlock workaround)"); - $display("INFO: Forced ntt_valid_o=1 (ntt done_o timing workaround)"); - - // Reset counters - pass_count = 0; - fail_count = 0; - kg_pass = 0; kg_fail = 0; - en_pass = 0; en_fail = 0; - dc_pass = 0; dc_fail = 0; - - // ============================================================ - // Process each vector - // ============================================================ - for (idx = 0; idx < vec_count; idx = idx + 1) begin - reg [255:0] d_val, msg_val, z_val; - reg [EXP_PK_WIDTH-1:0] exp_pk; - reg [EXP_SK_WIDTH-1:0] exp_sk; - reg [EXP_CT_WIDTH-1:0] exp_ct; - reg [EXP_SS_WIDTH-1:0] exp_ss; - - // Extract test vector fields - d_val = input_mem[idx][767:512]; - msg_val = input_mem[idx][511:256]; - z_val = input_mem[idx][255:0]; - - // Extract expected outputs - exp_ss = expected_mem[idx][0 +: EXP_SS_WIDTH]; - exp_ct = expected_mem[idx][EXP_SS_WIDTH +: EXP_CT_WIDTH]; - exp_sk = expected_mem[idx][EXP_SS_WIDTH + EXP_CT_WIDTH +: EXP_SK_WIDTH]; - exp_pk = expected_mem[idx][EXP_SS_WIDTH + EXP_CT_WIDTH + EXP_SK_WIDTH +: EXP_PK_WIDTH]; - - $display("----------------------------------------------------"); - $display("VECTOR %0d (count=%0d)", idx, idx); - print_hex256(d_val, " d "); - print_hex256(msg_val, " msg"); - print_hex256(z_val, " z "); - print_hex256(exp_ss, " expected ss"); - - // ======================================================== - // STEP 1: KeyGen (mode=00) - // ======================================================== - $display("--- KeyGen ---"); - - // Force d_reg to KAT value RIGHT NOW (before starting KeyGen) - // The force persists until we release it - force u_dut.d_reg = d_val; - - // Start KeyGen - mode <= 2'b00; - i_k <= 3'd2; - valid_i <= 1'b1; - @(posedge clk); - valid_i <= 1'b0; - - // Wait for done_o - wait_for_done("KeyGen"); - if (wfd_result) begin - // Release force now that KeyGen is done - release u_dut.d_reg; - - // Check pk_valid and sk_valid - if (pk_valid && sk_valid) begin - // Check pk output - if (pk_o[EXP_PK_WIDTH-1:0] == exp_pk) begin - $display(" PASS: pk matches expected"); - kg_pass = kg_pass + 1; - end else begin - $display(" FAIL: pk mismatch"); - print_hex256(pk_o[255:0], " pk[low] "); - print_hex256(exp_pk[255:0], " exp[low] "); - kg_fail = kg_fail + 1; - end - - // Check sk output - if (sk_o[SK_WIDTH-1:0] == exp_sk[SK_WIDTH-1:0]) begin - $display(" PASS: sk matches expected"); - end else begin - $display(" FAIL: sk mismatch"); - kg_fail = kg_fail + 1; - end - end else begin - $display(" FAIL: pk_valid=%b sk_valid=%b", pk_valid, sk_valid); - kg_fail = kg_fail + 1; - end - end else begin - release u_dut.d_reg; - $display(" FAIL: KeyGen timeout"); - kg_fail = kg_fail + 1; - - // DUT is stuck. Reset for next operation. - rst_n <= 1'b0; - repeat (5) @(posedge clk); - rst_n <= 1'b1; - force u_dut.chain_kc_ready_o = 1'b1; - force u_dut.ntt_valid_o = 1'b1; - @(posedge clk); - end - - // Wait for DUT to return to IDLE - repeat (2) @(posedge clk); - - // ======================================================== - // STEP 2: Encaps (mode=01) - // ======================================================== - $display("--- Encaps ---"); - - // Force m_reg to KAT value - force u_dut.m_reg = msg_val; - - // Start Encaps - mode <= 2'b01; - i_k <= 3'd2; - valid_i <= 1'b1; - @(posedge clk); - valid_i <= 1'b0; - - // Wait for done_o - wait_for_done("Encaps"); - if (wfd_result) begin - release u_dut.m_reg; - - if (ct_valid && K_valid) begin - // Check ct output - if (ct_o[EXP_CT_WIDTH-1:0] == exp_ct) begin - $display(" PASS: ct matches expected"); - en_pass = en_pass + 1; - end else begin - $display(" FAIL: ct mismatch"); - print_hex256(ct_o[255:0], " ct[low] "); - print_hex256(exp_ct[255:0], " exp[low] "); - en_fail = en_fail + 1; - end - - // Check K (shared secret) - if (K_o == exp_ss) begin - $display(" PASS: K matches expected ss"); - end else begin - $display(" FAIL: K mismatch"); - print_hex256(K_o, " K "); - print_hex256(exp_ss, " exp_ss"); - en_fail = en_fail + 1; - end - end else begin - $display(" FAIL: ct_valid=%b K_valid=%b", ct_valid, K_valid); - en_fail = en_fail + 1; - end - end else begin - release u_dut.m_reg; - $display(" FAIL: Encaps timeout"); - en_fail = en_fail + 1; - - // DUT is stuck. Reset for next operation. - rst_n <= 1'b0; - repeat (5) @(posedge clk); - rst_n <= 1'b1; - force u_dut.chain_kc_ready_o = 1'b1; - force u_dut.ntt_valid_o = 1'b1; - @(posedge clk); - end - - // Wait for DUT to return to IDLE - repeat (2) @(posedge clk); - - // ======================================================== - // STEP 3: Decaps (mode=10) - // ======================================================== - $display("--- Decaps ---"); - - // Force z_reg to KAT value - force u_dut.z_reg = z_val; - - // Start Decaps - mode <= 2'b10; - i_k <= 3'd2; - valid_i <= 1'b1; - @(posedge clk); - valid_i <= 1'b0; - - // Wait for done_o - wait_for_done("Decaps"); - if (wfd_result) begin - release u_dut.z_reg; - - if (K_valid_dec) begin - $display(" PASS: Decaps completed (K_valid_dec asserted)"); - dc_pass = dc_pass + 1; - end else begin - $display(" FAIL: Decaps K_valid_dec not asserted"); - dc_fail = dc_fail + 1; - end - end else begin - release u_dut.z_reg; - $display(" FAIL: Decaps timeout (placeholder states — expected)"); - dc_fail = dc_fail + 1; - - // Decaps FSM is now stuck. Reset DUT so next vector - // can start with a clean state. - rst_n <= 1'b0; - repeat (5) @(posedge clk); - rst_n <= 1'b1; - // Re-apply workaround forces (reset may have cleared them) - force u_dut.chain_kc_ready_o = 1'b1; - force u_dut.ntt_valid_o = 1'b1; - @(posedge clk); - end - - // Wait for DUT to return to IDLE - repeat (2) @(posedge clk); - end - - // ------------------------------------------------------------ - // Release deadlock workarounds - // ------------------------------------------------------------ - release u_dut.chain_kc_ready_o; - release u_dut.ntt_valid_o; - - // ============================================================ - // Summary - // ============================================================ - $display("===================================================="); - $display("TEST COMPLETE"); - $display(" KeyGen: PASS=%0d FAIL=%0d", kg_pass, kg_fail); - $display(" Encaps: PASS=%0d FAIL=%0d", en_pass, en_fail); - $display(" Decaps: PASS=%0d FAIL=%0d", dc_pass, dc_fail); - $display(" Total: PASS=%0d FAIL=%0d", - kg_pass + en_pass + dc_pass, - kg_fail + en_fail + dc_fail); - $display("===================================================="); - $finish; - end - - // ================================================================ - // Timeout watchdog - // ================================================================ - initial begin - #(TIMEOUT_CYCLES * 10 * 100); // TIMEOUT_CYCLES * 10ns * extra margin - $display("FATAL: Global simulation timeout reached (%0d ns)", - TIMEOUT_CYCLES * 10 * 100); - $finish; - end - -endmodule diff --git a/sync_rtl/top/TB/xsim_run.tcl b/sync_rtl/top/TB/xsim_run.tcl deleted file mode 100644 index 7f40ab1..0000000 --- a/sync_rtl/top/TB/xsim_run.tcl +++ /dev/null @@ -1,187 +0,0 @@ -# NOTE: On some systems, you may need: -# export LD_PRELOAD=/usr/lib64/libtinfo.so.5 -# before running this script. - -# xsim_run.tcl - Vivado xsim compilation and simulation for mlkem_top KAT testbench -# -# Compiles ALL RTL dependencies for mlkem_top plus the testbench. -# Run from the project root: ~/Dev/mlkem/ -# -# Prerequisites: -# source /opt/Xilinx/Vivado/2019.2/settings64.sh -# -# Usage examples: -# # Run mlkem_top KAT testbench -# xsim tb_mlkem_top_xsim -R -# -# # Step-by-step: -# vivado -mode batch -source sync_rtl/top/TB/xsim_run.tcl -# -# # Or via run_tb.sh: -# ./run_tb.sh mlkem_top - -# ================================================================ -# Configuration -# ================================================================ -set COMMON_DIR sync_rtl/common -set SHA3_DIR sync_rtl/sha3 -set SHA3C_DIR sync_rtl/sha3_chain -set RNG_DIR sync_rtl/rng -set NTT_DIR sync_rtl/ntt -set PA_DIR sync_rtl/poly_arith -set PM_DIR sync_rtl/poly_mul -set CBD_DIR sync_rtl/sample_cbd -set SNT_DIR sync_rtl/sample_ntt -set CD_DIR sync_rtl/comp_decomp -set MA_DIR sync_rtl/mod_add -set STOR_DIR sync_rtl/storage -set TOP_DIR sync_rtl/top -set TB_DIR sync_rtl/top/TB - -# ================================================================ -# Step 1: Compile common infrastructure -# ================================================================ -puts "=== Compiling common infrastructure ===" - -# Pipeline register (used by many modules) -xvlog -sv -i . ${COMMON_DIR}/pipeline_reg.v - -# Skid buffer (backpressure buffer) -xvlog -sv -i . ${COMMON_DIR}/skid_buffer.v - -# ================================================================ -# Step 2: Compile SHA3 / Keccak core -# ================================================================ -puts "=== Compiling SHA3/Keccak core ===" - -# Keccak round (combinational, θ/ρ/π/χ/ι) -xvlog -sv ${SHA3_DIR}/keccak_round.v - -# Keccak core (24-round sequential keccak-f[1600]) -xvlog -sv ${SHA3_DIR}/keccak_core.v - -# SHA3 top wrapper (G/H/J modes, with internal keccak_core) -xvlog -sv -i . ${SHA3_DIR}/sha3_top.v - -# ================================================================ -# Step 3: Compile SHA3 chain (G function) -# ================================================================ -puts "=== Compiling SHA3 chain ===" - -# sha3_chain_top_shared (G: d → rho, sigma, with external keccak_core) -xvlog -sv -i . ${SHA3C_DIR}/sha3_chain_top_shared.v - -# ================================================================ -# Step 4: Compile RNG -# ================================================================ -puts "=== Compiling RNG ===" - -# rng_sync (256-bit Galois LFSR) -xvlog -sv ${RNG_DIR}/rng_sync.v - -# ================================================================ -# Step 5: Compile NTT core and dependencies -# ================================================================ -puts "=== Compiling NTT core ===" - -# Zeta ROM (twiddle factors, 128 × 12-bit) -xvlog -sv ${NTT_DIR}/zeta_rom.v - -# Barrett modular multiplier (a·b mod q) -xvlog -sv ${NTT_DIR}/barrett_mul.v - -# Butterfly unit (CT/GS butterfly for NTT/INTT) -xvlog -sv ${NTT_DIR}/butterfly_unit.v - -# NTT core (256-coeff NTT/INTT FSM) -xvlog -sv -i . ${NTT_DIR}/ntt_core.v - -# ================================================================ -# Step 6: Compile polynomial arithmetic -# ================================================================ -puts "=== Compiling polynomial arithmetic ===" - -# poly_arith_sync (element-wise poly add/sub) -xvlog -sv ${PA_DIR}/poly_arith_sync.v - -# ================================================================ -# Step 7: Compile polynomial multiplication -# ================================================================ -puts "=== Compiling polynomial multiplication ===" - -# Zeta ROM for poly_mul (degree-1 basecase) -xvlog -sv ${PM_DIR}/poly_mul_zeta_rom.v - -# Basecase multiplier (degree-1 Karatsuba) -xvlog -sv ${PM_DIR}/basecase_mul.v - -# poly_mul_sync (NTT-domain polynomial multiplier) -xvlog -sv -i . ${PM_DIR}/poly_mul_sync.v - -# ================================================================ -# Step 8: Compile sampling modules -# ================================================================ -puts "=== Compiling sampling modules ===" - -# sample_cbd_sync_shared (CBD sampling with external keccak) -xvlog -sv -i . ${CBD_DIR}/sample_cbd_sync_shared.v - -# sample_ntt_sync_shared (SampleNTT with external keccak) -xvlog -sv -i . ${SNT_DIR}/sample_ntt_sync_shared.v - -# ================================================================ -# Step 9: Compile compression and modular arithmetic -# ================================================================ -puts "=== Compiling compression and modular arithmetic ===" - -# comp_decomp_sync (Compress_q / Decompress_q) -xvlog -sv ${CD_DIR}/comp_decomp_sync.v - -# mod_add_sync ((a + b) mod q, streaming) -xvlog -sv ${MA_DIR}/mod_add_sync.v - -# ================================================================ -# Step 10: Compile storage (BRAM) -# ================================================================ -puts "=== Compiling storage BRAMs ===" - -# Single-port BRAM -xvlog -sv ${STOR_DIR}/s_bram.v - -# Simple dual-port BRAM -xvlog -sv ${STOR_DIR}/sd_bram.v - -# ================================================================ -# Step 11: Compile top-level integration -# ================================================================ -puts "=== Compiling top-level integration ===" - -# keccak_arbiter (round-robin arbiter for shared keccak) -xvlog -sv -i . ${TOP_DIR}/keccak_arbiter.v - -# mlkem_top (top-level KeyGen/Encaps/Decaps FSM) -xvlog -sv -i . ${TOP_DIR}/mlkem_top.v - -# ================================================================ -# Step 12: Compile testbench -# ================================================================ -puts "=== Compiling testbench ===" - -# tb_mlkem_top_xsim (KAT vector testbench) -xvlog -sv ${TB_DIR}/tb_mlkem_top_xsim.v - -# ================================================================ -# Step 13: Elaborate snapshot (xelab) -# ================================================================ -puts "=== Elaborating snapshot ===" -xelab tb_mlkem_top_xsim -s tb_mlkem_top_xsim --timescale 1ns/1ps - -# ================================================================ -# Step 14: Run simulation -# ================================================================ -puts "" -puts "=== Running mlkem_top KAT simulation ===" -xsim tb_mlkem_top_xsim -R - -puts "" -puts "=== mlkem_top simulation complete ===" diff --git a/sync_rtl/top/keccak_arbiter.v b/sync_rtl/top/keccak_arbiter.v deleted file mode 100644 index 8a08e99..0000000 --- a/sync_rtl/top/keccak_arbiter.v +++ /dev/null @@ -1,143 +0,0 @@ -// keccak_arbiter.v - Fixed-priority arbiter for sharing a single keccak_core -// -// Allows N consumers (sha3_chain, sample_cbd, sample_ntt, sha3_top) to -// share one keccak_core instance. Consumer 0 has highest priority — used -// for sha3_chain which needs fast turnaround during KeyGen. -// -// State machine: -// IDLE: Wait for any cons_valid_i. Grant to highest-priority consumer -// (lowest index). Assert kc_valid_i to start permutation. -// BUSY: Hold grant until kc_valid_o fires (permutation done), then -// return to IDLE. cons_valid_o pulses for the granted consumer. -// -// Parameters: -// NUM_CONSUMERS = 4 -// -// Interface: -// Keccak side: kc_state_i/o, kc_valid_i/o, kc_ready_i/o (single instance) -// Consumer side: packed per-consumer valid/ready/state vectors - -module keccak_arbiter #( - parameter NUM_CONSUMERS = 4 -) ( - input clk, - input rst_n, - - // ── Keccak core side (single keccak_core instance) ────────────── - output [1599:0] kc_state_i, - output kc_valid_i, - input kc_ready_o, - input [1599:0] kc_state_o, - input kc_valid_o, - output kc_ready_i, - - // ── Consumer side (N copies, packed) ──────────────────────────── - input [NUM_CONSUMERS*1600-1:0] cons_state_i, - input [NUM_CONSUMERS-1:0] cons_valid_i, - output [NUM_CONSUMERS-1:0] cons_ready_o, - output [NUM_CONSUMERS*1600-1:0] cons_state_o, - output [NUM_CONSUMERS-1:0] cons_valid_o, - /* verilator lint_off UNUSEDSIGNAL */ - input [NUM_CONSUMERS-1:0] cons_ready_i - /* verilator lint_on UNUSEDSIGNAL */ -); - - // ================================================================ - // State machine - // ================================================================ - localparam ST_IDLE = 1'b0; - localparam ST_BUSY = 1'b1; - - reg state_r, state_next; - - // ================================================================ - // Grant logic - // ================================================================ - localparam GRANT_W = $clog2(NUM_CONSUMERS); - - reg [GRANT_W-1:0] grant_r; // registered grant (held during BUSY) - reg [GRANT_W-1:0] grant_comb; // priority-encoded index (combinational) - - // Any consumer requesting - wire any_valid; - assign any_valid = |cons_valid_i; - - // Priority encoder: consumer 0 has highest priority (lowest index). - // Reverse iteration so last assignment wins → lowest-index priority. - integer i; - always @(*) begin - grant_comb = {GRANT_W{1'b0}}; - for (i = NUM_CONSUMERS - 1; i >= 0; i = i - 1) begin - if (cons_valid_i[i]) begin - /* verilator lint_off WIDTHTRUNC */ - grant_comb = i; // intentional truncation: i ∈ [0,NUM_CONSUMERS-1] fits GRANT_W - /* verilator lint_on WIDTHTRUNC */ - end - end - end - - // Active grant: combinational in IDLE, registered (held) in BUSY - wire [GRANT_W-1:0] active_grant; - assign active_grant = (state_r == ST_IDLE) ? grant_comb : grant_r; - - // ================================================================ - // FSM next-state logic - // ================================================================ - always @(*) begin - state_next = state_r; - case (state_r) - ST_IDLE: if (kc_ready_o && any_valid) state_next = ST_BUSY; - ST_BUSY: if (kc_valid_o) state_next = ST_IDLE; - default: state_next = ST_IDLE; - endcase - end - - // ================================================================ - // Sequential logic - // ================================================================ - always @(posedge clk or negedge rst_n) begin - if (!rst_n) begin - state_r <= ST_IDLE; - grant_r <= {GRANT_W{1'b0}}; - end else begin - state_r <= state_next; - // Capture grant on IDLE→BUSY transition - if (state_r == ST_IDLE && state_next == ST_BUSY) - grant_r <= grant_comb; - end - end - - // ================================================================ - // Keccak core side - // ================================================================ - // Route selected consumer's state to keccak - assign kc_state_i = cons_state_i[active_grant * 1600 +: 1600]; - - // Start permutation when IDLE, keccak ready, and any consumer wants access - assign kc_valid_i = (state_r == ST_IDLE) && kc_ready_o && any_valid; - - // Always accept keccak output (keccak_core's ready_i) - assign kc_ready_i = 1'b1; - - // ================================================================ - // Consumer side (generated per consumer) - // ================================================================ - genvar g; - generate - for (g = 0; g < NUM_CONSUMERS; g = g + 1) begin : gen_consumer - // cons_ready_o: this consumer is granted AND keccak is ready - assign cons_ready_o[g] = (active_grant == g) - && any_valid - && (state_r == ST_IDLE) - && kc_ready_o; - - // cons_valid_o: this consumer was granted AND keccak finished - assign cons_valid_o[g] = (grant_r == g) && kc_valid_o; - - // cons_state_o: broadcast keccak output to all consumers. - // Each consumer latches only when its own valid_o is high. - assign cons_state_o[g*1600 +: 1600] = kc_state_o; - end - endgenerate - -endmodule diff --git a/sync_rtl/top/mlkem_top.v b/sync_rtl/top/mlkem_top.v deleted file mode 100644 index acc41e2..0000000 --- a/sync_rtl/top/mlkem_top.v +++ /dev/null @@ -1,1658 +0,0 @@ -// mlkem_top.v - Top-level ML-KEM integration module -// -// Monolithic FSM implementing KeyGen, Encaps, and Decaps (FIPS 203) -// using shared Keccak architecture with keccak_arbiter. -// -// Architecture: -// keccak_core (shared) ← keccak_arbiter #(3) -// ├── Consumer 0: sha3_chain_top_shared (G function) -// ├── Consumer 1: sample_cbd_sync_shared (CBD sampling) -// └── Consumer 2: sample_ntt_sync_shared (NTT sampling) -// sha3_top (separate, own keccak_core) — for H/KDF calls -// rng_sync, ntt_core, poly_mul_sync, poly_arith_sync, -// comp_decomp_sync, mod_add_sync -// sd_bram × 1 (large) — polynomial coefficient storage -// -// Parameters: -// K = 4 (max module rank; actual k selected at runtime via i_k) - -`include "sync_rtl/common/defines.vh" - -/* verilator lint_off UNUSEDPARAM */ -module mlkem_top #( - parameter K = 4 -) ( -/* verilator lint_on UNUSEDPARAM */ - input clk, - input rst_n, - input [1:0] mode, // 00=KeyGen, 01=Encaps, 10=Decaps - input [2:0] i_k, // actual k (2,3,4) - input valid_i, - output ready_o, - - // KeyGen outputs - output [12*K*256-1:0] pk_o, // public key (raw t_hat polys + rho) - output [12*K*256-1:0] sk_o, // secret key (raw s_hat polys) - output pk_valid, - output sk_valid, - - // Encaps outputs - output [12*K*256-1:0] ct_o, // ciphertext - output [255:0] K_o, // shared secret - output ct_valid, - output K_valid, - - // Decaps output - output [255:0] K_o_dec, // shared secret - output K_valid_dec, - output done_o -); - - // ==================================================================== - // Local parameters - // ==================================================================== - localparam N = `N; // 256 - localparam Q = `Q; // 3329 - localparam N_CONSUMERS = 3; // sha3_chain, sample_cbd, sample_ntt - localparam N_POLYS = 48; // polynomial slots - localparam POLY_SIZE = N; // 256 coeffs per polynomial - localparam BRAM_DEPTH = POLY_SIZE * N_POLYS; // 12288 - localparam BRAM_AW = $clog2(BRAM_DEPTH); // 14 - - // BRAM address map (base address = poly_idx * 256) - // A matrix: poly 0 .. 15 (K*K max) - // s_hat: poly 16 .. 19 (K max) - // e_hat: poly 20 .. 23 - // t_hat: poly 24 .. 27 - // y_hat: poly 28 .. 31 - // e1: poly 32 .. 35 - // u: poly 36 .. 39 - // scratch0: poly 44 - // scratch1: poly 45 - localparam A_BASE = 0; - localparam S_BASE = 16; - localparam E_BASE = 20; - localparam T_BASE = 24; - localparam Y_BASE = 28; - localparam E1_BASE = 32; - localparam U_BASE = 36; - localparam SCRATCH0 = 44; - localparam SCRATCH1 = 45; - - function [BRAM_AW-1:0] poly_addr; - input [5:0] poly_idx; - input [7:0] coeff_idx; - begin - poly_addr = (poly_idx * POLY_SIZE) + coeff_idx; - end - endfunction - - // ==================================================================== - // I/O registers - // ==================================================================== - reg [1:0] mode_r; - reg [2:0] k_r; // actual k (2,3,4) - reg ready_o_r; - reg pk_valid_r, sk_valid_r; - reg ct_valid_r, K_valid_r; - reg K_valid_dec_r; - reg done_o_r; - - // KeyGen output registers - reg [12*K*256-1:0] pk_o_r; - reg [12*K*256-1:0] sk_o_r; - - // Encaps output registers - reg [12*K*256-1:0] ct_o_r; - reg [255:0] K_o_r; - - // Decaps output registers - reg [255:0] K_o_dec_r; - - // Internal data registers - reg [255:0] d_reg; // RNG output d - reg [255:0] rho_reg; // G output rho - reg [255:0] sigma_reg; // G output sigma - wire [255:0] d_rev; // byte-reversed d (FIPS 203 byte order) - genvar gi; - generate - for (gi = 0; gi < 32; gi = gi + 1) begin : gen_d_rev - assign d_rev[gi*8 +: 8] = d_reg[(31-gi)*8 +: 8]; - end - endgenerate - reg [255:0] m_reg; // Encaps message m - reg [255:0] Kbar_reg; // G output K-bar - reg [255:0] r_reg; // G output r - reg [255:0] Hpk_reg; // H(pk) for Encaps - reg [255:0] z_reg; // implicit rejection value - - // s_hat capture registers (filled during CBD→NTT output) - reg [N*12-1:0] s_hat0_reg, s_hat1_reg; - - // t_hat output registers (computed during t_hat computation) - reg [N*12-1:0] t_hat0_reg, t_hat1_reg; - - // t_hat computation scratch registers - reg [11:0] tmul_pipe_reg; // 1-cycle pipeline delay for poly_mul output - reg tmul_pipe_valid; // flag: tmul_pipe_reg holds valid data - reg [8:0] tmul_out_cnt; // output coefficient counter for accumulation - reg tmul_adv_row; // flag: advancing to next row (set in ADD_E, used in MUL_LD) - - // ==================================================================== - // Keccak arbiter signals (3 consumers → 1 keccak_core) - // ==================================================================== - // Arbiter ↔ keccak_core - wire [1599:0] arb_kc_state_i; - wire arb_kc_valid_i; - wire arb_kc_ready_o; - wire [1599:0] arb_kc_state_o; - wire arb_kc_valid_o; - wire arb_kc_ready_i; // always 1'b1 - - // Consumer-side packed vectors - wire [N_CONSUMERS*1600-1:0] arb_cons_state_i; - wire [N_CONSUMERS-1:0] arb_cons_valid_i; - wire [N_CONSUMERS-1:0] arb_cons_ready_o; - wire [N_CONSUMERS*1600-1:0] arb_cons_state_o; - wire [N_CONSUMERS-1:0] arb_cons_valid_o; - wire [N_CONSUMERS-1:0] arb_cons_ready_i; // all tied high - - // ==================================================================== - // sha3_chain_top_shared (consumer 0) signals - // ==================================================================== - wire chain_start, chain_done; - wire [255:0] chain_rho, chain_sigma; - wire [1599:0] chain_kc_state_o, chain_kc_state_i; - wire chain_kc_valid_o, chain_kc_valid_i; - wire chain_kc_ready_i, chain_kc_ready_o; - - // ==================================================================== - // sample_cbd_sync_shared (consumer 1) signals - // ==================================================================== - reg cbd_valid_i_r; - reg [7:0] cbd_nonce_r; - reg [1:0] cbd_eta_r; - wire cbd_ready_o; - wire [11:0] cbd_coeff_o; - wire cbd_valid_o, cbd_last_o; - wire [1599:0] cbd_kc_state_o, cbd_kc_state_i; - wire cbd_kc_valid_o, cbd_kc_valid_i; - wire cbd_kc_ready_i, cbd_kc_ready_o; - - // CBD seed mux: sigma_reg (KeyGen) or r_reg (Encaps) - reg cbd_use_r_seed; // 1 = use r_reg, 0 = use sigma_reg - wire [255:0] cbd_seed_muxed; - assign cbd_seed_muxed = cbd_use_r_seed ? r_reg : sigma_reg; - - // ==================================================================== - // sample_ntt_sync_shared (consumer 2) signals - // ==================================================================== - reg snt_valid_i_r; - reg [1:0] snt_i_idx_r, snt_j_idx_r; - wire snt_ready_o; - wire [11:0] snt_coeff_o; - wire snt_valid_o, snt_last_o; - wire [1599:0] snt_kc_state_o, snt_kc_state_i; - wire snt_kc_valid_o, snt_kc_valid_i; - wire snt_kc_ready_i, snt_kc_ready_o; - - // ==================================================================== - // sha3_top signals (separate keccak_core — not shared through arbiter) - // ==================================================================== - reg [1:0] sha3_mode_r; - reg [511:0] sha3_data_r; - reg sha3_valid_i_r; - wire sha3_ready_o; - wire [511:0] sha3_hash_o; - wire sha3_valid_o; - - // ==================================================================== - // rng_sync signals - // ==================================================================== - wire rng_valid_i; - wire rng_ready_o; - wire [255:0] rng_data_o; - wire rng_valid_o; - - // ==================================================================== - // ntt_core signals (FSM-driven inputs are regs) - // ==================================================================== - reg [11:0] ntt_coeff_in_r; - reg ntt_valid_i_r; - wire ntt_ready_o; - reg ntt_mode_r; // 0=NTT, 1=INTT - wire [11:0] ntt_coeff_out; - wire ntt_valid_o; - wire ntt_done_o; - - // ==================================================================== - // poly_mul_sync signals (FSM-driven inputs) - // ==================================================================== - reg [11:0] pmul_a_r, pmul_b_r; - reg pmul_valid_i_r; - wire pmul_ready_o; - wire [11:0] pmul_coeff_out; - wire pmul_valid_o; - - // ==================================================================== - // poly_arith_sync signals (FSM-driven inputs) - // ==================================================================== - reg [11:0] parith_a_r, parith_b_r; - reg parith_mode_r; // 0=add, 1=sub - reg parith_valid_i_r; - wire parith_ready_o; - wire [11:0] parith_coeff_out; - wire parith_valid_o; - - // ==================================================================== - // comp_decomp_sync signals (FSM-driven inputs) - // ==================================================================== - reg [11:0] comp_coeff_in_r; - reg [4:0] comp_d_r; - reg comp_mode_r; // 0=compress, 1=decompress - reg comp_valid_i_r; - wire comp_ready_o; - wire [11:0] comp_coeff_out; - wire comp_valid_o; - - // ==================================================================== - // mod_add_sync signals (FSM-driven inputs) - // ==================================================================== - reg [11:0] madd_a_r, madd_b_r; - reg madd_valid_i_r; - wire madd_ready_o; - wire [11:0] madd_sum; - wire madd_valid_o; - - // ==================================================================== - // BRAM signals (sd_bram: 1 read + 1 write port) - // ==================================================================== - reg [BRAM_AW-1:0] bram_rd_addr_r; - wire [11:0] bram_rd_data; - reg bram_wr_en_r; - reg [BRAM_AW-1:0] bram_wr_addr_r; - reg [11:0] bram_wr_data_r; - - // ==================================================================== - // FSM state definitions - // ==================================================================== - localparam S_IDLE = 7'd0; - - // --- KeyGen states --- - localparam S_KG_RNG_REQ = 7'd1; - localparam S_KG_RNG_WAIT = 7'd2; - localparam S_KG_G_START = 7'd3; - localparam S_KG_G_WAIT = 7'd4; - localparam S_KG_G_DONE = 7'd5; - localparam S_KG_SNT_INIT = 7'd6; - localparam S_KG_SNT_START = 7'd7; - localparam S_KG_SNT_COEFFS = 7'd8; - localparam S_KG_SNT_CLEANUP = 7'd9; - localparam S_KG_SNT_NTT_LOAD = 7'd10; - localparam S_KG_SNT_NTT_COMP = 7'd11; - localparam S_KG_SNT_NTT_OUT = 7'd12; - localparam S_KG_SNT_NEXT = 7'd13; - localparam S_KG_CBD_S_INIT = 7'd14; - localparam S_KG_CBD_S_START = 7'd15; - localparam S_KG_CBD_S_COEFFS = 7'd16; - localparam S_KG_CBD_S_CLEANUP = 7'd17; - localparam S_KG_CBD_S_NTT_LD = 7'd18; - localparam S_KG_CBD_S_NTT_CMP = 7'd19; - localparam S_KG_CBD_S_NTT_OUT = 7'd20; - localparam S_KG_CBD_S_NEXT = 7'd21; - localparam S_KG_CBD_E_INIT = 7'd22; - localparam S_KG_CBD_E_START = 7'd23; - localparam S_KG_CBD_E_COEFFS = 7'd24; - localparam S_KG_CBD_E_CLEANUP = 7'd25; - localparam S_KG_CBD_E_NTT_LD = 7'd26; - localparam S_KG_CBD_E_NTT_CMP = 7'd27; - localparam S_KG_CBD_E_NTT_OUT = 7'd28; - localparam S_KG_CBD_E_NEXT = 7'd29; - localparam S_KG_TMUL_INIT = 7'd30; - localparam S_KG_TMUL_MUL_LD = 7'd31; - localparam S_KG_TMUL_MUL_OUT = 7'd32; - localparam S_KG_TMUL_ACCUM = 7'd33; - localparam S_KG_TMUL_ADD_E = 7'd34; - localparam S_KG_TMUL_NEXT = 7'd35; - localparam S_KG_DONE = 7'd36; - - // --- Encaps states --- - localparam S_EN_RNG_REQ = 7'd37; - localparam S_EN_RNG_WAIT = 7'd38; - localparam S_EN_H_START = 7'd39; - localparam S_EN_H_WAIT = 7'd40; - localparam S_EN_G_START = 7'd41; - localparam S_EN_G_WAIT = 7'd42; - localparam S_EN_SNT_INIT = 7'd43; - localparam S_EN_SNT_START = 7'd44; - localparam S_EN_SNT_COEFFS = 7'd45; - localparam S_EN_SNT_CLEANUP = 7'd46; - localparam S_EN_SNT_NTT_LD = 7'd47; - localparam S_EN_SNT_NTT_CMP = 7'd48; - localparam S_EN_SNT_NTT_OUT = 7'd49; - localparam S_EN_SNT_NEXT = 7'd50; - localparam S_EN_CBD_Y_INIT = 7'd51; - localparam S_EN_CBD_Y_START = 7'd52; - localparam S_EN_CBD_Y_COEFFS = 7'd53; - localparam S_EN_CBD_Y_CLNUP = 7'd54; - localparam S_EN_CBD_Y_NTT_LD = 7'd55; - localparam S_EN_CBD_Y_NTT_CMP = 7'd56; - localparam S_EN_CBD_Y_NTT_OUT = 7'd57; - localparam S_EN_CBD_Y_NEXT = 7'd58; - localparam S_EN_DONE = 7'd59; - - // --- Decaps states --- - localparam S_DC_DECOMP_C1 = 7'd60; - localparam S_DC_DECOMP_C2 = 7'd61; - localparam S_DC_NTT_U_LD = 7'd62; - localparam S_DC_NTT_U_CMP = 7'd63; - localparam S_DC_NTT_U_OUT = 7'd64; - localparam S_DC_MUL_S = 7'd65; - localparam S_DC_INTT_V = 7'd66; - localparam S_DC_DECOMP_M = 7'd67; - localparam S_DC_G_CHECK = 7'd68; - localparam S_DC_REENC = 7'd69; - localparam S_DC_KDF = 7'd70; - localparam S_DC_DONE = 7'd71; - - // ==================================================================== - // FSM registers - // ==================================================================== - reg [6:0] state_r, state_next; - - // Loop counters (shared across states) - reg [1:0] loop_i; // row index (0..k-1) - reg [1:0] loop_j; // col index (0..k-1) - reg [1:0] loop_idx; // generic single-loop index - reg [8:0] coeff_cnt; // 0..256 coefficient counter - reg [5:0] poly_idx_reg; // current poly base index - reg phase_active; // 1 while sub-phase is doing work - reg phase_done; // 1 when sub-phase work is complete - - // ==================================================================== - // Output assignments - // ==================================================================== - assign ready_o = ready_o_r; - assign pk_o = pk_o_r; - assign sk_o = sk_o_r; - assign pk_valid = pk_valid_r; - assign sk_valid = sk_valid_r; - assign ct_o = ct_o_r; - assign K_o = K_o_r; - assign ct_valid = ct_valid_r; - assign K_valid = K_valid_r; - assign K_o_dec = K_o_dec_r; - assign K_valid_dec = K_valid_dec_r; - assign done_o = done_o_r; - - // ==================================================================== - // Default module-side connections (combinational — read state_r) - // ==================================================================== - - // -- sha3_chain (consumer 0) -- - assign chain_start = (state_r == S_KG_G_START); - assign chain_kc_ready_o = arb_cons_ready_o[0]; - assign chain_kc_state_o = arb_cons_state_o[0*1600 +: 1600]; - assign chain_kc_valid_o = arb_cons_valid_o[0]; - assign arb_cons_state_i[0*1600 +: 1600] = chain_kc_state_i; - assign arb_cons_valid_i[0] = chain_kc_valid_i; - assign arb_cons_ready_i[0] = 1'b1; - - // -- sample_cbd (consumer 1) -- - assign cbd_kc_ready_o = arb_cons_ready_o[1]; - assign cbd_kc_state_o = arb_cons_state_o[1*1600 +: 1600]; - assign cbd_kc_valid_o = arb_cons_valid_o[1]; - assign arb_cons_state_i[1*1600 +: 1600] = cbd_kc_state_i; - assign arb_cons_valid_i[1] = cbd_kc_valid_i; - assign arb_cons_ready_i[1] = 1'b1; - - // -- sample_ntt (consumer 2) -- - assign snt_kc_ready_o = arb_cons_ready_o[2]; - assign snt_kc_state_o = arb_cons_state_o[2*1600 +: 1600]; - assign snt_kc_valid_o = arb_cons_valid_o[2]; - assign arb_cons_state_i[2*1600 +: 1600] = snt_kc_state_i; - assign arb_cons_valid_i[2] = snt_kc_valid_i; - assign arb_cons_ready_i[2] = 1'b1; - - // -- rng_sync (combinational drive) -- - assign rng_valid_i = (state_r == S_KG_RNG_REQ || state_r == S_EN_RNG_REQ); - - // ==================================================================== - // FSM combinational next-state logic - // - // Transitions are triggered by: - // - phase_done: sub-phase work completed (set in sequential block) - // - External ready/valid signals (rng_valid_o, chain_done, etc.) - // - ntt_done_o: NTT core completion - // - // Loop-back for iteration: uses combinational check on registered - // loop_i/loop_j counters to decide whether to loop or advance. - // ==================================================================== - always @(*) begin - state_next = state_r; - case (state_r) - - // ============================================================ - // IDLE - // ============================================================ - S_IDLE: begin - if (valid_i && ready_o_r) begin - case (mode) - 2'b00: state_next = S_KG_RNG_REQ; - 2'b01: state_next = S_EN_RNG_REQ; - 2'b10: state_next = S_DC_DECOMP_C1; - default: state_next = S_IDLE; - endcase - end - end - - // ============================================================ - // KEYGEN - // ============================================================ - S_KG_RNG_REQ: state_next = S_KG_RNG_WAIT; - S_KG_RNG_WAIT: if (rng_valid_o) state_next = S_KG_G_START; - S_KG_G_START: state_next = S_KG_G_WAIT; - S_KG_G_WAIT: if (chain_done) state_next = S_KG_G_DONE; - S_KG_G_DONE: state_next = S_KG_SNT_INIT; - - // -- SampleNTT A-matrix loop -- - S_KG_SNT_INIT: state_next = S_KG_SNT_START; - S_KG_SNT_START: if (snt_ready_o) state_next = S_KG_SNT_COEFFS; - S_KG_SNT_COEFFS: if (phase_done) state_next = S_KG_SNT_CLEANUP; - S_KG_SNT_CLEANUP: state_next = S_KG_SNT_NTT_LOAD; - S_KG_SNT_NTT_LOAD: if (phase_done) state_next = S_KG_SNT_NTT_COMP; - S_KG_SNT_NTT_COMP: if (ntt_done_o) state_next = S_KG_SNT_NTT_OUT; - S_KG_SNT_NTT_OUT: if (phase_done) state_next = S_KG_SNT_NEXT; - - // S_KG_SNT_NEXT: loop or advance - S_KG_SNT_NEXT: begin - if (loop_j + 2'd1 < k_r[1:0]) - state_next = S_KG_SNT_START; - else if (loop_i + 2'd1 < k_r[1:0]) - state_next = S_KG_SNT_START; - else - state_next = S_KG_CBD_S_INIT; - end - - // -- CBD s loop -- - S_KG_CBD_S_INIT: state_next = S_KG_CBD_S_START; - S_KG_CBD_S_START: if (cbd_ready_o) state_next = S_KG_CBD_S_COEFFS; - S_KG_CBD_S_COEFFS: if (phase_done) state_next = S_KG_CBD_S_CLEANUP; - S_KG_CBD_S_CLEANUP: state_next = S_KG_CBD_S_NTT_LD; - S_KG_CBD_S_NTT_LD: if (phase_done) state_next = S_KG_CBD_S_NTT_CMP; - S_KG_CBD_S_NTT_CMP: if (ntt_done_o) state_next = S_KG_CBD_S_NTT_OUT; - S_KG_CBD_S_NTT_OUT: if (phase_done) state_next = S_KG_CBD_S_NEXT; - - S_KG_CBD_S_NEXT: begin - if (loop_idx + 2'd1 < k_r[1:0]) - state_next = S_KG_CBD_S_START; - else - state_next = S_KG_CBD_E_INIT; - end - - // -- CBD e loop -- - S_KG_CBD_E_INIT: state_next = S_KG_CBD_E_START; - S_KG_CBD_E_START: if (cbd_ready_o) state_next = S_KG_CBD_E_COEFFS; - S_KG_CBD_E_COEFFS: if (phase_done) state_next = S_KG_CBD_E_CLEANUP; - S_KG_CBD_E_CLEANUP: state_next = S_KG_CBD_E_NTT_LD; - S_KG_CBD_E_NTT_LD: if (phase_done) state_next = S_KG_CBD_E_NTT_CMP; - S_KG_CBD_E_NTT_CMP: if (ntt_done_o) state_next = S_KG_CBD_E_NTT_OUT; - S_KG_CBD_E_NTT_OUT: if (phase_done) state_next = S_KG_CBD_E_NEXT; - - S_KG_CBD_E_NEXT: begin - if (loop_idx + 2'd1 < k_r[1:0]) - state_next = S_KG_CBD_E_START; - else - state_next = S_KG_TMUL_INIT; - end - - // -- t_hat = sum(A·s) + e -- - S_KG_TMUL_INIT: state_next = S_KG_TMUL_MUL_LD; - S_KG_TMUL_MUL_LD: if (phase_done) state_next = S_KG_TMUL_MUL_OUT; - S_KG_TMUL_MUL_OUT: if (phase_done) state_next = S_KG_TMUL_NEXT; - S_KG_TMUL_ACCUM: if (phase_done) state_next = S_KG_TMUL_ADD_E; - - // After ADD_E: if more rows, loop to MUL_LD with next row; else DONE - S_KG_TMUL_ADD_E: begin - if (phase_done) begin - if (loop_i + 2'd1 < k_r[1:0]) - state_next = S_KG_TMUL_MUL_LD; - else - state_next = S_KG_DONE; - end - end - - // After MUL_OUT: check if more j terms for this row - S_KG_TMUL_NEXT: begin - if (loop_j + 2'd1 < k_r[1:0]) begin - state_next = S_KG_TMUL_MUL_LD; // more j columns - end else begin - state_next = S_KG_TMUL_ACCUM; // all j done → accumulate - end - end - - S_KG_DONE: state_next = S_IDLE; - - // ============================================================ - // ENCAPS - // ============================================================ - S_EN_RNG_REQ: state_next = S_EN_RNG_WAIT; - S_EN_RNG_WAIT: if (rng_valid_o) state_next = S_EN_H_START; - S_EN_H_START: state_next = S_EN_H_WAIT; - S_EN_H_WAIT: if (sha3_valid_o) state_next = S_EN_G_START; - S_EN_G_START: state_next = S_EN_G_WAIT; - S_EN_G_WAIT: if (sha3_valid_o) state_next = S_EN_SNT_INIT; - - S_EN_SNT_INIT: state_next = S_EN_SNT_START; - S_EN_SNT_START: if (snt_ready_o) state_next = S_EN_SNT_COEFFS; - S_EN_SNT_COEFFS: if (phase_done) state_next = S_EN_SNT_CLEANUP; - S_EN_SNT_CLEANUP: state_next = S_EN_SNT_NTT_LD; - S_EN_SNT_NTT_LD: if (phase_done) state_next = S_EN_SNT_NTT_CMP; - S_EN_SNT_NTT_CMP: if (ntt_done_o) state_next = S_EN_SNT_NTT_OUT; - S_EN_SNT_NTT_OUT: if (phase_done) state_next = S_EN_SNT_NEXT; - - S_EN_SNT_NEXT: begin - if (loop_j + 2'd1 < k_r[1:0]) - state_next = S_EN_SNT_START; - else if (loop_i + 2'd1 < k_r[1:0]) - state_next = S_EN_SNT_START; - else - state_next = S_EN_CBD_Y_INIT; - end - - S_EN_CBD_Y_INIT: state_next = S_EN_CBD_Y_START; - S_EN_CBD_Y_START: if (cbd_ready_o) state_next = S_EN_CBD_Y_COEFFS; - S_EN_CBD_Y_COEFFS: if (phase_done) state_next = S_EN_CBD_Y_CLNUP; - S_EN_CBD_Y_CLNUP: state_next = S_EN_CBD_Y_NTT_LD; - S_EN_CBD_Y_NTT_LD: if (phase_done) state_next = S_EN_CBD_Y_NTT_CMP; - S_EN_CBD_Y_NTT_CMP: if (ntt_done_o) state_next = S_EN_CBD_Y_NTT_OUT; - S_EN_CBD_Y_NTT_OUT: if (phase_done) state_next = S_EN_CBD_Y_NEXT; - - S_EN_CBD_Y_NEXT: begin - if (loop_idx + 2'd1 < k_r[1:0]) - state_next = S_EN_CBD_Y_START; - else - state_next = S_EN_DONE; - end - - S_EN_DONE: state_next = S_IDLE; - - // ============================================================ - // DECAPS (simplified placeholder states flow) - // ============================================================ - S_DC_DECOMP_C1: if (phase_done) state_next = S_DC_DECOMP_C2; - S_DC_DECOMP_C2: if (phase_done) state_next = S_DC_NTT_U_LD; - S_DC_NTT_U_LD: if (phase_done) state_next = S_DC_NTT_U_CMP; - S_DC_NTT_U_CMP: if (ntt_done_o) state_next = S_DC_NTT_U_OUT; - S_DC_NTT_U_OUT: if (phase_done) state_next = S_DC_MUL_S; - S_DC_MUL_S: if (phase_done) state_next = S_DC_INTT_V; - S_DC_INTT_V: if (phase_done) state_next = S_DC_DECOMP_M; - S_DC_DECOMP_M: if (phase_done) state_next = S_DC_G_CHECK; - S_DC_G_CHECK: if (phase_done) state_next = S_DC_REENC; - S_DC_REENC: if (phase_done) state_next = S_DC_KDF; - S_DC_KDF: if (phase_done) state_next = S_DC_DONE; - S_DC_DONE: state_next = S_IDLE; - - default: state_next = S_IDLE; - endcase - end - - // ==================================================================== - // FSM sequential logic - // ==================================================================== - always @(posedge clk or negedge rst_n) begin - if (!rst_n) begin - state_r <= S_IDLE; - mode_r <= 2'd0; - k_r <= 3'd2; - ready_o_r <= 1'b1; - pk_valid_r <= 1'b0; - sk_valid_r <= 1'b0; - ct_valid_r <= 1'b0; - K_valid_r <= 1'b0; - K_valid_dec_r <= 1'b0; - done_o_r <= 1'b0; - pk_o_r <= 0; - sk_o_r <= 0; - ct_o_r <= 0; - K_o_r <= 256'd0; - K_o_dec_r <= 256'd0; - d_reg <= 256'd0; - rho_reg <= 256'd0; - sigma_reg <= 256'd0; - m_reg <= 256'd0; - Kbar_reg <= 256'd0; - r_reg <= 256'd0; - Hpk_reg <= 256'd0; - z_reg <= 256'd0; - loop_i <= 2'd0; - loop_j <= 2'd0; - loop_idx <= 2'd0; - coeff_cnt <= 9'd0; - poly_idx_reg <= 6'd0; - phase_active <= 1'b0; - phase_done <= 1'b0; - s_hat0_reg <= 0; - s_hat1_reg <= 0; - t_hat0_reg <= 0; - t_hat1_reg <= 0; - tmul_pipe_reg <= 12'd0; - tmul_pipe_valid <= 1'b0; - tmul_out_cnt <= 9'd0; - tmul_adv_row <= 1'b0; - - // Drive all FSM-controlled outputs to safe defaults - cbd_valid_i_r <= 1'b0; - cbd_nonce_r <= 8'd0; - cbd_eta_r <= 2'd0; - cbd_use_r_seed <= 1'b0; - snt_valid_i_r <= 1'b0; - snt_i_idx_r <= 2'd0; - snt_j_idx_r <= 2'd0; - sha3_mode_r <= 2'd0; - sha3_data_r <= 512'd0; - sha3_valid_i_r <= 1'b0; - ntt_coeff_in_r <= 12'd0; - ntt_valid_i_r <= 1'b0; - ntt_mode_r <= 1'b0; - pmul_a_r <= 12'd0; - pmul_b_r <= 12'd0; - pmul_valid_i_r <= 1'b0; - parith_a_r <= 12'd0; - parith_b_r <= 12'd0; - parith_mode_r <= 1'b0; - parith_valid_i_r <= 1'b0; - comp_coeff_in_r <= 12'd0; - comp_d_r <= 5'd0; - comp_mode_r <= 1'b0; - comp_valid_i_r <= 1'b0; - madd_a_r <= 12'd0; - madd_b_r <= 12'd0; - madd_valid_i_r <= 1'b0; - bram_wr_en_r <= 1'b0; - bram_wr_addr_r <= 0; - bram_wr_data_r <= 12'd0; - bram_rd_addr_r <= 0; - - end else begin - state_r <= state_next; - - // Default: clear one-cycle pulse outputs - pk_valid_r <= 1'b0; - sk_valid_r <= 1'b0; - ct_valid_r <= 1'b0; - K_valid_r <= 1'b0; - K_valid_dec_r <= 1'b0; - done_o_r <= 1'b0; - - // Default: BRAM write off - bram_wr_en_r <= 1'b0; - - // Default: de-assert streaming valid signals unless driven - // (These are single-cycle; phase_active prevents glitches) - if (!phase_active) begin - ntt_valid_i_r <= 1'b0; - cbd_valid_i_r <= 1'b0; - snt_valid_i_r <= 1'b0; - sha3_valid_i_r <= 1'b0; - pmul_valid_i_r <= 1'b0; - parith_valid_i_r <= 1'b0; - comp_valid_i_r <= 1'b0; - madd_valid_i_r <= 1'b0; - end - - // ============================================================ - // S_IDLE: latch inputs - // ============================================================ - if (state_r == S_IDLE && valid_i && ready_o_r) begin - mode_r <= mode; - k_r <= i_k; - ready_o_r <= 1'b0; - end - - // ============================================================ - // KEYGEN: RNG → G function - // ============================================================ - if (state_r == S_KG_RNG_WAIT && rng_valid_o) begin - d_reg <= rng_data_o; - end - - if (state_r == S_KG_G_WAIT && chain_done) begin - rho_reg <= chain_rho; - sigma_reg <= chain_sigma; - end - - // ============================================================ - // KEYGEN: SampleNTT loop - // ============================================================ - if (state_r == S_KG_SNT_INIT) begin - loop_i <= 2'd0; - loop_j <= 2'd0; - phase_done <= 1'b0; - end - - if (state_r == S_KG_SNT_START) begin - snt_valid_i_r <= 1'b1; - snt_i_idx_r <= loop_i; - snt_j_idx_r <= loop_j; - coeff_cnt <= 9'd0; - phase_active <= 1'b1; - phase_done <= 1'b0; - end - - if (state_r == S_KG_SNT_COEFFS) begin - snt_valid_i_r <= 1'b0; - if (snt_valid_o) begin - bram_wr_en_r <= 1'b1; - bram_wr_addr_r <= poly_addr(SCRATCH0, coeff_cnt[7:0]); - bram_wr_data_r <= snt_coeff_o; - coeff_cnt <= coeff_cnt + 9'd1; - if (snt_last_o) begin - phase_done <= 1'b1; - phase_active <= 1'b0; - end - end - end - - if (state_r == S_KG_SNT_CLEANUP) begin - coeff_cnt <= 9'd0; - phase_done <= 1'b0; - phase_active <= 1'b0; - end - - if (state_r == S_KG_SNT_NTT_LOAD) begin - phase_active <= 1'b1; - if (coeff_cnt < 9'd256) begin - bram_rd_addr_r <= poly_addr(SCRATCH0, coeff_cnt[7:0]); - ntt_coeff_in_r <= bram_rd_data; - ntt_valid_i_r <= 1'b1; - if (ntt_ready_o) begin - coeff_cnt <= coeff_cnt + 9'd1; - end - end else begin - ntt_valid_i_r <= 1'b0; - phase_done <= 1'b1; - phase_active <= 1'b0; - coeff_cnt <= 9'd0; - end - end - - if (state_r == S_KG_SNT_NTT_COMP) begin - phase_done <= 1'b0; - coeff_cnt <= 9'd0; - phase_active <= 1'b0; - end - - if (state_r == S_KG_SNT_NTT_OUT) begin - phase_active <= 1'b1; - if (ntt_valid_o) begin - bram_wr_en_r <= 1'b1; - bram_wr_addr_r <= poly_addr(A_BASE + (loop_i * K + loop_j), coeff_cnt[7:0]); - bram_wr_data_r <= ntt_coeff_out; - coeff_cnt <= coeff_cnt + 9'd1; - if (coeff_cnt == 9'd255) begin - phase_done <= 1'b1; - phase_active <= 1'b0; - end - end - end - - if (state_r == S_KG_SNT_NEXT) begin - phase_done <= 1'b0; - if (loop_j + 2'd1 < k_r[1:0]) begin - loop_j <= loop_j + 2'd1; - end else if (loop_i + 2'd1 < k_r[1:0]) begin - loop_i <= loop_i + 2'd1; - loop_j <= 2'd0; - end - end - - // ============================================================ - // KEYGEN: CBD s loop - // ============================================================ - if (state_r == S_KG_CBD_S_INIT) begin - loop_idx <= 2'd0; - phase_done <= 1'b0; - cbd_use_r_seed <= 1'b0; // use sigma_reg - end - - if (state_r == S_KG_CBD_S_START) begin - cbd_valid_i_r <= 1'b1; - cbd_nonce_r <= {6'b0, loop_idx}; - cbd_eta_r <= (k_r == 3'd2) ? 2'd3 : 2'd2; - coeff_cnt <= 9'd0; - phase_active <= 1'b1; - phase_done <= 1'b0; - end - - if (state_r == S_KG_CBD_S_COEFFS) begin - cbd_valid_i_r <= 1'b0; - if (cbd_valid_o) begin - bram_wr_en_r <= 1'b1; - bram_wr_addr_r <= poly_addr(SCRATCH0, coeff_cnt[7:0]); - bram_wr_data_r <= cbd_coeff_o; - coeff_cnt <= coeff_cnt + 9'd1; - if (cbd_last_o) begin - phase_done <= 1'b1; - phase_active <= 1'b0; - end - end - end - - if (state_r == S_KG_CBD_S_CLEANUP) begin - coeff_cnt <= 9'd0; - phase_done <= 1'b0; - phase_active <= 1'b0; - end - - if (state_r == S_KG_CBD_S_NTT_LD) begin - phase_active <= 1'b1; - if (coeff_cnt < 9'd256) begin - bram_rd_addr_r <= poly_addr(SCRATCH0, coeff_cnt[7:0]); - ntt_coeff_in_r <= bram_rd_data; - ntt_valid_i_r <= 1'b1; - if (ntt_ready_o) coeff_cnt <= coeff_cnt + 9'd1; - end else begin - ntt_valid_i_r <= 1'b0; - phase_done <= 1'b1; - phase_active <= 1'b0; - coeff_cnt <= 9'd0; - end - end - - if (state_r == S_KG_CBD_S_NTT_CMP) begin - phase_done <= 1'b0; - coeff_cnt <= 9'd0; - phase_active <= 1'b0; - end - - if (state_r == S_KG_CBD_S_NTT_OUT) begin - phase_active <= 1'b1; - if (ntt_valid_o) begin - bram_wr_en_r <= 1'b1; - bram_wr_addr_r <= poly_addr(S_BASE + loop_idx, coeff_cnt[7:0]); - bram_wr_data_r <= ntt_coeff_out; - // Capture into s_hat registers for t_hat computation - if (loop_idx == 2'd0) - s_hat0_reg[coeff_cnt[7:0] * 12 +: 12] <= ntt_coeff_out; - else - s_hat1_reg[coeff_cnt[7:0] * 12 +: 12] <= ntt_coeff_out; - coeff_cnt <= coeff_cnt + 9'd1; - if (coeff_cnt == 9'd255) begin - phase_done <= 1'b1; - phase_active <= 1'b0; - end - end - end - - if (state_r == S_KG_CBD_S_NEXT) begin - phase_done <= 1'b0; - if (loop_idx + 2'd1 < k_r[1:0]) - loop_idx <= loop_idx + 2'd1; - end - - // ============================================================ - // KEYGEN: CBD e loop (same pattern as s) - // ============================================================ - if (state_r == S_KG_CBD_E_INIT) begin - loop_idx <= 2'd0; - phase_done <= 1'b0; - end - - if (state_r == S_KG_CBD_E_START) begin - cbd_valid_i_r <= 1'b1; - cbd_nonce_r <= k_r + {5'b0, loop_idx}; - cbd_eta_r <= (k_r == 3'd2) ? 2'd3 : 2'd2; - coeff_cnt <= 9'd0; - phase_active <= 1'b1; - phase_done <= 1'b0; - end - - if (state_r == S_KG_CBD_E_COEFFS) begin - cbd_valid_i_r <= 1'b0; - if (cbd_valid_o) begin - bram_wr_en_r <= 1'b1; - bram_wr_addr_r <= poly_addr(SCRATCH0, coeff_cnt[7:0]); - bram_wr_data_r <= cbd_coeff_o; - coeff_cnt <= coeff_cnt + 9'd1; - if (cbd_last_o) begin - phase_done <= 1'b1; - phase_active <= 1'b0; - end - end - end - - if (state_r == S_KG_CBD_E_CLEANUP) begin - coeff_cnt <= 9'd0; - phase_done <= 1'b0; - phase_active <= 1'b0; - end - - if (state_r == S_KG_CBD_E_NTT_LD) begin - phase_active <= 1'b1; - if (coeff_cnt < 9'd256) begin - bram_rd_addr_r <= poly_addr(SCRATCH0, coeff_cnt[7:0]); - ntt_coeff_in_r <= bram_rd_data; - ntt_valid_i_r <= 1'b1; - if (ntt_ready_o) coeff_cnt <= coeff_cnt + 9'd1; - end else begin - ntt_valid_i_r <= 1'b0; - phase_done <= 1'b1; - phase_active <= 1'b0; - coeff_cnt <= 9'd0; - end - end - - if (state_r == S_KG_CBD_E_NTT_CMP) begin - phase_done <= 1'b0; - coeff_cnt <= 9'd0; - phase_active <= 1'b0; - end - - if (state_r == S_KG_CBD_E_NTT_OUT) begin - phase_active <= 1'b1; - if (ntt_valid_o) begin - bram_wr_en_r <= 1'b1; - bram_wr_addr_r <= poly_addr(E_BASE + loop_idx, coeff_cnt[7:0]); - bram_wr_data_r <= ntt_coeff_out; - coeff_cnt <= coeff_cnt + 9'd1; - if (coeff_cnt == 9'd255) begin - phase_done <= 1'b1; - phase_active <= 1'b0; - end - end - end - - if (state_r == S_KG_CBD_E_NEXT) begin - phase_done <= 1'b0; - if (loop_idx + 2'd1 < k_r[1:0]) - loop_idx <= loop_idx + 2'd1; - end - - // ============================================================ - // KEYGEN: t_hat computation - // - // For each row i (0..k-1): - // t_hat[i] = sum_j(A[i,j] * s_hat[j]) + e_hat[i] - // - // Phase 1 (S_KG_TMUL_MUL_LD): Load A[i,j], s_hat[j] into poly_mul - // Phase 2 (S_KG_TMUL_MUL_OUT): Read poly_mul result → SCRATCH0/SCRATCH1 - // Phase 3 (S_KG_TMUL_ACCUM): Accumulate all A·s terms using poly_arith - // Phase 4 (S_KG_TMUL_ADD_E): Add e_hat[i] → store in t_hat_i_reg - // ============================================================ - if (state_r == S_KG_TMUL_INIT) begin - loop_i <= 2'd0; - loop_j <= 2'd0; - coeff_cnt <= 9'd0; - tmul_pipe_reg <= 12'd0; - tmul_pipe_valid <= 1'b0; - tmul_out_cnt <= 9'd0; - tmul_adv_row <= 1'b0; - phase_done <= 1'b0; - end - - // --- S_KG_TMUL_MUL_LD: Load A[i,j] and s_hat[j] into poly_mul --- - // Uses s_hat registers (combinational read) + A from BRAM (1-cycle delay). - // First cycle: handle row advancement (if flagged). - // Second cycle: prefetch first A coeff from BRAM. - // Cycles 3-258: feed 256 coeff pairs to poly_mul. - if (state_r == S_KG_TMUL_MUL_LD) begin - phase_active <= 1'b1; - if (coeff_cnt == 9'd0) begin - // Cycle 0: handle row advancement flag - if (tmul_adv_row) begin - loop_i <= loop_i + 2'd1; - loop_j <= 2'd0; - tmul_adv_row <= 1'b0; - end - coeff_cnt <= 9'd1; - end else if (coeff_cnt == 9'd1) begin - // Cycle 1: prefetch first A coefficient - bram_rd_addr_r <= poly_addr(A_BASE + (loop_i * K + loop_j), 8'd0); - coeff_cnt <= 9'd2; - end else if (coeff_cnt <= 9'd257) begin - // bram_rd_data holds A[i,j][coeff_cnt-2] from previous cycle - pmul_a_r <= bram_rd_data; - // s_hat value from register (combinational index) - if (loop_j == 2'd0) - pmul_b_r <= s_hat0_reg[(coeff_cnt - 9'd2) * 12 +: 12]; - else - pmul_b_r <= s_hat1_reg[(coeff_cnt - 9'd2) * 12 +: 12]; - pmul_valid_i_r <= 1'b1; - - // Prefetch next A coefficient - if (coeff_cnt < 9'd257) - bram_rd_addr_r <= poly_addr(A_BASE + (loop_i * K + loop_j), coeff_cnt[7:0] - 8'd1); - - coeff_cnt <= coeff_cnt + 9'd1; - - // After feeding coeff 255 (coeff_cnt reaches 258), done - if (coeff_cnt == 9'd257) begin - phase_done <= 1'b1; - phase_active <= 1'b0; - coeff_cnt <= 9'd0; - end - end - end - - // --- S_KG_TMUL_MUL_OUT: Read poly_mul result into BRAM scratch --- - // Phase 2a: Wait for first pmul_valid_o - // Phase 2b: Read 256 output coefficients - if (state_r == S_KG_TMUL_MUL_OUT) begin - phase_active <= 1'b1; - phase_done <= 1'b0; - - if (pmul_valid_o) begin - // Store to SCRATCH0 (first j term) or SCRATCH1 (subsequent terms) - if (loop_j == 2'd0) begin - bram_wr_addr_r <= poly_addr(SCRATCH0, coeff_cnt[7:0]); - end else begin - bram_wr_addr_r <= poly_addr(SCRATCH1, coeff_cnt[7:0]); - end - bram_wr_en_r <= 1'b1; - bram_wr_data_r <= pmul_coeff_out; - coeff_cnt <= coeff_cnt + 9'd1; - - if (coeff_cnt == 9'd255) begin - phase_done <= 1'b1; - phase_active <= 1'b0; - coeff_cnt <= 9'd0; - end - end - end - - // --- S_KG_TMUL_ACCUM: Accumulate SCRATCH0 and SCRATCH1 via poly_arith --- - // Streams SCRATCH0[k] + SCRATCH1[k] → poly_arith (add) → accumulates - // into SCRATCH0 (or back into t_hat register for final result). - // - // Pipeline: rd SCRATCH0 → (1 cycle) → parith with SCRATCH1 → (1 cycle) → write - // Total: ~1 + 256 + 2 = 259 cycles for 256 coefficients - if (state_r == S_KG_TMUL_ACCUM) begin - phase_active <= 1'b1; - phase_done <= 1'b0; - - // coeff_cnt tracks which coeff we're reading from BRAM - // tmul_out_cnt tracks parith results written - if (coeff_cnt == 9'd0 && tmul_out_cnt == 9'd0 && !tmul_pipe_valid) begin - // Start: read SCRATCH0[0] from BRAM - bram_rd_addr_r <= poly_addr(SCRATCH0, 8'd0); - coeff_cnt <= 9'd1; - end else if (coeff_cnt > 9'd0 && coeff_cnt <= 9'd256 && !tmul_pipe_valid) begin - // bram_rd_data has SCRATCH0[coeff_cnt-1] - // Need to read SCRATCH1[coeff_cnt-1] next - // Buffer the SCRATCH0 value, read SCRATCH1 - tmul_pipe_reg <= bram_rd_data; // SCRATCH0 coeff - tmul_pipe_valid <= 1'b1; - bram_rd_addr_r <= poly_addr(SCRATCH1, coeff_cnt[7:0] - 8'd1); - end else if (tmul_pipe_valid && !parith_valid_i_r) begin - // tmul_pipe_reg has SCRATCH0 coeff - // bram_rd_data has SCRATCH1 coeff (from previous read) - parith_a_r <= tmul_pipe_reg; // SCRATCH0 coeff - parith_b_r <= bram_rd_data; // SCRATCH1 coeff - parith_mode_r <= 1'b0; // add - parith_valid_i_r <= 1'b1; - tmul_pipe_valid <= 1'b0; - - // Prefetch next SCRATCH0 coefficient (if any remain) - if (coeff_cnt <= 9'd256) - bram_rd_addr_r <= poly_addr(SCRATCH0, coeff_cnt[7:0]); - coeff_cnt <= coeff_cnt + 9'd1; - end - - // Write parith result back to SCRATCH0 - if (parith_valid_o) begin - bram_wr_en_r <= 1'b1; - bram_wr_addr_r <= poly_addr(SCRATCH0, tmul_out_cnt[7:0]); - bram_wr_data_r <= parith_coeff_out; - tmul_out_cnt <= tmul_out_cnt + 9'd1; - - if (tmul_out_cnt == 9'd255) begin - phase_done <= 1'b1; - phase_active <= 1'b0; - coeff_cnt <= 9'd0; - tmul_out_cnt <= 9'd0; - tmul_pipe_valid <= 1'b0; - end - end - end - - // --- S_KG_TMUL_ADD_E: Add e_hat[i] to accumulated sum → t_hat_i_reg --- - // Streams SCRATCH0 (accumulated A·s sum) + e_hat[i] (from BRAM) - // through poly_arith (add mode), capturing result into t_hat_i_reg. - // - // Pipeline: rd e_hat → (1 cycle) → parith with SCRATCH0 → (1 cycle) → t_hat_i_reg - if (state_r == S_KG_TMUL_ADD_E) begin - phase_active <= 1'b1; - phase_done <= 1'b0; - - // coeff_cnt tracks which e_hat coeff we're reading - // tmul_out_cnt tracks parith results written to t_hat - if (coeff_cnt == 9'd0 && tmul_out_cnt == 9'd0 && !tmul_pipe_valid) begin - // Start: read e_hat[i][0] from BRAM - bram_rd_addr_r <= poly_addr(E_BASE + loop_i, 8'd0); - coeff_cnt <= 9'd1; - end else if (coeff_cnt > 9'd0 && coeff_cnt <= 9'd256 && !tmul_pipe_valid) begin - // bram_rd_data has e_hat[i][coeff_cnt-1] - // Buffer e_hat value, read accumulated sum SCRATCH0 - tmul_pipe_reg <= bram_rd_data; // e_hat coeff - tmul_pipe_valid <= 1'b1; - bram_rd_addr_r <= poly_addr(SCRATCH0, coeff_cnt[7:0] - 8'd1); - end else if (tmul_pipe_valid && !parith_valid_i_r) begin - // tmul_pipe_reg has e_hat coeff - // bram_rd_data has SCRATCH0 (accumulated sum) coeff - parith_a_r <= bram_rd_data; // accumulated sum - parith_b_r <= tmul_pipe_reg; // e_hat coeff - parith_mode_r <= 1'b0; // add - parith_valid_i_r <= 1'b1; - tmul_pipe_valid <= 1'b0; - - // Prefetch next e_hat coefficient - if (coeff_cnt <= 9'd256) - bram_rd_addr_r <= poly_addr(E_BASE + loop_i, coeff_cnt[7:0]); - coeff_cnt <= coeff_cnt + 9'd1; - end - - // Capture parith result into t_hat_i_reg - if (parith_valid_o) begin - if (loop_i == 2'd0) - t_hat0_reg[tmul_out_cnt[7:0] * 12 +: 12] <= parith_coeff_out; - else - t_hat1_reg[tmul_out_cnt[7:0] * 12 +: 12] <= parith_coeff_out; - tmul_out_cnt <= tmul_out_cnt + 9'd1; - - if (tmul_out_cnt == 9'd255) begin - phase_done <= 1'b1; - phase_active <= 1'b0; - coeff_cnt <= 9'd0; - tmul_out_cnt <= 9'd0; - tmul_pipe_valid <= 1'b0; - // Flag that we're advancing to next row (handled in MUL_LD) - if (loop_i + 2'd1 < k_r[1:0]) - tmul_adv_row <= 1'b1; - end - end - end - - // --- S_KG_TMUL_NEXT: Advance loop_j or transition to DONE --- - if (state_r == S_KG_TMUL_NEXT) begin - phase_done <= 1'b0; - if (loop_j + 2'd1 < k_r[1:0]) begin - loop_j <= loop_j + 2'd1; - end - // else: FSM transitions to S_KG_TMUL_ACCUM (handled by next-state logic) - end - - // ============================================================ - // KEYGEN: DONE — assign pk_o_r and sk_o_r - // ============================================================ - if (state_r == S_KG_DONE) begin - // For k=2, pk = {t_hat1[3071:0], t_hat0[3071:0], rho[255:0]} (padded) - // t_hat0 goes to bits [12*N-1:0] - // t_hat1 goes to bits [2*12*N-1 : 12*N] - // rho embeds at bits above (for k=2, bits [12*2*N+255 : 12*2*N]) - // For simplicity, assign only the lower parts (k=2): - pk_o_r[(0*N*12) +: N*12] <= t_hat0_reg; - pk_o_r[(1*N*12) +: N*12] <= t_hat1_reg; - // rho_reg is embedded in pk encoding (FIPS 203, byte-encoded) - // Store rho in the upper bits for k=2 - pk_o_r[(2*N*12) +: 256] <= rho_reg; - - sk_o_r[(0*N*12) +: N*12] <= s_hat0_reg; - sk_o_r[(1*N*12) +: N*12] <= s_hat1_reg; - - pk_valid_r <= 1'b1; - sk_valid_r <= 1'b1; - done_o_r <= 1'b1; - ready_o_r <= 1'b1; - end - - // ============================================================ - // ENCAPS: RNG → H → G - // ============================================================ - if (state_r == S_EN_RNG_WAIT && rng_valid_o) begin - m_reg <= rng_data_o; - end - - if (state_r == S_EN_H_START) begin - sha3_mode_r <= 2'b01; // H mode (SHA3-256) - sha3_data_r <= {256'b0, m_reg}; - sha3_valid_i_r <= 1'b1; - end - - if (state_r == S_EN_H_WAIT) begin - sha3_valid_i_r <= 1'b0; - if (sha3_valid_o) - Hpk_reg <= sha3_hash_o[255:0]; - end - - if (state_r == S_EN_G_START) begin - sha3_mode_r <= 2'b00; // G mode (SHA3-512) - sha3_data_r <= {248'b0, 8'd2, m_reg}; - sha3_valid_i_r <= 1'b1; - end - - if (state_r == S_EN_G_WAIT) begin - sha3_valid_i_r <= 1'b0; - if (sha3_valid_o) begin - Kbar_reg <= sha3_hash_o[255:0]; - r_reg <= sha3_hash_o[511:256]; - end - end - - // ============================================================ - // ENCAPS: SampleNTT loop - // ============================================================ - if (state_r == S_EN_SNT_INIT) begin - loop_i <= 2'd0; - loop_j <= 2'd0; - phase_done <= 1'b0; - end - - if (state_r == S_EN_SNT_START) begin - snt_valid_i_r <= 1'b1; - snt_i_idx_r <= loop_i; - snt_j_idx_r <= loop_j; - coeff_cnt <= 9'd0; - phase_active <= 1'b1; - phase_done <= 1'b0; - end - - if (state_r == S_EN_SNT_COEFFS) begin - snt_valid_i_r <= 1'b0; - if (snt_valid_o) begin - bram_wr_en_r <= 1'b1; - bram_wr_addr_r <= poly_addr(SCRATCH0, coeff_cnt[7:0]); - bram_wr_data_r <= snt_coeff_o; - coeff_cnt <= coeff_cnt + 9'd1; - if (snt_last_o) begin - phase_done <= 1'b1; - phase_active <= 1'b0; - end - end - end - - if (state_r == S_EN_SNT_CLEANUP) begin - coeff_cnt <= 9'd0; - phase_done <= 1'b0; - phase_active <= 1'b0; - end - - if (state_r == S_EN_SNT_NTT_LD) begin - phase_active <= 1'b1; - if (coeff_cnt < 9'd256) begin - bram_rd_addr_r <= poly_addr(SCRATCH0, coeff_cnt[7:0]); - ntt_coeff_in_r <= bram_rd_data; - ntt_valid_i_r <= 1'b1; - if (ntt_ready_o) coeff_cnt <= coeff_cnt + 9'd1; - end else begin - ntt_valid_i_r <= 1'b0; - phase_done <= 1'b1; - phase_active <= 1'b0; - coeff_cnt <= 9'd0; - end - end - - if (state_r == S_EN_SNT_NTT_CMP) begin - phase_done <= 1'b0; - coeff_cnt <= 9'd0; - phase_active <= 1'b0; - end - - if (state_r == S_EN_SNT_NTT_OUT) begin - phase_active <= 1'b1; - if (ntt_valid_o) begin - bram_wr_en_r <= 1'b1; - bram_wr_addr_r <= poly_addr(A_BASE + (loop_i * K + loop_j), coeff_cnt[7:0]); - bram_wr_data_r <= ntt_coeff_out; - coeff_cnt <= coeff_cnt + 9'd1; - if (coeff_cnt == 9'd255) begin - phase_done <= 1'b1; - phase_active <= 1'b0; - end - end - end - - if (state_r == S_EN_SNT_NEXT) begin - phase_done <= 1'b0; - if (loop_j + 2'd1 < k_r[1:0]) begin - loop_j <= loop_j + 2'd1; - end else if (loop_i + 2'd1 < k_r[1:0]) begin - loop_i <= loop_i + 2'd1; - loop_j <= 2'd0; - end - end - - // ============================================================ - // ENCAPS: CBD y loop - // ============================================================ - if (state_r == S_EN_CBD_Y_INIT) begin - loop_idx <= 2'd0; - phase_done <= 1'b0; - cbd_use_r_seed <= 1'b1; // use r_reg for seed - end - - if (state_r == S_EN_CBD_Y_START) begin - cbd_valid_i_r <= 1'b1; - cbd_nonce_r <= {6'b0, loop_idx}; - cbd_eta_r <= (k_r == 3'd2) ? 2'd3 : 2'd2; - coeff_cnt <= 9'd0; - phase_active <= 1'b1; - phase_done <= 1'b0; - end - - if (state_r == S_EN_CBD_Y_COEFFS) begin - cbd_valid_i_r <= 1'b0; - if (cbd_valid_o) begin - bram_wr_en_r <= 1'b1; - bram_wr_addr_r <= poly_addr(SCRATCH0, coeff_cnt[7:0]); - bram_wr_data_r <= cbd_coeff_o; - coeff_cnt <= coeff_cnt + 9'd1; - if (cbd_last_o) begin - phase_done <= 1'b1; - phase_active <= 1'b0; - end - end - end - - if (state_r == S_EN_CBD_Y_CLNUP) begin - coeff_cnt <= 9'd0; - phase_done <= 1'b0; - phase_active <= 1'b0; - end - - if (state_r == S_EN_CBD_Y_NTT_LD) begin - phase_active <= 1'b1; - if (coeff_cnt < 9'd256) begin - bram_rd_addr_r <= poly_addr(SCRATCH0, coeff_cnt[7:0]); - ntt_coeff_in_r <= bram_rd_data; - ntt_valid_i_r <= 1'b1; - if (ntt_ready_o) coeff_cnt <= coeff_cnt + 9'd1; - end else begin - ntt_valid_i_r <= 1'b0; - phase_done <= 1'b1; - phase_active <= 1'b0; - coeff_cnt <= 9'd0; - end - end - - if (state_r == S_EN_CBD_Y_NTT_CMP) begin - phase_done <= 1'b0; - coeff_cnt <= 9'd0; - phase_active <= 1'b0; - end - - if (state_r == S_EN_CBD_Y_NTT_OUT) begin - phase_active <= 1'b1; - if (ntt_valid_o) begin - bram_wr_en_r <= 1'b1; - bram_wr_addr_r <= poly_addr(Y_BASE + loop_idx, coeff_cnt[7:0]); - bram_wr_data_r <= ntt_coeff_out; - coeff_cnt <= coeff_cnt + 9'd1; - if (coeff_cnt == 9'd255) begin - phase_done <= 1'b1; - phase_active <= 1'b0; - end - end - end - - if (state_r == S_EN_CBD_Y_NEXT) begin - phase_done <= 1'b0; - if (loop_idx + 2'd1 < k_r[1:0]) - loop_idx <= loop_idx + 2'd1; - end - - // ============================================================ - // ENCAPS: DONE - // ============================================================ - if (state_r == S_EN_DONE) begin - ct_valid_r <= 1'b1; - K_valid_r <= 1'b1; - K_o_r <= Kbar_reg; - done_o_r <= 1'b1; - ready_o_r <= 1'b1; - end - - // ============================================================ - // DECAPS: placeholder states - // ============================================================ - if (state_r == S_DC_DECOMP_C1) begin - phase_done <= 1'b1; - end - if (state_r == S_DC_DECOMP_C2) begin - phase_done <= 1'b1; - end - if (state_r == S_DC_NTT_U_LD) begin - phase_done <= 1'b1; - phase_active <= 1'b0; - end - if (state_r == S_DC_NTT_U_CMP) begin - phase_done <= 1'b0; - phase_active <= 1'b0; - end - if (state_r == S_DC_NTT_U_OUT) begin - phase_done <= 1'b1; - end - if (state_r == S_DC_MUL_S) begin - phase_done <= 1'b1; - end - if (state_r == S_DC_INTT_V) begin - phase_done <= 1'b1; - end - if (state_r == S_DC_DECOMP_M) begin - phase_done <= 1'b1; - end - if (state_r == S_DC_G_CHECK) begin - phase_done <= 1'b1; - end - if (state_r == S_DC_REENC) begin - phase_done <= 1'b1; - end - if (state_r == S_DC_KDF) begin - phase_done <= 1'b1; - end - if (state_r == S_DC_DONE) begin - K_valid_dec_r <= 1'b1; - done_o_r <= 1'b1; - ready_o_r <= 1'b1; - end - - end - end - - // ==================================================================== - // MODULE INSTANTIATIONS - // ==================================================================== - - // --- keccak_core (shared) --- - keccak_core #(.ROUNDS(24)) u_keccak_shared ( - .clk (clk), - .rst_n (rst_n), - .state_i (arb_kc_state_i), - .valid_i (arb_kc_valid_i), - .ready_o (arb_kc_ready_o), - .state_o (arb_kc_state_o), - .valid_o (arb_kc_valid_o), - .ready_i (arb_kc_ready_i) - ); - - // --- keccak_arbiter (3 consumers) --- - keccak_arbiter #(.NUM_CONSUMERS(N_CONSUMERS)) u_arbiter ( - .clk (clk), - .rst_n (rst_n), - .kc_state_i (arb_kc_state_i), - .kc_valid_i (arb_kc_valid_i), - .kc_ready_o (arb_kc_ready_o), - .kc_state_o (arb_kc_state_o), - .kc_valid_o (arb_kc_valid_o), - .kc_ready_i (arb_kc_ready_i), - .cons_state_i (arb_cons_state_i), - .cons_valid_i (arb_cons_valid_i), - .cons_ready_o (arb_cons_ready_o), - .cons_state_o (arb_cons_state_o), - .cons_valid_o (arb_cons_valid_o), - .cons_ready_i (arb_cons_ready_i) - ); - - // --- sha3_chain_top_shared (consumer 0) --- - sha3_chain_top_shared u_chain ( - .clk (clk), - .rst_n (rst_n), - .d_in (d_rev), - .start_i (chain_start), - .done_o (chain_done), - .rho_out (chain_rho), - .sigma_out (chain_sigma), - .kc_state_o (chain_kc_state_o), - .kc_valid_o (chain_kc_valid_o), - .kc_ready_i (chain_kc_ready_i), - .kc_state_i (chain_kc_state_i), - .kc_valid_i (chain_kc_valid_i), - .kc_ready_o (chain_kc_ready_o) - ); - - // --- sample_cbd_sync_shared (consumer 1) --- - sample_cbd_sync_shared u_cbd ( - .clk (clk), - .rst_n (rst_n), - .seed_i (cbd_seed_muxed), - .nonce_i (cbd_nonce_r), - .eta_i (cbd_eta_r), - .valid_i (cbd_valid_i_r), - .ready_o (cbd_ready_o), - .coeff_o (cbd_coeff_o), - .valid_o (cbd_valid_o), - .ready_i (1'b1), - .last_o (cbd_last_o), - .kc_state_o (cbd_kc_state_o), - .kc_valid_o (cbd_kc_valid_o), - .kc_ready_i (cbd_kc_ready_i), - .kc_state_i (cbd_kc_state_i), - .kc_valid_i (cbd_kc_valid_i), - .kc_ready_o (cbd_kc_ready_o) - ); - - // --- sample_ntt_sync_shared (consumer 2) --- - sample_ntt_sync_shared #(.K(K)) u_snt ( - .clk (clk), - .rst_n (rst_n), - .rho_i (rho_reg), - .k_i (k_r), - .i_idx (snt_i_idx_r), - .j_idx (snt_j_idx_r), - .valid_i (snt_valid_i_r), - .ready_o (snt_ready_o), - .coeff_o (snt_coeff_o), - .valid_o (snt_valid_o), - .ready_i (1'b1), - .last_o (snt_last_o), - .kc_state_o (snt_kc_state_o), - .kc_valid_o (snt_kc_valid_o), - .kc_ready_i (snt_kc_ready_i), - .kc_state_i (snt_kc_state_i), - .kc_valid_i (snt_kc_valid_i), - .kc_ready_o (snt_kc_ready_o) - ); - - // --- sha3_top (separate keccak_core, for H/KDF calls) --- - sha3_top u_sha3 ( - .clk (clk), - .rst_n (rst_n), - .mode (sha3_mode_r), - .data_i (sha3_data_r), - .valid_i (sha3_valid_i_r), - .ready_o (sha3_ready_o), - .hash_o (sha3_hash_o), - .valid_o (sha3_valid_o), - .ready_i (1'b1) - ); - - // --- rng_sync --- - rng_sync u_rng ( - .clk (clk), - .rst_n (rst_n), - .valid_i (rng_valid_i), - .ready_o (rng_ready_o), - .data_o (rng_data_o), - .valid_o (rng_valid_o), - .ready_i (1'b1) - ); - - // --- ntt_core --- - ntt_core u_ntt ( - .clk (clk), - .rst_n (rst_n), - .coeff_in (ntt_coeff_in_r), - .valid_i (ntt_valid_i_r), - .ready_o (ntt_ready_o), - .mode (ntt_mode_r), - .coeff_out (ntt_coeff_out), - .valid_o (ntt_valid_o), - .ready_i (1'b1), - .done_o (ntt_done_o) - ); - - // --- poly_mul_sync --- - poly_mul_sync u_pmul ( - .clk (clk), - .rst_n (rst_n), - .coeff_a_in (pmul_a_r), - .coeff_b_in (pmul_b_r), - .valid_i (pmul_valid_i_r), - .ready_o (pmul_ready_o), - .coeff_out (pmul_coeff_out), - .valid_o (pmul_valid_o), - .ready_i (1'b1) - ); - - // --- poly_arith_sync --- - poly_arith_sync u_parith ( - .clk (clk), - .rst_n (rst_n), - .coeff_a_in (parith_a_r), - .coeff_b_in (parith_b_r), - .mode (parith_mode_r), - .valid_i (parith_valid_i_r), - .ready_o (parith_ready_o), - .coeff_out (parith_coeff_out), - .valid_o (parith_valid_o), - .ready_i (1'b1) - ); - - // --- comp_decomp_sync --- - comp_decomp_sync u_comp ( - .clk (clk), - .rst_n (rst_n), - .coeff_in (comp_coeff_in_r), - .d (comp_d_r), - .mode (comp_mode_r), - .valid_i (comp_valid_i_r), - .ready_o (comp_ready_o), - .coeff_out (comp_coeff_out), - .valid_o (comp_valid_o), - .ready_i (1'b1) - ); - - // --- mod_add_sync --- - mod_add_sync u_madd ( - .clk (clk), - .rst_n (rst_n), - .a (madd_a_r), - .b (madd_b_r), - .valid_i (madd_valid_i_r), - .ready_o (madd_ready_o), - .sum (madd_sum), - .valid_o (madd_valid_o), - .ready_i (1'b1) - ); - - // --- sd_bram (large, for all polynomial storage) --- - sd_bram #(.W(12), .D(BRAM_DEPTH), .A(BRAM_AW)) u_bram ( - .clk (clk), - .rd_addr (bram_rd_addr_r), - .rd_data (bram_rd_data), - .wr_en (bram_wr_en_r), - .wr_addr (bram_wr_addr_r), - .wr_data (bram_wr_data_r) - ); - -endmodule