Compare commits

...

15 Commits

Author SHA1 Message Date
8774e03a0e build(vivado): rewrite create_project.tcl for current KeyGen flow
The old script referenced 5 non-existent files (keccak_arbiter,
sha3_chain_top_shared, tb_mlkem_top_xsim, tb_kg/en/de) and stale
vectors, so read_verilog/elaborate failed outright.

Rewrite to mirror the verified XSIM flow (sync_rtl/top/TB/xsim_run.tcl):
  - load exactly the 14 sources mlkem_top depends on
  - sim top = tb_mlkem_kg_katK_xsim, runtime K via generic KP, case via
    -testplusarg CASE
  - copy KAT vectors into the xsim working dir via xsim.compile.tcl.pre
    (the only hook in 2019.2 that runs before $readmemh; an appended
    -tclbatch runs after Vivado's own 'run all', too late)
  - drop duplicate --relax (XSim adds it; passing again is an error)

Verified through the actual Vivado batch project flow:
  K=2 CASE 0 -> PASS (21403 cyc), K=4 CASE 2 -> PASS (54059 cyc),
  0 file-not-found warnings. gitignore the generated vivado_prj/.

Also rewrite README.md in Chinese documenting the mlkem_top workflow
and test flow.
2026-06-28 03:43:56 +08:00
3a53993754 refactor(kg): make ML-KEM K a runtime input k_i instead of a parameter
mlkem_top now sizes storage for KMAX=4 (worst case) and selects the
active ML-KEM parameter set at start_i via the k_i input. All K-derived
quantities (eta1, slot bases, ek/dk byte counts, H(ek) block count, FSM
bounds) are computed at runtime from the captured k_r.

Verified byte-exact against NIST KAT for all three parameter sets:
  K=2 (512)  cases 0-4, K=3 (768) cases 0-2, K=4 (1024) cases 0-2
  -> 11/11 PASS (ek==pk, dk==sk).
2026-06-28 03:24:58 +08:00
b7e4fd9323 test(top): add kat_k2_* vectors with uniform prefix for parametric TB
The parametric KAT TB (KP generic) builds filenames kat_k<K>_c<n>_*.hex, but
the K=2 vectors were committed earlier as kat_c<n>_*.hex (no k2 prefix), so
run_tb.sh top emitted 'file cannot be opened' warnings for K=2 and the data
read as X. Add kat_k2_* copies so all three parameter sets load cleanly.

./run_tb.sh top now: 0 file warnings, all 11 cases PASS (K=2:0..4, K=3:0..2,
K=4:0..2), exit 0.
2026-06-28 03:06:41 +08:00
b2bf798454 feat(mlkem_top): parameterize K in {2,3,4} (ML-KEM 512/768/1024)
Generalize KeyGen from K=2-hardcoded to compile-time parameter K:
- eta1 derived (3 for K=2, else 2); slot layout SLOT_S/E/T = K*K+{0,K,2K},
  NUM_SLOTS = K*K+3K; SAW=5 slot-addr width.
- A-stage: explicit a_i/a_j row-major counters (slot = i*K+j) instead of
  K=2 bit-tricks. C/N stages: parametric slot bases, 2K polys.
- M-stage: m_i/m_j widened to 3-bit (must reach K=4); slots i*K+j etc.
- E-stage: 2K polys, e_is_dk split, rho offset 384*K.
- H(ek): H_NBLK=ceil((EK_BYTES+1)/136), H_LAST padding generalized;
  h_blk 4-bit. Byte mems sized EK_BYTES/DK_BYTES.
- Widen dbg_byte_idx_i to [10:0] (ek up to 1568B for K=4).

Parametric TB (tb_mlkem_kg_katK, KP generic + CASE plusarg). Verified
byte-exact vs NIST KAT:
  K=2 (512):  cases 0..4  ek 800B  / dk 1632B
  K=3 (768):  cases 0..2  ek 1184B / dk 2400B  (~36k cyc)
  K=4 (1024): cases 0..2  ek 1568B / dk 3168B  (~54k cyc)
run_tb.sh top runs all three parameter sets.
2026-06-28 02:59:58 +08:00
2f46c0790f test(top): add xsim_run.tcl so run_tb.sh top runs KeyGen KAT 0..4
./run_tb.sh top now compiles the full KeyGen datapath + tb_mlkem_kg_katN
and runs all 5 NIST KAT cases (ek==pk 800B, dk==sk 1632B byte-exact).
Also registers 'top' in ./run_tb.sh --list.
2026-06-28 02:29:58 +08:00
42d3748ab6 test(mlkem_top): KeyGen verified vs NIST KAT count=0..4
Parameterized end-to-end TB (tb_mlkem_kg_katN, +CASE=n) loads d/z/ek/dk from
per-case hex files. All 5 cases pass byte-exact:
  ek == KAT pk (800B), dk == KAT sk (1632B), ~21350 cyc each.
Five independent seeds exercise distinct rejection-sampling paths.
Vectors derived from kat_MLKEM_512.rsp with sk-layout sanity checks
(sk = dk_pke || ek || H(ek) || z).
2026-06-28 02:23:18 +08:00
9824ed8f2c feat(mlkem_top): KeyGen stage 4 - H(ek) + full dk, end-to-end KAT pass
Add ST_H stage: second sha3_top (mb_en=1) computes H(ek) over 800B ek as 6
pre-padded SHA3-256 rate blocks. Per block: assemble 136 bytes (h_padbyte
applies 0x06...0x80 padding on final block) into h_block_r, feed (hold valid
until mb_ready drops), wait permute; capture digest on last block into hek_r.

Full dk readback tap: dk = dk_pke(768) || ek(800) || H(ek)(32) || z(32) = 1632B.

End-to-end TB (tb_mlkem_kg_kat_xsim, no force/release): drive KAT count=0 d/z,
run full KeyGen FSM (IDLE->G->A->C->N->M->E->H->DONE), verify:
  ek  == KAT pk (800B)  byte-exact
  dk  == KAT sk (1632B) byte-exact
Done in 21403 cycles. ML-KEM-512 KeyGen complete and KAT-verified.
Prior stage TBs (2c/2e/2f) still pass (no regression).
2026-06-28 02:18:52 +08:00
17914911c3 feat(mlkem_top): KeyGen stage 2f (byteEncode12 -> ek, dk_pke)
Add ST_E stage: serialize t_hat[0..1] -> ek_mem[0..767], s_hat[0..1] ->
dkp_mem[0..767] via byteEncode12 (2 coeffs -> 3 bytes, LSB-first 12-bit:
b0=c0[7:0], b1={c1[3:0],c0[11:8]}, b2=c1[11:4]), then copy rho into
ek_mem[768..799]. Byte readback tap (dbg_byte_sel/idx -> dbg_byte_o).

Verified vs KAT-derived golden: ek 800B (== KAT pk) + dk_pke 768B
(== KAT sk prefix) byte-exact (20430 cyc). Completes Stage 2 datapath.
2026-06-28 02:03:03 +08:00
a9e50ebc0c feat(mlkem_top): KeyGen stage 2e (matrix accumulate t_hat)
Add ST_M stage: t_hat[i] = e_hat[i] + sum_j A_hat[i][j] o s_hat[j] via
poly_mul_sync + inline mod-add accumulation. Per (i,j): stream 256 (A,shat)
pairs into poly_mul, then accumulate 256 products into T_i (seeded from E_i
when j==0, else running T_i). m_pending waits for poly_mul IDLE between terms.

Verified vs ml-kem-r golden: 512/512 t_hat coeffs exact (19885 cyc).
2026-06-28 01:53:23 +08:00
4c692e570a feat(mlkem_top): KeyGen stage 2d (forward NTT of s/e)
Add ST_N stage: forward NTT (ntt_core mode=0, no scaling) of s[0],s[1],
e[0],e[1] in place (slots S0,S1,E0,E1). Per slot: stream 256 coeffs into
ntt_core during LOAD, collect 256 outputs back to same slot. n_pending
waits for core IDLE between slots.

Verified vs ml-kem-r golden: 1024/1024 shat/ehat coeffs exact (17318 cyc).
2026-06-28 01:47:54 +08:00
2f206a6bc5 feat(mlkem_top): KeyGen stages 2a-2c (G, SampleNTT A_hat, CBD s/e)
Fresh valid/ready KeyGen FSM for ML-KEM-512 (K=2, eta1=3). Independent
keccak per consumer (no arbiter). Verified stage-by-stage vs ml-kem-r golden:
- 2a G(d||K): rho/sigma exact (d byte0-low, K at byte32, no reversal).
- 2b SampleNTT: A_hat[i][j] from seed rho||j||i, 1024/1024 coeffs exact.
- 2c CBD: s[i]=CBD3(PRF(sigma,i)), e[i]=CBD3(PRF(sigma,K+i)); signed->mod-q
  (+Q when negative); 2048/2048 (A+s+e) coeffs exact.

polymem register array (10 slots x 256), debug readback tap (dbg_slot/idx ->
coeff, rho/sigma taps) for stage TBs. a_busy/c_busy guards (defensive after
sample_ntt fix). FSM: IDLE->G->A->C->DONE (datapath extended in later stages).

Plan + progress doc in .claude/plans/keygen_plan.md.
2026-06-28 01:41:44 +08:00
6db3c7cc5e fix(sample_ntt): suppress spurious 257th valid_o after last_o
Phase-1 (d1 output) lacked the 'need_more' guard that phase-2 (d2) had, so
when the 256th accepted coefficient was a d1 whose group then advanced, the
FSM could fire one extra valid_o after last_o for certain seeds (e.g. KAT
count=0 rho, seed i=0/j=1 emitted 257 pulses). In mlkem_top KeyGen this
trailing pulse leaked into the next poly's index 0, shifting the stream.

Fix: gate phase-1 d1 output with 'd1_acc_r && need_more' (mirrors phase-2).
Applied to both sample_ntt_sync and sample_ntt_sync_shared.

Standalone TB had a coverage blind spot (stopped reading at 256, never
checked valid_o stayed low after last_o). Added a regression assertion:
counts spurious post-last_o pulses and fails if any. Verified the assertion
catches the bug on a reverted-fix copy (3 spurious) and passes on the fix.

Verified:
- 40-seed audit (sync) + 24-seed audit (shared): all exactly 256 pulses,
  last_o@256, zero post-last pulses.
- Verilator vs hashlib oracle: 1536/1536 (no real coeff dropped).
- Full framework regression: 4334/4334.
- mlkem_top KeyGen Stage 2c: 2048/2048 A_hat+s+e coeffs exact.
2026-06-28 01:35:35 +08:00
106b2925a8 feat(sha3): multi-block SHA3-256 absorb for H(ek); KeyGen golden vectors
Stage 0+1 of mlkem_top KeyGen integration:
- sha3_top: add multi-block SHA3-256 absorb FSM (mb_en/mb_block_i/mb_valid_i/
  mb_last_i/mb_ready_o). Caller pre-pads final block; module does pure absorb
  loop (state^=block; Keccak-p). Single-block G/H/J paths bit-identical when
  mb_en=0. Sticky digest register holds output until consumer acks.
- tb_sha3_mb_xsim: self-checking TB streams 800B ek (6 blocks) -> H(ek),
  verified == hashlib.sha3_256. Proper valid/ready handshake (no force).
- Existing G/H/J TBs (xsim + Verilator) tie off mb_* ports; both frameworks
  regress clean (Verilator 25/25, XSIM G/H/J + keccak + 7-vec + multiblock).
- test_framework/modules/mlkem_keygen/golden: full 256-coeff per-stage
  intermediates (rho/sigma, A_hat, s/e, s_hat/e_hat, t_hat, ek, dk_pke) for
  KAT count=0..4, dumped by ml-kem-r and self-verified against NIST KAT.
2026-06-27 23:37:23 +08:00
4997657d7e test(comp_decomp): add ML-KEM-1024 d=11/d=5 compress/decompress cases
Adds 4 Verilator cases covering d_u=11 and d_v=5 (ML-KEM-1024), which the
RTL already supports (d is 5-bit, products fit 24 bits). comp_decomp now
120/120 vectors. Also ignore .omo/ session runtime cache and archive the
06-27-sha3-g-test-specific-input trellis task.

Verified all 10 modules pass both frameworks:
- Verilator: 4334/4334 vectors
- XSIM (Vivado 2019.2): all 11 testbenches green, separate committed vectors
Oracles independently cross-checked vs hashlib (G/H/J/PRF) and FIPS 203
Alg 7/8/9/10/12 (sample_ntt, sample_cbd, ntt, poly_mul).
2026-06-27 21:04:57 +08:00
4d7ce69405 fix(sample_ntt,sha3): FIPS-203 SHAKE-128 squeeze + self-checking sha3 TBs
sample_ntt was non-conformant: both RTL and the test reference re-ran
keccak_p after every 3-byte squeeze instead of consuming the full
1344-bit SHAKE-128 rate. Only coeff[0] matched a standard sampler, so
the generated A matrix would not interoperate with any compliant ML-KEM.

- sample_ntt_sync{,_shared}.v: walk all 56 groups of the rate block via
  grp_ptr_r; re-permute only when the block is exhausted. Verified
  256/256 against ml-kem-r Rust sample_ntt on two seeds, and 1536/1536
  in the Verilator framework (runtime ~128x faster per poly).
- gen_vectors.py: use a self-contained hashlib.shake_128 oracle.

sha3 testbench fixes (all now self-check hash_o against verified vectors,
cross-checked with hashlib and ml-kem-r mlkem_G):
- tb_sha3_xsim_simple.v: test G/H/J modes, not just G.
- tb_keccak_core_xsim.v: correct the wrong EXPECTED_STATE constant
  (RTL was correct; lane0 = 0xf1258f7940e1dde7 per FIPS 202).
- tb_sha3_xsim.v: read expected file and self-check per vector; add
  vectors/g_basic_{input,expected}.hex (3 G / 2 H / 2 J).

Remove stale sha3_chain test (its RTL was deleted in 1cace51) and its
README references. Extend .gitignore for XSIM artifacts and result dumps.
2026-06-27 17:23:28 +08:00
195 changed files with 76250 additions and 636 deletions

23
.gitignore vendored
View File

@@ -10,6 +10,29 @@ __pycache__/
test_framework/reports/report_*.html
test_framework/modules/*/vectors/*.hex
# XSIM testbench result dumps (regenerated by simulation)
sync_rtl/**/TB/vectors/*_result.hex
# Vivado XSIM simulation artifacts
xsim.dir/
*.jou
*.log
*.pb
*.wdb
*.backup.jou
*.backup.log
.Xil/
webtalk*.jou
webtalk*.log
xelab.pb
xvlog.pb
# OS
.DS_Store
Thumbs.db
# Session runtime continuation cache
.omo/
# Generated Vivado project (create_project.tcl)
vivado_prj/

View File

@@ -115,6 +115,36 @@
".trellis/scripts/hooks/linear_sync.py": "e09cc4ce4699aada908808718698f33f705a3edf55c4dcf8f777ad892f80ca79",
".trellis/scripts/init_developer.py": "f9e6c0d882406e81c8cd6b1c5abb204b0befc0069ff89cf650cd536a80f8c60e",
".trellis/scripts/task.py": "40abdd46f5c2b6837610429a38eef50f1fc783fb1852dc4f52a891205e42ab04",
".trellis/workflow.md": "f4b8a6f89017f62071986d6d36cc32c4c7f01fe6f023f0fd9311eddc57d8c94f"
".trellis/workflow.md": "f4b8a6f89017f62071986d6d36cc32c4c7f01fe6f023f0fd9311eddc57d8c94f",
".trellis/.runtime/sessions/opencode_ses_0fa9bd669ffeYrt7zm7OK1GYM8.json": "0057637c43c0458e064360a5cdfb047da4a4107cf3e91bdcf9dab39f909af4b0",
".trellis/.runtime/update-check-claude_2ab4f024-6de1-48a9-a1e6-ae4f26b174a7.marker": "77c2ca150b61c7330da139378ffd3940d093f1bd74a1294689345d27e15b5124",
".trellis/.runtime/update-check-claude_4ff99829-c447-424f-a6b9-a34607b049fa.marker": "77c2ca150b61c7330da139378ffd3940d093f1bd74a1294689345d27e15b5124",
".trellis/.runtime/update-check-claude_d9118ffd-8f45-42ea-9801-d82379b3c23a.marker": "77c2ca150b61c7330da139378ffd3940d093f1bd74a1294689345d27e15b5124",
".trellis/.runtime/update-check-opencode_ses_0fa9ba12affeWK76gGIDEf0tDZ.marker": "77c2ca150b61c7330da139378ffd3940d093f1bd74a1294689345d27e15b5124",
".trellis/.runtime/update-check-opencode_ses_0fa9baae2ffeqp0asVrd8rcWFl.marker": "77c2ca150b61c7330da139378ffd3940d093f1bd74a1294689345d27e15b5124",
".trellis/.runtime/update-check-opencode_ses_0fa9bd669ffeYrt7zm7OK1GYM8.marker": "77c2ca150b61c7330da139378ffd3940d093f1bd74a1294689345d27e15b5124",
".trellis/.runtime/update-check-opencode_ses_0fff4a7a5ffeSofnz1j0YF4O56.marker": "77c2ca150b61c7330da139378ffd3940d093f1bd74a1294689345d27e15b5124",
".trellis/.runtime/update-check-opencode_ses_1005858f0ffeXfy2McZGWqgoG2.marker": "77c2ca150b61c7330da139378ffd3940d093f1bd74a1294689345d27e15b5124",
".trellis/.runtime/update-check-opencode_ses_1019cfb14ffewFpp4foONH6Wu6.marker": "77c2ca150b61c7330da139378ffd3940d093f1bd74a1294689345d27e15b5124",
".trellis/.runtime/update-check-opencode_ses_1019d29b8ffepGPHFwLKNJ0HlH.marker": "77c2ca150b61c7330da139378ffd3940d093f1bd74a1294689345d27e15b5124",
".trellis/scripts/common/__pycache__/__init__.cpython-313.pyc": "c507bcf29f62120973aca3d193c223167ec29838a39b00c56748dfc3f431c6c7",
".trellis/scripts/common/__pycache__/active_task.cpython-313.pyc": "3c357180210e0e2f2041ca45b56614e161959ab4809d72ebee33f43b9ac2aad8",
".trellis/scripts/common/__pycache__/config.cpython-313.pyc": "12eaa5b7207125527c503acbd5620afede4a80e1ac1a7eee2091a928db8270b3",
".trellis/scripts/common/__pycache__/developer.cpython-313.pyc": "0ef11d0d4912e31bf444d43584186ae22e5c94a915b6bb73bb1c5a6565c2f906",
".trellis/scripts/common/__pycache__/git.cpython-313.pyc": "df26e82d048e295eee4c1cbfa4bb2e7f109bd44bb5aba37ef8a2d40174609bd8",
".trellis/scripts/common/__pycache__/git_context.cpython-313.pyc": "ef792d63110597d6c1f0eabce437a4c5eecaf86d7582255c95f5d7c83a9a89a4",
".trellis/scripts/common/__pycache__/io.cpython-313.pyc": "8d20ac0339b6b0e6a4457502844d13d8b050250ff7021e55fcd8bff61d987434",
".trellis/scripts/common/__pycache__/log.cpython-313.pyc": "67224fab1a76d37d942f019b3d2a875c6497bb1d582f9dcc478e49c0c69d216a",
".trellis/scripts/common/__pycache__/packages_context.cpython-313.pyc": "4ee8a87d8112d233d8310b1364223ec13835e378d2aa62fe84139d089e28b5f6",
".trellis/scripts/common/__pycache__/paths.cpython-313.pyc": "a01b7eaf9ee4a61e42a4157da475e28655dec54ac2804895e052308dc91e8bca",
".trellis/scripts/common/__pycache__/safe_commit.cpython-313.pyc": "b42206d0d64a1ea72548e88d9730f186334566af1e1bff58d095845db37db407",
".trellis/scripts/common/__pycache__/session_context.cpython-313.pyc": "66dc9d914a744bb697f41f9187df38e8a00d39f93b2f73fc20cb3d3b112c2275",
".trellis/scripts/common/__pycache__/task_context.cpython-313.pyc": "7de2ac31464c7502db0a147e9d5758906a9ba7e4ae54e5e9e289e95730956d33",
".trellis/scripts/common/__pycache__/task_store.cpython-313.pyc": "29ae8e0e8b13f55b84a6271df2752b439bf4df7e6edba1f4ab77f69df04caa4c",
".trellis/scripts/common/__pycache__/task_utils.cpython-313.pyc": "122c0d3bb365524ed6523f5e5ca5168b0e119a28000a9bf16a7a2d4ad3d5b7c3",
".trellis/scripts/common/__pycache__/tasks.cpython-313.pyc": "b9db435c1953f006a6065881b8c1e1c350e010253930de0df4eea4f3062e51ed",
".trellis/scripts/common/__pycache__/trellis_config.cpython-313.pyc": "fede1256e0abfe954c965e605b6bd6eb6cf9f062c47e9215e82879a5c0fa6f3c",
".trellis/scripts/common/__pycache__/types.cpython-313.pyc": "9c3ac38bf04b034a8a6fb5c3dbd37918bac6bce28123c760d06c80a9b8502b75",
".trellis/scripts/common/__pycache__/workflow_phase.cpython-313.pyc": "eed71dc42941cbccbf2d4c38673c9ec465286a03163bcebc39e1c4ca0bbb3dab"
}
}

View File

@@ -0,0 +1 @@
{"file": ".trellis/spec/rtl/xsim-tb-conventions.md", "reason": "检查 testbench 修改是否符合 XSIM 规范"}

View File

@@ -0,0 +1 @@
{"file": ".trellis/spec/rtl/xsim-tb-conventions.md", "reason": "遵循 XSIM testbench 编写规范时钟、复位、DUT驱动协议"}

View File

@@ -0,0 +1,30 @@
# 修改 sha3 TB 测试 G 模式指定输入
## 需求
修改 `sync_rtl/sha3/TB/tb_sha3_xsim_simple.v`,将其中硬编码的测试向量替换为指定的 d、k 值,测试 sha3_top 的 G (SHA3-512) 模式。
## 测试输入
```
d = 0x6dbbc4375136df3b07f7c70e639e223e177e7fd53b161b3f4d57791794f12624 (256-bit)
k = 2 (8-bit)
mode = G (2'b00)
```
在 RTL 中G 模式的输入格式为 `data_i[263:0] = {d[255:0], k[7:0]}`d 在低位k 在高位),即:
```
data_i = {248'd0, 8'd2, 256'h6dbbc4375136df3b07f7c70e639e223e177e7fd53b161b3f4d57791794f12624}
```
## 修改方案
修改 `tb_sha3_xsim_simple.v`
1.`data_i = 512'd0` 替换为指定值 `{248'd0, 8'd2, 256'h6dbbc4375136df3b07f7c70e639e223e177e7fd53b161b3f4d57791794f12624}`
2. 删除 `G_EXPECTED_HASH` 参数和自检比较逻辑,改为仅打印 `hash_o` 结果
3. 更新顶部的注释说明
## 预期输出
运行后打印 `hash_o` 的值,可通过 Python 参考实现 `SHA_3.G(d, k)` 交叉验证。

View File

@@ -0,0 +1,26 @@
{
"id": "sha3-g-test-specific-input",
"name": "sha3-g-test-specific-input",
"title": "修改sha3 TB测试G模式指定输入d=k=2",
"description": "",
"status": "in_progress",
"dev_type": null,
"scope": null,
"package": null,
"priority": "P2",
"creator": "FallenSigh",
"assignee": "FallenSigh",
"createdAt": "2026-06-27",
"completedAt": null,
"branch": null,
"base_branch": "main",
"worktree_path": null,
"commit": null,
"pr_url": null,
"subtasks": [],
"children": [],
"parent": null,
"relatedFiles": [],
"notes": "",
"meta": {}
}

466
README.md
View File

@@ -1,299 +1,245 @@
# ML-KEM Hardware Implementation (FIPS 203)
# ML-KEM 硬件实现(FIPS 203
A synchronous, pipelined hardware implementation of **ML-KEM** (Module-Lattice-based Key Encapsulation Mechanism), the NIST PQC standard based on Kyber. Written in SystemVerilog, targeting FPGA simulation with Vivado XSIM and verified with Verilator.
基于 SystemVerilog 的 **ML-KEM**Module-Lattice-based Key Encapsulation MechanismNIST 后量子密码标准,源自 Kyber同步流水线硬件实现。面向 FPGA使用 Vivado XSIM 与 Verilator 进行仿真验证。
## Overview
本文档重点介绍顶层密钥生成模块 **`mlkem_top`** 的工作流程及其测试流程。各底层算子SHA-3、NTT、CBD 采样等)已独立验证,本文不再展开。
ML-KEM is a post-quantum key encapsulation mechanism (KEM) standardized by NIST in FIPS 203. It provides IND-CCA2 security based on the hardness of the Module Learning With Errors (MLWE) problem over the polynomial ring Z_q[x]/(x^256 + 1).
## 概述
This implementation decomposes ML-KEM's core operations into independent, synchronous hardware modules with standardized valid/ready streaming interfaces. All modules operate at **100 MHz** (10ns period) and use active-low reset.
ML-KEM 是 NIST 在 FIPS 203 中标准化的后量子密钥封装机制,其安全性基于多项式环 Z_q[x]/(x²⁵⁶+1) 上的 Module-LWE 难题。
### Parameters
`mlkem_top` 实现 **FIPS 203 算法 16KeyGen_internal** 的完整密钥生成数据通路:给定种子 `d``z`,输出封装密钥 `ek`(公钥)和解封装密钥 `dk`(私钥)。模块运行于 **100 MHz**10 ns 周期),低电平复位。
| Parameter | Value | Description |
|-----------|-------|-------------|
| **q** | 3329 | Prime modulus |
| **n** | 256 | Polynomial degree |
| **k** | 2 | Module rank (ML-KEM-512) |
| η₁ | 3 | CBD parameter (secret key) |
| η₂ | 2 | CBD parameter (ciphertext) |
| d_u | 10 | Compress bits |
| d_v | 4 | Compress bits |
### 运行时参数选择
## Repository Structure
**ML-KEM 的安全等级 K 在运行时通过输入端口 `k_i` 选择**而非编译期参数。存储按最坏情况ML-KEM-1024KMAX=4静态分配`k_i``start_i` 时被采样到内部寄存器 `k_r`,据此选取激活的子区间。
| k_i | 方案 | 模块秩 K | η₁ | ek 字节数 | dk 字节数 | KeyGen 周期数 |
|:---:|:---|:---:|:---:|:---:|:---:|:---:|
| 2 | ML-KEM-512 | 2 | 3 | 800 | 1632 | 21 403 |
| 3 | ML-KEM-768 | 3 | 2 | 1184 | 2400 | 36 207 |
| 4 | ML-KEM-1024 | 4 | 2 | 1568 | 3168 | 54 005 |
> 注:`k_i` 仅在 `start_i` 时采样,且假定取值 ∈ {2,3,4}越界值0/1/57当前不做保护会产生错误的尺寸计算。
固定参数:**q = 3329**(素数模)、**n = 256**多项式次数。du/dv 仅用于封装/解封装KeyGen 不涉及。
## `mlkem_top` 接口
```
mlkem/
├── sync_rtl/ # RTL source (SystemVerilog)
├── common/ # Shared infrastructure
│ ├── pipeline_reg.v # Single-stage valid/ready pipeline register
│ ├── skid_buffer.v # 2-entry skid buffer for backpressure
│ └── defines.vh # Global parameters (Q, N, CLK_PERIOD)
├── sha3/ # Keccak-f[1600] and SHA-3/SHAKE modes
├── keccak_round.v # Single Keccak-f round (θ,ρ,π,χ,ι)
│ ├── keccak_core.v # 24-round sequential Keccak-f[1600] core
│ └── sha3_top.v # SHA3-512(G)/SHA3-256(H)/SHAKE-256(J) wrapper
├── sha3_chain/ # G function for key generation
│ └── sha3_chain_top.v # SHA3-512 chain: G(d||k=2) → rho, sigma
│ ├── rng/ # Pseudorandom number generator
│ │ └── rng_sync.v # 256-bit Galois LFSR (taps: 255,253,252,247,0)
│ ├── ntt/ # Number Theoretic Transform
│ │ ├── zeta_rom.v # Twiddle factor ROM (128 × 12-bit, ζ^br(i))
│ │ ├── barrett_mul.v # Barrett modular multiplier (a·b mod q)
│ │ ├── butterfly_unit.v # CT/GS butterfly (NTT/INTT)
│ │ └── ntt_core.v # NTT core: LOAD→COMPUTE→OUTPUT FSM
│ ├── poly_arith/ # Polynomial arithmetic
│ │ └── poly_arith_sync.v # Element-wise poly add/sub (PolyAdd/PolySub)
│ ├── poly_mul/ # Polynomial multiplication
│ │ ├── poly_mul_zeta_rom.v # Zeta ROM for degree-1 basecase multiply
│ │ ├── basecase_mul.v # Degree-1 Karatsuba basecase multiplier
│ │ └── poly_mul_sync.v # Full NTT-domain polynomial multiplier
│ ├── sample_cbd/ # Centered Binomial Distribution sampling
│ │ └── sample_cbd_sync.v # CBDη via SHAKE-256 PRF(seed, nonce)
│ ├── sample_ntt/ # NTT-domain sampling (A matrix)
│ │ └── sample_ntt_sync.v # SampleNTT via SHAKE-128 rejection sampling
│ ├── comp_decomp/ # Coefficient compression
│ │ └── comp_decomp_sync.v # Compress_q / Decompress_q
│ ├── mod_add/ # Modular arithmetic
│ │ └── mod_add_sync.v # (a + b) mod q, streaming
│ └── storage/ # On-chip storage
│ ├── s_bram.v # Single-port behavioral BRAM
│ └── sd_bram.v # Simple dual-port behavioral BRAM
├── test_framework/ # Verilator C++ test framework
│ ├── run_all.py # CLI entry point
│ ├── config.json # Verilator path, clock period, timeouts
│ ├── lib/ # Core framework libraries
│ │ ├── test_runner.py # Discovery, compile, run, compare pipeline
│ │ ├── sim_controller.py # Verilator compile/run wrapper
│ │ ├── vector_gen.py # Base class for vector generators
│ │ ├── result_checker.py # Hex-file comparison
│ │ └── reporter.py # Terminal + HTML output
│ └── modules/ # Per-module test definitions
│ ├── <module>/test_plan.json # Test configuration
│ └── <module>/gen_vectors.py # Python reference + vector generator
├── run_tb.sh # Vivado XSIM testbench runner
├── .trellis/ # Trellis workflow system
│ ├── workflow.md # Development phases
│ ├── spec/ # Coding specs (RTL, testbench conventions)
│ └── tasks/ # Active and archived tasks
└── .opencode/ # OpenCode agent configuration
module mlkem_top #(parameter KMAX = 4) (
input clk, rst_n,
input [2:0] k_i, // 运行时方案选择2/3/4
input [255:0] d_i, // KeyGen 种子 dbyte0 在 d_i[7:0]
input [255:0] z_i, // 隐式拒绝种子 z
input start_i, // 启动脉冲
output busy_o, // 运行中拉高
output done_o, // ek/dk 就绪时拉高
// 调试回读端口(供 TB 逐字节核对,无需宽总线)
input [3:0] dbg_slot_i, input [7:0] dbg_idx_i, output [11:0] dbg_coeff_o,
input dbg_byte_sel_i, input [10:0] dbg_byte_idx_i, output [7:0] dbg_byte_o,
input [11:0] dbg_dk_idx_i, output [7:0] dbg_dk_o,
output [255:0] dbg_rho_o, dbg_sigma_o
);
```
## Module Architecture
`busy_o`/`done_o` 提供握手;`dbg_*` 端口为只读调试抽头,让 TB 可以逐系数 / 逐字节读出中间结果与最终的 ek/dk而无需引出整条数据总线。
### Core Operations
## 工作流程
`mlkem_top` 复用了已独立验证的叶子模块(每个模块自带 keccak_core无共享仲裁器`sha3_top``sample_ntt_sync``sample_cbd_sync``ntt_core``poly_mul_sync`。顶层是一个 8 状态 FSM串行驱动这些算子并把所有中间多项式存放在统一的系数寄存器阵列 `polymem` 中。
### KeyGen 算法FIPS 203 算法 16
```
┌──────────┐
seed │ sample_ │ coeffs (256 × 12-bit)
nonce ─┤ cbd_sync ├─────────────────────┐
└──────────┘
┌──────────┐ ┌─────────────┐
rho │ sample_ │ coeffs │ poly_arith │
k,i,j─┤ ntt_sync ├─────────────┤ poly_mul │──► result
└──────────┘ │ comp_decomp │
└─────────────┘
┌──────────┐ ▲
d_in │ sha3_ │ rho, sigma │
│ chain_top├────────────────────┘
└──────────┘
(ρ, σ) = G(d ‖ K) // SHA3-512
Â[i][j] = SampleNTT(ρ ‖ j ‖ i) i,j ∈ 0..K-1 // SHAKE-128 拒绝采样
s[i] = CBD_η1(PRF(σ, i)) i ∈ 0..K-1 // SHAKE-256
e[i] = CBD_η1(PRF(σ, K+i)) i ∈ 0..K-1
ŝ[i] = NTT(s[i]), ê[i] = NTT(e[i])
t̂[i] = ê[i] + Σⱼ Â[i][j] ∘ ŝ[j] // NTT 域逐点乘 + 累加
ek = byteEncode₁₂(t̂[0..K-1]) ‖ ρ
dk = byteEncode₁₂(ŝ[0..K-1]) ‖ ek ‖ H(ek) ‖ z
```
### Interface Protocol
All modules use a uniform **valid/ready** streaming interface:
### FSM 状态机
```
clk ──╮ ╰──╮ ╰──╮ ╰──╮ ╰──
valid_i ──╯ ╰─────╯ ╰─────
ready_o ──────╮ ╰─────────
data_i ──[A]─────[B]─────────[C]──
valid_o ─────────╮ ╰───────
ready_i ─────────────╮ ╰─────────
data_o ─────────[A']───────[B']──
start_i
ST_IDLE ─────────────────► ST_G
│ G(d‖K),捕获 ρ/σ
│ ▼
ST_A 生成 Â[i][j]K² 个多项式SampleNTT
│ │
│ ▼
│ ST_C 采样 s[i], e[i]2K 个多项式CBD
│ │
│ ▼
│ ST_N 原地前向 NTTŝ[i], ê[i]2K 次)
│ │
│ ▼
│ ST_M t̂[i] = ê[i] + Σⱼ Â[i][j]∘ŝ[j]
│ │
│ ▼
│ ST_E byteEncode₁₂ → ek_mem / dkp_memek 尾接 ρ
│ │
│ ▼
│ ST_H H(ek):多块 SHA3-256
│ done_o │
└────────── ST_DONE ◄───────┘
```
- **Input**: Assert `valid_i` when `ready_o` is high; data transferred on posedge when both are high.
- **Output**: Module asserts `valid_o` when result is ready; downstream asserts `ready_i` to consume.
- **Pipeline**: Modules use `pipeline_reg` internally for 1-cycle latency.
| 状态 | 名称 | 动作 | 使用的算子 |
|:---:|:---|:---|:---|
| ST_G | 哈希 G | `(ρ,σ)=G(d‖K)``data_i={K_byte, d}` | `sha3_top`SHA3-512 |
| ST_A | 矩阵采样 | 逐个生成 Â[i][j],行主序写入 slot `i*K+j`,每个 256 系数 | `sample_ntt_sync` |
| ST_C | CBD 采样 | s[0..K-1]nonce 0..K-1、e[0..K-1]nonce K..2K-1有符号→模 q | `sample_cbd_sync` |
| ST_N | 前向 NTT | 对 ŝ、ê 共 2K 个多项式逐个原地变换 | `ntt_core`mode=0 |
| ST_M | 矩阵乘累加 | 对每个 (i,j):流入 256 对 (Â,ŝ) 做逐点乘,累加进 t̂[i]j=0 时以 ê[i] 初始化) | `poly_mul_sync` |
| ST_E | 字节编码 | byteEncode₁₂t̂→ek_memŝ→dkp_mem末尾拷入 ρ 的 32 字节 | — |
| ST_H | 哈希 H | 对 ek 做多块 SHA3-256得到 H(ek)调用方预填充末块0x06…0x80 | `sha3_top`(多块模式) |
Modules with multi-cycle operations (NTT, sampling) additionally use a `done_o` signal or `last_o` flag.
各状态之间以 valid/ready 握手串接FSM 拉高对应算子的 `valid_i`,在 `ready_o` 时认为请求被接收,再逐拍收集 `valid_o` 输出,直到 `last_o`/`done_o`
## Getting Started
### 存储布局
### Prerequisites
所有多项式存于 `polymem``NUM_SLOTS×256` 个 12-bit 系数,`NUM_SLOTS = KMAX²+3·KMAX = 28`)。每个 slot 256 系数,槽基址在运行时由 `k_r` 推导:
- **Vivado 2019.2+** (for XSIM simulation): `/opt/Xilinx/Vivado/2019.2/`
- **Verilator 5.046** (for C++ testbench): available via `dnf` on Fedora
- **Python 3.10+** (for vector generation): stdlib only
```
slot 0 .. K²-1 : Â[i][j] (下标 i*K + j
slot_s_rt = K² : ŝ[i] ST_N 原地覆盖 s[i]
slot_e_rt = K² + K : ê[i]
slot_t_rt = K² + 2K : t̂[i]
```
### Setup
字节输出存于 `ek_mem`KMAX 最大 1568B`dkp_mem`(最大 1536B。byteEncode₁₂ 规则:每 2 个系数打包成 3 字节LSB 优先 12-bit
```
b0 = c0[7:0]
b1 = {c1[3:0], c0[11:8]}
b2 = c1[11:4]
```
完整私钥 dk 的字节布局(与 NIST KAT 的 sk 对齐):
```
dk = dk_pke(384·K) ‖ ek(384·K+32) ‖ H(ek)(32) ‖ z(32)
```
H(ek) 阶段采用预填充多块吸收:调用方逐块组装 136 字节速率块,在 `ek_bytes` 位置填 `0x06`、末块最后字节或上 `0x80`;分块数 `h_nblk_rt` 为 6/9/12对应 K=2/3/4
## 测试流程
`mlkem_top` 的验证策略是:**对全部三种安全等级,把硬件产出的 `ek`/`dk` 与 NIST KAT 标准答案逐字节比对**。验证素材、参数化 TB、运行脚本三者配合完成。
### 1. 黄金向量NIST KAT
测试向量来自 NIST FIPS 203 的 KAT 响应文件,经 `sync_rtl/top/TB/gen_vectors.py` 解析后生成每个用例的独立 hex 文件,存于 `sync_rtl/top/TB/vectors/`
| 文件 | 内容 | 字节长度(按 K |
|:---|:---|:---|
| `kat_k<K>_c<n>_d.hex` | KeyGen 种子 d | 32 |
| `kat_k<K>_c<n>_z.hex` | 隐式拒绝种子 z | 32 |
| `kat_k<K>_c<n>_ek.hex` | 期望公钥 pk== ek | 384·K+32 |
| `kat_k<K>_c<n>_dk.hex` | 期望私钥 sk== dk | 768·K+96 |
其中 `K ∈ {2,3,4}``n` 为用例号。当前覆盖:**K=2 共 5 个用例c0c4K=3 / K=4 各 3 个用例c0c2**,合计 11 个用例。
向量采用 “byte0 在低位” 约定256-bit 值满足 `bit[8m+:8] = byte m`
### 2. 参数化测试平台
`sync_rtl/top/TB/tb_mlkem_kg_katK_xsim.v` 是参数化自检 TB
- 通过 `parameter KP`(由 `xelab -generic_top KP=2|3|4` 设定)选择安全等级;
- 通过 `+CASE=n` plusarg 选择用例号,据此加载对应的 `kat_k<KP>_c<n>_*.hex`
- **将 `KP` 驱动到 DUT 的运行时输入 `k_i`**不再用参数覆盖KMAX 取默认 4
- 复位 → 加载 d/z 与 k_i → 拉 `start_i` 一拍 → 轮询 `done_o`(超时上限 200 万周期);
- 完成后通过 `dbg_byte_o`(读 ek0..EKB-1`dbg_dk_o`(读完整 dk0..DKB-1逐字节回读与黄金向量比对
- 全部相符打印 `K=<K> CASE <n> PASS`,否则打印前 8 个不匹配字节并报 `FAIL`
### 3. 运行测试
测试经由统一脚本 `run_tb.sh` 分发(自动 source Vivado 环境并设置 `LD_PRELOAD`
```bash
# Clone repository
git clone <repo-url> mlkem
cd mlkem
./run_tb.sh top
```
# Source Vivado (for XSIM)
该命令执行 `sync_rtl/top/TB/xsim_run.tcl`,其流程为:
1. **编译**`xvlog`):全部叶子算子 RTL + `mlkem_top.v` + 参数化 TB
2. **细化**`xelab`):为每种 K 生成一个快照 —— `KP=2→mlkem_kg_k2``KP=3→mlkem_kg_k3``KP=4→mlkem_kg_k4`
3. **仿真**`xsim -R -testplusarg CASE=n`):依次跑完每种 K 的全部用例。
整体测试矩阵:
```
K=2 (ML-KEM-512) : CASE 0,1,2,3,4 → ek 800B, dk 1632B
K=3 (ML-KEM-768) : CASE 0,1,2 → ek 1184B, dk 2400B
K=4 (ML-KEM-1024): CASE 0,1,2 → ek 1568B, dk 3168B
```
### 4. 预期结果
11 个用例全部 PASS每个用例确认 `ek == pk``dk == sk` 逐字节相等:
```
=== ML-KEM K=2 KAT case 0: KeyGen done in 21403 cyc ===
K=2 CASE 0 PASS: ek (800B)==pk, dk (1632B)==sk
...
K=4 CASE 2 PASS: ek (1568B)==pk, dk (3168B)==sk
```
### 验证注意事项
- **干净重跑**:每轮仿真前清理 `xsim.dir``.Xil`,避免旧快照污染(`rm -rf xsim.dir .Xil`)。
- **`$readmemh` 缺文件只是 WARNING**:文件名拼错时数据读为 X不会报错极易造成假 PASS。务必确认日志中无 `cannot be opened` 警告。
- **以日志文件为准**:将每个 `xsim` 调用重定向到独立日志后再 grep `PASS|FAIL|cannot be opened`,不要只看终端滚屏的模糊输出。
## 手动 XSIM 命令
```bash
source /opt/Xilinx/Vivado/2019.2/settings64.sh
export LD_PRELOAD=/usr/lib64/libtinfo.so.5 # ncurses fix for 2019.2 on modern Linux
export LD_PRELOAD=/usr/lib64/libtinfo.so.5 # Vivado 2019.2 的 ncurses 兼容修复
rm -rf xsim.dir .Xil
# 1) 编译(叶子算子 + 顶层 + TB
xvlog -sv --relax -i . \
sync_rtl/sha3/keccak_round.v sync_rtl/sha3/keccak_core.v sync_rtl/sha3/sha3_top.v \
sync_rtl/sample_ntt/sample_ntt_sync.v sync_rtl/sample_cbd/sample_cbd_sync.v \
sync_rtl/ntt/barrett_mul.v sync_rtl/ntt/zeta_rom.v sync_rtl/ntt/butterfly_unit.v sync_rtl/ntt/ntt_core.v \
sync_rtl/poly_mul/basecase_mul.v sync_rtl/poly_mul/poly_mul_zeta_rom.v sync_rtl/poly_mul/poly_mul_sync.v \
sync_rtl/top/mlkem_top.v \
sync_rtl/top/TB/tb_mlkem_kg_katK_xsim.v
# 2) 细化某一种 K
xelab tb_mlkem_kg_katK_xsim -generic_top KP=4 -s mlkem_kg_k4 --timescale 1ns/1ps
# 3) 跑某个用例
xsim mlkem_kg_k4 -R -testplusarg CASE=0
```
### Running Tests
## 先决条件
#### Vivado XSIM (Verilog Testbench)
- **Vivado 2019.2+**XSIM 仿真):`/opt/Xilinx/Vivado/2019.2/`
- **Verilator 5.046**(底层算子 C++ 验证)
- **Python 3.10+**(向量生成,仅用标准库)
## Vivado 2019.2 兼容性说明
在 Fedora 44 上经实测的必要 workaround
```bash
# List available modules
./run_tb.sh --list
# Run a specific module
./run_tb.sh mod_add
./run_tb.sh ntt
./run_tb.sh sample_cbd
# Run all modules
for m in mod_add rng poly_arith comp_decomp storage \
sha3_chain ntt poly_mul sample_cbd sample_ntt; do
./run_tb.sh "$m"
done
export LD_PRELOAD=/usr/lib64/libtinfo.so.5 # 必需ncurses 兼容库
xvlog -sv --relax -i . <file>.v # 用 -i非 -include_dirs指定包含目录--relax 放宽严格 SV 检查
xelab <top> -s <snap> --timescale 1ns/1ps # xelab 需显式 --timescale
```
Each module's testbench is in `sync_rtl/<module>/TB/`:
- `tb_<module>_xsim.v` — Verilog testbench (file-based vectors via `$readmemh`)
- `gen_vectors.py` — Python vector generator
- `vectors/<module>_input.hex` — Test input vectors
- `xsim_run.tcl` — Vivado compile/elaborate/simulate script
## 参考
#### Verilator (C++ Testbench)
- [FIPS 203: ML-KEM](https://csrc.nist.gov/pubs/fips/203/final) —— NIST 标准(算法 16 KeyGen_internal
- [FIPS 202: SHA-3 / SHAKE](https://csrc.nist.gov/pubs/fips/202/final) —— Keccak 哈希族
- [CRYSTALS-Kyber](https://pq-crystals.org/kyber/) —— 原始提案
```bash
cd test_framework
python3 run_all.py --list # List modules
python3 run_all.py --module ntt # Test a single module
python3 run_all.py --quick # Smoke test all modules
```
### Manual XSIM Commands
```bash
# Compile
xvlog -sv -i . sync_rtl/common/pipeline_reg.v sync_rtl/mod_add/mod_add_sync.v
xvlog -sv sync_rtl/mod_add/TB/tb_mod_add_xsim.v
# Elaborate
xelab tb_mod_add_xsim -s sim --timescale 1ns/1ps
# Simulate
xsim sim -R
```
## Design Decisions
### Synchronous Valid/Ready Streaming
All modules use a synchronous valid/ready handshake rather than fixed-latency interfaces. This allows:
- Natural backpressure propagation
- Easy composition of modules in pipelines
- Deterministic timing closure at 100MHz
### Barrett Modular Reduction
All modular multiplications use Barrett reduction (no DSP blocks, no division units):
- Precompute μ = ⌊2^k / q⌋ (k = 24 for q=3329)
- Compute a·b ≈ (a·b·μ) >> k, then correct with conditional subtraction
- Fully combinational, no pipeline stalls
### Cooley-Tukey / Gentleman-Sande NTT
The NTT core implements both forward (Cooley-Tukey) and inverse (Gentleman-Sande) transforms using a radix-2 decimation-in-time architecture:
- 7 butterfly stages (256 = 2^7 coefficients)
- Bit-reversed input/output ordering
- On-chip coefficient register file (256 × 12-bit)
- 24-cycle pipeline for Keccak permutations (shared with SHA-3 modules)
### Keccak-f[1600] Core
A single Keccak-f[1600] permutation engine is shared across all SHA-3/SHAKE modules (`sha3_top`, `sample_cbd_sync`, `sample_ntt_sync`). The core implements:
- 24 rounds with round constants (ι step)
- Full 1600-bit state (5×5×64 lanes)
- 24-cycle latency per permutation
- Input/output via valid/ready streaming interface
## Module Reference
| Module | Ports | Latency | Description |
|--------|-------|---------|-------------|
| `pipeline_reg` | data_i/o, valid_i/o, ready_i/o | 1 cycle | Generic pipeline stage |
| `skid_buffer` | data_i/o, valid_i/o, ready_i/o | 0-1 cycles | Backpressure buffer |
| `rng_sync` | valid_i → data_o[255:0] | 1 cycle | Galois LFSR PRNG |
| `mod_add_sync` | a[11:0], b[11:0] → sum[11:0] | 1 cycle | Modular addition |
| `ntt_core` | 256×coeff_in → 256×coeff_out | ~200 cycles | NTT/INTT transform |
| `poly_arith_sync` | coeff_a/b[11:0] → coeff_out[11:0] | 1 cycle | Poly add/sub |
| `poly_mul_sync` | 512×coeff → 256×coeff | ~300 cycles | NTT-domain poly multiply |
| `comp_decomp_sync` | coeff_in[11:0], d[4:0] → coeff_out | 1 cycle | Compress/Decompress |
| `sha3_top` | data_i[511:0], mode → hash_o[511:0] | ~24 cycles | SHA3/SHAKE |
| `sha3_chain_top` | d_in[255:0], start → rho, sigma | ~24 cycles | G function |
| `sample_cbd_sync` | seed[255:0], nonce, eta → 256×coeff | ~300 cycles | CBD sampling |
| `sample_ntt_sync` | rho[255:0], k,i,j → 256×coeff | ~4000 cycles | SampleNTT |
| `s_bram` | rd/wr addr, data | 1 cycle | Single-port BRAM |
| `sd_bram` | rd addr, wr addr, data | 1 cycle | Dual-port BRAM |
## Test Coverage
| Module | Verilator (C++) | XSIM (Verilog) | Status |
|--------|:---:|:---:|:---:|
| sha3_top | ✅ | ✅ | PASS |
| keccak_core | — | ✅ | PASS |
| sha3_chain_top | ✅ | ✅ | PASS |
| rng_sync | ✅ | ✅ | PASS |
| mod_add_sync | ✅ | ✅ | PASS |
| ntt_core | ✅ | ✅ | PASS |
| poly_arith_sync | ✅ | ✅ | PASS |
| poly_mul_sync | ✅ | ✅ | PASS |
| comp_decomp_sync | ✅ | ✅ | PASS |
| sample_cbd_sync | ✅ | ✅ | PASS |
| sample_ntt_sync | ✅ | ✅ | PASS |
| s_bram / sd_bram | ✅ | ✅ | PASS |
| pipeline_reg | Through parent | — | OK |
| skid_buffer | Through parent | — | OK |
## Vivado 2019.2 Compatibility Notes
This project was tested with Vivado 2019.2 on Fedora 44. Known workarounds:
```bash
# Required: ncurses compatibility library
export LD_PRELOAD=/usr/lib64/libtinfo.so.5
# Use -i flag (not -include_dirs) for include paths
xvlog -sv -i . <file>.v
# Add --timescale to xelab
xelab <top> -s <snap> --timescale 1ns/1ps
# Add --relax for strict SystemVerilog mode
xvlog -sv --relax <file>.v
```
## TODO / Roadmap
- [ ] Top-level integration module (full KeyGen / Encaps / Decaps FSM)
- [ ] AXI-Stream bridge for FPGA integration
- [ ] Resource optimization (share Keccak instances, pipeline balancing)
- [ ] Formal verification of Barrett multiplier
- [ ] Power analysis and side-channel hardening
- [ ] XDC constraints for FPGA synthesis (timing, I/O)
## License
[Specify license]
## References
- [FIPS 203: ML-KEM](https://csrc.nist.gov/pubs/fips/203/final) — NIST standard
- [FIPS 202: SHA-3 / SHAKE](https://csrc.nist.gov/pubs/fips/202/final) — Keccak-based hash
- [CRYSTALS-Kyber](https://pq-crystals.org/kyber/) — Original submission

View File

@@ -1,101 +1,115 @@
# create_project.tcl — 自动创建 Vivado 工程,添加所有 RTL 源文件和 testbench
# create_project.tcl — 自动创建 Vivado 工程(仿真用),加载 ML-KEM KeyGen
# 顶层 mlkem_top 及其全部叶子算子与参数化 KAT testbench。
#
# 与已验证的 XSIM 流程sync_rtl/top/TB/xsim_run.tcl保持一致
# - 仅加载 mlkem_top 实际依赖的 14 个源文件
# - 顶层仿真模块 = tb_mlkem_kg_katK_xsim
# - 运行时安全等级由 generic KP2/3/4选择用例号由 +CASE 选择
#
# Usage:
# cd ~/Dev/mlkem
# vivado -mode batch -source create_project.tcl
#
# Or in Vivado Tcl Console:
# 或在 Vivado Tcl Console 中:
# source create_project.tcl
#
# 切换被仿真的配置(默认 KP=2, CASE=0编辑下方 SIM_KP / SIM_CASE 后重跑,
# 或在工程打开后执行:
# set_property generic "KP=4" [get_filesets sim_1]
# set_property -name {xsim.simulate.xsim.more_options} -value {-testplusarg CASE=2} -objects [get_filesets sim_1]
set PROJECT_NAME mlkem
set PROJECT_DIR [file normalize [file dirname [info script]]]
# Create project (simulation-only, no FPGA part needed)
# 默认仿真配置(可改)
set SIM_KP 2 ;# ML-KEM 方案2=512, 3=768, 4=1024
set SIM_CASE 0 ;# KAT 用例号K=2: 0..4, K=3/4: 0..2
# 仅仿真工程,无需指定 FPGA partXSim 用默认 part 即可)
create_project -force ${PROJECT_NAME} ${PROJECT_DIR}/vivado_prj
# Set top-level testbench
set_property top tb_mlkem_top_xsim [current_fileset -simset]
set_property target_simulator XSim [current_project]
# ── Common infrastructure ──
read_verilog -sv [glob ${PROJECT_DIR}/sync_rtl/common/*.v]
# ===================================================================
# RTL 源文件 —— 与 xsim_run.tcl 完全一致的 14 个文件
# ===================================================================
# ── 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
# ── SHA3 Chain (shared variant for top-level integration) ──
read_verilog -sv ${PROJECT_DIR}/sync_rtl/sha3_chain/sha3_chain_top_shared.v
# ── RNG ──
read_verilog -sv ${PROJECT_DIR}/sync_rtl/rng/rng_sync.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
# ── NTT ──
read_verilog -sv ${PROJECT_DIR}/sync_rtl/ntt/zeta_rom.v
read_verilog -sv ${PROJECT_DIR}/sync_rtl/ntt/barrett_mul.v
read_verilog -sv ${PROJECT_DIR}/sync_rtl/ntt/zeta_rom.v
read_verilog -sv ${PROJECT_DIR}/sync_rtl/ntt/butterfly_unit.v
read_verilog -sv ${PROJECT_DIR}/sync_rtl/ntt/ntt_core.v
# ── Polynomial Arithmetic ──
read_verilog -sv ${PROJECT_DIR}/sync_rtl/poly_arith/poly_arith_sync.v
# ── Polynomial Multiplication ──
read_verilog -sv ${PROJECT_DIR}/sync_rtl/poly_mul/poly_mul_zeta_rom.v
# ── 多项式乘法 ──
read_verilog -sv ${PROJECT_DIR}/sync_rtl/poly_mul/basecase_mul.v
read_verilog -sv ${PROJECT_DIR}/sync_rtl/poly_mul/poly_mul_zeta_rom.v
read_verilog -sv ${PROJECT_DIR}/sync_rtl/poly_mul/poly_mul_sync.v
# ── Sampling ──
read_verilog -sv ${PROJECT_DIR}/sync_rtl/sample_cbd/sample_cbd_sync_shared.v
read_verilog -sv ${PROJECT_DIR}/sync_rtl/sample_ntt/sample_ntt_sync_shared.v
# ── Compression & Modular Arithmetic ──
read_verilog -sv ${PROJECT_DIR}/sync_rtl/comp_decomp/comp_decomp_sync.v
read_verilog -sv ${PROJECT_DIR}/sync_rtl/mod_add/mod_add_sync.v
# ── Storage (BRAM) ──
read_verilog -sv ${PROJECT_DIR}/sync_rtl/storage/s_bram.v
read_verilog -sv ${PROJECT_DIR}/sync_rtl/storage/sd_bram.v
# ── Top-level Integration ──
read_verilog -sv ${PROJECT_DIR}/sync_rtl/top/keccak_arbiter.v
# ── 顶层 KeyGen 集成 ──
read_verilog -sv ${PROJECT_DIR}/sync_rtl/top/mlkem_top.v
# ── Testbench ──
read_verilog -sv ${PROJECT_DIR}/sync_rtl/top/TB/tb_mlkem_top_xsim.v
# ── 参数化 KAT testbench ──
read_verilog -sv ${PROJECT_DIR}/sync_rtl/top/TB/tb_mlkem_kg_katK_xsim.v
# ── Independent KG / EN / DE testbenches ──
read_verilog -sv ${PROJECT_DIR}/sync_rtl/kg/TB/tb_kg_xsim.v
read_verilog -sv ${PROJECT_DIR}/sync_rtl/en/TB/tb_en_xsim.v
read_verilog -sv ${PROJECT_DIR}/sync_rtl/de/TB/tb_de_xsim.v
# ===================================================================
# 仿真设置
# ===================================================================
# ── Include path for `include directives ──
set_property include_dirs ${PROJECT_DIR} [current_fileset -simset]
# 顶层仿真模块
set_property top tb_mlkem_kg_katK_xsim [get_filesets sim_1]
set_property top_lib xil_defaultlib [get_filesets sim_1]
# ── Simulation settings ──
# `include "sync_rtl/common/defines.vh" 的包含路径(相对工程根)
set_property include_dirs ${PROJECT_DIR} [get_filesets sim_1]
# 运行时安全等级:通过 TB 顶层 generic KP 传入2/3/4
set_property generic "KP=${SIM_KP}" [get_filesets sim_1]
# 跑到 $finish 为止显式时标XSim 默认已加 --relax勿重复
set_property -name {xsim.simulate.runtime} -value {all} -objects [get_filesets sim_1]
set_property -name {xsim.elaborate.xelab.more_options} -value {--timescale 1ns/1ps} -objects [get_filesets sim_1]
set_property -name {xsim.elaborate.xelab.more_options} \
-value {--timescale 1ns/1ps} -objects [get_filesets sim_1]
# Copy test vectors to simulation directory before run
# (Vivado GUI runs xsim in vivado_prj/mlkem.sim/sim_1/behav/xsim/)
# $readmemh looks relative to the xsim working directory
# ===================================================================
# 测试向量:Vivado GUI vivado_prj/mlkem.sim/sim_1/behav/xsim/ 下运行
# xsim而 TB 的 $readmemh 路径相对工程根sync_rtl/top/TB/vectors/…)。
# 用 compile 的 pre-hook在 xsim 工作目录、且在 compile/elaborate/simulate
# 之前执行)把整套 KAT 向量复制到同名相对路径下CASE 经 -testplusarg 选择。
#
# 注意2019.2 的 sim_1 没有 simulate.tcl.pre 属性,且追加 -tclbatch 会排在
# Vivado 自带(含 "run all")的 tclbatch 之后、即仿真跑完才执行(太迟)。
# 因此用 xsim.compile.tcl.pre —— 它最早执行且就在仿真工作目录里。
# ===================================================================
set pre_tcl [file join ${PROJECT_DIR} vivado_prj copy_vectors_pre.tcl]
set fp [open $pre_tcl w]
puts $fp "# Auto-generated: copy test vectors to xsim working directory"
puts $fp "# Auto-generated by create_project.tcl: KAT xsim "
puts $fp "file mkdir sync_rtl/top/TB/vectors"
puts $fp "file copy -force [file join ${PROJECT_DIR} sync_rtl top TB vectors mlkem_top_input.hex] sync_rtl/top/TB/vectors/"
puts $fp "file copy -force [file join ${PROJECT_DIR} sync_rtl top TB vectors mlkem_top_expected.hex] sync_rtl/top/TB/vectors/"
puts $fp "puts {Vectors copied successfully}"
puts $fp "foreach v \[glob -nocomplain [file join ${PROJECT_DIR} sync_rtl top TB vectors kat_k*_c*_*.hex]\] {"
puts $fp " file copy -force \$v sync_rtl/top/TB/vectors/"
puts $fp "}"
puts $fp "puts {\[create_project\] KAT vectors copied to xsim working dir}"
close $fp
set_property -name {xsim.compile.tcl.pre} -value $pre_tcl -objects [get_filesets sim_1]
set_property -name {xsim.simulate.xsim.more_options} \
-value "-tclbatch $pre_tcl" \
-value "-testplusarg CASE=${SIM_CASE}" \
-objects [get_filesets sim_1]
# Save project
# ===================================================================
puts "========================================"
puts " Project created: ${PROJECT_DIR}/vivado_prj/${PROJECT_NAME}.xpr"
puts " Run simulation:"
puts " launch_simulation"
puts " run all"
puts " 仿: ML-KEM K=${SIM_KP}, KAT CASE=${SIM_CASE}"
puts " 仿: launch_simulation; run all"
puts " : K=${SIM_KP} CASE ${SIM_CASE} PASS: ek==pk, dk==sk"
puts ""
puts " K=4 SIM_KP/SIM_CASE "
puts " generic relaunch_sim"
puts "========================================"

View File

@@ -208,8 +208,22 @@ module tb_sample_ntt_xsim;
// Wait for DUT to return to IDLE before next vector.
// The DUT may still be processing its last Keccak permutation
// (ST_WAIT ST_DONE ST_IDLE), which takes ~20+ cycles.
while (!ready_o) begin
@(posedge clk);
// ASSERTION: after the 256th coeff (last_o), valid_o must stay
// low until IDLE any extra pulse is a spurious 257th output
// (regression guard for the phase-1 need_more fix).
begin
integer extra_pulses;
extra_pulses = 0;
while (!ready_o) begin
@(posedge clk);
if (valid_o) extra_pulses = extra_pulses + 1;
end
if (extra_pulses != 0) begin
$display("ERROR: Vector %0d emitted %0d spurious valid_o pulse(s) after last_o",
idx, extra_pulses);
fail_count = fail_count + 1;
if (pass_count > 0) pass_count = pass_count - 1; // revoke the earlier PASS
end
end
end // inner begin block
end

View File

@@ -3,12 +3,14 @@
// Generates one k×k polynomial (256 coefficients) via SHAKE-128 XOF
// rejection sampling from seed rho || j || i.
//
// Matches Python reference (sample.py/SHA_3.py) bit-exactly:
// FIPS 202/203 conformant SHAKE-128 squeeze:
// - Absorb: S = Keccak-p(padded(rho || j || i))
// - For each squeeze: take S[23:0] (3 bytes), extract d1[11:0], d2[23:12]
// - Squeeze the full 1344-bit (168-byte) rate as 56 groups of 3 bytes,
// each group g read from S[24*g +: 24]; extract d1[11:0], d2[23:12]
// - Accept d if d < Q=3329
// - S = Keccak-p(S) (permute between every 3-byte squeeze)
// - Repeat until 256 coefficients collected
// - Only after all 56 groups of the block are consumed: S = Keccak-p(S)
// (re-permute once per rate block, NOT per 3-byte group)
// - Repeat until 256 coefficients collected (~3 blocks)
//
// Parameters:
// K = 4 (ML-KEM parameter)
@@ -52,6 +54,10 @@ module sample_ntt_sync #(parameter K = 4) (
// ================================================================
localparam Q = `Q; // 3329
// SHAKE-128 rate = 1344 bits = 168 bytes = 56 groups of 3 bytes.
// After consuming all 56 groups of a block, re-permute the state.
localparam GRP_MAX = 6'd55;
// ================================================================
// FSM state encoding
// ================================================================
@@ -84,6 +90,13 @@ module sample_ntt_sync #(parameter K = 4) (
// ================================================================
reg [1599:0] squeeze_state_r;
// ================================================================
// Group pointer: which 3-byte group within the 1344-bit rate
// block is currently being consumed (0..GRP_MAX). Re-permute when
// it would exceed GRP_MAX.
// ================================================================
reg [5:0] grp_ptr_r;
// ================================================================
// Registered d1, d2 and acceptance flags
// ================================================================
@@ -121,15 +134,21 @@ module sample_ntt_sync #(parameter K = 4) (
};
// ================================================================
// Comb: extract d1,d2 from squeeze state
// Comb: extract d1,d2 from the current 3-byte group of squeeze state
// ================================================================
// squeeze_state_r[7:0]=c0, [15:8]=c1, [23:16]=c2
// group g occupies bits [24*g +: 24]: c0=byte0, c1=byte1, c2=byte2
// d1 = {c1[3:0], c0}
// d2 = {c2, c1[7:4]}
wire [10:0] grp_bit_off;
assign grp_bit_off = grp_ptr_r * 11'd24; // 0..1320, +24 1344 (rate)
wire [23:0] grp_bits;
assign grp_bits = squeeze_state_r[ grp_bit_off +: 24 ];
wire [7:0] c0, c1, c2;
assign c0 = squeeze_state_r[7:0];
assign c1 = squeeze_state_r[15:8];
assign c2 = squeeze_state_r[23:16];
assign c0 = grp_bits[7:0];
assign c1 = grp_bits[15:8];
assign c2 = grp_bits[23:16];
wire [11:0] d1_comb, d2_comb;
assign d1_comb = {c1[3:0], c0};
@@ -161,10 +180,10 @@ module sample_ntt_sync #(parameter K = 4) (
.ready_i (1'b1)
);
// kc_valid_i: asserted during ABSORB and first phase of SQUEEZE.
// Keccak captures it on the transition (when ready_o=1).
// kc_valid_i: asserted on the ABSORB load, and for one cycle when the
// squeeze block is exhausted (SQUEEZE WAIT) to re-permute the state.
assign kc_valid_i = (state_next == ST_ABSORB) ||
(state_r == ST_SQUEEZE && sq_phase_r == 2'd0);
(state_r == ST_SQUEEZE && state_next == ST_WAIT);
// kc_state_i: absorb_state in ABSORB, squeeze_state_r otherwise
assign kc_state_i = (state_next == ST_ABSORB) ? absorb_state : squeeze_state_r;
@@ -186,6 +205,11 @@ module sample_ntt_sync #(parameter K = 4) (
assign ready_o = (state_r == ST_IDLE);
wire need_more = (coeff_cnt_r < 9'd256);
// grp_done: current 3-byte group fully consumed (phase 2 resolved):
// d2 rejected, no longer need coefficients, or d2 was just accepted out.
wire grp_done = (state_r == ST_SQUEEZE) && (sq_phase_r == 2'd2) &&
(!d2_acc_r || !need_more || (valid_o_r && ready_i));
// ================================================================
// FSM: state_next (combinational)
// ================================================================
@@ -205,11 +229,18 @@ module sample_ntt_sync #(parameter K = 4) (
end
ST_SQUEEZE: begin
// Sub-phase transitions managed in sequential logic.
// Only transitions to ST_WAIT from phase 2 when done.
if (sq_phase_r == 2'd2 &&
(!d2_acc_r || !need_more || (valid_o_r && ready_i)))
state_next = ST_WAIT;
// A group is fully consumed once phase 2 resolves (d2 output,
// rejected, or no longer needed). Then either advance to the
// next group in this block, re-permute (block exhausted), or
// finish.
if (grp_done) begin
if (!need_more)
state_next = ST_DONE;
else if (grp_ptr_r < GRP_MAX)
state_next = ST_SQUEEZE; // next group, no re-permute
else
state_next = ST_WAIT; // block exhausted: re-permute
end
end
ST_WAIT: begin
@@ -239,6 +270,7 @@ module sample_ntt_sync #(parameter K = 4) (
sq_phase_r <= 2'd0;
coeff_cnt_r <= 9'd0;
squeeze_state_r <= 1600'd0;
grp_ptr_r <= 6'd0;
d1_r <= 12'd0;
d2_r <= 12'd0;
d1_acc_r <= 1'b0;
@@ -265,10 +297,12 @@ module sample_ntt_sync #(parameter K = 4) (
end
// ---------------------------------------------------------
// Latch keccak output when valid_o fires
// Latch keccak output when valid_o fires. A fresh block
// starts at group 0 (ABSORB load or WAIT re-permute result).
// ---------------------------------------------------------
if (kc_valid_o) begin
squeeze_state_r <= kc_state_o;
grp_ptr_r <= 6'd0;
end
// ---------------------------------------------------------
@@ -300,7 +334,7 @@ module sample_ntt_sync #(parameter K = 4) (
// ----- Phase 1: output d1 -----
2'd1: begin
if (d1_acc_r) begin
if (d1_acc_r && need_more) begin
if (!valid_o_r) begin
// First cycle: assert output
coeff_o_r <= d1_r;
@@ -315,7 +349,7 @@ module sample_ntt_sync #(parameter K = 4) (
end
end
end else begin
// d1 rejected, skip to phase 2
// d1 rejected or no longer needed: skip to phase 2
valid_o_r <= 1'b0;
sq_phase_r <= 2'd2;
end
@@ -347,6 +381,13 @@ module sample_ntt_sync #(parameter K = 4) (
valid_o_r <= 1'b0;
end
endcase
// Group consumed but block not exhausted: advance to the
// next 3-byte group within the same block (no re-permute).
if (grp_done && need_more && grp_ptr_r < GRP_MAX) begin
grp_ptr_r <= grp_ptr_r + 6'd1;
sq_phase_r <= 2'd0;
end
end else if (state_r != ST_SQUEEZE && state_next == ST_SQUEEZE) begin
// About to enter SQUEEZE: reset phase and output
sq_phase_r <= 2'd0;

View File

@@ -8,12 +8,14 @@
// Generates one k×k polynomial (256 coefficients) via SHAKE-128 XOF
// rejection sampling from seed rho || j || i.
//
// Matches Python reference (sample.py/SHA_3.py) bit-exactly:
// FIPS 202/203 conformant SHAKE-128 squeeze:
// - Absorb: S = Keccak-p(padded(rho || j || i))
// - For each squeeze: take S[23:0] (3 bytes), extract d1[11:0], d2[23:12]
// - Squeeze the full 1344-bit (168-byte) rate as 56 groups of 3 bytes,
// each group g read from S[24*g +: 24]; extract d1[11:0], d2[23:12]
// - Accept d if d < Q=3329
// - S = Keccak-p(S) (permute between every 3-byte squeeze)
// - Repeat until 256 coefficients collected
// - Only after all 56 groups of the block are consumed: S = Keccak-p(S)
// (re-permute once per rate block, NOT per 3-byte group)
// - Repeat until 256 coefficients collected (~3 blocks)
//
// Parameters:
// K = 4 (ML-KEM parameter)
@@ -75,6 +77,10 @@ module sample_ntt_sync_shared #(parameter K = 4) (
// ================================================================
localparam Q = `Q; // 3329
// SHAKE-128 rate = 1344 bits = 168 bytes = 56 groups of 3 bytes.
// After consuming all 56 groups of a block, re-permute the state.
localparam GRP_MAX = 6'd55;
// ================================================================
// FSM state encoding
// ================================================================
@@ -107,6 +113,12 @@ module sample_ntt_sync_shared #(parameter K = 4) (
// ================================================================
reg [1599:0] squeeze_state_r;
// ================================================================
// Group pointer: which 3-byte group within the 1344-bit rate
// block is currently being consumed (0..GRP_MAX).
// ================================================================
reg [5:0] grp_ptr_r;
// ================================================================
// Registered d1, d2 and acceptance flags
// ================================================================
@@ -144,15 +156,21 @@ module sample_ntt_sync_shared #(parameter K = 4) (
};
// ================================================================
// Comb: extract d1,d2 from squeeze state
// Comb: extract d1,d2 from the current 3-byte group of squeeze state
// ================================================================
// squeeze_state_r[7:0]=c0, [15:8]=c1, [23:16]=c2
// group g occupies bits [24*g +: 24]: c0=byte0, c1=byte1, c2=byte2
// d1 = {c1[3:0], c0}
// d2 = {c2, c1[7:4]}
wire [10:0] grp_bit_off;
assign grp_bit_off = grp_ptr_r * 11'd24; // 0..1320, +24 1344 (rate)
wire [23:0] grp_bits;
assign grp_bits = squeeze_state_r[ grp_bit_off +: 24 ];
wire [7:0] c0, c1, c2;
assign c0 = squeeze_state_r[7:0];
assign c1 = squeeze_state_r[15:8];
assign c2 = squeeze_state_r[23:16];
assign c0 = grp_bits[7:0];
assign c1 = grp_bits[15:8];
assign c2 = grp_bits[23:16];
wire [11:0] d1_comb, d2_comb;
assign d1_comb = {c1[3:0], c0};
@@ -176,9 +194,10 @@ module sample_ntt_sync_shared #(parameter K = 4) (
// kc_ready_i: always ready to accept keccak output
assign kc_ready_i = 1'b1;
// kc_valid_i: asserted during ABSORB and first phase of SQUEEZE.
// kc_valid_i: asserted on the ABSORB load, and for one cycle when the
// squeeze block is exhausted (SQUEEZE WAIT) to re-permute the state.
assign kc_valid_i = (state_next == ST_ABSORB) ||
(state_r == ST_SQUEEZE && sq_phase_r == 2'd0);
(state_r == ST_SQUEEZE && state_next == ST_WAIT);
// kc_state_i: absorb_state in ABSORB, squeeze_state_r otherwise
assign kc_state_i = (state_next == ST_ABSORB) ? absorb_state : squeeze_state_r;
@@ -200,6 +219,11 @@ module sample_ntt_sync_shared #(parameter K = 4) (
assign ready_o = (state_r == ST_IDLE);
wire need_more = (coeff_cnt_r < 9'd256);
// grp_done: current 3-byte group fully consumed (phase 2 resolved):
// d2 rejected, no longer need coefficients, or d2 was just accepted out.
wire grp_done = (state_r == ST_SQUEEZE) && (sq_phase_r == 2'd2) &&
(!d2_acc_r || !need_more || (valid_o_r && ready_i));
// ================================================================
// FSM: state_next (combinational)
// ================================================================
@@ -219,11 +243,18 @@ module sample_ntt_sync_shared #(parameter K = 4) (
end
ST_SQUEEZE: begin
// Sub-phase transitions managed in sequential logic.
// Only transitions to ST_WAIT from phase 2 when done.
if (sq_phase_r == 2'd2 &&
(!d2_acc_r || !need_more || (valid_o_r && ready_i)))
state_next = ST_WAIT;
// A group is fully consumed once phase 2 resolves (d2 output,
// rejected, or no longer needed). Then either advance to the
// next group in this block, re-permute (block exhausted), or
// finish.
if (grp_done) begin
if (!need_more)
state_next = ST_DONE;
else if (grp_ptr_r < GRP_MAX)
state_next = ST_SQUEEZE; // next group, no re-permute
else
state_next = ST_WAIT; // block exhausted: re-permute
end
end
ST_WAIT: begin
@@ -253,6 +284,7 @@ module sample_ntt_sync_shared #(parameter K = 4) (
sq_phase_r <= 2'd0;
coeff_cnt_r <= 9'd0;
squeeze_state_r <= 1600'd0;
grp_ptr_r <= 6'd0;
d1_r <= 12'd0;
d2_r <= 12'd0;
d1_acc_r <= 1'b0;
@@ -279,10 +311,12 @@ module sample_ntt_sync_shared #(parameter K = 4) (
end
// ---------------------------------------------------------
// Latch keccak output when valid_o fires
// Latch keccak output when valid_o fires. A fresh block
// starts at group 0 (ABSORB load or WAIT re-permute result).
// ---------------------------------------------------------
if (kc_valid_o) begin
squeeze_state_r <= kc_state_o;
grp_ptr_r <= 6'd0;
end
// ---------------------------------------------------------
@@ -314,7 +348,7 @@ module sample_ntt_sync_shared #(parameter K = 4) (
// ----- Phase 1: output d1 -----
2'd1: begin
if (d1_acc_r) begin
if (d1_acc_r && need_more) begin
if (!valid_o_r) begin
// First cycle: assert output
coeff_o_r <= d1_r;
@@ -329,7 +363,7 @@ module sample_ntt_sync_shared #(parameter K = 4) (
end
end
end else begin
// d1 rejected, skip to phase 2
// d1 rejected or no longer needed: skip to phase 2
valid_o_r <= 1'b0;
sq_phase_r <= 2'd2;
end
@@ -361,6 +395,13 @@ module sample_ntt_sync_shared #(parameter K = 4) (
valid_o_r <= 1'b0;
end
endcase
// Group consumed but block not exhausted: advance to the
// next 3-byte group within the same block (no re-permute).
if (grp_done && need_more && grp_ptr_r < GRP_MAX) begin
grp_ptr_r <= grp_ptr_r + 6'd1;
sq_phase_r <= 2'd0;
end
end else if (state_r != ST_SQUEEZE && state_next == ST_SQUEEZE) begin
// About to enter SQUEEZE: reset phase and output
sq_phase_r <= 2'd0;

View File

@@ -53,9 +53,11 @@ module tb_keccak_core_xsim;
//
// Keccak-f[1600](0) after 24 rounds, flat 1600-bit output.
// Verilog packing: {lane24, lane23, ..., lane1, lane0}
// where lane[i] = A[i%5][i/5] at bits [i*64+63 : i*64]
// where lane[i] = A[i%5][i/5] at bits [i*64+63 : i*64].
// lane0 = 0xf1258f7940e1dde7 is the well-known FIPS 202 test value;
// independently recomputed and confirmed against the RTL output.
// ================================================================
parameter [1599:0] EXPECTED_STATE = 1600'hbfb7e1b9bd5d5750a1ad89d6b16dd89e76c82a7b8b784ff1a8f71cbe511a4b37593f83e2476e446a9607dab51d2284543912af66d5169a42b000c95e3f38a1d14df070f6937de8028965308c22a1d7ed39beddcf42fc7c09f566afaa29ffc221e0bedc7fe0a51684906ebd59a992e4c2e88479b3c8e88c45bfe624f5737b96a5d0656897dda87cafe0f3909e35059e7a83831c8c135d1f2ac3c03f088c216b4c4a445d8c512ddea81c7cc6d86579ec7d3ca0d28f00c7d66020fb5a92a1a94488625f47811fa2dc9d;
parameter [1599:0] EXPECTED_STATE = 1600'heaf1ff7b5ceca24975f644e97f30a13b16f53526e70465c21841f924a2c509e4940c7922ae3a26148c3ee88a1ccf32c8b87c5a554fd00ecb613670957bc4661164befef28cc970f205e5635a21d9ae6101f22f1a11a5569f43b831cd0347c82681a57c16dbcf555fa9a6e6260d712103eb5aa93f2317d63530935ab7d08ffc64ad30a6f71b19059c8c5bda0cd6192e7690fee5a0a44647c4ff97a42d7f8e6fd48b284e056253d057bd1547306f80494dd598261ea65aa9ee84d5ccf933c0478af1258f7940e1dde7;
// ================================================================
// Test sequence

View File

@@ -116,6 +116,10 @@ int main(int argc, char** argv) {
for (int w = 0; w < 16; w++) dut->data_i[w] = 0;
dut->valid_i = 0;
dut->ready_i = 0;
// multi-block absorb path disabled for single-block G/H/J tests
dut->mb_en = 0;
dut->mb_valid_i = 0;
dut->mb_last_i = 0;
// Reset: 2 full cycles
for (int i = 0; i < 2; i++) posedge(dut);

View File

@@ -0,0 +1,124 @@
// tb_sha3_mb_xsim.v - Multi-block SHA3-256 absorb self-check for sha3_top.
//
// Streams pre-padded 1088-bit rate blocks (mb_h_blocks.hex) into sha3_top
// with mb_en=1, then compares the 256-bit digest against mb_h_expected.hex
// (= hashlib.sha3_256(ek) for KAT count=0, ek = 800 bytes -> 6 blocks).
//
// Run (from project root):
// xvlog -sv sync_rtl/sha3/keccak_round.v sync_rtl/sha3/keccak_core.v \
// sync_rtl/sha3/sha3_top.v sync_rtl/sha3/TB/tb_sha3_mb_xsim.v
// xelab tb_sha3_mb_xsim -s mb_sim --timescale 1ns/1ps
// xsim mb_sim -R
`timescale 1ns/1ps
module tb_sha3_mb_xsim;
parameter BLOCK_FILE = "sync_rtl/sha3/TB/vectors/mb_h_blocks.hex";
parameter EXPECTED_FILE = "sync_rtl/sha3/TB/vectors/mb_h_expected.hex";
parameter MAX_BLOCKS = 16;
reg clk = 0;
reg rst_n = 0;
// single-block ports (unused here, tie off)
reg [1:0] mode = 2'b01;
reg [511:0] data_i = 0;
reg valid_i = 0;
wire ready_o;
wire [511:0] hash_o;
wire valid_o;
reg ready_i = 0;
// multi-block ports
reg mb_en = 1'b1;
reg [1087:0] mb_block_i = 0;
reg mb_valid_i = 0;
reg mb_last_i = 0;
wire mb_ready_o;
sha3_top dut (
.clk(clk), .rst_n(rst_n),
.mode(mode), .data_i(data_i), .valid_i(valid_i),
.ready_o(ready_o), .hash_o(hash_o), .valid_o(valid_o), .ready_i(ready_i),
.mb_en(mb_en), .mb_block_i(mb_block_i),
.mb_valid_i(mb_valid_i), .mb_last_i(mb_last_i), .mb_ready_o(mb_ready_o)
);
always #5 clk = ~clk;
reg [1087:0] blocks [0:MAX_BLOCKS-1];
reg [255:0] expected_mem [0:0];
reg [255:0] expected;
integer nblocks;
integer i;
// count valid (non-x) lines loaded
function integer count_blocks;
integer k;
begin
count_blocks = 0;
for (k = 0; k < MAX_BLOCKS; k = k + 1)
if (blocks[k] !== {1088{1'bx}}) count_blocks = k + 1;
end
endfunction
initial begin
for (i = 0; i < MAX_BLOCKS; i = i + 1) blocks[i] = {1088{1'bx}};
$readmemh(BLOCK_FILE, blocks);
$readmemh(EXPECTED_FILE, expected_mem);
expected = expected_mem[0];
nblocks = count_blocks();
$display("=== Multi-block SHA3-256 absorb TB ===");
$display("Loaded %0d blocks; expected digest = %064x", nblocks, expected);
// reset
rst_n = 0; ready_i = 0;
repeat (4) @(posedge clk);
rst_n = 1;
@(posedge clk);
// stream blocks hold valid/last stable across the accept edge
// (deassert only after mb_ready_o drops) to avoid sampling races.
for (i = 0; i < nblocks; i = i + 1) begin
mb_block_i = blocks[i];
mb_last_i = (i == nblocks - 1);
mb_valid_i = 1'b1;
// wait until module is ready, then one more edge is the accept
while (!mb_ready_o) @(posedge clk);
@(posedge clk); // accept edge (valid & ready both high)
while (mb_ready_o) @(posedge clk); // ready drops => accepted, now safe
mb_valid_i = 1'b0;
mb_last_i = 1'b0;
// wait for this block's permutation to finish (ready again or DONE)
while (!mb_ready_o && !valid_o) @(posedge clk);
$display(" after block %0d: state[255:0] = %064x", i, dut.mb_state_r[255:0]);
end
// wait for digest
i = 0;
while (!valid_o && i < 1000) begin @(posedge clk); i = i + 1; end
if (!valid_o) begin
$display("FAIL: digest never became valid (timeout)");
$finish;
end
if (hash_o[255:0] === expected) begin
$display("PASS: H(ek) = %064x", hash_o[255:0]);
$display("ALL TESTS PASSED");
end else begin
$display("FAIL: digest mismatch");
$display(" got = %064x", hash_o[255:0]);
$display(" expected = %064x", expected);
end
ready_i = 1; // ack the digest
@(posedge clk);
$finish;
end
// global safety timeout
initial begin
#100000;
$display("FAIL: global timeout");
$finish;
end
endmodule

View File

@@ -26,6 +26,7 @@ module tb_sha3_xsim;
// Parameters
// ================================================================
parameter VECTOR_FILE = "sync_rtl/sha3/TB/vectors/g_basic_input.hex";
parameter EXPECTED_FILE = "sync_rtl/sha3/TB/vectors/g_basic_expected.hex";
parameter RESULT_FILE = "sync_rtl/sha3/TB/vectors/g_basic_result.hex";
parameter MAX_VECTORS = 256;
parameter TIMEOUT_CYCLES = 1000;
@@ -55,7 +56,13 @@ module tb_sha3_xsim;
.ready_o (ready_o),
.hash_o (hash_o),
.valid_o (valid_o),
.ready_i (ready_i)
.ready_i (ready_i),
// multi-block absorb path disabled for single-block G/H/J tests
.mb_en (1'b0),
.mb_block_i (1088'b0),
.mb_valid_i (1'b0),
.mb_last_i (1'b0),
.mb_ready_o ()
);
// ================================================================
@@ -69,6 +76,7 @@ module tb_sha3_xsim;
// 520 bits per word: bits[519:512]=padding+mode, bits[511:0]=data_i
// ================================================================
reg [519:0] vector_mem [0:MAX_VECTORS-1];
reg [511:0] expected_mem [0:MAX_VECTORS-1]; // expected hash per vector
integer vec_count;
integer idx;
integer cycle_count;
@@ -100,6 +108,8 @@ module tb_sha3_xsim;
// Load vectors from hex file
$readmemh(VECTOR_FILE, vector_mem);
// Load expected hashes (one 512-bit hex per line, MSB-first)
$readmemh(EXPECTED_FILE, expected_mem);
// Count non-zero entries to determine actual vector count
// (XSim leaves unloaded entries as 520'hX)
@@ -180,9 +190,29 @@ module tb_sha3_xsim;
$display("ERROR: Timeout waiting for valid_o on vector %0d", idx);
fail_count = fail_count + 1;
end else begin
// Capture hash output
// Capture hash output and self-check against expected.
// G (mode 0) uses all 512 bits; H/J use the low 256 bits.
captured_hash = hash_o;
pass_count = pass_count + 1;
begin
reg [511:0] exp_hash;
reg match;
exp_hash = expected_mem[idx];
if (vec_mode == 2'd0)
match = (captured_hash === exp_hash);
else
match = (captured_hash[255:0] === exp_hash[255:0]);
if (match) begin
pass_count = pass_count + 1;
$display("PASS: Vector %0d (mode=%0d)", idx, vec_mode);
end else begin
fail_count = fail_count + 1;
$display("FAIL: Vector %0d (mode=%0d) hash mismatch", idx, vec_mode);
$display(" got = %0h", (vec_mode==2'd0) ? captured_hash : {256'd0, captured_hash[255:0]});
$display(" exp = %0h", (vec_mode==2'd0) ? exp_hash : {256'd0, exp_hash[255:0]});
end
end
// Write result to output file
// Format: "RESULT: MODE HASH_HEX"
@@ -216,6 +246,11 @@ module tb_sha3_xsim;
$display(" Failed: %0d", fail_count);
$display(" Results written to: %s", RESULT_FILE);
$display("========================================");
if (fail_count == 0)
$display("ALL TESTS PASSED (%0d/%0d)", pass_count, vec_count);
else
$display("TESTS FAILED: %0d of %0d", fail_count, vec_count);
$display("========================================");
$finish;
end

View File

@@ -1,12 +1,14 @@
// tb_sha3_xsim_simple.v - Simple self-checking testbench for sha3_top
// tb_sha3_xsim_simple.v - Self-checking testbench for sha3_top (G/H/J modes)
//
// Tests sha3_top in G mode (SHA3-512) with a hardcoded all-zero input.
// Verifies the output hash against an expected value.
// Uses $display for output and $error for mismatches.
// Self-checking: pass/fail determined by $error count at $finish.
// Drives sha3_top in all three modes and checks hash_o against expected
// values computed by the verified Python reference (server_code SHA_3,
// KAT-validated). Vectors are deterministic (gen_vectors seed=20260627).
//
// NOTE: This testbench uses the RTL's actual padding (suffix "10").
// The expected hash was pre-computed using the same algorithm as the RTL.
// G (mode=00, SHA3-512): data_i[263:0] = d||k, output 512 bits
// H (mode=01, SHA3-256): data_i[255:0] = ek, output low 256 bits
// J (mode=10, SHAKE-256): data_i[511:0] = z||c, output low 256 bits
//
// data_i / hash_o use MSB-first hex packing (hex[511:0] literal == data_i).
//
// Usage:
// xvlog -sv sha3_top.v tb_sha3_xsim_simple.v
@@ -42,7 +44,13 @@ module tb_sha3_xsim_simple;
.ready_o (ready_o),
.hash_o (hash_o),
.valid_o (valid_o),
.ready_i (ready_i)
.ready_i (ready_i),
// multi-block absorb path disabled for single-block G/H/J tests
.mb_en (1'b0),
.mb_block_i (1088'b0),
.mb_valid_i (1'b0),
.mb_last_i (1'b0),
.mb_ready_o ()
);
// ================================================================
@@ -52,111 +60,119 @@ module tb_sha3_xsim_simple;
always #5 clk = ~clk;
// ================================================================
// Expected hash value for G mode with all-zero input
//
// Input: data_i[263:0] = 264'd0 (all zeros)
// mode = 2'b00 (G mode, SHA3-512)
//
// RTL g_pad = {1'b1, 308'b0, 1'b1, 2'b10, data_i[263:0]}
// absorb_state = {1024'b0, g_pad}
//
// Expected hash_o = Keccak-f[1600](absorb_state) lower 512 bits
// Expected vectors (verified Python reference, seed=20260627)
// ================================================================
parameter [511:0] G_EXPECTED_HASH = 512'h93d50514dbf28b7f2b6aa4f34bc6bd53368a9a20c6568940dc8eb3ce0a8e357f8608c63ce7b579f6916c69ca3f196527ccc92b87c515edc12e159e0f3092e1d9;
// G: data_i[263:0] = {k=2, d}; output 512-bit SHA3-512
localparam [511:0] G_DATA = 512'h000000000000000000000000000000000000000000000000000000000000007DBC2AC0D13D719B37B4E2D4691951FF890A97854EF5D3A8957EF67A54978E26C9;
localparam [511:0] G_EXP = 512'h615E530C77D5D834311E922DB99D5B7F1D57C7B08F029FD829914D3F4035FB730350FD00A852A5CCE9CFC79CF8C61384FEA115030E41750A6AE2CFE055D7976D;
// H: data_i[255:0] = ek; output 256-bit SHA3-256 (in hash_o[255:0])
localparam [511:0] H_DATA = 512'h000000000000000000000000000000000000000000000000000000000000000047885BF4E257CF39645D34C593047B7570D6ABBA300599D96171A950BB5027D5;
localparam [255:0] H_EXP = 256'h6B44867E24B29A9231570DF5E1D6D14DB0C29EBD7A40AE98606EF66B8244C308;
// J: data_i[511:0] = {c, z}; output 256-bit SHAKE-256 (in hash_o[255:0])
localparam [511:0] J_DATA = 512'hB73DCA0F437D2334320494E5D0F728D73F5275E342572FF9B0219DC338CB3C2F0F7398474A3D68C4C90B777F42FA4C12B1FC8F70E1DAADF20755473CC2653D3C;
localparam [255:0] J_EXP = 256'hECEC4DAD11DFF42D911925DB83F13D119209AB4EE182E9E9BA0F29F5524B240E;
// ================================================================
// Test sequence
// ================================================================
reg [511:0] captured_hash;
integer error_count;
integer cycle_count;
parameter TIMEOUT = 200;
// ================================================================
// Drive one mode and self-check against expected output
// ================================================================
task run_mode(input [1:0] m, input [511:0] din,
input [511:0] exp, input integer out_bits,
input [127:0] label);
reg [511:0] got;
begin
@(posedge clk);
mode <= m;
data_i <= din;
valid_i <= 1'b1;
@(posedge clk);
valid_i <= 1'b0;
cycle_count = 0;
while (!valid_o && cycle_count < TIMEOUT) begin
@(posedge clk);
cycle_count = cycle_count + 1;
end
if (cycle_count >= TIMEOUT) begin
$display("FAIL [%0s]: TIMEOUT, valid_o not asserted", label);
error_count = error_count + 1;
end else begin
got = hash_o;
if (out_bits == 512) begin
if (got !== exp) begin
$display("FAIL [%0s]: hash mismatch", label);
$display(" got = 512'h%0h", got);
$display(" exp = 512'h%0h", exp);
error_count = error_count + 1;
end else begin
$display("PASS [%0s]: hash_o = 512'h%0h", label, got);
end
end else begin
// Compare low 256 bits only
if (got[255:0] !== exp[255:0]) begin
$display("FAIL [%0s]: hash mismatch", label);
$display(" got = 256'h%0h", got[255:0]);
$display(" exp = 256'h%0h", exp[255:0]);
error_count = error_count + 1;
end else begin
$display("PASS [%0s]: hash_o = 256'h%0h", label, got[255:0]);
end
end
end
// Wait for DUT to return to IDLE
@(posedge clk);
while (!ready_o) @(posedge clk);
end
endtask
// ================================================================
// Test sequence
// ================================================================
initial begin
error_count = 0;
$display("========================================");
$display(" SHA3 Top Simple Self-Checking Testbench");
$display(" Mode: G (SHA3-512)");
$display(" Input: data_i = 512'd0");
$display(" SHA3 Top Testbench (G / H / J modes)");
$display("========================================");
// Initialize
mode = 2'd0; // G mode
data_i = 512'd0;
valid_i = 1'b0;
ready_i = 1'b1; // always ready
mode <= 2'd0;
data_i <= 512'd0;
valid_i <= 1'b0;
ready_i <= 1'b1;
// Reset: rst_n low for 3 cycles
rst_n = 1'b0;
rst_n <= 1'b0;
repeat (3) @(posedge clk);
rst_n = 1'b1;
rst_n <= 1'b1;
@(posedge clk);
$display("INFO: Reset complete. Starting test...");
$display("INFO: Reset complete. Running G/H/J...");
// Drive test vector
mode = 2'd0;
data_i = 512'd0;
valid_i = 1'b1;
@(posedge clk);
valid_i = 1'b0;
run_mode(2'd0, G_DATA, G_EXP, 512, "G SHA3-512");
run_mode(2'd1, H_DATA, {256'd0,H_EXP},256, "H SHA3-256");
run_mode(2'd2, J_DATA, {256'd0,J_EXP},256, "J SHAKE-256");
$display("INFO: Vector driven (mode=G, data=0). Waiting for valid_o...");
// Wait for valid_o
cycle_count = 0;
while (!valid_o && cycle_count < TIMEOUT) begin
@(posedge clk);
cycle_count = cycle_count + 1;
end
if (cycle_count >= TIMEOUT) begin
$error("TIMEOUT: valid_o not asserted within %0d cycles", TIMEOUT);
error_count = error_count + 1;
end else begin
captured_hash = hash_o;
$display("INFO: valid_o asserted after %0d cycles", cycle_count + 1);
$display("INFO: hash_o = 512'h%0h", captured_hash);
// Check against expected
if (captured_hash !== G_EXPECTED_HASH) begin
$error("MISMATCH!");
$display(" Expected: 512'h%0h", G_EXPECTED_HASH);
$display(" Got: 512'h%0h", captured_hash);
error_count = error_count + 1;
end else begin
$display("PASS: hash_o matches expected value.");
end
end
// One extra cycle
@(posedge clk);
// ============================================================
// Summary
// ============================================================
$display("========================================");
if (error_count == 0) begin
$display("ALL TESTS PASSED");
end else begin
$display("TESTS FAILED: %0d error(s)", error_count);
end
$display("========================================");
// Vivado xsim: $finish with error code
if (error_count > 0)
$finish;
if (error_count == 0)
$display("ALL TESTS PASSED (3/3 modes)");
else
$finish;
$display("TESTS FAILED: %0d error(s)", error_count);
$display("========================================");
$finish;
end
// ================================================================
// Timeout watchdog
// ================================================================
initial begin
#(TIMEOUT * 10 * 10); // TIMEOUT * 10ns * extra margin
#(TIMEOUT * 10 * 100);
$display("FATAL: Global simulation timeout");
$finish;
end

View File

@@ -0,0 +1,7 @@
615E530C77D5D834311E922DB99D5B7F1D57C7B08F029FD829914D3F4035FB730350FD00A852A5CCE9CFC79CF8C61384FEA115030E41750A6AE2CFE055D7976D
5A7DEC7ECB7A1217993059A6CBAF7754BF774311A936963A10568900EEE6DB3BDAB89C84A5650189B0E8B2526BE916FDA070A0AB2E33399590B87D315C55D5CB
BE71BF8A954846FB70D52DE11DCC189E25B6A931E63BD2A3BB546E4C02A8929500F1AE56BFAF3D61ACF85ECFA2B5D8E02778CBBED34D22552A371B4DE938ED6B
0000000000000000000000000000000000000000000000000000000000000000A63A98E0A2FB57548A6906708813766DA0F1E9ACF3831A6E77C4A56227E9473E
0000000000000000000000000000000000000000000000000000000000000000CFB62681BD3A993605FB6C80D93E8A308C5494EF0641F92C18F83002453A8FA2
0000000000000000000000000000000000000000000000000000000000000000B09665ECDF8E2934BC244DF46E36AF3B3DB2C18524300A896BE8837558BEE367
0000000000000000000000000000000000000000000000000000000000000000EB253D3B38BBF839B448BBC0149ED56E12E4EE72D31DE12D881994CA16AA0C2A

View File

@@ -0,0 +1,7 @@
00000000000000000000000000000000000000000000000000000000000000007DBC2AC0D13D719B37B4E2D4691951FF890A97854EF5D3A8957EF67A54978E26C9
0000000000000000000000000000000000000000000000000000000000000000C247885BF4E257CF39645D34C593047B7570D6ABBA300599D96171A950BB5027D5
0000000000000000000000000000000000000000000000000000000000000000B038CB3C2F0F7398474A3D68C4C90B777F42FA4C12B1FC8F70E1DAADF20755473C
010000000000000000000000000000000000000000000000000000000000000000F9D94DE0F1EF4D2CB73DCA0F437D2334320494E5D0F728D73F5275E342572FF9
0100000000000000000000000000000000000000000000000000000000000000008A1733CED3BC820A5D410AD00B0E4ACB0C260A8EBCD1B70FECF85B59256609CB
02CC2F7B1D60813526FB623E09F10D22635605046A66888277667DACCA02B420BBE795DC9A6DA171DA1DE082111568D55A8A27FE9B009275761098B44B484B3684
02E94BA9958BE80EDB47A9C83C07DBE09EA32CF4B1A59AD014938117DA74B87E9840E880E1A6F0C9E69C5E78D61A357D30ECC92FE5890DF046D93D94E87EA4ECB0

View File

@@ -0,0 +1,6 @@
537be01216c3a897d6923257af0713f9291cc342993653d55120a2df51673d65baf45fc64c24f26614842c8793a2b9b7307dc5eacb82e0877c091f738748194d78e1beacfbf69960c21c77c581e7bcb952ab54536298dc6836195672bc9043571d2897da5ec8f47af5f5006b872857d3125360bcb0ec6338f91931489273f468e17e1d830001b780
02859394b52a4cda4d3910a3548462a50fc8926778b2877c50832dd243654015beb34328e6365aa6803769743c00eacfb08d5258e83bcc101d5ca99de98897e6d8a85a446009f85b92aa57f23150bc211731e486b20c63c83d8b61dbb4063860e525156b692f2848439296c629929e5319391cbac5099d3bb0c4b08c0a20322abf46d29f3208cf35
bd65bd35a545a1865862b4d1c1b86c6011c642ac120c32bd7faa4292383e21f2212ff1587c78710cbb5ac948718a9cd648a7fb29b397c88987ca299070f60a04e62a9de92650426993d5008a239c2cb4ca77873ac5a822c288cd08ea85075037bb666265b15e8589b19be5d23e24aa09c44e1ad363b7fc101a1ae854f3072706d9867110bcd3d657
408e5bae7f3143a020ef13c8d065c2cd60868c51b7390e5c314c731796028925591a5ee636af48417d6686198910a8751a32e102cfe192c72c6129ca5fc1268fc006203bc32ca00cf9162a3d85b76841f112a0124078e148aad5c33676faa9760aa3a722ad2bd13c17ae9a229311f1da5c50ecbba32098752532001704e9871ad657160c336b990d
3b8c5da23a8f510e7e28cc0180136829e04664534d446a3d49d1bc9216c95c2153b2c3608c1886cb39164746079c4a8243fbc607e9cbc0d5440278b9348d22ba80cdc036309a6f4e83a4bca35c27158a00d246ced1a380c967739aad3a4849023c946523ef7b844c1539086fb2894610a95d7519551ad50ff3be091340496ba64f056c1df7ec6e54
8000000000000000000000000000000615f74355ca862c3cdf3dab780c35cf24b88bf144706090a1c17e41205f9f13794c1a9033ace032aa0f0c85ff94c8d3c9bca46fd7461ff5dab8403a2af8b1c242f08be4763fd5d68d198e9016b80f1c77505b2b56480c37bb4cc084f08993c2cdb2771f266b33353c265af09a027649489d81f4595cc3b395

View File

@@ -0,0 +1 @@
c6aa5100ed06d0c2db8cc3d1a36a62055b182f8d51ea71602501857e7c5d87ca

View File

@@ -1,22 +1,32 @@
// sha3_top.v - SHA3/SHAKE top wrapper with valid/ready interface
//
// Implements SHA3-512 (G), SHA3-256 (H), SHAKE-256 (J) over a single
// Keccak-f[1600] core. Supports single-block absorption (Phase 1.1).
// Keccak-f[1600] core. Supports single-block absorption, plus a separate
// multi-block SHA3-256 streaming absorb path for long inputs (e.g. H(ek)).
//
// Modes:
// 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
//
// Interface:
// clk, rst_n - clock, active-low reset
// Multi-block SHA3-256 (mb_en=1):
// Streams pre-padded 1088-bit rate blocks. The CALLER applies SHA3-256
// padding (suffix 0x06 ... 0x80) to the final block so this module only
// does the absorb loop: state ^= block; state = Keccak-p(state); repeat.
// The single-block paths above are bit-identical when mb_en=0.
//
// Interface (single-block):
// mode[1:0] - 00=G, 01=H, 10=J
// data_i - 512-bit message input
// valid_i - input valid
// ready_o - can accept new input
// hash_o - 512-bit hash output (lower 256 for H/J)
// valid_o - output valid
// ready_i - consumer accepts output
// valid_i / ready_o / hash_o[511:0] / valid_o / ready_i
//
// Interface (multi-block SHA3-256, active when mb_en=1):
// mb_en - 1 selects the multi-block absorb path
// mb_block_i - one pre-padded 1088-bit (136-byte) rate block, byte 0 in [7:0]
// mb_valid_i - block valid
// mb_ready_o - module can accept a block
// mb_last_i - asserted with the final (already-padded) block
// result reuses hash_o[255:0] / valid_o / ready_i
module sha3_top (
input clk,
@@ -27,7 +37,13 @@ module sha3_top (
output ready_o,
output [511:0] hash_o,
output valid_o,
input ready_i
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
);
// ================================================================
@@ -67,6 +83,42 @@ module sha3_top (
(mode == 2'b10) ? {{(1600-1088){1'b0}}, j_pad} :
1600'd0;
// ================================================================
// Multi-block SHA3-256 absorb FSM (active only when mb_en=1)
//
// Running sponge state mb_state_r (init 0). For each pre-padded
// 1088-bit rate block: mb_state_r ^= block; mb_state_r = Keccak-p(...).
// After the last block, squeeze 256 bits. The caller pads the final
// block (SHA3-256 suffix 0x06 ... 0x80), so this FSM is pure absorb.
// ================================================================
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
// ================================================================
// Keccak core
// ================================================================
@@ -77,10 +129,14 @@ module sha3_top (
/* verilator lint_on UNUSEDSIGNAL */
wire kc_valid_o;
// Keccak input: multi-block xored state when mb_en, else single-block absorb.
wire [1599:0] kc_state_i_mux;
assign kc_state_i_mux = mb_en ? mb_xored : absorb_state;
keccak_core #(.ROUNDS(24)) u_keccak (
.clk (clk),
.rst_n (rst_n),
.state_i (absorb_state),
.state_i (kc_state_i_mux),
.valid_i (kc_valid_i),
.ready_o (kc_ready_o), // unused but must connect
.state_o (kc_state_o),
@@ -91,14 +147,10 @@ module sha3_top (
// ================================================================
// FSM combinational logic
// ================================================================
assign ready_o = (state_r == ST_IDLE);
assign ready_o = !mb_en && (state_r == ST_IDLE);
// kc_valid_i: start keccak_core during IDLE when input accepted.
// Driven from state_next to avoid NBA latency: when state_r==IDLE
// and valid_i1, state_next=PERMUTE immediately (combinational).
// keccak_core sees valid_i=1 on the stable cycle before the posedge.
// On subsequent PERMUTE cycles, busy_r blocks re-start.
assign kc_valid_i = (state_next == ST_PERMUTE);
// 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);
always @(*) begin
state_next = state_r;
@@ -116,8 +168,9 @@ module sha3_top (
// Register for squeezed output (only 512 bits needed)
reg [511:0] squeezed_state_r;
assign valid_o = (state_r == ST_SQUEEZE);
assign hash_o = 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
@@ -127,13 +180,35 @@ module sha3_top (
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;
state_r <= state_next;
mb_state <= mb_state_next;
// Latch squeezed output when keccak_core finishes
// --- 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;
// On the final block, latch the 256-bit digest (sticky for MB_DONE).
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

View File

@@ -0,0 +1,45 @@
// tb_mlkem_kg_2a_xsim.v - Stage 2a: verify G(d||K) -> rho/sigma in mlkem_top.
`timescale 1ns/1ps
module tb_mlkem_kg_2a_xsim;
reg clk=0, rst_n=0, start_i=0;
reg [255:0] d_i, z_i=0;
wire busy_o, done_o;
reg [3:0] dbg_slot_i=0; reg [7:0] dbg_idx_i=0; wire [11:0] dbg_coeff_o;
wire [255:0] dbg_rho_o, dbg_sigma_o;
mlkem_top #(.K(2)) dut (
.clk(clk), .rst_n(rst_n), .d_i(d_i), .z_i(z_i), .start_i(start_i),
.busy_o(busy_o), .done_o(done_o),
.dbg_slot_i(dbg_slot_i), .dbg_idx_i(dbg_idx_i), .dbg_coeff_o(dbg_coeff_o),
.dbg_rho_o(dbg_rho_o), .dbg_sigma_o(dbg_sigma_o)
);
always #5 clk = ~clk;
localparam [255:0] D_LIT = 256'h2426f1941779574d3f1b163bd57f7e173e229e630ec7f7073bdf365137c4bb6d;
localparam [255:0] RHO_EXP = 256'h15f74355ca862c3cdf3dab780c35cf24b88bf144706090a1c17e41205f9f1379;
localparam [255:0] SIG_EXP = 256'h69b042001b5630b1a039116cbfd29f62c0bde5a6b571504a9fcce68bed667fd5;
integer c;
initial begin
d_i = D_LIT;
rst_n=0; repeat(4) @(posedge clk); rst_n=1; @(posedge clk);
start_i=1; @(posedge clk); start_i=0;
c=0; while(!done_o && c<1000) begin @(posedge clk); c=c+1; end
if(!done_o) begin $display("FAIL: timeout"); $finish; end
$display("=== Stage 2a: G(d||K) ===");
if (dbg_rho_o===RHO_EXP && dbg_sigma_o===SIG_EXP) begin
$display("PASS: rho = %064x", dbg_rho_o);
$display("PASS: sigma = %064x", dbg_sigma_o);
$display("ALL TESTS PASSED");
end else begin
$display("FAIL:");
$display(" rho got=%064x", dbg_rho_o);
$display(" rho exp=%064x", RHO_EXP);
$display(" sig got=%064x", dbg_sigma_o);
$display(" sig exp=%064x", SIG_EXP);
end
$finish;
end
initial begin #50000; $display("FAIL: global timeout"); $finish; end
endmodule

View File

@@ -0,0 +1,60 @@
// tb_mlkem_kg_2c_xsim.v - Stage 2c: verify A_hat + s + e stored in mlkem_top.
// Reads golden kg_c000_AsE.hex (8 polys x 256 = 2048 lines, mod-q) and checks
// polymem slots A00,A01,A10,A11,S0,S1,E0,E1 via the debug readback tap.
`timescale 1ns/1ps
module tb_mlkem_kg_2c_xsim;
reg clk=0, rst_n=0, start_i=0;
reg [255:0] d_i, z_i=0;
wire busy_o, done_o;
reg [3:0] dbg_slot_i=0; reg [7:0] dbg_idx_i=0; wire [11:0] dbg_coeff_o;
wire [255:0] dbg_rho_o, dbg_sigma_o;
mlkem_top #(.K(2)) dut (
.clk(clk), .rst_n(rst_n), .d_i(d_i), .z_i(z_i), .start_i(start_i),
.busy_o(busy_o), .done_o(done_o),
.dbg_slot_i(dbg_slot_i), .dbg_idx_i(dbg_idx_i), .dbg_coeff_o(dbg_coeff_o),
.dbg_rho_o(dbg_rho_o), .dbg_sigma_o(dbg_sigma_o)
);
always #5 clk = ~clk;
localparam [255:0] D_LIT = 256'h2426f1941779574d3f1b163bd57f7e173e229e630ec7f7073bdf365137c4bb6d;
reg [11:0] gold [0:2047];
// slot order matches golden file order
reg [3:0] slot_of [0:7];
integer c, p, idx, errors, gi;
initial begin
$readmemh("sync_rtl/top/TB/vectors/kg_c000_AsE.hex", gold);
slot_of[0]=4'd0; slot_of[1]=4'd1; slot_of[2]=4'd2; slot_of[3]=4'd3; // A00..A11
slot_of[4]=4'd4; slot_of[5]=4'd5; // S0,S1
slot_of[6]=4'd6; slot_of[7]=4'd7; // E0,E1
d_i = D_LIT;
rst_n=0; repeat(4) @(posedge clk); rst_n=1; @(posedge clk);
start_i=1; @(posedge clk); start_i=0;
c=0; while(!done_o && c<200000) begin @(posedge clk); c=c+1; end
if(!done_o) begin $display("FAIL: timeout after %0d cyc", c); $finish; end
$display("=== Stage 2c: A_hat + s + e (8 polys) === done in %0d cyc", c);
errors = 0;
for (p = 0; p < 8; p = p + 1) begin
for (idx = 0; idx < 256; idx = idx + 1) begin
dbg_slot_i = slot_of[p];
dbg_idx_i = idx[7:0];
@(posedge clk); @(posedge clk); // 2 cyc for registered readback
gi = p*256 + idx;
if (dbg_coeff_o !== gold[gi]) begin
if (errors < 8)
$display(" MISMATCH slot%0d[%0d]: got=%03x exp=%03x",
slot_of[p], idx, dbg_coeff_o, gold[gi]);
errors = errors + 1;
end
end
end
if (errors == 0) $display("ALL TESTS PASSED (2048/2048 coeffs)");
else $display("TESTS FAILED: %0d mismatches", errors);
$finish;
end
initial begin #5000000; $display("FAIL: global timeout"); $finish; end
endmodule

View File

@@ -0,0 +1,57 @@
// tb_mlkem_kg_2d_xsim.v - Stage 2d: verify forward NTT of s/e in mlkem_top.
// After ST_N, slots S0,S1,E0,E1 must hold shat_0,shat_1,ehat_0,ehat_1.
// Golden: kg_c000_sehat.hex (4 polys x 256 = 1024 lines, mod-q).
`timescale 1ns/1ps
module tb_mlkem_kg_2d_xsim;
reg clk=0, rst_n=0, start_i=0;
reg [255:0] d_i, z_i=0;
wire busy_o, done_o;
reg [3:0] dbg_slot_i=0; reg [7:0] dbg_idx_i=0; wire [11:0] dbg_coeff_o;
wire [255:0] dbg_rho_o, dbg_sigma_o;
mlkem_top #(.K(2)) dut (
.clk(clk), .rst_n(rst_n), .d_i(d_i), .z_i(z_i), .start_i(start_i),
.busy_o(busy_o), .done_o(done_o),
.dbg_slot_i(dbg_slot_i), .dbg_idx_i(dbg_idx_i), .dbg_coeff_o(dbg_coeff_o),
.dbg_rho_o(dbg_rho_o), .dbg_sigma_o(dbg_sigma_o)
);
always #5 clk = ~clk;
localparam [255:0] D_LIT = 256'h2426f1941779574d3f1b163bd57f7e173e229e630ec7f7073bdf365137c4bb6d;
reg [11:0] gold [0:1023];
reg [3:0] slot_of [0:3]; // S0,S1,E0,E1
integer c, p, idx, errors, gi;
initial begin
$readmemh("sync_rtl/top/TB/vectors/kg_c000_sehat.hex", gold);
slot_of[0]=4'd4; slot_of[1]=4'd5; slot_of[2]=4'd6; slot_of[3]=4'd7;
d_i = D_LIT;
rst_n=0; repeat(4) @(posedge clk); rst_n=1; @(posedge clk);
start_i=1; @(posedge clk); start_i=0;
c=0; while(!done_o && c<300000) begin @(posedge clk); c=c+1; end
if(!done_o) begin $display("FAIL: timeout after %0d cyc", c); $finish; end
$display("=== Stage 2d: NTT(s/e) -> shat/ehat === done in %0d cyc", c);
errors = 0;
for (p = 0; p < 4; p = p + 1) begin
for (idx = 0; idx < 256; idx = idx + 1) begin
dbg_slot_i = slot_of[p];
dbg_idx_i = idx[7:0];
@(posedge clk); @(posedge clk);
gi = p*256 + idx;
if (dbg_coeff_o !== gold[gi]) begin
if (errors < 8)
$display(" MISMATCH slot%0d[%0d]: got=%03x exp=%03x",
slot_of[p], idx, dbg_coeff_o, gold[gi]);
errors = errors + 1;
end
end
end
if (errors == 0) $display("ALL TESTS PASSED (1024/1024 shat/ehat coeffs)");
else $display("TESTS FAILED: %0d mismatches", errors);
$finish;
end
initial begin #10000000; $display("FAIL: global timeout"); $finish; end
endmodule

View File

@@ -0,0 +1,57 @@
// tb_mlkem_kg_2e_xsim.v - Stage 2e: verify t_hat = e_hat + sum_j A[i][j]*s_hat[j].
// After ST_M, slots T0,T1 must hold that_0,that_1.
// Golden: kg_c000_that.hex (2 polys x 256 = 512 lines, mod-q).
`timescale 1ns/1ps
module tb_mlkem_kg_2e_xsim;
reg clk=0, rst_n=0, start_i=0;
reg [255:0] d_i, z_i=0;
wire busy_o, done_o;
reg [3:0] dbg_slot_i=0; reg [7:0] dbg_idx_i=0; wire [11:0] dbg_coeff_o;
wire [255:0] dbg_rho_o, dbg_sigma_o;
mlkem_top #(.K(2)) dut (
.clk(clk), .rst_n(rst_n), .d_i(d_i), .z_i(z_i), .start_i(start_i),
.busy_o(busy_o), .done_o(done_o),
.dbg_slot_i(dbg_slot_i), .dbg_idx_i(dbg_idx_i), .dbg_coeff_o(dbg_coeff_o),
.dbg_rho_o(dbg_rho_o), .dbg_sigma_o(dbg_sigma_o)
);
always #5 clk = ~clk;
localparam [255:0] D_LIT = 256'h2426f1941779574d3f1b163bd57f7e173e229e630ec7f7073bdf365137c4bb6d;
reg [11:0] gold [0:511];
reg [3:0] slot_of [0:1]; // T0,T1
integer c, p, idx, errors, gi;
initial begin
$readmemh("sync_rtl/top/TB/vectors/kg_c000_that.hex", gold);
slot_of[0]=4'd8; slot_of[1]=4'd9;
d_i = D_LIT;
rst_n=0; repeat(4) @(posedge clk); rst_n=1; @(posedge clk);
start_i=1; @(posedge clk); start_i=0;
c=0; while(!done_o && c<400000) begin @(posedge clk); c=c+1; end
if(!done_o) begin $display("FAIL: timeout after %0d cyc", c); $finish; end
$display("=== Stage 2e: t_hat = e_hat + sum A o s_hat === done in %0d cyc", c);
errors = 0;
for (p = 0; p < 2; p = p + 1) begin
for (idx = 0; idx < 256; idx = idx + 1) begin
dbg_slot_i = slot_of[p];
dbg_idx_i = idx[7:0];
@(posedge clk); @(posedge clk);
gi = p*256 + idx;
if (dbg_coeff_o !== gold[gi]) begin
if (errors < 8)
$display(" MISMATCH slot%0d[%0d]: got=%03x exp=%03x",
slot_of[p], idx, dbg_coeff_o, gold[gi]);
errors = errors + 1;
end
end
end
if (errors == 0) $display("ALL TESTS PASSED (512/512 t_hat coeffs)");
else $display("TESTS FAILED: %0d mismatches", errors);
$finish;
end
initial begin #20000000; $display("FAIL: global timeout"); $finish; end
endmodule

View File

@@ -0,0 +1,66 @@
// tb_mlkem_kg_2f_xsim.v - Stage 2f: verify byteEncode12 -> ek (800B), dk_pke (768B).
// ek = byteEncode12(t_hat[0..1]) || rho ; dk_pke = byteEncode12(s_hat[0..1]).
// Golden: c000_ek.hex (single 1600-hex line), c000_dkpke.hex (1536-hex line).
`timescale 1ns/1ps
module tb_mlkem_kg_2f_xsim;
reg clk=0, rst_n=0, start_i=0;
reg [255:0] d_i, z_i=0;
wire busy_o, done_o;
reg [3:0] dbg_slot_i=0; reg [7:0] dbg_idx_i=0; wire [11:0] dbg_coeff_o;
reg dbg_byte_sel_i=0; reg [9:0] dbg_byte_idx_i=0; wire [7:0] dbg_byte_o;
wire [255:0] dbg_rho_o, dbg_sigma_o;
mlkem_top #(.K(2)) dut (
.clk(clk), .rst_n(rst_n), .d_i(d_i), .z_i(z_i), .start_i(start_i),
.busy_o(busy_o), .done_o(done_o),
.dbg_slot_i(dbg_slot_i), .dbg_idx_i(dbg_idx_i), .dbg_coeff_o(dbg_coeff_o),
.dbg_byte_sel_i(dbg_byte_sel_i), .dbg_byte_idx_i(dbg_byte_idx_i), .dbg_byte_o(dbg_byte_o),
.dbg_rho_o(dbg_rho_o), .dbg_sigma_o(dbg_sigma_o)
);
always #5 clk = ~clk;
localparam [255:0] D_LIT = 256'h2426f1941779574d3f1b163bd57f7e173e229e630ec7f7073bdf365137c4bb6d;
// golden bytes loaded as memories: 1 byte per entry
reg [7:0] ek_gold [0:799];
reg [7:0] dkp_gold [0:767];
integer c, i, errors;
initial begin
$readmemh("sync_rtl/top/TB/vectors/c000_ek_bytes.hex", ek_gold);
$readmemh("sync_rtl/top/TB/vectors/c000_dkpke_bytes.hex", dkp_gold);
d_i = D_LIT;
rst_n=0; repeat(4) @(posedge clk); rst_n=1; @(posedge clk);
start_i=1; @(posedge clk); start_i=0;
c=0; while(!done_o && c<500000) begin @(posedge clk); c=c+1; end
if(!done_o) begin $display("FAIL: timeout after %0d cyc", c); $finish; end
$display("=== Stage 2f: byteEncode12 -> ek/dk_pke === done in %0d cyc", c);
errors = 0;
// ek: 800 bytes (sel=0)
dbg_byte_sel_i = 1'b0;
for (i = 0; i < 800; i = i + 1) begin
dbg_byte_idx_i = i[9:0];
@(posedge clk); @(posedge clk);
if (dbg_byte_o !== ek_gold[i]) begin
if (errors < 8) $display(" EK MISMATCH[%0d]: got=%02x exp=%02x", i, dbg_byte_o, ek_gold[i]);
errors = errors + 1;
end
end
// dk_pke: 768 bytes (sel=1)
dbg_byte_sel_i = 1'b1;
for (i = 0; i < 768; i = i + 1) begin
dbg_byte_idx_i = i[9:0];
@(posedge clk); @(posedge clk);
if (dbg_byte_o !== dkp_gold[i]) begin
if (errors < 8) $display(" DKP MISMATCH[%0d]: got=%02x exp=%02x", i, dbg_byte_o, dkp_gold[i]);
errors = errors + 1;
end
end
if (errors == 0) $display("ALL TESTS PASSED (ek 800B + dk_pke 768B exact)");
else $display("TESTS FAILED: %0d byte mismatches", errors);
$finish;
end
initial begin #30000000; $display("FAIL: global timeout"); $finish; end
endmodule

View File

@@ -0,0 +1,79 @@
// tb_mlkem_kg_katK_xsim.v - ML-KEM KeyGen vs NIST KAT, parametric K (KP) + CASE.
// xelab -generic_top KP=2|3|4 ; xsim -testplusarg CASE=n
// KP=2 -> k2 vectors (ML-KEM-512), KP=3 -> k3 (768), KP=4 -> k4 (1024).
// ek = 384*KP+32 bytes (==KAT pk), dk = 768*KP+96 bytes (==KAT sk).
`timescale 1ns/1ps
module tb_mlkem_kg_katK_xsim;
parameter KP = 2;
localparam EKB = 384*KP + 32;
localparam DKB = 768*KP + 96;
reg clk=0, rst_n=0, start_i=0;
reg [2:0] k_i;
reg [255:0] d_i, z_i;
wire busy_o, done_o;
reg [3:0] dbg_slot_i=0; reg [7:0] dbg_idx_i=0; wire [11:0] dbg_coeff_o;
reg dbg_byte_sel_i=0; reg [10:0] dbg_byte_idx_i=0; wire [7:0] dbg_byte_o;
reg [11:0] dbg_dk_idx_i=0; wire [7:0] dbg_dk_o;
wire [255:0] dbg_rho_o, dbg_sigma_o;
// KMAX defaults to 4 (worst-case sizing); KP selects the runtime k value.
mlkem_top dut (
.clk(clk), .rst_n(rst_n), .k_i(k_i), .d_i(d_i), .z_i(z_i), .start_i(start_i),
.busy_o(busy_o), .done_o(done_o),
.dbg_slot_i(dbg_slot_i), .dbg_idx_i(dbg_idx_i), .dbg_coeff_o(dbg_coeff_o),
.dbg_byte_sel_i(dbg_byte_sel_i), .dbg_byte_idx_i(dbg_byte_idx_i), .dbg_byte_o(dbg_byte_o),
.dbg_dk_idx_i(dbg_dk_idx_i), .dbg_dk_o(dbg_dk_o),
.dbg_rho_o(dbg_rho_o), .dbg_sigma_o(dbg_sigma_o)
);
always #5 clk = ~clk;
reg [255:0] dmem [0:0];
reg [255:0] zmem [0:0];
reg [7:0] ek_gold [0:EKB-1];
reg [7:0] dk_gold [0:DKB-1];
integer c, i, errors, casenum;
reg [8*80-1:0] tag, dfile, zfile, ekfile, dkfile;
initial begin
if (!$value$plusargs("CASE=%d", casenum)) casenum = 0;
$sformat(tag, "k%0d", KP);
$sformat(dfile, "sync_rtl/top/TB/vectors/kat_%0s_c%0d_d.hex", tag, casenum);
$sformat(zfile, "sync_rtl/top/TB/vectors/kat_%0s_c%0d_z.hex", tag, casenum);
$sformat(ekfile, "sync_rtl/top/TB/vectors/kat_%0s_c%0d_ek.hex", tag, casenum);
$sformat(dkfile, "sync_rtl/top/TB/vectors/kat_%0s_c%0d_dk.hex", tag, casenum);
$readmemh(dfile, dmem);
$readmemh(zfile, zmem);
$readmemh(ekfile, ek_gold);
$readmemh(dkfile, dk_gold);
d_i = dmem[0]; z_i = zmem[0];
k_i = KP[2:0];
rst_n=0; repeat(4) @(posedge clk); rst_n=1; @(posedge clk);
start_i=1; @(posedge clk); start_i=0;
c=0; while(!done_o && c<2000000) begin @(posedge clk); c=c+1; end
if(!done_o) begin $display("FAIL K=%0d case %0d: timeout", KP, casenum); $finish; end
$display("=== ML-KEM K=%0d KAT case %0d: KeyGen done in %0d cyc ===", KP, casenum, c);
errors = 0;
dbg_byte_sel_i = 1'b0;
for (i = 0; i < EKB; i = i + 1) begin
dbg_byte_idx_i = i[10:0]; @(posedge clk); @(posedge clk);
if (dbg_byte_o !== ek_gold[i]) begin
if (errors < 8) $display(" EK[%0d] got=%02x exp=%02x", i, dbg_byte_o, ek_gold[i]);
errors = errors + 1;
end
end
for (i = 0; i < DKB; i = i + 1) begin
dbg_dk_idx_i = i[11:0]; @(posedge clk); @(posedge clk);
if (dbg_dk_o !== dk_gold[i]) begin
if (errors < 8) $display(" DK[%0d] got=%02x exp=%02x", i, dbg_dk_o, dk_gold[i]);
errors = errors + 1;
end
end
if (errors == 0) $display("K=%0d CASE %0d PASS: ek (%0dB)==pk, dk (%0dB)==sk", KP, casenum, EKB, DKB);
else $display("K=%0d CASE %0d FAIL: %0d mismatches", KP, casenum, errors);
$finish;
end
initial begin #120000000; $display("FAIL: global timeout"); $finish; end
endmodule

View File

@@ -0,0 +1,72 @@
// tb_mlkem_kg_katN_xsim.v - ML-KEM-512 KeyGen vs NIST KAT, case selected by +CASE=n.
// Loads d, z, ek, dk from per-case hex files (no literals via text channel).
// d/z: single 256-bit word ($readmemh, byte0 in [7:0]).
// ek : 800 bytes (== KAT pk). dk: 1632 bytes (== KAT sk).
`timescale 1ns/1ps
module tb_mlkem_kg_katN_xsim;
reg clk=0, rst_n=0, start_i=0;
reg [255:0] d_i, z_i;
wire busy_o, done_o;
reg [3:0] dbg_slot_i=0; reg [7:0] dbg_idx_i=0; wire [11:0] dbg_coeff_o;
reg dbg_byte_sel_i=0; reg [9:0] dbg_byte_idx_i=0; wire [7:0] dbg_byte_o;
reg [11:0] dbg_dk_idx_i=0; wire [7:0] dbg_dk_o;
wire [255:0] dbg_rho_o, dbg_sigma_o;
mlkem_top #(.K(2)) dut (
.clk(clk), .rst_n(rst_n), .d_i(d_i), .z_i(z_i), .start_i(start_i),
.busy_o(busy_o), .done_o(done_o),
.dbg_slot_i(dbg_slot_i), .dbg_idx_i(dbg_idx_i), .dbg_coeff_o(dbg_coeff_o),
.dbg_byte_sel_i(dbg_byte_sel_i), .dbg_byte_idx_i(dbg_byte_idx_i), .dbg_byte_o(dbg_byte_o),
.dbg_dk_idx_i(dbg_dk_idx_i), .dbg_dk_o(dbg_dk_o),
.dbg_rho_o(dbg_rho_o), .dbg_sigma_o(dbg_sigma_o)
);
always #5 clk = ~clk;
reg [255:0] dmem [0:0];
reg [255:0] zmem [0:0];
reg [7:0] ek_gold [0:799];
reg [7:0] dk_gold [0:1631];
integer c, i, errors, casenum;
reg [8*64-1:0] dfile, zfile, ekfile, dkfile;
initial begin
if (!$value$plusargs("CASE=%d", casenum)) casenum = 0;
$sformat(dfile, "sync_rtl/top/TB/vectors/kat_c%0d_d.hex", casenum);
$sformat(zfile, "sync_rtl/top/TB/vectors/kat_c%0d_z.hex", casenum);
$sformat(ekfile, "sync_rtl/top/TB/vectors/kat_c%0d_ek.hex", casenum);
$sformat(dkfile, "sync_rtl/top/TB/vectors/kat_c%0d_dk.hex", casenum);
$readmemh(dfile, dmem);
$readmemh(zfile, zmem);
$readmemh(ekfile, ek_gold);
$readmemh(dkfile, dk_gold);
d_i = dmem[0];
z_i = zmem[0];
rst_n=0; repeat(4) @(posedge clk); rst_n=1; @(posedge clk);
start_i=1; @(posedge clk); start_i=0;
c=0; while(!done_o && c<600000) begin @(posedge clk); c=c+1; end
if(!done_o) begin $display("FAIL case %0d: timeout", casenum); $finish; end
$display("=== KAT case %0d: KeyGen done in %0d cyc ===", casenum, c);
errors = 0;
dbg_byte_sel_i = 1'b0;
for (i = 0; i < 800; i = i + 1) begin
dbg_byte_idx_i = i[9:0]; @(posedge clk); @(posedge clk);
if (dbg_byte_o !== ek_gold[i]) begin
if (errors < 8) $display(" EK[%0d] got=%02x exp=%02x", i, dbg_byte_o, ek_gold[i]);
errors = errors + 1;
end
end
for (i = 0; i < 1632; i = i + 1) begin
dbg_dk_idx_i = i[11:0]; @(posedge clk); @(posedge clk);
if (dbg_dk_o !== dk_gold[i]) begin
if (errors < 8) $display(" DK[%0d] got=%02x exp=%02x", i, dbg_dk_o, dk_gold[i]);
errors = errors + 1;
end
end
if (errors == 0) $display("CASE %0d PASS: ek==KAT.pk (800B), dk==KAT.sk (1632B)", casenum);
else $display("CASE %0d FAIL: %0d byte mismatches", casenum, errors);
$finish;
end
initial begin #40000000; $display("FAIL: global timeout"); $finish; end
endmodule

View File

@@ -0,0 +1,68 @@
// tb_mlkem_kg_kat_xsim.v - Stage 4 end-to-end: full ML-KEM-512 KeyGen vs NIST KAT.
// Drives d/z (KAT count=0), runs KeyGen, verifies:
// ek (800B, sel=0) == KAT pk
// dk (1632B, dk tap) == KAT sk (= dk_pke || ek || H(ek) || z)
// No force/release pure valid/ready via start_i/done_o.
`timescale 1ns/1ps
module tb_mlkem_kg_kat_xsim;
reg clk=0, rst_n=0, start_i=0;
reg [255:0] d_i, z_i;
wire busy_o, done_o;
reg [3:0] dbg_slot_i=0; reg [7:0] dbg_idx_i=0; wire [11:0] dbg_coeff_o;
reg dbg_byte_sel_i=0; reg [9:0] dbg_byte_idx_i=0; wire [7:0] dbg_byte_o;
reg [11:0] dbg_dk_idx_i=0; wire [7:0] dbg_dk_o;
wire [255:0] dbg_rho_o, dbg_sigma_o;
mlkem_top #(.K(2)) dut (
.clk(clk), .rst_n(rst_n), .d_i(d_i), .z_i(z_i), .start_i(start_i),
.busy_o(busy_o), .done_o(done_o),
.dbg_slot_i(dbg_slot_i), .dbg_idx_i(dbg_idx_i), .dbg_coeff_o(dbg_coeff_o),
.dbg_byte_sel_i(dbg_byte_sel_i), .dbg_byte_idx_i(dbg_byte_idx_i), .dbg_byte_o(dbg_byte_o),
.dbg_dk_idx_i(dbg_dk_idx_i), .dbg_dk_o(dbg_dk_o),
.dbg_rho_o(dbg_rho_o), .dbg_sigma_o(dbg_sigma_o)
);
always #5 clk = ~clk;
// KAT count=0 (byte0-low literals)
localparam [255:0] D_LIT = 256'h2426f1941779574d3f1b163bd57f7e173e229e630ec7f7073bdf365137c4bb6d;
localparam [255:0] Z_LIT = 256'h687acf9406694974d383032f7579378f449c75d0560af56cf921ec48404896f6;
reg [7:0] ek_gold [0:799];
reg [7:0] dk_gold [0:1631];
integer c, i, errors;
initial begin
$readmemh("sync_rtl/top/TB/vectors/c000_ek_bytes.hex", ek_gold);
$readmemh("sync_rtl/top/TB/vectors/c000_dk_full_bytes.hex", dk_gold);
d_i = D_LIT; z_i = Z_LIT;
rst_n=0; repeat(4) @(posedge clk); rst_n=1; @(posedge clk);
start_i=1; @(posedge clk); start_i=0;
c=0; while(!done_o && c<600000) begin @(posedge clk); c=c+1; end
if(!done_o) begin $display("FAIL: timeout after %0d cyc", c); $finish; end
$display("=== Stage 4: ML-KEM-512 KeyGen end-to-end vs NIST KAT === done in %0d cyc", c);
errors = 0;
// ek == KAT pk (800B)
dbg_byte_sel_i = 1'b0;
for (i = 0; i < 800; i = i + 1) begin
dbg_byte_idx_i = i[9:0]; @(posedge clk); @(posedge clk);
if (dbg_byte_o !== ek_gold[i]) begin
if (errors < 8) $display(" EK[%0d] got=%02x exp=%02x", i, dbg_byte_o, ek_gold[i]);
errors = errors + 1;
end
end
// dk == KAT sk (1632B)
for (i = 0; i < 1632; i = i + 1) begin
dbg_dk_idx_i = i[11:0]; @(posedge clk); @(posedge clk);
if (dbg_dk_o !== dk_gold[i]) begin
if (errors < 8) $display(" DK[%0d] got=%02x exp=%02x", i, dbg_dk_o, dk_gold[i]);
errors = errors + 1;
end
end
if (errors == 0) $display("ALL TESTS PASSED: ek==KAT.pk (800B), dk==KAT.sk (1632B)");
else $display("TESTS FAILED: %0d byte mismatches", errors);
$finish;
end
initial begin #40000000; $display("FAIL: global timeout"); $finish; end
endmodule

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,768 @@
fa
da
6a
79
a3
79
d2
cb
36
c8
56
45
0c
44
6f
44
84
b8
6a
56
0c
61
70
56
4d
00
2e
4b
74
07
3f
66
a6
fb
6a
57
bc
e1
be
92
a1
a1
b5
31
c6
1f
50
88
2a
00
84
50
85
42
a1
e1
c3
b3
a9
50
f2
07
2e
9a
16
54
4e
46
ca
20
28
4b
60
12
a6
2c
69
7a
c8
58
61
5e
18
1e
1e
a0
b5
5b
00
21
19
09
0b
7b
87
19
20
e9
b8
94
b0
7a
28
12
69
dc
a1
5f
af
4a
09
b0
00
4c
ac
61
a2
ce
a7
3f
28
05
7d
bf
12
19
d0
77
47
b3
81
cf
0d
e5
2a
ba
d3
0c
a0
f5
78
73
b2
bf
a0
12
bd
5b
c2
48
05
f3
65
7a
d0
ba
6b
c4
98
8c
d9
c6
de
49
2c
0d
43
3c
e5
aa
32
8b
d6
c6
cb
50
24
63
34
0d
c5
e0
29
d2
c8
71
3d
78
0f
31
f4
41
c2
4c
40
00
e5
67
99
a6
bc
66
b4
a1
93
c7
3c
ed
56
0f
8a
e4
3f
9b
20
75
ce
b7
78
97
6b
7f
11
1a
cb
38
a3
06
f2
b7
0a
2b
d8
75
2e
82
80
86
ba
0f
3e
81
1a
8c
3b
0d
5f
8b
90
72
15
9e
56
ba
1e
10
08
00
91
95
af
58
a8
5a
3e
27
1f
00
ac
25
cc
f3
23
3c
b8
71
67
68
ad
98
e7
b1
f2
89
0d
b6
17
0f
2b
61
4f
56
c1
93
38
71
ae
1a
41
30
24
ca
9a
21
37
79
5c
8a
2e
9e
15
28
0f
f1
08
ae
e3
28
23
57
51
e5
69
ca
63
a7
82
1f
29
ad
26
70
6b
23
12
24
d9
51
60
bd
75
22
dd
e0
bf
e6
e0
a8
26
19
74
88
5a
2f
df
21
7f
8c
16
c4
f6
7c
0e
9f
b2
a2
f7
03
0c
af
88
1d
2c
8b
2e
6a
68
63
90
61
92
10
8b
00
42
60
b0
ad
ea
07
c0
b3
49
d5
88
11
0a
9c
bb
69
9b
39
52
bb
11
2c
c7
c8
d9
a7
59
b9
55
4c
1f
99
1e
a1
f5
1f
4c
61
78
e4
38
27
c5
14
9b
da
07
7f
bd
76
9a
3b
81
8d
f7
1a
42
86
07
83
fd
23
3d
1b
26
a9
6a
57
3e
99
eb
91
5f
6b
c1
8d
81
3d
ed
14
a3
04
c1
35
8e
47
05
70
d2
54
78
a6
b6
ba
2a
c5
61
28
90
b5
a5
69
e5
26
33
42
45
9c
b9
ca
76
74
f2
28
39
69
54
af
74
8d
9d
50
13
53
42
71
39
04
cc
59
10
6e
0b
b2
19
42
b4
06
6f
86
bf
5d
9c
3c
f1
b6
c0
86
92
c5
b9
88
1b
29
97
10
88
a8
b4
15
e2
6c
4a
25
67
58
8b
2d
df
b6
8d
11
14
6f
cf
f0
b4
cb
79
c5
74
87
01
8c
25
54
1d
32
67
a1
06
40
e4
30
bf
eb
bb
4f
45
a7
99
c9
f5
54
d1
b6
9d
70
c7
9d
17
12
4f
9c
01
cf
3a
d6
56
9e
77
a4
e1
b6
57
04
70
10
06
45
2f
45
a7
2f
32
98
c6
60
82
0f
1c
20
6a
f7
00
c9
a6
21
92
3c
39
11
cd
51
8e
02
24
04
c8
70
c3
d3
b3
b6
83
1a
82
53
6a
31
70
33
4e
31
59
b0
c9
59
03
6c
43
2c
f5
b4
84
b1
2c
75
cc
c3
c9
6c
e3
28
fb
ba
79
e2
f7
24
78
9a
8d
27
f7
af
8b
b0
86
45
d2
c9
a3
e8
7f
80
42
c3
62
27
19
4a
3c
0e
14
d0
91
29
d0
69
d5
37
9d
bd
60
65
65
d9
15
a3
bc
98
82
e8
74
23
a0
62
00
0a
5f
4c
55
23
ec
94
47
ce
a1
64
3a
97
ad
33
c1
98
62
46
ad
91
e2
73
ce
32
ac
af
f4
53
35
99
65
37
07
21

View File

@@ -0,0 +1,800 @@
80
b7
01
00
83
1d
7e
e1
68
f4
73
92
48
31
19
f9
38
63
ec
b0
bc
60
53
12
d3
57
28
87
6b
00
f5
f5
7a
f4
c8
5e
da
97
28
1d
57
43
90
bc
72
56
19
36
68
dc
98
62
53
54
ab
52
b9
bc
e7
81
c5
77
1c
c2
60
99
f6
fb
ac
be
e1
78
4d
19
48
87
73
1f
09
7c
87
e0
82
cb
ea
c5
7d
30
b7
b9
a2
93
87
2c
84
14
66
f2
24
4c
c6
5f
f4
ba
65
3d
67
51
df
a2
20
51
d5
53
36
99
42
c3
1c
29
f9
13
07
af
57
32
92
d6
97
a8
c3
16
12
e0
7b
53
35
cf
08
32
9f
d2
46
bf
2a
32
20
0a
8c
b0
c4
b0
3b
9d
09
c5
ba
1c
39
19
53
9e
92
29
c6
96
92
43
48
28
2f
69
6b
15
25
e5
60
38
06
b4
db
61
8b
3d
c8
63
0c
b2
86
e4
31
17
21
bc
50
31
f2
57
aa
92
5b
f8
09
60
44
5a
a8
d8
e6
97
88
e9
9d
a9
5c
1d
10
cc
3b
e8
58
52
8d
b0
cf
ea
00
3c
74
69
37
80
a6
5a
36
e6
28
43
b3
be
15
40
65
43
d2
2d
83
50
7c
87
b2
78
67
92
c8
0f
a5
62
84
54
a3
10
39
4d
da
4c
2a
b5
94
93
85
02
57
d6
d3
bc
10
71
86
d9
06
27
07
f3
54
e8
1a
1a
10
fc
b7
63
d3
1a
4e
c4
09
aa
24
3e
d2
e5
9b
b1
89
85
5e
b1
65
62
66
bb
37
50
07
85
ea
08
cd
88
c2
22
a8
c5
3a
87
77
ca
b4
2c
9c
23
8a
00
d5
93
69
42
50
26
e9
9d
2a
e6
04
0a
f6
70
90
29
ca
87
89
c8
97
b3
29
fb
a7
48
d6
9c
8a
71
48
c9
5a
bb
0c
71
78
7c
58
f1
2f
21
f2
21
3e
38
92
42
aa
7f
bd
32
0c
12
ac
42
c6
11
60
6c
b8
c1
d1
b4
62
58
86
a1
45
a5
35
bd
65
bd
0d
99
6b
33
0c
16
57
d6
1a
87
e9
04
17
00
32
25
75
98
20
a3
bb
ec
50
5c
da
f1
11
93
22
9a
ae
17
3c
d1
2b
ad
22
a7
a3
0a
76
a9
fa
76
36
c3
d5
aa
48
e1
78
40
12
a0
12
f1
41
68
b7
85
3d
2a
16
f9
0c
a0
2c
c3
3b
20
06
c0
8f
26
c1
5f
ca
29
61
2c
c7
92
e1
cf
02
e1
32
1a
75
a8
10
89
19
86
66
7d
41
48
af
36
e6
5e
1a
59
25
89
02
96
17
73
4c
31
5c
0e
39
b7
51
8c
86
60
cd
c2
65
d0
c8
13
ef
20
a0
43
31
7f
ae
5b
8e
40
54
6e
ec
f7
1d
6c
05
4f
a6
6b
49
40
13
09
be
f3
0f
d5
1a
55
19
75
5d
a9
10
46
89
b2
6f
08
39
15
4c
84
7b
ef
23
65
94
3c
02
49
48
3a
ad
9a
73
67
c9
80
a3
d1
ce
46
d2
00
8a
15
27
5c
a3
bc
a4
83
4e
6f
9a
30
36
c0
cd
80
ba
22
8d
34
b9
78
02
44
d5
c0
cb
e9
07
c6
fb
43
82
4a
9c
07
46
47
16
39
cb
86
18
8c
60
c3
b2
53
21
5c
c9
16
92
bc
d1
49
3d
6a
44
4d
53
64
46
e0
29
68
13
80
01
cc
28
7e
0e
51
8f
3a
a2
5d
8c
3b
95
b3
c3
5c
59
f4
81
9d
48
49
76
02
9a
f0
5a
26
3c
35
33
6b
26
1f
77
b2
cd
c2
93
89
f0
84
c0
4c
bb
37
0c
48
56
2b
5b
50
77
1c
0f
b8
16
90
8e
19
8d
d6
d5
3f
76
e4
8b
f0
42
c2
b1
f8
2a
3a
40
b8
da
f5
1f
46
d7
6f
a4
bc
c9
d3
c8
94
ff
85
0c
0f
aa
32
e0
ac
33
90
1a
4c
79
13
9f
5f
20
41
7e
c1
a1
90
60
70
44
f1
8b
b8
24
cf
35
0c
78
ab
3d
df
3c
2c
86
ca
55
43
f7
15

View File

@@ -0,0 +1 @@
2426f1941779574d3f1b163bd57f7e173e229e630ec7f7073bdf365137c4bb6d

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,800 @@
80
b7
01
00
83
1d
7e
e1
68
f4
73
92
48
31
19
f9
38
63
ec
b0
bc
60
53
12
d3
57
28
87
6b
00
f5
f5
7a
f4
c8
5e
da
97
28
1d
57
43
90
bc
72
56
19
36
68
dc
98
62
53
54
ab
52
b9
bc
e7
81
c5
77
1c
c2
60
99
f6
fb
ac
be
e1
78
4d
19
48
87
73
1f
09
7c
87
e0
82
cb
ea
c5
7d
30
b7
b9
a2
93
87
2c
84
14
66
f2
24
4c
c6
5f
f4
ba
65
3d
67
51
df
a2
20
51
d5
53
36
99
42
c3
1c
29
f9
13
07
af
57
32
92
d6
97
a8
c3
16
12
e0
7b
53
35
cf
08
32
9f
d2
46
bf
2a
32
20
0a
8c
b0
c4
b0
3b
9d
09
c5
ba
1c
39
19
53
9e
92
29
c6
96
92
43
48
28
2f
69
6b
15
25
e5
60
38
06
b4
db
61
8b
3d
c8
63
0c
b2
86
e4
31
17
21
bc
50
31
f2
57
aa
92
5b
f8
09
60
44
5a
a8
d8
e6
97
88
e9
9d
a9
5c
1d
10
cc
3b
e8
58
52
8d
b0
cf
ea
00
3c
74
69
37
80
a6
5a
36
e6
28
43
b3
be
15
40
65
43
d2
2d
83
50
7c
87
b2
78
67
92
c8
0f
a5
62
84
54
a3
10
39
4d
da
4c
2a
b5
94
93
85
02
57
d6
d3
bc
10
71
86
d9
06
27
07
f3
54
e8
1a
1a
10
fc
b7
63
d3
1a
4e
c4
09
aa
24
3e
d2
e5
9b
b1
89
85
5e
b1
65
62
66
bb
37
50
07
85
ea
08
cd
88
c2
22
a8
c5
3a
87
77
ca
b4
2c
9c
23
8a
00
d5
93
69
42
50
26
e9
9d
2a
e6
04
0a
f6
70
90
29
ca
87
89
c8
97
b3
29
fb
a7
48
d6
9c
8a
71
48
c9
5a
bb
0c
71
78
7c
58
f1
2f
21
f2
21
3e
38
92
42
aa
7f
bd
32
0c
12
ac
42
c6
11
60
6c
b8
c1
d1
b4
62
58
86
a1
45
a5
35
bd
65
bd
0d
99
6b
33
0c
16
57
d6
1a
87
e9
04
17
00
32
25
75
98
20
a3
bb
ec
50
5c
da
f1
11
93
22
9a
ae
17
3c
d1
2b
ad
22
a7
a3
0a
76
a9
fa
76
36
c3
d5
aa
48
e1
78
40
12
a0
12
f1
41
68
b7
85
3d
2a
16
f9
0c
a0
2c
c3
3b
20
06
c0
8f
26
c1
5f
ca
29
61
2c
c7
92
e1
cf
02
e1
32
1a
75
a8
10
89
19
86
66
7d
41
48
af
36
e6
5e
1a
59
25
89
02
96
17
73
4c
31
5c
0e
39
b7
51
8c
86
60
cd
c2
65
d0
c8
13
ef
20
a0
43
31
7f
ae
5b
8e
40
54
6e
ec
f7
1d
6c
05
4f
a6
6b
49
40
13
09
be
f3
0f
d5
1a
55
19
75
5d
a9
10
46
89
b2
6f
08
39
15
4c
84
7b
ef
23
65
94
3c
02
49
48
3a
ad
9a
73
67
c9
80
a3
d1
ce
46
d2
00
8a
15
27
5c
a3
bc
a4
83
4e
6f
9a
30
36
c0
cd
80
ba
22
8d
34
b9
78
02
44
d5
c0
cb
e9
07
c6
fb
43
82
4a
9c
07
46
47
16
39
cb
86
18
8c
60
c3
b2
53
21
5c
c9
16
92
bc
d1
49
3d
6a
44
4d
53
64
46
e0
29
68
13
80
01
cc
28
7e
0e
51
8f
3a
a2
5d
8c
3b
95
b3
c3
5c
59
f4
81
9d
48
49
76
02
9a
f0
5a
26
3c
35
33
6b
26
1f
77
b2
cd
c2
93
89
f0
84
c0
4c
bb
37
0c
48
56
2b
5b
50
77
1c
0f
b8
16
90
8e
19
8d
d6
d5
3f
76
e4
8b
f0
42
c2
b1
f8
2a
3a
40
b8
da
f5
1f
46
d7
6f
a4
bc
c9
d3
c8
94
ff
85
0c
0f
aa
32
e0
ac
33
90
1a
4c
79
13
9f
5f
20
41
7e
c1
a1
90
60
70
44
f1
8b
b8
24
cf
35
0c
78
ab
3d
df
3c
2c
86
ca
55
43
f7
15

View File

@@ -0,0 +1 @@
687acf9406694974d383032f7579378f449c75d0560af56cf921ec48404896f6

View File

@@ -0,0 +1 @@
9b68d9d2390fa18739b239a58649393a28f97f6b164ec5e4334f4df864fc9cd6

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,800 @@
de
e7
89
22
bb
8d
a2
f4
76
4d
ca
45
f8
ea
4c
1f
53
0a
1c
57
1d
3a
d1
92
4b
58
96
98
cb
27
19
e0
69
fd
94
3c
14
52
c5
d1
68
b2
b3
57
b2
65
83
1c
01
9c
b3
55
7a
0b
f7
18
7e
4d
10
8b
f7
70
c7
4d
b4
03
89
cc
71
8f
3b
c1
1c
e3
ab
a8
43
66
ab
24
51
94
b9
41
f8
1b
7a
e7
02
41
9b
b9
8d
73
ba
00
37
83
30
6c
7b
3a
36
77
a5
43
a0
10
0c
31
75
e8
c0
20
ca
26
65
12
90
9c
35
50
c4
f6
5c
0e
a3
e2
4a
47
23
7d
9a
4a
0b
5a
e5
88
f9
83
31
1f
aa
36
e8
91
af
8e
a1
b3
08
c8
31
79
24
61
54
c7
65
ac
5b
5a
15
45
6e
19
33
08
00
28
37
d1
43
54
e0
66
a3
4a
44
09
af
bb
15
08
5a
ad
c9
e2
2b
8d
b5
58
3d
45
b0
a4
ac
72
47
4a
2a
b9
4b
79
2e
53
1a
b0
cb
88
2c
13
a4
13
9a
71
ff
a3
78
3b
53
71
78
f3
4e
11
1b
6c
3f
12
0a
76
d4
cd
ce
c4
61
84
30
35
ac
d2
85
ed
62
7d
8b
d2
b0
b9
97
cc
ce
b4
ad
ae
36
15
a7
3b
ba
0a
7c
7b
b9
b1
33
58
bb
51
ff
8a
57
4d
86
b5
00
02
72
cd
27
0a
0a
1b
24
bb
91
75
06
70
1c
2f
44
1f
c5
b7
9d
d4
51
cb
3c
ac
c7
40
12
7b
d4
11
60
4b
da
c4
64
da
1a
2f
83
91
8c
5b
2f
b6
e5
28
4c
97
2b
93
35
7a
83
78
28
b1
13
26
32
bb
6f
7b
fb
be
c3
d9
47
bd
40
3d
86
99
00
66
db
65
53
72
24
34
c7
c0
e3
99
2f
00
9b
b2
38
f7
a6
b3
e5
25
1e
da
94
3a
77
03
fb
a2
89
aa
20
53
a8
57
79
6c
2c
b9
45
49
4c
0b
a7
91
a9
e3
cb
fa
80
0d
89
88
c8
12
19
97
d9
75
b3
d0
35
95
ad
d6
4a
3e
ac
b8
ba
36
a4
d8
b3
bf
dc
11
b7
d5
62
39
08
7c
90
f3
52
c0
ee
c4
08
57
f0
89
cc
fa
7c
9a
68
3a
1d
e3
cd
8f
f2
8b
22
15
3d
de
23
1e
5f
74
80
5d
68
3e
b8
c3
46
ba
16
c7
fe
68
06
4b
20
59
c8
73
8e
5a
c1
9b
64
d4
34
3f
5c
9d
8b
f9
78
03
02
b0
67
6c
20
2a
21
29
2c
c1
5f
c1
58
9a
69
83
8a
d1
ea
3d
0c
37
06
f8
e1
b0
11
f6
12
99
a5
6e
c2
51
50
51
fb
94
73
4b
30
8a
f3
c3
5e
45
ab
fa
dc
12
8f
e6
98
38
aa
37
08
05
14
d6
c3
74
8c
91
6b
d6
55
08
0a
10
35
ff
1a
76
3e
45
0b
56
86
4c
c2
32
af
ee
53
91
9f
f8
89
a8
20
a7
a6
55
86
31
b8
8f
73
18
c0
33
80
0f
30
7c
19
b2
d0
a8
b6
58
82
d8
77
09
79
a5
70
1a
c6
02
f7
1b
72
a2
6b
82
52
5a
a6
7d
77
c7
5e
b6
87
1d
c0
19
b4
65
58
3a
25
0d
b4
70
49
06
18
7e
8d
fb
3b
70
72
69
88
f9
c5
2c
12
26
6c
63
91
d4
92
6c
b7
99
78
00
7c
a4
6e
f6
08
82
80
6f
fd
59
c6
4e
d7
03
33
98
9a
ac
51
86
99
04
40
b8
9c
3c
d1
36
3b
e4
04
70
6d
bb
63
a5
a0
07
a0
fa
c2
61
a0
28
8f
91
6f
af
0a
a4
e9
44
55
2f
10
80
1a
3a
5d
de
26
33
98
01
5c
c3
52
27
bd
17
11
35
62
51
aa
93
5a
89
bc
2e
3d
2c
08
e1
c9
a8
c1
e4
41
6f
30
3b
b7
3b
31
48
58
ca
4c
21
0c
95
92
83
fc
86
5b
02
77
68
c5
d6
04
7f
d3
6d
bc
bc
4e
df
3e
a5
cc
6a
50
cb
05
2b
cd
31

View File

@@ -0,0 +1 @@
a02e20d538b412ff074d121a80b0583e0b54e85b267da0789c5ca565342ee66d

View File

@@ -0,0 +1 @@
905eb1f02ade542733c35132f5a998d3ec80d20ec8ed235bf228081157034763

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,800 @@
f5
e2
4e
4e
14
b6
65
36
65
ca
02
89
a3
72
8c
bb
a2
28
fe
11
67
26
c1
25
1e
99
92
a9
f0
06
09
34
64
5b
26
23
24
ac
b5
c6
b5
7d
26
e3
92
26
e2
2c
f0
c3
3f
7f
f5
a4
d9
79
23
4f
2b
79
49
f5
66
db
66
c3
5b
27
3d
c9
77
8a
64
f2
bc
fe
91
4c
0d
81
52
7d
41
8a
11
25
79
e5
d0
8b
1c
42
95
87
32
34
25
d7
a7
83
51
45
34
57
cd
86
83
45
af
a1
62
18
33
20
02
c9
5d
84
06
c1
49
38
c0
39
69
3d
6c
12
16
af
b9
98
30
99
03
11
09
be
01
93
a1
b6
e1
24
36
10
3f
dd
08
4a
7b
84
38
0a
cc
35
81
78
31
c0
55
8d
4f
80
82
ba
58
b9
17
48
41
a8
40
c2
96
48
53
65
6c
23
27
f7
95
21
32
c6
dd
12
9d
bf
50
23
ce
1b
3a
92
f7
73
6f
c1
95
28
b7
1d
21
a2
7c
3d
7b
74
51
d5
a8
fc
02
a7
86
f7
55
45
d2
45
15
49
bc
95
db
bb
87
72
4f
72
d2
ad
f1
d6
19
b1
b9
43
86
c1
4c
37
12
8c
2c
1c
60
f4
c0
2b
28
cc
53
6c
50
8a
37
0b
a9
a2
f4
61
8c
f1
c6
4f
35
56
84
f2
5a
6e
e9
9d
3f
89
ce
01
36
b4
7d
7b
26
f0
e6
a6
0c
c9
4f
c4
57
38
34
17
2a
3e
fb
84
c9
fb
66
40
1b
76
c9
00
07
e8
f7
b1
9b
51
32
92
13
8b
79
14
7a
36
46
80
db
cb
21
17
62
35
8c
d3
2a
3c
44
72
0d
f6
ba
22
dc
8d
30
19
c0
c4
80
3f
2a
56
7d
9e
bc
6a
5b
c0
12
d1
f6
34
71
98
91
da
13
24
ea
f2
28
37
92
64
b3
da
95
5d
aa
3a
2f
b8
83
68
94
c8
e8
00
06
78
21
41
25
7c
25
4d
90
5a
23
8a
6b
41
ac
3c
76
cb
87
ea
34
27
28
ea
6e
48
bc
66
81
68
42
ff
24
55
e8
5c
67
f8
c4
88
74
f4
69
bd
a5
6f
dd
83
a5
7d
d4
07
67
98
a3
d8
54
ce
40
bc
c6
b3
49
a1
98
fc
6f
a4
71
3c
94
79
49
46
e2
49
20
17
79
70
9a
b7
51
04
59
e2
fa
32
5b
b3
c8
16
b2
af
3d
9c
af
36
fa
5c
21
73
79
cf
eb
79
7a
90
80
fe
23
37
4f
a0
2f
04
7c
77
5c
b4
60
2b
78
59
f7
d7
9c
0a
f7
3f
11
b4
28
47
91
5b
3d
32
46
e1
04
40
31
f6
1b
aa
d9
87
f3
c6
cc
93
28
0b
23
c8
39
0e
48
a2
10
80
92
c7
b4
19
ba
e1
3a
e5
00
67
81
3a
99
b5
da
80
e5
80
05
c6
96
5f
fe
45
3a
e5
73
50
1b
24
21
24
51
52
57
c4
06
27
8c
2f
7f
39
45
74
89
44
45
c6
12
e4
11
4f
0a
60
40
4c
da
97
6f
a6
3b
9a
28
57
81
e0
ab
3d
77
ad
2b
00
2f
1c
88
5e
f7
46
61
02
43
b7
51
ab
4b
ce
a3
88
02
7c
41
06
3b
01
67
91
36
08
73
64
cf
db
13
92
fa
ab
b9
e2
0a
51
77
b9
4b
f5
a3
93
b7
bd
d8
3a
7d
82
34
31
73
b8
78
1b
44
33
44
84
35
4b
71
79
b2
25
aa
be
e9
9f
23
07
95
d1
fb
24
8a
a5
61
5e
85
c0
ad
b4
9b
7f
51
04
71
2b
86
d4
03
4d
45
79
75
d4
1b
7c
88
c0
66
4e
09
1e
47
e9
79
83
03
c3
90
15
83
c1
36
06
ee
d7
88
3a
53
7a
c0
e1
47
06
8b
8c
4a
c0
56
fb
a1
08
ff
10
83
a9
18
6e
c0
5b
33
86
27
a8
dc
e4
3e
5c
41
41
0c
d6
bb
35
a3
30
d2
0b
77
bb
3a
90
34
b4
e3
c4
43
bb
eb
41
b6
69
1f
11
ab
11

View File

@@ -0,0 +1 @@
d026bb15f52e8df87779ff953ccf42a9d5401111c402c448d77cb291bbe6aa1e

View File

@@ -0,0 +1 @@
4c660325d7e121da05bc9389a09fd51d982d8990a27da29834af1930b2c4b089

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,800 @@
36
31
00
8f
71
83
b4
9b
55
f5
c4
b6
43
19
36
a5
cc
87
17
49
cd
95
e8
c6
5f
02
3a
f1
ab
06
13
5c
70
2c
f2
c1
51
12
c1
29
f7
48
93
33
70
10
42
4a
82
c1
79
28
53
8e
93
90
42
45
29
4b
e1
66
5d
cd
f7
a4
68
57
9d
03
d0
cc
50
9b
50
96
f7
a0
43
e4
5c
67
03
62
dc
18
bc
52
45
b0
c6
94
cf
6f
49
21
17
d1
57
74
28
c8
bc
e8
87
1b
78
66
9c
95
1b
07
a8
57
75
11
b0
8b
86
57
36
0b
cb
7a
59
06
0a
23
6b
b3
77
28
87
d9
b6
ff
48
21
bf
f7
54
fb
e8
40
f2
27
4e
81
95
13
9c
47
2d
bb
f9
6a
72
37
1a
30
05
9e
55
ea
84
31
3c
5f
fb
c9
61
27
92
43
69
7c
0d
61
23
cc
a8
36
54
c5
1c
25
e3
4b
c5
ed
63
67
79
89
05
cd
93
4e
21
01
74
fb
17
5e
d0
33
87
da
1c
31
4d
37
34
cb
28
1d
b0
61
1f
eb
a3
85
90
58
4b
41
90
12
a2
34
78
29
51
9a
00
fc
aa
33
67
1e
42
a5
3a
e0
80
7c
11
74
9b
dd
fa
90
b5
05
b8
62
45
6a
b3
cb
ab
9b
42
43
e3
01
5c
05
18
36
bd
b2
33
bb
81
4e
f9
10
29
00
a5
cd
cc
a2
ab
57
f6
bd
af
ba
4b
60
23
09
50
00
b1
9a
cc
11
0e
33
6a
a0
12
ba
6b
91
11
a9
d6
c3
0a
06
a2
db
36
84
25
25
29
7e
44
73
89
a7
90
4d
93
36
0d
64
0d
48
78
0d
fb
64
59
22
d0
a0
5b
88
33
85
78
34
e8
89
a2
41
9c
2b
97
45
3e
3f
ab
cc
f0
64
20
06
c6
a7
ad
c7
a9
86
87
59
ae
11
cd
e6
a6
8a
da
ca
3f
6e
a4
7e
c5
73
a6
4b
89
c7
ad
26
33
ed
57
15
91
71
1d
9d
53
10
e9
d8
3c
69
97
b6
ae
31
7f
3f
c7
01
1a
a0
b9
fc
17
11
56
77
9b
85
ea
47
08
27
6d
dc
f9
6b
b8
00
17
32
40
08
e8
23
55
e7
81
84
fb
98
79
d3
f4
2c
87
d9
56
2d
f3
4c
55
14
6d
42
4a
15
0f
11
12
36
49
53
30
48
08
b6
d5
ba
66
d2
83
2a
a5
32
d0
d4
21
2d
f7
b3
85
47
7e
b5
7a
ae
f2
f3
85
a5
46
60
ae
dc
b4
ed
d9
6e
bd
fb
05
0b
d8
1d
eb
3a
09
aa
fc
a5
11
52
82
ce
74
c4
39
26
24
c9
74
a9
4a
60
12
95
33
02
09
d5
9f
0a
00
33
37
97
90
ae
bb
5b
43
d5
18
06
6a
5a
41
74
93
36
88
a6
41
41
c1
dc
a3
2e
21
a6
79
33
10
b3
1b
e1
9e
72
1b
5a
e5
a8
3b
45
d4
24
ed
02
67
ec
36
3a
8a
95
6a
e6
4b
1c
14
04
70
65
60
27
09
5b
14
85
90
26
0f
90
99
08
dc
82
c4
74
ab
d4
e3
95
4e
54
28
8e
76
05
ee
33
81
c0
c1
b4
53
ba
a2
2b
50
6c
3c
3a
3e
3a
dc
38
51
a5
36
eb
b7
48
3d
52
a3
4c
3c
1d
10
09
76
b3
6a
21
f7
b9
21
82
fa
38
ce
10
b6
90
f5
7e
33
86
1c
34
97
27
a6
d7
9d
f4
56
70
f3
e8
83
44
b4
3d
0b
79
0e
4b
ba
92
bd
60
b4
fd
6a
5e
1c
9b
60
b4
eb
10
b7
11
00
d9
95
58
c9
d1
26
df
79
84
a3
7c
60
a8
49
75
b1
ea
ba
a0
26
29
f4
2b
35
e5
bc
90
7e
09
3e
96
8b
56
d7
d9
1e
a2
a6
26
0c
86
6e
5b
83
cc
ee
54
30
33
45
13
8a
e9
7c
55
f5
78
a6
ec
3b
40
58
b7
d1
e1
4a
c9
2e
37
0c
f7
70
04
2a
d3
f7
15
23
59
22
6c
2c
2a
bc
6b
cb
87
46
2f

View File

@@ -0,0 +1 @@
ceb50eb4b3aef8f26edd5fa3e9a981332e03d08876a872a111510801ebd485b5

View File

@@ -0,0 +1 @@
199df3f68d5bceaff94649482882cac90c9d9d5c0e68b54a0dc2d849aba2458d

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,800 @@
a1
dc
74
33
29
94
bc
28
99
c8
5b
59
a4
d4
3d
2e
f0
8f
5c
1a
a6
7a
48
72
c4
c3
55
d3
66
4f
08
69
9a
8a
e8
5f
17
d7
44
50
b6
28
c5
f3
1b
de
38
47
21
d7
3a
cb
51
ab
cf
b3
61
d8
50
18
4d
92
5e
01
3a
0a
83
52
95
35
c9
b2
62
c7
c4
8f
81
b9
5e
69
3e
24
28
78
d0
16
89
02
c4
1c
14
a8
a3
d5
60
cd
31
04
4b
7e
46
59
c1
c9
cb
4c
18
59
31
97
60
91
55
59
4a
08
8b
9a
82
7b
c4
73
28
46
aa
c3
53
fa
8c
ff
a4
86
a0
d8
4d
36
83
14
e6
59
17
f7
39
8c
6b
d1
2f
22
37
00
b1
7b
88
3b
eb
bd
f1
2c
1a
42
e8
9c
95
85
53
d0
68
6c
f7
68
3c
af
71
24
37
27
af
e2
24
9b
00
97
25
87
33
5f
6b
00
52
cd
21
77
80
0a
4f
a1
22
57
25
e0
8b
95
51
cd
a1
e4
5b
a6
e3
cd
bb
71
73
0c
b7
2a
1f
1c
6c
f1
bc
58
52
0c
9e
52
20
3c
68
95
1c
27
98
52
3c
20
38
ba
68
01
fb
3c
32
1c
f5
ca
21
8c
68
0c
32
0b
34
46
ab
15
3a
3c
4c
d7
cb
ca
35
6b
58
d2
54
b6
a2
4a
67
22
58
d1
a8
bd
36
a8
1b
e9
7b
51
5e
b4
21
22
f3
2a
7d
39
7b
2f
cb
03
99
46
c3
8e
41
b5
b4
c5
76
4c
6c
50
c2
90
a4
05
aa
74
6c
52
7c
51
35
8b
c0
9c
5b
52
da
33
a0
94
6c
9d
8a
2f
0d
a3
ba
7a
24
91
3d
83
b4
d9
09
91
3e
2c
55
bf
b5
02
0f
6c
87
68
82
71
e0
17
88
88
9c
97
b1
2a
b8
89
05
b4
9a
6c
02
d3
40
0b
7a
61
72
fb
b1
06
c0
16
c8
5c
c7
07
3f
a7
88
a8
e3
7f
f2
a2
a7
7d
66
4a
a1
a6
a0
cb
c9
34
2e
68
49
54
95
76
51
46
2c
b2
db
74
02
c6
5a
2e
c9
8d
58
44
1e
57
16
6c
66
4a
8a
75
3a
69
98
7b
19
30
95
90
97
e9
88
c7
da
31
94
24
62
c8
36
28
a8
1b
ce
f6
d4
28
80
f6
03
98
08
c7
27
bc
cc
6d
20
44
39
56
b2
a2
d4
8f
58
a8
79
72
97
cf
e8
e3
29
01
d4
68
f8
05
4a
f6
58
c7
b3
b7
ce
d2
92
c3
86
64
07
c1
a7
79
59
68
1c
25
b4
6c
34
55
71
63
79
19
44
80
36
33
57
23
c1
7b
52
26
07
41
59
21
9f
47
9b
25
53
86
4c
66
53
a0
bc
74
b0
a1
52
16
0b
f8
8b
50
56
5a
47
b5
4a
97
09
47
55
a0
c1
7c
85
66
cd
92
2a
d4
9b
54
ad
75
c5
bd
50
01
6a
50
9d
7e
ca
81
9b
36
11
0c
93
ae
0e
a4
7a
e4
6a
cb
c4
62
71
15
60
0c
b1
23
65
d1
e6
a9
42
41
31
83
4c
4c
4c
72
44
2d
1a
7c
8e
b7
35
1b
27
7b
e6
0b
70
ec
17
01
11
a3
8a
3c
e0
94
4e
24
2c
ea
26
c4
cb
80
c4
33
65
30
45
a7
bf
4d
9a
6f
09
06
30
6c
00
59
f4
2b
51
28
95
c2
ef
74
4d
b5
a7
72
0a
d0
35
3a
66
7d
43
c4
41
9e
61
48
44
18
80
f7
88
a7
8b
d9
47
19
f0
10
d1
42
24
df
c0
68
a1
c6
c6
b4
60
8e
8b
84
0d
7a
62
68
bf
f3
83
b7
00
1b
e6
e6
6f
bf
e7
74
da
4b
9c
9a
01
c5
c6
2c
55
30
81
96
a6
b7
22
04
b5
0a
e3
92
25
c3
1a
8a
ac
c5
9b
e0
9b
a0
33
f4
3d
35
81
35
82
b2
8e
aa
83
9c
70
61
98
14
94
9f
76
8e
11
4b
01
b8
4b
87
87
79
45
82
f8
cd
7f
6f
b0
73
81
77
0e
bb
a5
03
1c
c5

View File

@@ -0,0 +1 @@
d8a6e796ddac221affc15ef4e485b1f6c748a545b7cefc6ab65613797b3cf9a9

View File

@@ -0,0 +1 @@
2426f1941779574d3f1b163bd57f7e173e229e630ec7f7073bdf365137c4bb6d

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,800 @@
80
b7
01
00
83
1d
7e
e1
68
f4
73
92
48
31
19
f9
38
63
ec
b0
bc
60
53
12
d3
57
28
87
6b
00
f5
f5
7a
f4
c8
5e
da
97
28
1d
57
43
90
bc
72
56
19
36
68
dc
98
62
53
54
ab
52
b9
bc
e7
81
c5
77
1c
c2
60
99
f6
fb
ac
be
e1
78
4d
19
48
87
73
1f
09
7c
87
e0
82
cb
ea
c5
7d
30
b7
b9
a2
93
87
2c
84
14
66
f2
24
4c
c6
5f
f4
ba
65
3d
67
51
df
a2
20
51
d5
53
36
99
42
c3
1c
29
f9
13
07
af
57
32
92
d6
97
a8
c3
16
12
e0
7b
53
35
cf
08
32
9f
d2
46
bf
2a
32
20
0a
8c
b0
c4
b0
3b
9d
09
c5
ba
1c
39
19
53
9e
92
29
c6
96
92
43
48
28
2f
69
6b
15
25
e5
60
38
06
b4
db
61
8b
3d
c8
63
0c
b2
86
e4
31
17
21
bc
50
31
f2
57
aa
92
5b
f8
09
60
44
5a
a8
d8
e6
97
88
e9
9d
a9
5c
1d
10
cc
3b
e8
58
52
8d
b0
cf
ea
00
3c
74
69
37
80
a6
5a
36
e6
28
43
b3
be
15
40
65
43
d2
2d
83
50
7c
87
b2
78
67
92
c8
0f
a5
62
84
54
a3
10
39
4d
da
4c
2a
b5
94
93
85
02
57
d6
d3
bc
10
71
86
d9
06
27
07
f3
54
e8
1a
1a
10
fc
b7
63
d3
1a
4e
c4
09
aa
24
3e
d2
e5
9b
b1
89
85
5e
b1
65
62
66
bb
37
50
07
85
ea
08
cd
88
c2
22
a8
c5
3a
87
77
ca
b4
2c
9c
23
8a
00
d5
93
69
42
50
26
e9
9d
2a
e6
04
0a
f6
70
90
29
ca
87
89
c8
97
b3
29
fb
a7
48
d6
9c
8a
71
48
c9
5a
bb
0c
71
78
7c
58
f1
2f
21
f2
21
3e
38
92
42
aa
7f
bd
32
0c
12
ac
42
c6
11
60
6c
b8
c1
d1
b4
62
58
86
a1
45
a5
35
bd
65
bd
0d
99
6b
33
0c
16
57
d6
1a
87
e9
04
17
00
32
25
75
98
20
a3
bb
ec
50
5c
da
f1
11
93
22
9a
ae
17
3c
d1
2b
ad
22
a7
a3
0a
76
a9
fa
76
36
c3
d5
aa
48
e1
78
40
12
a0
12
f1
41
68
b7
85
3d
2a
16
f9
0c
a0
2c
c3
3b
20
06
c0
8f
26
c1
5f
ca
29
61
2c
c7
92
e1
cf
02
e1
32
1a
75
a8
10
89
19
86
66
7d
41
48
af
36
e6
5e
1a
59
25
89
02
96
17
73
4c
31
5c
0e
39
b7
51
8c
86
60
cd
c2
65
d0
c8
13
ef
20
a0
43
31
7f
ae
5b
8e
40
54
6e
ec
f7
1d
6c
05
4f
a6
6b
49
40
13
09
be
f3
0f
d5
1a
55
19
75
5d
a9
10
46
89
b2
6f
08
39
15
4c
84
7b
ef
23
65
94
3c
02
49
48
3a
ad
9a
73
67
c9
80
a3
d1
ce
46
d2
00
8a
15
27
5c
a3
bc
a4
83
4e
6f
9a
30
36
c0
cd
80
ba
22
8d
34
b9
78
02
44
d5
c0
cb
e9
07
c6
fb
43
82
4a
9c
07
46
47
16
39
cb
86
18
8c
60
c3
b2
53
21
5c
c9
16
92
bc
d1
49
3d
6a
44
4d
53
64
46
e0
29
68
13
80
01
cc
28
7e
0e
51
8f
3a
a2
5d
8c
3b
95
b3
c3
5c
59
f4
81
9d
48
49
76
02
9a
f0
5a
26
3c
35
33
6b
26
1f
77
b2
cd
c2
93
89
f0
84
c0
4c
bb
37
0c
48
56
2b
5b
50
77
1c
0f
b8
16
90
8e
19
8d
d6
d5
3f
76
e4
8b
f0
42
c2
b1
f8
2a
3a
40
b8
da
f5
1f
46
d7
6f
a4
bc
c9
d3
c8
94
ff
85
0c
0f
aa
32
e0
ac
33
90
1a
4c
79
13
9f
5f
20
41
7e
c1
a1
90
60
70
44
f1
8b
b8
24
cf
35
0c
78
ab
3d
df
3c
2c
86
ca
55
43
f7
15

View File

@@ -0,0 +1 @@
687acf9406694974d383032f7579378f449c75d0560af56cf921ec48404896f6

View File

@@ -0,0 +1 @@
9b68d9d2390fa18739b239a58649393a28f97f6b164ec5e4334f4df864fc9cd6

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,800 @@
de
e7
89
22
bb
8d
a2
f4
76
4d
ca
45
f8
ea
4c
1f
53
0a
1c
57
1d
3a
d1
92
4b
58
96
98
cb
27
19
e0
69
fd
94
3c
14
52
c5
d1
68
b2
b3
57
b2
65
83
1c
01
9c
b3
55
7a
0b
f7
18
7e
4d
10
8b
f7
70
c7
4d
b4
03
89
cc
71
8f
3b
c1
1c
e3
ab
a8
43
66
ab
24
51
94
b9
41
f8
1b
7a
e7
02
41
9b
b9
8d
73
ba
00
37
83
30
6c
7b
3a
36
77
a5
43
a0
10
0c
31
75
e8
c0
20
ca
26
65
12
90
9c
35
50
c4
f6
5c
0e
a3
e2
4a
47
23
7d
9a
4a
0b
5a
e5
88
f9
83
31
1f
aa
36
e8
91
af
8e
a1
b3
08
c8
31
79
24
61
54
c7
65
ac
5b
5a
15
45
6e
19
33
08
00
28
37
d1
43
54
e0
66
a3
4a
44
09
af
bb
15
08
5a
ad
c9
e2
2b
8d
b5
58
3d
45
b0
a4
ac
72
47
4a
2a
b9
4b
79
2e
53
1a
b0
cb
88
2c
13
a4
13
9a
71
ff
a3
78
3b
53
71
78
f3
4e
11
1b
6c
3f
12
0a
76
d4
cd
ce
c4
61
84
30
35
ac
d2
85
ed
62
7d
8b
d2
b0
b9
97
cc
ce
b4
ad
ae
36
15
a7
3b
ba
0a
7c
7b
b9
b1
33
58
bb
51
ff
8a
57
4d
86
b5
00
02
72
cd
27
0a
0a
1b
24
bb
91
75
06
70
1c
2f
44
1f
c5
b7
9d
d4
51
cb
3c
ac
c7
40
12
7b
d4
11
60
4b
da
c4
64
da
1a
2f
83
91
8c
5b
2f
b6
e5
28
4c
97
2b
93
35
7a
83
78
28
b1
13
26
32
bb
6f
7b
fb
be
c3
d9
47
bd
40
3d
86
99
00
66
db
65
53
72
24
34
c7
c0
e3
99
2f
00
9b
b2
38
f7
a6
b3
e5
25
1e
da
94
3a
77
03
fb
a2
89
aa
20
53
a8
57
79
6c
2c
b9
45
49
4c
0b
a7
91
a9
e3
cb
fa
80
0d
89
88
c8
12
19
97
d9
75
b3
d0
35
95
ad
d6
4a
3e
ac
b8
ba
36
a4
d8
b3
bf
dc
11
b7
d5
62
39
08
7c
90
f3
52
c0
ee
c4
08
57
f0
89
cc
fa
7c
9a
68
3a
1d
e3
cd
8f
f2
8b
22
15
3d
de
23
1e
5f
74
80
5d
68
3e
b8
c3
46
ba
16
c7
fe
68
06
4b
20
59
c8
73
8e
5a
c1
9b
64
d4
34
3f
5c
9d
8b
f9
78
03
02
b0
67
6c
20
2a
21
29
2c
c1
5f
c1
58
9a
69
83
8a
d1
ea
3d
0c
37
06
f8
e1
b0
11
f6
12
99
a5
6e
c2
51
50
51
fb
94
73
4b
30
8a
f3
c3
5e
45
ab
fa
dc
12
8f
e6
98
38
aa
37
08
05
14
d6
c3
74
8c
91
6b
d6
55
08
0a
10
35
ff
1a
76
3e
45
0b
56
86
4c
c2
32
af
ee
53
91
9f
f8
89
a8
20
a7
a6
55
86
31
b8
8f
73
18
c0
33
80
0f
30
7c
19
b2
d0
a8
b6
58
82
d8
77
09
79
a5
70
1a
c6
02
f7
1b
72
a2
6b
82
52
5a
a6
7d
77
c7
5e
b6
87
1d
c0
19
b4
65
58
3a
25
0d
b4
70
49
06
18
7e
8d
fb
3b
70
72
69
88
f9
c5
2c
12
26
6c
63
91
d4
92
6c
b7
99
78
00
7c
a4
6e
f6
08
82
80
6f
fd
59
c6
4e
d7
03
33
98
9a
ac
51
86
99
04
40
b8
9c
3c
d1
36
3b
e4
04
70
6d
bb
63
a5
a0
07
a0
fa
c2
61
a0
28
8f
91
6f
af
0a
a4
e9
44
55
2f
10
80
1a
3a
5d
de
26
33
98
01
5c
c3
52
27
bd
17
11
35
62
51
aa
93
5a
89
bc
2e
3d
2c
08
e1
c9
a8
c1
e4
41
6f
30
3b
b7
3b
31
48
58
ca
4c
21
0c
95
92
83
fc
86
5b
02
77
68
c5
d6
04
7f
d3
6d
bc
bc
4e
df
3e
a5
cc
6a
50
cb
05
2b
cd
31

View File

@@ -0,0 +1 @@
a02e20d538b412ff074d121a80b0583e0b54e85b267da0789c5ca565342ee66d

View File

@@ -0,0 +1 @@
905eb1f02ade542733c35132f5a998d3ec80d20ec8ed235bf228081157034763

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,800 @@
f5
e2
4e
4e
14
b6
65
36
65
ca
02
89
a3
72
8c
bb
a2
28
fe
11
67
26
c1
25
1e
99
92
a9
f0
06
09
34
64
5b
26
23
24
ac
b5
c6
b5
7d
26
e3
92
26
e2
2c
f0
c3
3f
7f
f5
a4
d9
79
23
4f
2b
79
49
f5
66
db
66
c3
5b
27
3d
c9
77
8a
64
f2
bc
fe
91
4c
0d
81
52
7d
41
8a
11
25
79
e5
d0
8b
1c
42
95
87
32
34
25
d7
a7
83
51
45
34
57
cd
86
83
45
af
a1
62
18
33
20
02
c9
5d
84
06
c1
49
38
c0
39
69
3d
6c
12
16
af
b9
98
30
99
03
11
09
be
01
93
a1
b6
e1
24
36
10
3f
dd
08
4a
7b
84
38
0a
cc
35
81
78
31
c0
55
8d
4f
80
82
ba
58
b9
17
48
41
a8
40
c2
96
48
53
65
6c
23
27
f7
95
21
32
c6
dd
12
9d
bf
50
23
ce
1b
3a
92
f7
73
6f
c1
95
28
b7
1d
21
a2
7c
3d
7b
74
51
d5
a8
fc
02
a7
86
f7
55
45
d2
45
15
49
bc
95
db
bb
87
72
4f
72
d2
ad
f1
d6
19
b1
b9
43
86
c1
4c
37
12
8c
2c
1c
60
f4
c0
2b
28
cc
53
6c
50
8a
37
0b
a9
a2
f4
61
8c
f1
c6
4f
35
56
84
f2
5a
6e
e9
9d
3f
89
ce
01
36
b4
7d
7b
26
f0
e6
a6
0c
c9
4f
c4
57
38
34
17
2a
3e
fb
84
c9
fb
66
40
1b
76
c9
00
07
e8
f7
b1
9b
51
32
92
13
8b
79
14
7a
36
46
80
db
cb
21
17
62
35
8c
d3
2a
3c
44
72
0d
f6
ba
22
dc
8d
30
19
c0
c4
80
3f
2a
56
7d
9e
bc
6a
5b
c0
12
d1
f6
34
71
98
91
da
13
24
ea
f2
28
37
92
64
b3
da
95
5d
aa
3a
2f
b8
83
68
94
c8
e8
00
06
78
21
41
25
7c
25
4d
90
5a
23
8a
6b
41
ac
3c
76
cb
87
ea
34
27
28
ea
6e
48
bc
66
81
68
42
ff
24
55
e8
5c
67
f8
c4
88
74
f4
69
bd
a5
6f
dd
83
a5
7d
d4
07
67
98
a3
d8
54
ce
40
bc
c6
b3
49
a1
98
fc
6f
a4
71
3c
94
79
49
46
e2
49
20
17
79
70
9a
b7
51
04
59
e2
fa
32
5b
b3
c8
16
b2
af
3d
9c
af
36
fa
5c
21
73
79
cf
eb
79
7a
90
80
fe
23
37
4f
a0
2f
04
7c
77
5c
b4
60
2b
78
59
f7
d7
9c
0a
f7
3f
11
b4
28
47
91
5b
3d
32
46
e1
04
40
31
f6
1b
aa
d9
87
f3
c6
cc
93
28
0b
23
c8
39
0e
48
a2
10
80
92
c7
b4
19
ba
e1
3a
e5
00
67
81
3a
99
b5
da
80
e5
80
05
c6
96
5f
fe
45
3a
e5
73
50
1b
24
21
24
51
52
57
c4
06
27
8c
2f
7f
39
45
74
89
44
45
c6
12
e4
11
4f
0a
60
40
4c
da
97
6f
a6
3b
9a
28
57
81
e0
ab
3d
77
ad
2b
00
2f
1c
88
5e
f7
46
61
02
43
b7
51
ab
4b
ce
a3
88
02
7c
41
06
3b
01
67
91
36
08
73
64
cf
db
13
92
fa
ab
b9
e2
0a
51
77
b9
4b
f5
a3
93
b7
bd
d8
3a
7d
82
34
31
73
b8
78
1b
44
33
44
84
35
4b
71
79
b2
25
aa
be
e9
9f
23
07
95
d1
fb
24
8a
a5
61
5e
85
c0
ad
b4
9b
7f
51
04
71
2b
86
d4
03
4d
45
79
75
d4
1b
7c
88
c0
66
4e
09
1e
47
e9
79
83
03
c3
90
15
83
c1
36
06
ee
d7
88
3a
53
7a
c0
e1
47
06
8b
8c
4a
c0
56
fb
a1
08
ff
10
83
a9
18
6e
c0
5b
33
86
27
a8
dc
e4
3e
5c
41
41
0c
d6
bb
35
a3
30
d2
0b
77
bb
3a
90
34
b4
e3
c4
43
bb
eb
41
b6
69
1f
11
ab
11

View File

@@ -0,0 +1 @@
d026bb15f52e8df87779ff953ccf42a9d5401111c402c448d77cb291bbe6aa1e

View File

@@ -0,0 +1 @@
4c660325d7e121da05bc9389a09fd51d982d8990a27da29834af1930b2c4b089

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,800 @@
36
31
00
8f
71
83
b4
9b
55
f5
c4
b6
43
19
36
a5
cc
87
17
49
cd
95
e8
c6
5f
02
3a
f1
ab
06
13
5c
70
2c
f2
c1
51
12
c1
29
f7
48
93
33
70
10
42
4a
82
c1
79
28
53
8e
93
90
42
45
29
4b
e1
66
5d
cd
f7
a4
68
57
9d
03
d0
cc
50
9b
50
96
f7
a0
43
e4
5c
67
03
62
dc
18
bc
52
45
b0
c6
94
cf
6f
49
21
17
d1
57
74
28
c8
bc
e8
87
1b
78
66
9c
95
1b
07
a8
57
75
11
b0
8b
86
57
36
0b
cb
7a
59
06
0a
23
6b
b3
77
28
87
d9
b6
ff
48
21
bf
f7
54
fb
e8
40
f2
27
4e
81
95
13
9c
47
2d
bb
f9
6a
72
37
1a
30
05
9e
55
ea
84
31
3c
5f
fb
c9
61
27
92
43
69
7c
0d
61
23
cc
a8
36
54
c5
1c
25
e3
4b
c5
ed
63
67
79
89
05
cd
93
4e
21
01
74
fb
17
5e
d0
33
87
da
1c
31
4d
37
34
cb
28
1d
b0
61
1f
eb
a3
85
90
58
4b
41
90
12
a2
34
78
29
51
9a
00
fc
aa
33
67
1e
42
a5
3a
e0
80
7c
11
74
9b
dd
fa
90
b5
05
b8
62
45
6a
b3
cb
ab
9b
42
43
e3
01
5c
05
18
36
bd
b2
33
bb
81
4e
f9
10
29
00
a5
cd
cc
a2
ab
57
f6
bd
af
ba
4b
60
23
09
50
00
b1
9a
cc
11
0e
33
6a
a0
12
ba
6b
91
11
a9
d6
c3
0a
06
a2
db
36
84
25
25
29
7e
44
73
89
a7
90
4d
93
36
0d
64
0d
48
78
0d
fb
64
59
22
d0
a0
5b
88
33
85
78
34
e8
89
a2
41
9c
2b
97
45
3e
3f
ab
cc
f0
64
20
06
c6
a7
ad
c7
a9
86
87
59
ae
11
cd
e6
a6
8a
da
ca
3f
6e
a4
7e
c5
73
a6
4b
89
c7
ad
26
33
ed
57
15
91
71
1d
9d
53
10
e9
d8
3c
69
97
b6
ae
31
7f
3f
c7
01
1a
a0
b9
fc
17
11
56
77
9b
85
ea
47
08
27
6d
dc
f9
6b
b8
00
17
32
40
08
e8
23
55
e7
81
84
fb
98
79
d3
f4
2c
87
d9
56
2d
f3
4c
55
14
6d
42
4a
15
0f
11
12
36
49
53
30
48
08
b6
d5
ba
66
d2
83
2a
a5
32
d0
d4
21
2d
f7
b3
85
47
7e
b5
7a
ae
f2
f3
85
a5
46
60
ae
dc
b4
ed
d9
6e
bd
fb
05
0b
d8
1d
eb
3a
09
aa
fc
a5
11
52
82
ce
74
c4
39
26
24
c9
74
a9
4a
60
12
95
33
02
09
d5
9f
0a
00
33
37
97
90
ae
bb
5b
43
d5
18
06
6a
5a
41
74
93
36
88
a6
41
41
c1
dc
a3
2e
21
a6
79
33
10
b3
1b
e1
9e
72
1b
5a
e5
a8
3b
45
d4
24
ed
02
67
ec
36
3a
8a
95
6a
e6
4b
1c
14
04
70
65
60
27
09
5b
14
85
90
26
0f
90
99
08
dc
82
c4
74
ab
d4
e3
95
4e
54
28
8e
76
05
ee
33
81
c0
c1
b4
53
ba
a2
2b
50
6c
3c
3a
3e
3a
dc
38
51
a5
36
eb
b7
48
3d
52
a3
4c
3c
1d
10
09
76
b3
6a
21
f7
b9
21
82
fa
38
ce
10
b6
90
f5
7e
33
86
1c
34
97
27
a6
d7
9d
f4
56
70
f3
e8
83
44
b4
3d
0b
79
0e
4b
ba
92
bd
60
b4
fd
6a
5e
1c
9b
60
b4
eb
10
b7
11
00
d9
95
58
c9
d1
26
df
79
84
a3
7c
60
a8
49
75
b1
ea
ba
a0
26
29
f4
2b
35
e5
bc
90
7e
09
3e
96
8b
56
d7
d9
1e
a2
a6
26
0c
86
6e
5b
83
cc
ee
54
30
33
45
13
8a
e9
7c
55
f5
78
a6
ec
3b
40
58
b7
d1
e1
4a
c9
2e
37
0c
f7
70
04
2a
d3
f7
15
23
59
22
6c
2c
2a
bc
6b
cb
87
46
2f

View File

@@ -0,0 +1 @@
ceb50eb4b3aef8f26edd5fa3e9a981332e03d08876a872a111510801ebd485b5

View File

@@ -0,0 +1 @@
199df3f68d5bceaff94649482882cac90c9d9d5c0e68b54a0dc2d849aba2458d

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,800 @@
a1
dc
74
33
29
94
bc
28
99
c8
5b
59
a4
d4
3d
2e
f0
8f
5c
1a
a6
7a
48
72
c4
c3
55
d3
66
4f
08
69
9a
8a
e8
5f
17
d7
44
50
b6
28
c5
f3
1b
de
38
47
21
d7
3a
cb
51
ab
cf
b3
61
d8
50
18
4d
92
5e
01
3a
0a
83
52
95
35
c9
b2
62
c7
c4
8f
81
b9
5e
69
3e
24
28
78
d0
16
89
02
c4
1c
14
a8
a3
d5
60
cd
31
04
4b
7e
46
59
c1
c9
cb
4c
18
59
31
97
60
91
55
59
4a
08
8b
9a
82
7b
c4
73
28
46
aa
c3
53
fa
8c
ff
a4
86
a0
d8
4d
36
83
14
e6
59
17
f7
39
8c
6b
d1
2f
22
37
00
b1
7b
88
3b
eb
bd
f1
2c
1a
42
e8
9c
95
85
53
d0
68
6c
f7
68
3c
af
71
24
37
27
af
e2
24
9b
00
97
25
87
33
5f
6b
00
52
cd
21
77
80
0a
4f
a1
22
57
25
e0
8b
95
51
cd
a1
e4
5b
a6
e3
cd
bb
71
73
0c
b7
2a
1f
1c
6c
f1
bc
58
52
0c
9e
52
20
3c
68
95
1c
27
98
52
3c
20
38
ba
68
01
fb
3c
32
1c
f5
ca
21
8c
68
0c
32
0b
34
46
ab
15
3a
3c
4c
d7
cb
ca
35
6b
58
d2
54
b6
a2
4a
67
22
58
d1
a8
bd
36
a8
1b
e9
7b
51
5e
b4
21
22
f3
2a
7d
39
7b
2f
cb
03
99
46
c3
8e
41
b5
b4
c5
76
4c
6c
50
c2
90
a4
05
aa
74
6c
52
7c
51
35
8b
c0
9c
5b
52
da
33
a0
94
6c
9d
8a
2f
0d
a3
ba
7a
24
91
3d
83
b4
d9
09
91
3e
2c
55
bf
b5
02
0f
6c
87
68
82
71
e0
17
88
88
9c
97
b1
2a
b8
89
05
b4
9a
6c
02
d3
40
0b
7a
61
72
fb
b1
06
c0
16
c8
5c
c7
07
3f
a7
88
a8
e3
7f
f2
a2
a7
7d
66
4a
a1
a6
a0
cb
c9
34
2e
68
49
54
95
76
51
46
2c
b2
db
74
02
c6
5a
2e
c9
8d
58
44
1e
57
16
6c
66
4a
8a
75
3a
69
98
7b
19
30
95
90
97
e9
88
c7
da
31
94
24
62
c8
36
28
a8
1b
ce
f6
d4
28
80
f6
03
98
08
c7
27
bc
cc
6d
20
44
39
56
b2
a2
d4
8f
58
a8
79
72
97
cf
e8
e3
29
01
d4
68
f8
05
4a
f6
58
c7
b3
b7
ce
d2
92
c3
86
64
07
c1
a7
79
59
68
1c
25
b4
6c
34
55
71
63
79
19
44
80
36
33
57
23
c1
7b
52
26
07
41
59
21
9f
47
9b
25
53
86
4c
66
53
a0
bc
74
b0
a1
52
16
0b
f8
8b
50
56
5a
47
b5
4a
97
09
47
55
a0
c1
7c
85
66
cd
92
2a
d4
9b
54
ad
75
c5
bd
50
01
6a
50
9d
7e
ca
81
9b
36
11
0c
93
ae
0e
a4
7a
e4
6a
cb
c4
62
71
15
60
0c
b1
23
65
d1
e6
a9
42
41
31
83
4c
4c
4c
72
44
2d
1a
7c
8e
b7
35
1b
27
7b
e6
0b
70
ec
17
01
11
a3
8a
3c
e0
94
4e
24
2c
ea
26
c4
cb
80
c4
33
65
30
45
a7
bf
4d
9a
6f
09
06
30
6c
00
59
f4
2b
51
28
95
c2
ef
74
4d
b5
a7
72
0a
d0
35
3a
66
7d
43
c4
41
9e
61
48
44
18
80
f7
88
a7
8b
d9
47
19
f0
10
d1
42
24
df
c0
68
a1
c6
c6
b4
60
8e
8b
84
0d
7a
62
68
bf
f3
83
b7
00
1b
e6
e6
6f
bf
e7
74
da
4b
9c
9a
01
c5
c6
2c
55
30
81
96
a6
b7
22
04
b5
0a
e3
92
25
c3
1a
8a
ac
c5
9b
e0
9b
a0
33
f4
3d
35
81
35
82
b2
8e
aa
83
9c
70
61
98
14
94
9f
76
8e
11
4b
01
b8
4b
87
87
79
45
82
f8
cd
7f
6f
b0
73
81
77
0e
bb
a5
03
1c
c5

View File

@@ -0,0 +1 @@
d8a6e796ddac221affc15ef4e485b1f6c748a545b7cefc6ab65613797b3cf9a9

View File

@@ -0,0 +1 @@
2426f1941779574d3f1b163bd57f7e173e229e630ec7f7073bdf365137c4bb6d

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@
687acf9406694974d383032f7579378f449c75d0560af56cf921ec48404896f6

View File

@@ -0,0 +1 @@
9b68d9d2390fa18739b239a58649393a28f97f6b164ec5e4334f4df864fc9cd6

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@
a02e20d538b412ff074d121a80b0583e0b54e85b267da0789c5ca565342ee66d

View File

@@ -0,0 +1 @@
905eb1f02ade542733c35132f5a998d3ec80d20ec8ed235bf228081157034763

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@
d026bb15f52e8df87779ff953ccf42a9d5401111c402c448d77cb291bbe6aa1e

View File

@@ -0,0 +1 @@
2426f1941779574d3f1b163bd57f7e173e229e630ec7f7073bdf365137c4bb6d

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@
687acf9406694974d383032f7579378f449c75d0560af56cf921ec48404896f6

View File

@@ -0,0 +1 @@
9b68d9d2390fa18739b239a58649393a28f97f6b164ec5e4334f4df864fc9cd6

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@
a02e20d538b412ff074d121a80b0583e0b54e85b267da0789c5ca565342ee66d

View File

@@ -0,0 +1 @@
905eb1f02ade542733c35132f5a998d3ec80d20ec8ed235bf228081157034763

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@
d026bb15f52e8df87779ff953ccf42a9d5401111c402c448d77cb291bbe6aa1e

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,512 @@
780
01b
300
1d8
17e
68e
3f4
927
148
193
8f9
633
0ec
bcb
360
125
7d3
285
b87
006
5f5
7af
8f4
5ec
7da
289
71d
435
c90
72b
956
361
c68
98d
362
545
2ab
b95
7bc
81e
7c5
1c7
0c2
996
bf6
acf
1be
78e
94d
481
387
1f7
c09
877
2e0
cb8
5ea
7dc
730
b9b
3a2
879
42c
148
266
24f
64c
5fc
af4
65b
73d
516
2df
20a
551
53d
936
429
cc3
291
3f9
071
7af
325
692
97d
3a8
16c
012
7be
553
cf3
208
9f3
6d2
bf4
22a
203
c0a
b08
0c4
3bb
99d
c50
cba
391
319
9e5
992
c62
296
439
848
2f2
b69
156
525
60e
638
b40
1db
8b6
83d
63c
20c
86b
1e4
173
c21
50b
231
57f
2aa
5b9
9f8
600
a44
a85
6d8
97e
988
9de
ca9
1d5
c10
3bc
8e8
525
08d
cfb
0ea
3c0
974
376
680
5aa
636
28e
343
beb
015
654
243
2dd
083
7c5
287
78b
267
c89
50f
62a
484
a35
910
4d3
cda
2a4
4b5
939
285
570
3d6
bcd
110
867
6d9
270
307
54f
ae8
1a1
c10
b7f
363
1ad
44e
09c
4aa
3e2
5d2
9be
9b1
858
15e
65b
662
bb6
037
075
a85
08e
8cd
c28
822
c5a
73a
778
4ca
2cb
39c
8a2
500
93d
269
504
926
9de
62a
04e
60a
70f
990
ca2
987
c88
397
29b
7fb
48a
cd6
8a9
871
c94
b5a
0cb
871
7c7
158
2ff
221
21f
83e
923
a42
7fa
2bd
0c3
c12
42a
1c6
601
86c
c1b
4d1
62b
658
a18
545
35a
5bd
bd6
90d
6b9
c33
160
657
1ad
987
04e
017
320
525
987
320
bba
0ec
5c5
1da
11f
293
9a2
7ae
3c1
bd1
ad2
722
a3a
60a
a97
6fa
367
5c3
aad
148
78e
240
a01
112
41f
768
85b
a3d
162
cf9
a00
32c
3bc
620
c00
68f
c12
a5f
29c
c61
c72
192
cfe
102
32e
51a
a87
910
198
686
7d6
841
af4
636
5ee
91a
255
289
960
317
4c7
c31
0e5
739
51b
68c
608
2cd
65c
8d0
13c
0ef
a02
143
7f3
bae
8e5
440
6e5
7ec
1df
56c
4f0
ba6
496
340
091
3be
0ff
ad5
551
519
5d7
0a9
461
289
6fb
908
153
44c
7b8
3ef
652
c94
023
849
3a4
aad
739
967
80c
1a3
ced
246
00d
58a
271
35c
bca
3a4
4e8
a6f
309
036
cdc
a80
22b
48d
b93
278
440
0d5
cbc
7e9
c60
3fb
824
c4a
079
746
164
b39
86c
c18
608
2c3
53b
c21
c95
216
bc9
9d1
3d4
46a
4d4
453
466
9e0
682
013
018
8cc
7e2
10e
8f5
23a
5da
b8c
953
3b3
5cc
459
81f
89d
494
276
9a0
af0
265
53c
333
66b
1f2
277
cdb
3c2
899
4f0
c08
b4c
37b
80c
564
b2b
505
c77
0f1
6b8
901
98e
8d1
5d6
3fd
476
8be
2f0
c24
8b1
2af
03a
b84
5da
1ff
746
6fd
ca4
c9b
8d3
94c
5ff
0c8
a0f
32a
ce0
33a
a90
4c1

View File

@@ -0,0 +1,43 @@
# xsim_run.tcl - Vivado XSIM for mlkem_top ML-KEM KeyGen, all K in {2,3,4}.
#
# Compiles the full KeyGen datapath + leaf modules, then runs the parametric
# NIST KAT testbench for ML-KEM-512 (K=2), 768 (K=3), 1024 (K=4). Each case
# verifies ek==KAT.pk and dk==KAT.sk byte-exact.
#
# ./run_tb.sh top
# ---- 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/ntt/barrett_mul.v
xvlog -sv --relax -i . sync_rtl/ntt/zeta_rom.v
xvlog -sv --relax -i . sync_rtl/ntt/butterfly_unit.v
xvlog -sv --relax -i . sync_rtl/ntt/ntt_core.v
xvlog -sv --relax -i . sync_rtl/poly_mul/basecase_mul.v
xvlog -sv --relax -i . sync_rtl/poly_mul/poly_mul_zeta_rom.v
xvlog -sv --relax -i . sync_rtl/poly_mul/poly_mul_sync.v
xvlog -sv --relax -i . sync_rtl/top/mlkem_top.v
# ---- Step 2: compile parametric KAT testbench ----
xvlog -sv --relax sync_rtl/top/TB/tb_mlkem_kg_katK_xsim.v
# ---- Step 3: elaborate one snapshot per K ----
xelab tb_mlkem_kg_katK_xsim -generic_top KP=2 -s mlkem_kg_k2 --timescale 1ns/1ps
xelab tb_mlkem_kg_katK_xsim -generic_top KP=3 -s mlkem_kg_k3 --timescale 1ns/1ps
xelab tb_mlkem_kg_katK_xsim -generic_top KP=4 -s mlkem_kg_k4 --timescale 1ns/1ps
# ---- Step 4: run KAT cases (K=2: 0..4, K=3/4: 0..2) ----
xsim mlkem_kg_k2 -R -testplusarg CASE=0
xsim mlkem_kg_k2 -R -testplusarg CASE=1
xsim mlkem_kg_k2 -R -testplusarg CASE=2
xsim mlkem_kg_k2 -R -testplusarg CASE=3
xsim mlkem_kg_k2 -R -testplusarg CASE=4
xsim mlkem_kg_k3 -R -testplusarg CASE=0
xsim mlkem_kg_k3 -R -testplusarg CASE=1
xsim mlkem_kg_k3 -R -testplusarg CASE=2
xsim mlkem_kg_k4 -R -testplusarg CASE=0
xsim mlkem_kg_k4 -R -testplusarg CASE=1
xsim mlkem_kg_k4 -R -testplusarg CASE=2

Some files were not shown because too many files have changed in this diff Show More