v / vlib / x / crypto / mldsa / ntt.v
188 lines · 155 sloc · 6.39 KB · e2e5cf8db56f3562c7baa735061690be936bdf3e
Raw
1// Copyright 2025 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4//
5// Ported to V from Go's crypto/internal/fips140/mldsa.
6module mldsa
7
8// appendix b: zeta^BitRev8(k) mod q in montgomery domain
9const zetas = [u32(4193792), 25847, 5771523, 7861508, 237124, 7602457, 7504169, 466468, 1826347,
10 2353451, 8021166, 6288512, 3119733, 5495562, 3111497, 2680103, 2725464, 1024112, 7300517, 3585928,
11 7830929, 7260833, 2619752, 6271868, 6262231, 4520680, 6980856, 5102745, 1757237, 8360995, 4010497,
12 280005, 2706023, 95776, 3077325, 3530437, 6718724, 4788269, 5842901, 3915439, 4519302, 5336701,
13 3574422, 5512770, 3539968, 8079950, 2348700, 7841118, 6681150, 6736599, 3505694, 4558682, 3507263,
14 6239768, 6779997, 3699596, 811944, 531354, 954230, 3881043, 3900724, 5823537, 2071892, 5582638,
15 4450022, 6851714, 4702672, 5339162, 6927966, 3475950, 2176455, 6795196, 7122806, 1939314, 4296819,
16 7380215, 5190273, 5223087, 4747489, 126922, 3412210, 7396998, 2147896, 2715295, 5412772, 4686924,
17 7969390, 5903370, 7709315, 7151892, 8357436, 7072248, 7998430, 1349076, 1852771, 6949987, 5037034,
18 264944, 508951, 3097992, 44288, 7280319, 904516, 3958618, 4656075, 8371839, 1653064, 5130689,
19 2389356, 8169440, 759969, 7063561, 189548, 4827145, 3159746, 6529015, 5971092, 8202977, 1315589,
20 1341330, 1285669, 6795489, 7567685, 6940675, 5361315, 4499357, 4751448, 3839961, 2091667, 3407706,
21 2316500, 3817976, 5037939, 2244091, 5933984, 4817955, 266997, 2434439, 7144689, 3513181, 4860065,
22 4621053, 7183191, 5187039, 900702, 1859098, 909542, 819034, 495491, 6767243, 8337157, 7857917,
23 7725090, 5257975, 2031748, 3207046, 4823422, 7855319, 7611795, 4784579, 342297, 286988, 5942594,
24 4108315, 3437287, 5038140, 1735879, 203044, 2842341, 2691481, 5790267, 1265009, 4055324, 1247620,
25 2486353, 1595974, 4613401, 1250494, 2635921, 4832145, 5386378, 1869119, 1903435, 7329447, 7047359,
26 1237275, 5062207, 6950192, 7929317, 1312455, 3306115, 6417775, 7100756, 1917081, 5834105, 7005614,
27 1500165, 777191, 2235880, 3406031, 7838005, 5548557, 6709241, 6533464, 5796124, 4656147, 594136,
28 4603424, 6366809, 2432395, 2454455, 8215696, 1957272, 3369112, 185531, 7173032, 5196991, 162844,
29 1616392, 3014001, 810149, 1652634, 4686184, 6581310, 5341501, 3523897, 3866901, 269760, 2213111,
30 7404533, 1717735, 472078, 7953734, 1723600, 6577327, 1910376, 6712985, 7276084, 8119771, 4546524,
31 5441381, 6144432, 7959518, 6094090, 183443, 7403526, 1612842, 4834730, 7826001, 3919660, 8332111,
32 7018208, 3937738, 1400424, 7534263, 1976782]!
33
34// algo. 41: NTT (s. 7.5)
35@[direct_array_access]
36fn ntt(f_ RingElement) NttElement {
37 mut f := unsafe { f_ } // workaround for false mutability notice
38 mut m := u8(0)
39
40 mut len := 128
41 for len >= 8 {
42 mut start := 0
43 for start < 256 {
44 m++
45 zeta := FieldElement(zetas[m])
46
47 mut j := 0
48 for j < len {
49 t := field_montgomery_mul(zeta, f[start + len + j])
50 f[start + len + j] = field_sub(f[start + j], t)
51 f[start + j] = field_add(f[start + j], t)
52
53 t2 := field_montgomery_mul(zeta, f[start + len + j + 1])
54 f[start + len + j + 1] = field_sub(f[start + j + 1], t2)
55 f[start + j + 1] = field_add(f[start + j + 1], t2)
56
57 j += 2
58 }
59 start += 2 * len
60 }
61 len /= 2
62 }
63
64 for start := 0; start < 256; start += 8 {
65 m++
66 zeta := FieldElement(zetas[m])
67
68 mut t := field_montgomery_mul(zeta, f[start + 4])
69 f[start + 4] = field_sub(f[start], t)
70 f[start] = field_add(f[start], t)
71
72 t = field_montgomery_mul(zeta, f[start + 5])
73 f[start + 5] = field_sub(f[start + 1], t)
74 f[start + 1] = field_add(f[start + 1], t)
75
76 t = field_montgomery_mul(zeta, f[start + 6])
77 f[start + 6] = field_sub(f[start + 2], t)
78 f[start + 2] = field_add(f[start + 2], t)
79
80 t = field_montgomery_mul(zeta, f[start + 7])
81 f[start + 7] = field_sub(f[start + 3], t)
82 f[start + 3] = field_add(f[start + 3], t)
83 }
84
85 for start := 0; start < 256; start += 4 {
86 m++
87 zeta := FieldElement(zetas[m])
88
89 mut t := field_montgomery_mul(zeta, f[start + 2])
90 f[start + 2] = field_sub(f[start], t)
91 f[start] = field_add(f[start], t)
92
93 t = field_montgomery_mul(zeta, f[start + 3])
94 f[start + 3] = field_sub(f[start + 1], t)
95 f[start + 1] = field_add(f[start + 1], t)
96 }
97
98 for start := 0; start < 256; start += 2 {
99 m++
100 zeta := FieldElement(zetas[m])
101
102 t := field_montgomery_mul(zeta, f[start + 1])
103 f[start + 1] = field_sub(f[start], t)
104 f[start] = field_add(f[start], t)
105 }
106
107 return NttElement(f)
108}
109
110// algo. 42: NTT^-1 (s. 7.5)
111@[direct_array_access]
112fn inverse_ntt(f_ NttElement) RingElement {
113 mut f := unsafe { f_ } // workaround for false mutability notice
114 mut m := u8(255)
115
116 for start := 0; start < 256; start += 2 {
117 zeta := FieldElement(zetas[m])
118 m--
119
120 t := f[start]
121 f[start] = field_add(t, f[start + 1])
122 f[start + 1] = field_montgomery_mul_sub(zeta, f[start + 1], t)
123 }
124
125 for start := 0; start < 256; start += 4 {
126 zeta := FieldElement(zetas[m])
127 m--
128
129 mut t := f[start]
130 f[start] = field_add(t, f[start + 2])
131 f[start + 2] = field_montgomery_mul_sub(zeta, f[start + 2], t)
132
133 t = f[start + 1]
134 f[start + 1] = field_add(t, f[start + 3])
135 f[start + 3] = field_montgomery_mul_sub(zeta, f[start + 3], t)
136 }
137
138 for start := 0; start < 256; start += 8 {
139 zeta := FieldElement(zetas[m])
140 m--
141
142 mut t := f[start]
143 f[start] = field_add(t, f[start + 4])
144 f[start + 4] = field_montgomery_mul_sub(zeta, f[start + 4], t)
145
146 t = f[start + 1]
147 f[start + 1] = field_add(t, f[start + 5])
148 f[start + 5] = field_montgomery_mul_sub(zeta, f[start + 5], t)
149
150 t = f[start + 2]
151 f[start + 2] = field_add(t, f[start + 6])
152 f[start + 6] = field_montgomery_mul_sub(zeta, f[start + 6], t)
153
154 t = f[start + 3]
155 f[start + 3] = field_add(t, f[start + 7])
156 f[start + 7] = field_montgomery_mul_sub(zeta, f[start + 7], t)
157 }
158
159 mut len2 := 8
160 for len2 < 256 {
161 mut start := 0
162 for start < 256 {
163 zeta := FieldElement(zetas[m])
164 m--
165
166 mut j := 0
167 for j < len2 {
168 mut t := f[start + j]
169 f[start + j] = field_add(t, f[start + len2 + j])
170 f[start + len2 + j] = field_montgomery_mul_sub(zeta, f[start + len2 + j], t)
171
172 t = f[start + j + 1]
173 f[start + j + 1] = field_add(t, f[start + len2 + j + 1])
174 f[start + len2 + j + 1] = field_montgomery_mul_sub(zeta, f[start + len2 + j + 1], t)
175
176 j += 2
177 }
178 start += 2 * len2
179 }
180 len2 *= 2
181 }
182
183 // algo. 42, line 21: f = 8347681 = 256^-1 mod q; in montgomery: 16382
184 for i in 0 .. 256 {
185 f[i] = field_montgomery_mul(f[i], 16382)
186 }
187 return RingElement(f)
188}
189