Compare commits
3 Commits
5a7d5d6a47
...
4f46c1cd02
| Author | SHA1 | Date | |
|---|---|---|---|
| 4f46c1cd02 | |||
| 460a6ed70c | |||
| 851630f73c |
@@ -36,11 +36,11 @@ set_property target_simulator XSim [current_project]
|
||||
# ── SHA3 / Keccak ──
|
||||
read_verilog -sv ${PROJECT_DIR}/sync_rtl/sha3/keccak_round.v
|
||||
read_verilog -sv ${PROJECT_DIR}/sync_rtl/sha3/keccak_core.v
|
||||
read_verilog -sv ${PROJECT_DIR}/sync_rtl/sha3/sha3_top.v
|
||||
read_verilog -sv ${PROJECT_DIR}/sync_rtl/sha3/sha3_top_shared.v
|
||||
|
||||
# ── 采样 ──
|
||||
read_verilog -sv ${PROJECT_DIR}/sync_rtl/sample_ntt/sample_ntt_sync.v
|
||||
read_verilog -sv ${PROJECT_DIR}/sync_rtl/sample_cbd/sample_cbd_sync.v
|
||||
# ── 采样(共享 keccak_core 变体)──
|
||||
read_verilog -sv ${PROJECT_DIR}/sync_rtl/sample_ntt/sample_ntt_sync_shared.v
|
||||
read_verilog -sv ${PROJECT_DIR}/sync_rtl/sample_cbd/sample_cbd_sync_shared.v
|
||||
|
||||
# ── NTT ──
|
||||
read_verilog -sv ${PROJECT_DIR}/sync_rtl/ntt/barrett_mul.v
|
||||
|
||||
183
sync_rtl/sha3/sha3_top_shared.v
Normal file
183
sync_rtl/sha3/sha3_top_shared.v
Normal file
@@ -0,0 +1,183 @@
|
||||
// sha3_top_shared.v - SHA3/SHAKE wrapper with EXTERNAL (shared) keccak_core.
|
||||
//
|
||||
// Identical to sha3_top.v except the internal keccak_core instance is
|
||||
// replaced by explicit kc_* ports, so several Keccak consumers can share a
|
||||
// single keccak_core via a phase mux (see mlkem_top). The sponge state
|
||||
// (mb_state_r) and all FSM/squeeze logic stay here; only the 24-round
|
||||
// permutation is external. Bit-identical to sha3_top when wired to a
|
||||
// dedicated keccak_core.
|
||||
//
|
||||
// Single-block modes (mb_en=0):
|
||||
// 00 = G (SHA3-512): rate=576, suffix=01, msg_len=264, out=512
|
||||
// 01 = H (SHA3-256): rate=1088, suffix=01, msg_len=256, out=256
|
||||
// 10 = J (SHAKE-256): rate=1088, suffix=1111,msg_len=512,out=256
|
||||
//
|
||||
// Multi-block SHA3-256 (mb_en=1): streams pre-padded 1088-bit rate blocks;
|
||||
// the CALLER applies SHA3-256 padding to the final block.
|
||||
//
|
||||
// Keccak interface (port names mirror the keccak_core port each connects to):
|
||||
// kc_state_o[1599:0] - keccak result (input, from keccak_core.state_o)
|
||||
// kc_valid_o - keccak output valid (input, from keccak_core.valid_o)
|
||||
// kc_ready_o - keccak ready for input (input, from keccak_core.ready_o)
|
||||
// kc_state_i[1599:0] - keccak input state (output, to keccak_core.state_i)
|
||||
// kc_valid_i - request permutation (output, to keccak_core.valid_i)
|
||||
// kc_ready_i - accept keccak output (output, to keccak_core.ready_i, always 1)
|
||||
|
||||
module sha3_top_shared (
|
||||
input clk,
|
||||
input rst_n,
|
||||
input [1:0] mode,
|
||||
input [511:0] data_i,
|
||||
input valid_i,
|
||||
output ready_o,
|
||||
output [511:0] hash_o,
|
||||
output valid_o,
|
||||
input ready_i,
|
||||
// --- multi-block SHA3-256 absorb (tie mb_en=0 to disable) ---
|
||||
input mb_en,
|
||||
input [1087:0] mb_block_i,
|
||||
input mb_valid_i,
|
||||
input mb_last_i,
|
||||
output mb_ready_o,
|
||||
// --- external (shared) keccak_core interface ---
|
||||
input [1599:0] kc_state_o,
|
||||
input kc_valid_o,
|
||||
/* verilator lint_off UNUSEDSIGNAL */
|
||||
input kc_ready_o,
|
||||
/* verilator lint_on UNUSEDSIGNAL */
|
||||
output [1599:0] kc_state_i,
|
||||
output kc_valid_i,
|
||||
output kc_ready_i
|
||||
);
|
||||
|
||||
// ================================================================
|
||||
// FSM state encoding
|
||||
// ================================================================
|
||||
localparam ST_IDLE = 2'd0;
|
||||
localparam ST_PERMUTE = 2'd1;
|
||||
localparam ST_SQUEEZE = 2'd2;
|
||||
|
||||
reg [1:0] state_r, state_next;
|
||||
|
||||
// ================================================================
|
||||
// Absorb state: message || suffix || pad10*1 into rate bits
|
||||
// ================================================================
|
||||
wire [575:0] g_pad;
|
||||
wire [1087:0] h_pad;
|
||||
wire [1087:0] j_pad;
|
||||
|
||||
assign g_pad = {1'b1, {308{1'b0}}, 1'b1, 2'b10, data_i[263:0]};
|
||||
assign h_pad = {1'b1, {828{1'b0}}, 1'b1, 2'b10, data_i[255:0]};
|
||||
// J: SHAKE suffix is "1111" — all ones, order irrelevant
|
||||
assign j_pad = {1'b1, {570{1'b0}}, 1'b1, 4'b1111, data_i[511:0]};
|
||||
|
||||
wire [1599:0] absorb_state;
|
||||
assign absorb_state = (mode == 2'b00) ? {{(1600-576){1'b0}}, g_pad} :
|
||||
(mode == 2'b01) ? {{(1600-1088){1'b0}}, h_pad} :
|
||||
(mode == 2'b10) ? {{(1600-1088){1'b0}}, j_pad} :
|
||||
1600'd0;
|
||||
|
||||
// ================================================================
|
||||
// Multi-block SHA3-256 absorb FSM (active only when mb_en=1)
|
||||
// ================================================================
|
||||
localparam MB_IDLE = 2'd0; // ready for a block (or first block)
|
||||
localparam MB_PERMUTE = 2'd1; // keccak running on xored state
|
||||
localparam MB_DONE = 2'd2; // squeeze: present 256-bit digest
|
||||
|
||||
reg [1:0] mb_state, mb_state_next;
|
||||
reg [1599:0] mb_state_r; // running sponge state
|
||||
reg mb_last_r; // captured last-block flag
|
||||
reg [255:0] mb_digest_r; // latched 256-bit digest (sticky in MB_DONE)
|
||||
|
||||
// XOR the incoming block into the low 1088 bits (rate) of the state.
|
||||
wire [1599:0] mb_xored;
|
||||
assign mb_xored = mb_state_r ^ {{(1600-1088){1'b0}}, mb_block_i};
|
||||
|
||||
// Accept a block only in MB_IDLE while enabled.
|
||||
assign mb_ready_o = mb_en && (mb_state == MB_IDLE);
|
||||
wire mb_accept = mb_en && (mb_state == MB_IDLE) && mb_valid_i;
|
||||
wire mb_kc_valid = mb_accept; // start keccak on the accept cycle
|
||||
|
||||
always @(*) begin
|
||||
mb_state_next = mb_state;
|
||||
case (mb_state)
|
||||
MB_IDLE: if (mb_accept) mb_state_next = MB_PERMUTE;
|
||||
MB_PERMUTE: if (kc_valid_o) mb_state_next = mb_last_r ? MB_DONE : MB_IDLE;
|
||||
MB_DONE: if (ready_i) mb_state_next = MB_IDLE;
|
||||
default: mb_state_next = MB_IDLE;
|
||||
endcase
|
||||
end
|
||||
|
||||
// ================================================================
|
||||
// External keccak_core interface (was internal keccak_core)
|
||||
// ================================================================
|
||||
// Keccak input: multi-block xored state when mb_en, else single-block absorb.
|
||||
assign kc_state_i = mb_en ? mb_xored : absorb_state;
|
||||
// Always accept keccak output (matches the dedicated-core ready_i=1'b1).
|
||||
assign kc_ready_i = 1'b1;
|
||||
// kc_valid_i: single-block start (state_next==PERMUTE) OR multi-block accept.
|
||||
assign kc_valid_i = mb_en ? mb_kc_valid : (state_next == ST_PERMUTE);
|
||||
|
||||
// ================================================================
|
||||
// FSM combinational logic
|
||||
// ================================================================
|
||||
assign ready_o = !mb_en && (state_r == ST_IDLE);
|
||||
|
||||
always @(*) begin
|
||||
state_next = state_r;
|
||||
case (state_r)
|
||||
ST_IDLE: if (valid_i && ready_o) state_next = ST_PERMUTE;
|
||||
ST_PERMUTE: if (kc_valid_o) state_next = ST_SQUEEZE;
|
||||
ST_SQUEEZE: if (valid_o && ready_i) state_next = ST_IDLE;
|
||||
default: state_next = ST_IDLE;
|
||||
endcase
|
||||
end
|
||||
|
||||
// ================================================================
|
||||
// Output
|
||||
// ================================================================
|
||||
reg [511:0] squeezed_state_r;
|
||||
|
||||
// valid_o / hash_o serve both paths, selected by mb_en.
|
||||
assign valid_o = mb_en ? (mb_state == MB_DONE) : (state_r == ST_SQUEEZE);
|
||||
assign hash_o = mb_en ? {256'b0, mb_digest_r} : squeezed_state_r;
|
||||
|
||||
// ================================================================
|
||||
// Sequential logic
|
||||
// ================================================================
|
||||
always @(posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
state_r <= ST_IDLE;
|
||||
squeezed_state_r <= 512'd0;
|
||||
mb_state <= MB_IDLE;
|
||||
mb_state_r <= 1600'd0;
|
||||
mb_last_r <= 1'b0;
|
||||
mb_digest_r <= 256'd0;
|
||||
end else begin
|
||||
state_r <= state_next;
|
||||
mb_state <= mb_state_next;
|
||||
|
||||
// --- single-block: latch squeezed output ---
|
||||
if (state_r == ST_PERMUTE && kc_valid_o) begin
|
||||
squeezed_state_r <= kc_state_o[511:0];
|
||||
end
|
||||
|
||||
// --- multi-block: capture last flag on accept ---
|
||||
if (mb_accept) begin
|
||||
mb_last_r <= mb_last_i;
|
||||
end
|
||||
|
||||
// --- multi-block: latch permuted state when keccak finishes ---
|
||||
if (mb_state == MB_PERMUTE && kc_valid_o) begin
|
||||
mb_state_r <= kc_state_o;
|
||||
if (mb_last_r) mb_digest_r <= kc_state_o[255:0];
|
||||
end
|
||||
|
||||
// --- multi-block: clear running state after digest consumed ---
|
||||
if (mb_state == MB_DONE && ready_i) begin
|
||||
mb_state_r <= 1600'd0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
@@ -9,9 +9,9 @@
|
||||
# ---- Step 1: compile RTL ----
|
||||
xvlog -sv --relax -i . sync_rtl/sha3/keccak_round.v
|
||||
xvlog -sv --relax -i . sync_rtl/sha3/keccak_core.v
|
||||
xvlog -sv --relax -i . sync_rtl/sha3/sha3_top.v
|
||||
xvlog -sv --relax -i . sync_rtl/sample_ntt/sample_ntt_sync.v
|
||||
xvlog -sv --relax -i . sync_rtl/sample_cbd/sample_cbd_sync.v
|
||||
xvlog -sv --relax -i . sync_rtl/sha3/sha3_top_shared.v
|
||||
xvlog -sv --relax -i . sync_rtl/sample_ntt/sample_ntt_sync_shared.v
|
||||
xvlog -sv --relax -i . sync_rtl/sample_cbd/sample_cbd_sync_shared.v
|
||||
xvlog -sv --relax -i . sync_rtl/ntt/barrett_mul.v
|
||||
xvlog -sv --relax -i . sync_rtl/ntt/zeta_rom.v
|
||||
xvlog -sv --relax -i . sync_rtl/ntt/butterfly_unit.v
|
||||
|
||||
@@ -179,20 +179,86 @@ module mlkem_top #(
|
||||
reg sha3_ack; // consumer ready for hash
|
||||
wire [511:0] g_data = {248'b0, 5'b0, k_r, d_i}; // data_i[263:256]=k, [255:0]=d
|
||||
|
||||
sha3_top u_sha3 (
|
||||
// ================================================================
|
||||
// Shared keccak_core + phase mux (3 consumers -> 1 core)
|
||||
//
|
||||
// G/H (u_sha3), SampleNTT (u_snt) and CBD (u_cbd) each need a Keccak
|
||||
// permutation, but they run in DISJOINT top-FSM phases (ST_G/ST_H, ST_A,
|
||||
// ST_C respectively), so at most one is ever active. One keccak_core
|
||||
// serves all three: kc_state_i/kc_valid_i are muxed by phase; kc_valid_o
|
||||
// is broadcast but GATED per consumer so an inactive consumer never
|
||||
// latches a permutation result meant for another (the samplers latch
|
||||
// squeeze state unconditionally on their kc_valid_o input).
|
||||
// ================================================================
|
||||
wire [1599:0] kc_state_o; // shared core output (to all consumers)
|
||||
wire kc_valid_o; // shared core output-valid
|
||||
wire kc_ready_o; // shared core input-ready
|
||||
|
||||
// per-consumer drives toward the core
|
||||
wire [1599:0] sha3_kc_state_i, snt_kc_state_i, cbd_kc_state_i;
|
||||
wire sha3_kc_valid_i, snt_kc_valid_i, cbd_kc_valid_i;
|
||||
/* verilator lint_off UNUSEDSIGNAL */
|
||||
wire sha3_kc_ready_i, snt_kc_ready_i, cbd_kc_ready_i; // all 1'b1
|
||||
/* verilator lint_on UNUSEDSIGNAL */
|
||||
|
||||
// phase selects (mutually exclusive)
|
||||
wire sel_sha3 = (st == ST_G) || (st == ST_H);
|
||||
wire sel_snt = (st == ST_A);
|
||||
wire sel_cbd = (st == ST_C);
|
||||
|
||||
// gated output-valid: only the active consumer sees kc_valid_o
|
||||
wire kc_valid_o_sha3 = kc_valid_o & sel_sha3;
|
||||
wire kc_valid_o_snt = kc_valid_o & sel_snt;
|
||||
wire kc_valid_o_cbd = kc_valid_o & sel_cbd;
|
||||
|
||||
// input mux: route the active consumer's request to the core
|
||||
wire [1599:0] kc_state_i_mux = sel_snt ? snt_kc_state_i :
|
||||
sel_cbd ? cbd_kc_state_i :
|
||||
sha3_kc_state_i;
|
||||
wire kc_valid_i_mux = sel_snt ? snt_kc_valid_i :
|
||||
sel_cbd ? cbd_kc_valid_i :
|
||||
sel_sha3 ? sha3_kc_valid_i : 1'b0;
|
||||
|
||||
keccak_core #(.ROUNDS(24)) u_keccak (
|
||||
.clk(clk), .rst_n(rst_n),
|
||||
.mode(2'b00), // G = SHA3-512
|
||||
.state_i(kc_state_i_mux),
|
||||
.valid_i(kc_valid_i_mux),
|
||||
.ready_o(kc_ready_o),
|
||||
.state_o(kc_state_o),
|
||||
.valid_o(kc_valid_o),
|
||||
.ready_i(1'b1) // consumers always accept (kc_ready_i=1)
|
||||
);
|
||||
|
||||
// ---- single shared sha3_top serving BOTH G and H ----
|
||||
// G (ST_G) uses single-block mode (mb_en=0); H(ek) (ST_H) uses the
|
||||
// multi-block absorb path (mb_en=1). These phases are disjoint in the
|
||||
// top FSM, so one sha3_top (one keccak_core) is sufficient. mb_en and
|
||||
// ready_i are muxed by phase; data_i/mode only matter while mb_en=0.
|
||||
wire sha3_mb_en = (st == ST_H);
|
||||
sha3_top_shared u_sha3 (
|
||||
.clk(clk), .rst_n(rst_n),
|
||||
.mode(2'b00), // G = SHA3-512 (only used when mb_en=0)
|
||||
.data_i(g_data),
|
||||
.valid_i(sha3_valid),
|
||||
.ready_o(sha3_ready),
|
||||
.hash_o(sha3_hash),
|
||||
.valid_o(sha3_vo),
|
||||
.ready_i(sha3_ack),
|
||||
.mb_en(1'b0), .mb_block_i(1088'b0), .mb_valid_i(1'b0),
|
||||
.mb_last_i(1'b0), .mb_ready_o()
|
||||
.ready_i(sha3_mb_en ? h_ack : sha3_ack),
|
||||
.mb_en(sha3_mb_en),
|
||||
.mb_block_i(h_block_r),
|
||||
.mb_valid_i(h_mbvalid),
|
||||
.mb_last_i(h_mblast),
|
||||
.mb_ready_o(h_mbready),
|
||||
// shared keccak_core interface (gated by phase in the mux below)
|
||||
.kc_state_o(kc_state_o),
|
||||
.kc_valid_o(kc_valid_o_sha3),
|
||||
.kc_ready_o(kc_ready_o),
|
||||
.kc_state_i(sha3_kc_state_i),
|
||||
.kc_valid_i(sha3_kc_valid_i),
|
||||
.kc_ready_i(sha3_kc_ready_i)
|
||||
);
|
||||
|
||||
// ---- second sha3_top dedicated to multi-block H(ek) (SHA3-256, 800B->6 blk) ----
|
||||
// ---- multi-block H(ek) state (SHA3-256, 6/9/12 blocks); fed to shared u_sha3 ----
|
||||
reg [1087:0] h_block_r; // current pre-padded rate block
|
||||
reg h_mbvalid;
|
||||
reg h_mblast;
|
||||
@@ -213,21 +279,11 @@ module mlkem_top #(
|
||||
reg [7:0] h_wb_pad; // pad constant to use if g is out of ek range
|
||||
reg h_wb_inek; // 1 if g is within ek range (use BRAM data)
|
||||
|
||||
sha3_top u_sha3_h (
|
||||
.clk(clk), .rst_n(rst_n),
|
||||
.mode(2'b01), // unused in mb mode
|
||||
.data_i(512'b0),
|
||||
.valid_i(1'b0),
|
||||
.ready_o(),
|
||||
.hash_o(h_hash),
|
||||
.valid_o(h_vo),
|
||||
.ready_i(h_ack),
|
||||
.mb_en(1'b1),
|
||||
.mb_block_i(h_block_r),
|
||||
.mb_valid_i(h_mbvalid),
|
||||
.mb_last_i(h_mblast),
|
||||
.mb_ready_o(h_mbready)
|
||||
);
|
||||
// h_hash / h_vo are now served by the shared u_sha3 above (mb_en=1 during
|
||||
// ST_H). They alias the single core's outputs; the H consumer logic below
|
||||
// already gates on st==ST_H, and u_sha3's valid_o/hash_o are mb-selected.
|
||||
assign h_hash = sha3_hash;
|
||||
assign h_vo = sha3_vo;
|
||||
|
||||
// SHA3-256 over ek (ek_bytes_rt bytes): rate=136. Padded length = h_nblk_rt*136.
|
||||
// pad: byte ek_bytes_rt = 0x06 (domain + first pad bit), last byte |= 0x80.
|
||||
@@ -266,7 +322,7 @@ module mlkem_top #(
|
||||
wire snt_last;
|
||||
reg snt_ack; // we accept coeffs
|
||||
|
||||
sample_ntt_sync #(.K(KMAX)) u_snt (
|
||||
sample_ntt_sync_shared #(.K(KMAX)) u_snt (
|
||||
.clk(clk), .rst_n(rst_n),
|
||||
.rho_i(rho_r),
|
||||
.k_i(k_r),
|
||||
@@ -277,7 +333,14 @@ module mlkem_top #(
|
||||
.coeff_o(snt_coeff),
|
||||
.valid_o(snt_vo),
|
||||
.ready_i(snt_ack),
|
||||
.last_o(snt_last)
|
||||
.last_o(snt_last),
|
||||
// shared keccak_core interface
|
||||
.kc_state_o(kc_state_o),
|
||||
.kc_valid_o(kc_valid_o_snt),
|
||||
.kc_ready_o(kc_ready_o),
|
||||
.kc_state_i(snt_kc_state_i),
|
||||
.kc_valid_i(snt_kc_valid_i),
|
||||
.kc_ready_i(snt_kc_ready_i)
|
||||
);
|
||||
|
||||
// ---- sample_cbd_sync: s[i]=CBD3(PRF(sigma,i)), e[i]=CBD3(PRF(sigma,K+i)) ----
|
||||
@@ -288,7 +351,7 @@ module mlkem_top #(
|
||||
wire cbd_last;
|
||||
reg cbd_ack;
|
||||
|
||||
sample_cbd_sync u_cbd (
|
||||
sample_cbd_sync_shared u_cbd (
|
||||
.clk(clk), .rst_n(rst_n),
|
||||
.seed_i(sigma_r),
|
||||
.nonce_i(c_nonce),
|
||||
@@ -298,7 +361,14 @@ module mlkem_top #(
|
||||
.coeff_o(cbd_coeff),
|
||||
.valid_o(cbd_vo),
|
||||
.ready_i(cbd_ack),
|
||||
.last_o(cbd_last)
|
||||
.last_o(cbd_last),
|
||||
// shared keccak_core interface
|
||||
.kc_state_o(kc_state_o),
|
||||
.kc_valid_o(kc_valid_o_cbd),
|
||||
.kc_ready_o(kc_ready_o),
|
||||
.kc_state_i(cbd_kc_state_i),
|
||||
.kc_valid_i(cbd_kc_valid_i),
|
||||
.kc_ready_i(cbd_kc_ready_i)
|
||||
);
|
||||
|
||||
// signed (two's complement) -> [0,Q): add Q when negative
|
||||
|
||||
Reference in New Issue
Block a user