feat(dec): Decaps D5 - (K',r')=G(m'||h) + K-bar=J(z||c)

FO transform hash derivations (FIPS 203 Alg 17 steps 6-7), reusing the
shared SHA3 core:

- ST_DEC_G: (K',r') = G(m'||h) via the single-block SHA3-512 path (mode 11,
  dec_g_data = {hek_r, mprime_r}; h was captured into hek_r at D0 load).
  K' -> ss_r (candidate shared secret, ss_o), r' -> r_r (PRF seed for D6).
- ST_DEC_J: K-bar = J(z||c) via the multi-block absorb port (mb_en=1),
  modeled on the H(ek) machine: assemble 136-byte blocks, byte source is
  z_r (g<32), c_in_bram (32<=g<msglen), or SHAKE256 pad (0x1F suffix, last
  byte |=0x80 -- the only difference from H's 0x06). mb_* inputs muxed
  between H and J by state. K-bar -> kbar_r (dbg_kbar_o).
- FSM: MENC -> G -> J -> DONE.

Bring-up note: c_in_bram read through cin_rd_addr_r (a register) plus the
registered BRAM is 2-cycle latency, but the assemble/writeback pipeline only
budgets 1 -- so the first c byte at the z->c boundary read X and poisoned the
whole sponge. Fixed by driving cin_rd_addr combinationally from dj_c_idx
during ST_DEC_J (dropping the register stage) so data lands the next cycle.

Verified: dec D5 K=2/3/4 all cases PASS (ct 768/1088/1568B -> 6/9/12 J blocks);
K' matches the KAT shared secret for valid ciphertexts; KeyGen + Encaps
unregressed.
This commit is contained in:
2026-06-29 20:37:03 +08:00
parent 7f519fe826
commit 189411e8d1
39 changed files with 11352 additions and 21 deletions

View File

@@ -66,7 +66,7 @@
- **D2 — s_hat 解码 + u_hat = NTT(u')** ✅:复用 Encaps TDEC 机(ST_DEC_SDEC),字节源从 ek 切到 dkp_bram(td_byte mux + dkp_rd_addr 在 SDEC 走 td_ekaddr),s_hat 写 bank_a slot j*K(与 t_hat 同布局,D3 MAC 可直接读)。复用前向 NTT 机(ST_DEC_NTT,n_slot_max=k_r)对 bank_se rel 0..K-1 的 u' 原地变换成 u_hat。**踩坑:NTT 原地覆盖 u' → verify_d1 复查 u' 必失败;改为 verify_d1 只查 v'(bank_t 未动),u' 正确性由 u_hat==NTT(u') golden 传递性证明。** K=2/3/4 全过,KG/Enc 回归通过。
- **D3 — w = v' INTT(Σ s∘u_hat)** ✅:复用 Encaps V 机(ST_DEC_W,u_row=0 单多项式)。MAC s_hat[j](bank_a slot j*K)∘ u_hat[j](bank_se rel j)→psum bank_t[UPSUM],与 V MAC 完全同址,免改。INTT 原地。SUB:w = v' psum,(v'psum) 负则 +Q。**关键:v'/psum 读口冲突 → D1 把 v' 落到 bank_a slot DEC_VASLOT=1(s_hat 在 j*K,slot 1 恒空 K≥2),SUB 时 psum(bank_t)+v'(bank_a)并行读,正如 V-ADD 并读 psum+e2。** K=2/3/4 w 全过。
- **D4 — m' = byteEncode₁(Compress₁(w))** ✅:ST_DEC_MENC,逐系数读 bank_t[UPSUM] 的 w,Compress₁(w)=1 iff 832<w≤2496(Q=3329),LSB-first 打包进 mprime_r[255:0],经 dbg_mprime_o 暴露。TB verify_d4 对 32 字节 golden(== KAT 解密的 m'==原始 m)。K=2/3/4 全过,KG/Enc 回归通过。K-PKE.Decrypt 硬件全链路打通。
- **D5 — G(m'‖h) → (K',r') + J(z‖c) → K̄**:G 复用、J 多块(0x1F pad)。dbg 对 K'/r'/K̄
- **D5 — G(m'‖h) → (K',r') + J(z‖c) → K̄**:G 复用单块 SHA3-512 路径(ST_DEC_G,mode=11,dec_g_data={hek_r,mprime_r}),输出 K'→ss_r(候选 ss,ss_o),r'→r_r(D6 PRF 种子,dbg_r_o)。J 复用多块吸收口(ST_DEC_J,mb_en=1),仿照 H(ek) 机器组装 136B/块,字节源 g<32 取 z_r、32≤g<msglen 取 c_in_bram、否则 SHAKE256 pad(0x1F 后缀,末字节|0x80,与 H 的 0x06 唯一区别)。mb_* 端口按 ST_DEC_J 在 H/J 间多路选择。K̄→kbar_r(dbg_kbar_o)。**踩坑:c_in_bram 读经 cin_rd_addr_r 寄存器 + BRAM 寄存 = 2 拍延迟,而组装/写回流水只容 1 拍 → z→c 边界首个 c 字节(byte32)读到 X,毒化整个 keccak。改为 ST_DEC_J 时 cin_rd_addr 组合直接取 dj_c_idx(去掉寄存器级),数据次拍到达正好对齐写回。** K=2/3/4(密文 768/1088/1568B → 6/9/12 块)全过;K'==KAT ss(有效密文)验证 FO 正确;KG/Enc 回归通过
- **D6 — c' = Encrypt(ek_pke,m',r')**:复用 Encaps E1E7 写 ct_bram。dbg 对 c'==KAT.ct(有效 ct 时)。
- **D7 — 比较 + 拒绝 mux + 端到端 KAT**:c'==c 常量时间比较,ss=mux。干净 TB:
- 有效 ct(KAT.ct):ss==KAT.ss(c'==c → K')。

View File

@@ -88,15 +88,16 @@ module tb_mlkem_dec_katK_xsim;
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("=== Decaps D4 done in %0d cyc ===", c);
$display("=== Decaps D5 done in %0d cyc ===", c);
verify_d0;
verify_d1;
verify_d2;
verify_d3;
verify_d4;
if (errors == 0) $display("K=%0d CASE %0d PASS (D4): w + m' recovery OK", KP, casenum);
else $display("K=%0d CASE %0d FAIL (D4): %0d total errors", KP, casenum, errors);
verify_d5;
if (errors == 0) $display("K=%0d CASE %0d PASS (D5): K'/r' = G(m'||h), K-bar = J(z||c) OK", KP, casenum);
else $display("K=%0d CASE %0d FAIL (D5): %0d total errors", KP, casenum, errors);
$finish;
end
@@ -286,4 +287,51 @@ module tb_mlkem_dec_katK_xsim;
errors = errors + be;
end
endtask
// D5: verify K' (ss_o), r' (dbg_r_o), K-bar (dbg_kbar_o) against golden.
reg [7:0] kp_b [0:31];
reg [7:0] rp_b [0:31];
reg [7:0] kb_b [0:31];
task verify_d5;
integer j, be;
reg [8*100-1:0] fn;
begin
// K' = G(m'||h) low half -> ss_o
$sformat(fn, "sync_rtl/top/TB/vectors/decgold/dc_k%0d_c%0d_kprime.hex", KP, casenum);
$readmemh(fn, kp_b);
be = 0;
for (j = 0; j < 32; j = j + 1)
if (ss_o[8*j +: 8] !== kp_b[j]) begin
if (be < 4) $display(" K'[%0d] got=%02x exp=%02x", j, ss_o[8*j +: 8], kp_b[j]);
be = be + 1;
end
if (be == 0) $display(" PASS: K' == golden (32 bytes)");
else $display(" FAIL: K' %0d byte mismatches", be);
errors = errors + be;
// r' = G(m'||h) high half -> dbg_r_o
$sformat(fn, "sync_rtl/top/TB/vectors/decgold/dc_k%0d_c%0d_rprime.hex", KP, casenum);
$readmemh(fn, rp_b);
be = 0;
for (j = 0; j < 32; j = j + 1)
if (dbg_r_o[8*j +: 8] !== rp_b[j]) begin
if (be < 4) $display(" r'[%0d] got=%02x exp=%02x", j, dbg_r_o[8*j +: 8], rp_b[j]);
be = be + 1;
end
if (be == 0) $display(" PASS: r' == golden (32 bytes)");
else $display(" FAIL: r' %0d byte mismatches", be);
errors = errors + be;
// K-bar = J(z||c) -> dbg_kbar_o
$sformat(fn, "sync_rtl/top/TB/vectors/decgold/dc_k%0d_c%0d_kbar.hex", KP, casenum);
$readmemh(fn, kb_b);
be = 0;
for (j = 0; j < 32; j = j + 1)
if (dbg_kbar_o[8*j +: 8] !== kb_b[j]) begin
if (be < 4) $display(" K-bar[%0d] got=%02x exp=%02x", j, dbg_kbar_o[8*j +: 8], kb_b[j]);
be = be + 1;
end
if (be == 0) $display(" PASS: K-bar == golden (32 bytes)");
else $display(" FAIL: K-bar %0d byte mismatches", be);
errors = errors + be;
end
endtask
endmodule

View File

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

View File

@@ -0,0 +1,32 @@
d8
83
47
7c
2a
eb
d6
5a
11
7f
4f
0c
15
05
90
b0
8a
57
13
25
ed
3e
37
8e
4f
e9
b1
af
c9
98
72
21

View File

@@ -0,0 +1,32 @@
2b
5c
52
ee
72
94
63
31
98
3b
a0
50
be
0f
43
50
55
c0
54
79
01
e0
35
59
b3
56
51
78
89
ea
27
c5

View File

@@ -0,0 +1,32 @@
08
cd
24
5f
59
e6
cb
6e
36
87
c6
63
27
49
b6
c0
73
7d
18
37
01
f0
b0
49
2b
84
33
58
89
3c
6a
24

View File

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

View File

@@ -0,0 +1,32 @@
12
10
3c
dc
50
6a
c9
50
3e
5d
5c
1b
f0
a6
9a
cc
46
d2
85
fd
3e
38
6b
83
bf
97
d1
51
d9
d7
ae
f4

View File

@@ -0,0 +1,32 @@
63
df
b8
42
bf
76
7f
89
71
78
39
64
2a
9b
92
fc
cf
82
bf
46
a9
f3
9b
a1
a3
29
29
95
f3
f9
34
dc

View File

@@ -0,0 +1,32 @@
a9
1d
9b
93
5b
57
c1
e9
bb
4f
4a
6a
8f
2b
9b
36
8a
20
07
f6
53
78
4c
01
c1
6f
a3
4b
a5
58
2c
cb

View File

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

View File

@@ -0,0 +1,32 @@
d1
79
b1
cc
1a
8f
4a
19
f4
08
5b
74
33
68
62
07
3b
c7
ca
5e
de
23
5b
40
6a
99
41
6a
2f
58
26
2b

View File

@@ -0,0 +1,32 @@
13
5b
97
48
c6
aa
6d
1a
e9
b5
42
0c
72
67
9f
f6
5c
ae
62
2b
8a
7d
f5
4c
d7
65
01
31
b5
fd
77
f8

View File

@@ -0,0 +1,32 @@
bd
b9
ea
a5
62
80
be
33
30
be
de
f9
32
ca
62
b8
3f
d7
33
88
b5
21
66
75
37
f9
6b
4f
53
3a
ad
2e

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,32 @@
51
95
69
07
f1
73
e1
cc
99
d4
72
ca
06
c6
57
39
62
bf
ef
5d
7e
a6
36
e2
d8
43
d7
20
0b
21
1e
40

View File

@@ -0,0 +1,32 @@
b4
08
d5
d1
15
71
3f
0a
93
04
7d
bb
ea
83
2e
43
40
78
76
86
d5
9a
9a
2d
10
6b
d6
62
ba
0a
a0
35

View File

@@ -0,0 +1,32 @@
95
ad
a5
16
59
59
17
37
1a
53
3e
83
f3
d7
95
10
06
92
67
41
28
1c
42
ea
73
71
13
29
ed
f7
25
5a

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,32 @@
25
89
30
2d
db
8d
af
8c
5b
03
d1
e8
54
14
9a
e5
59
78
ac
cb
a8
c4
e4
06
86
d5
e5
7e
82
5b
87
1a

View File

@@ -0,0 +1,32 @@
8c
97
02
42
40
61
11
e2
63
68
ad
87
60
c4
d0
2a
8b
28
d1
7d
13
82
10
ad
c1
27
19
7b
50
96
81
40

View File

@@ -0,0 +1,32 @@
8f
0d
5a
52
a5
87
1d
6e
df
1d
94
0c
0b
ec
6b
e5
80
05
ae
c6
b1
d5
47
26
2a
df
36
e6
e8
6e
98
b9

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,32 @@
07
13
2d
84
fb
8c
49
59
05
a8
ca
67
09
e2
56
3e
90
fe
55
27
ab
72
e0
f8
0d
e1
db
34
29
ee
54
be

View File

@@ -0,0 +1,32 @@
c0
d4
57
64
e3
db
f0
94
8b
91
4d
6f
65
c9
2b
d0
eb
d2
15
56
e5
07
67
53
af
48
df
8f
ff
d6
ba
dc

View File

@@ -0,0 +1,32 @@
c9
f6
7b
d4
70
62
84
c9
62
9b
6f
b1
3a
25
db
24
5a
70
94
63
9e
95
77
e2
8b
e5
14
df
09
02
01
70

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,32 @@
52
d0
42
14
da
32
7d
b1
27
94
31
10
1e
f0
b8
d8
c1
ab
39
fb
c3
69
60
18
4a
a8
69
c2
4b
16
79
71

View File

@@ -0,0 +1,32 @@
23
f2
11
b8
4a
6e
e2
0c
8c
29
f6
e5
31
4c
91
b4
14
e9
40
51
3d
38
0a
dd
17
bd
72
4a
b3
a1
3a
52

View File

@@ -0,0 +1,32 @@
3e
27
51
88
8a
87
ac
c8
33
a6
e8
83
01
8e
16
0d
e9
28
5e
2b
f9
60
33
f0
ca
8b
e9
7d
42
b1
63
85

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,32 @@
b8
cb
b2
8a
5e
0c
1a
2c
c3
87
ec
be
75
b0
bb
2d
0f
c4
40
26
26
d6
3e
ec
e2
2f
4b
82
f2
77
cd
d0

View File

@@ -0,0 +1,32 @@
26
22
50
3a
2a
54
4f
35
83
92
90
3e
6f
2a
dc
5a
2d
94
fe
01
05
83
b5
74
a5
4d
9a
7e
6d
22
3a
24

View File

@@ -0,0 +1,32 @@
fd
db
06
63
19
03
51
7f
ff
a8
a7
df
a6
97
43
4e
45
ab
84
d5
0e
bc
d5
28
31
8d
18
bf
e3
26
97
89

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,32 @@
70
ee
c6
f0
65
1b
ca
f1
9e
f2
82
c3
c7
7f
34
9b
99
12
31
0f
4c
31
72
7f
4c
61
89
c0
0c
4b
81
97

View File

@@ -0,0 +1,32 @@
72
3a
b6
2b
92
58
0b
3d
ef
8c
e8
87
00
1e
ef
e4
d9
05
65
aa
ca
f5
43
0e
e2
aa
b7
de
cf
99
db
76

View File

@@ -0,0 +1,32 @@
b3
f9
50
1f
16
4f
37
5b
5c
52
6d
e4
16
e6
95
78
9c
a9
ae
b8
fe
be
06
47
53
b9
c6
83
36
2e
28
67

View File

@@ -195,7 +195,11 @@ module mlkem_top #(
.rd_addr(cin_rd_addr), .rd_data(cin_rd_data),
.wr_en(c_in_we), .wr_addr(c_in_addr), .wr_data(c_in_byte)
);
assign cin_rd_addr = cin_rd_addr_r;
// c_in read addr: D5 J presents dj_c_idx combinationally (no extra register
// stage) so the registered BRAM read yields the byte 1 cycle later, matching
// the assemble/writeback pipeline. Otherwise the registered cin_rd_addr_r
// (D1 walker / idle) drives it.
assign cin_rd_addr = (st == ST_DEC_J) ? dj_c_idx[10:0] : cin_rd_addr_r;
// ================================================================
// Polynomial storage, sized for KMAX (worst case). Runtime k uses a
@@ -482,6 +486,8 @@ module mlkem_top #(
localparam ST_DEC_NTT = 5'd23; // D2: u_hat[i] = NTT(u'[i]) in place (bank_se rel i)
localparam ST_DEC_W = 5'd24; // D3: w = v' - INTT(sum_j s_hat[j] o u_hat[j])
localparam ST_DEC_MENC = 5'd25; // D4: m' = byteEncode_1(Compress_1(w))
localparam ST_DEC_G = 5'd26; // D5: (K',r') = G(m' || h), SHA3-512 single block
localparam ST_DEC_J = 5'd27; // D5: K-bar = J(z || c), multi-block SHAKE256
localparam ST_DONE = 5'd31;
reg [4:0] st, st_next;
@@ -524,7 +530,9 @@ module mlkem_top #(
reg sha3_ack; // consumer ready for hash
wire [511:0] kg_g_data = {248'b0, 5'b0, k_r, d_i}; // KeyGen G: [263:256]=k, [255:0]=d
wire [511:0] enc_g_data = {hek_r, m_r}; // Encaps G: m || H(ek), 64 bytes
wire [511:0] g_data = (st == ST_ENC_G) ? enc_g_data : kg_g_data;
wire [511:0] dec_g_data = {hek_r, mprime_r}; // Decaps D5 G: m' || h, 64 bytes
wire [511:0] g_data = (st == ST_ENC_G) ? enc_g_data :
(st == ST_DEC_G) ? dec_g_data : kg_g_data;
// ================================================================
// Shared keccak_core + phase mux (3 consumers -> 1 core)
@@ -551,7 +559,8 @@ module mlkem_top #(
// phase selects (mutually exclusive). Encaps adds ST_ENC_H/G (sha3),
// ST_ENC_A (snt), ST_ENC_C (cbd).
wire sel_sha3 = (st == ST_G) || (st == ST_H) ||
(st == ST_ENC_H) || (st == ST_ENC_G);
(st == ST_ENC_H) || (st == ST_ENC_G) ||
(st == ST_DEC_G) || (st == ST_DEC_J);
wire sel_snt = (st == ST_A) || (st == ST_ENC_A);
wire sel_cbd = (st == ST_C) || (st == ST_ENC_C);
@@ -578,15 +587,17 @@ module mlkem_top #(
.ready_i(1'b1) // consumers always accept (kc_ready_i=1)
);
// ---- single shared sha3_top serving BOTH G and H ----
// G (ST_G) uses single-block mode (mb_en=0); H(ek) (ST_H) uses the
// multi-block absorb path (mb_en=1). These phases are disjoint in the
// top FSM, so one sha3_top (one keccak_core) is sufficient. mb_en and
// ready_i are muxed by phase; data_i/mode only matter while mb_en=0.
wire sha3_mb_en = (st == ST_H) || (st == ST_ENC_H);
// sha3 single-block mode: 2'b00 = G(33B) for KeyGen, 2'b11 = G(64B) for
// Encaps (m||H(ek)). mode only matters when mb_en=0.
wire [1:0] sha3_mode = (st == ST_ENC_G) ? 2'b11 : 2'b00;
// G/H/J share one sha3_top. Single-block (mb_en=0): KeyGen G (ST_G, mode 00),
// Encaps G (ST_ENC_G, mode 11), Decaps D5 G (ST_DEC_G, mode 11). Multi-block
// absorb (mb_en=1): H(ek) (ST_H/ST_ENC_H, SHA3-256 pad) and Decaps D5 J
// (ST_DEC_J, SHAKE256 pad over z||c). mb_* inputs are muxed by phase.
wire sha3_mb_en = (st == ST_H) || (st == ST_ENC_H) || (st == ST_DEC_J);
wire [1:0] sha3_mode = (st == ST_ENC_G || st == ST_DEC_G) ? 2'b11 : 2'b00;
// multi-block feed mux: J (ST_DEC_J) drives dj_*, else H drives h_*.
wire [1087:0] mb_block_mux = (st == ST_DEC_J) ? dj_block_r : h_block_r;
wire mb_valid_mux = (st == ST_DEC_J) ? dj_mbvalid : h_mbvalid;
wire mb_last_mux = (st == ST_DEC_J) ? dj_mblast : h_mblast;
wire mb_ack_mux = (st == ST_DEC_J) ? dj_ack : h_ack;
sha3_top_shared u_sha3 (
.clk(clk), .rst_n(rst_n),
.mode(sha3_mode), // G = SHA3-512 (only used when mb_en=0)
@@ -595,11 +606,11 @@ module mlkem_top #(
.ready_o(sha3_ready),
.hash_o(sha3_hash),
.valid_o(sha3_vo),
.ready_i(sha3_mb_en ? h_ack : sha3_ack),
.ready_i(sha3_mb_en ? mb_ack_mux : sha3_ack),
.mb_en(sha3_mb_en),
.mb_block_i(h_block_r),
.mb_valid_i(h_mbvalid),
.mb_last_i(h_mblast),
.mb_block_i(mb_block_mux),
.mb_valid_i(mb_valid_mux),
.mb_last_i(mb_last_mux),
.mb_ready_o(h_mbready),
// shared keccak_core interface (gated by phase in the mux below)
.kc_state_o(kc_state_o),
@@ -631,6 +642,43 @@ module mlkem_top #(
reg [7:0] h_wb_pad; // pad constant to use if g is out of ek range
reg h_wb_inek; // 1 if g is within ek range (use BRAM data)
// ---- Decaps D5 J(z||c) multi-block SHAKE256 state ----
// Message = z (32 B, from z_r) || c (ct_bytes_rt B, from c_in_bram). Rate=136.
// SHAKE256 pad: byte at msg_len = 0x1F, last byte of last block |= 0x80.
// Reuses the shared u_sha3 mb_* port (muxed by ST_DEC_J above).
reg [1087:0] dj_block_r; // current pre-padded rate block
reg dj_mbvalid;
reg dj_mblast;
reg dj_ack;
reg [3:0] dj_blk; // block index 0..DJ_NBLK-1 (z||c up to ~1600B -> <=12 blks)
reg [7:0] dj_byte; // 0..136 byte being assembled
reg [1:0] dj_phase; // 0=assemble 1=feed 2=wait-perm 3=done
reg dj_done;
// writeback pipeline (c_in_bram registered read, 1-cyc latency)
reg dj_wb_vld;
reg [7:0] dj_wb_idx; // position within 136-byte block
reg dj_wb_inc; // 1 if global byte g is within c range (use BRAM)
reg dj_wb_inz; // 1 if g < 32 (use z_r byte)
reg [7:0] dj_wb_pad; // pad constant if g out of msg range
reg [4:0] dj_wb_zidx; // z byte index (g) when inz
// J message length = 32 (z) + ct_bytes_rt; total padded blocks.
wire [11:0] dj_msglen = 12'd32 + {1'b0, ct_bytes_rt};
wire [11:0] dj_last_byte = (dj_msglen / 12'd136) * 12'd136 + 12'd135; // last byte of final block
wire [3:0] dj_nblk = (dj_msglen / 12'd136) + 4'd1;
// global byte index for the address presented this cycle (assemble)
wire [11:0] dj_g = {4'd0, dj_blk} * 12'd136 + {4'd0, dj_byte};
// c_in_bram byte index (when g>=32): g-32
wire [11:0] dj_c_idx = dj_g - 12'd32;
// SHAKE256 pad constant for global byte g
function [7:0] dj_padconst(input [11:0] g);
begin
if (g == dj_last_byte && g == dj_msglen) dj_padconst = 8'h9f; // 0x1F|0x80
else if (g == dj_msglen) dj_padconst = 8'h1f;
else if (g == dj_last_byte) dj_padconst = 8'h80;
else dj_padconst = 8'h00;
end
endfunction
// h_hash / h_vo are now served by the shared u_sha3 above (mb_en=1 during
// ST_H). They alias the single core's outputs; the H consumer logic below
// already gates on st==ST_H, and u_sha3's valid_o/hash_o are mb-selected.
@@ -1075,7 +1123,10 @@ module mlkem_top #(
// D3: w = v' - INTT(sum_j s_hat[j] o u_hat[j]). Single output poly
// (u_row 0..0); MAC->INTT->SUB, then D4 encodes m'.
ST_DEC_W: if (u_row >= 3'd1) st_next = ST_DEC_MENC;
ST_DEC_MENC: if (men_done) st_next = ST_DONE;
ST_DEC_MENC: if (men_done) st_next = ST_DEC_G;
// D5: (K',r') = G(m'||h) single-block, then K-bar = J(z||c) multi-block.
ST_DEC_G: if (sha3_vo) st_next = ST_DEC_J;
ST_DEC_J: if (dj_done) st_next = ST_DONE;
ST_G: if (sha3_vo) st_next = ST_A;
ST_A: if (a_pair >= kk_rt) st_next = ST_C;
ST_C: if (c_poly >= {1'b0, k_r, 1'b0}) st_next = ST_N;
@@ -1220,6 +1271,15 @@ module mlkem_top #(
men_ph <= 2'd0;
men_done <= 1'b0;
mprime_r <= 256'd0;
dj_blk <= 4'd0;
dj_byte <= 8'd0;
dj_phase <= 2'd0;
dj_mbvalid <= 1'b0;
dj_mblast <= 1'b0;
dj_ack <= 1'b0;
dj_done <= 1'b0;
dj_wb_vld <= 1'b0;
dj_block_r <= 1088'd0;
h_blk <= 3'd0;
h_byte <= 8'd0;
h_phase <= 2'd0;
@@ -1885,6 +1945,93 @@ module mlkem_top #(
sha3_ack <= 1'b0;
end
// Arm Decaps D5 G when m' is ready (ST_DEC_MENC -> ST_DEC_G): fire the
// 64-byte single-block G(m'||h). dec_g_data = {hek_r, mprime_r}.
if (st == ST_DEC_MENC && st_next == ST_DEC_G) begin
sha3_valid <= 1'b1;
sha3_ack <= 1'b1;
end
// Capture (K', r') when D5 G completes. K' = low half (candidate ss),
// r' = high half (PRF seed for D6 re-encrypt). Reuse ss_r / r_r.
if (st == ST_DEC_G && sha3_vo) begin
ss_r <= sha3_hash[255:0]; // K' = G bytes 0..31
r_r <= sha3_hash[511:256]; // r' = G bytes 32..63
sha3_ack <= 1'b0;
end
// Arm D5 J(z||c) when G completes (ST_DEC_G -> ST_DEC_J): assemble the
// first 136-byte block. dj_ack high to consume the final digest.
if (st == ST_DEC_G && st_next == ST_DEC_J) begin
dj_blk <= 4'd0;
dj_byte <= 8'd0;
dj_phase <= 2'd0;
dj_mbvalid<= 1'b0;
dj_mblast <= 1'b0;
dj_ack <= 1'b1;
dj_done <= 1'b0;
dj_wb_vld <= 1'b0;
cin_rd_addr_r <= 11'd0; // present c byte 0 (g=32 -> c_idx 0)
end
// ---- ST_DEC_J: K-bar = J(z||c) multi-block SHAKE256 ----
// Mirror of the H(ek) multi-block machine. Byte source by global g:
// g < 32 -> z_r byte g
// 32 <= g < msglen -> c_in_bram byte (g-32), registered read
// else -> SHAKE256 pad constant
// c_in_bram read is registered: present c_idx for dj_byte this cycle,
// write back the byte that arrived for the addr presented last cycle.
if (st == ST_DEC_J && !dj_done) begin
case (dj_phase)
2'd0: begin
// writeback the byte read for the previous address
if (dj_wb_vld) begin
if (dj_wb_inz)
dj_block_r[dj_wb_idx*8 +: 8] <= z_r[dj_wb_zidx*8 +: 8];
else if (dj_wb_inc)
dj_block_r[dj_wb_idx*8 +: 8] <= cin_rd_data;
else
dj_block_r[dj_wb_idx*8 +: 8] <= dj_wb_pad;
end
if (dj_byte <= 8'd135) begin
dj_wb_vld <= 1'b1;
dj_wb_idx <= dj_byte;
dj_wb_inz <= (dj_g < 12'd32);
dj_wb_inc <= (dj_g >= 12'd32) && (dj_g < dj_msglen);
dj_wb_zidx <= dj_g[4:0];
dj_wb_pad <= dj_padconst(dj_g);
// c_in addr is presented combinationally (cin_rd_addr
// mux uses dj_c_idx during ST_DEC_J); data lands next
// cycle, matching this byte's writeback.
dj_byte <= dj_byte + 8'd1;
end else begin
dj_wb_vld <= 1'b0;
dj_byte <= 8'd0;
dj_mbvalid <= 1'b1;
dj_mblast <= (dj_blk == dj_nblk - 4'd1);
dj_phase <= 2'd1;
end
end
2'd1: begin
if (dj_mbvalid && !h_mbready) begin
dj_mbvalid <= 1'b0;
dj_mblast <= 1'b0;
dj_phase <= 2'd2;
end
end
2'd2: begin
if (sha3_vo) begin
kbar_r <= sha3_hash[255:0];
dj_done <= 1'b1;
dj_phase<= 2'd3;
end else if (h_mbready) begin
dj_blk <= dj_blk + 4'd1;
dj_phase <= 2'd0;
end
end
default: ; // done
endcase
end
// Arm rho-load when entering ST_ENC_LOAD. rho = ek[384k .. 384k+31].
if (st == ST_ENC_G && st_next == ST_ENC_LOAD) begin
rl_idx <= 6'd0;