Embedded SDK
Embedded SDK
Loading...
Searching...
No Matches
cx_mldsa_smallpoly.c
Go to the documentation of this file.
1/*****************************************************************************
2 * (c) 2026 Ledger SAS.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *****************************************************************************/
26#ifdef HAVE_MLDSA_OPTIMIZATION
27
28#include "cx_mldsa_smallpoly.h"
29#include <string.h>
30
31/*********************
32 * STATIC DATA
33 *********************/
34
35// clang-format off
40static const int16_t mldsa_small_zetas[128] = {
41 -1044, -758, -359, -1517, 1493, 1422, 287, 202,
42 -171, 622, 1577, 182, 962, -1202, -1474, 1468,
43 573, -1325, 264, 383, -829, 1458, -1602, -130,
44 -681, 1017, 732, 608, -1542, 411, -205, -1571,
45 1223, 652, -552, 1015, -1293, 1491, -282, -1544,
46 516, -8, -320, -666, -1618, -1162, 126, 1469,
47 -853, -90, -271, 830, 107, -1421, -247, -951,
48 -398, 961, -1508, -725, 448, -1065, 677, -1275,
49 -1103, 430, 555, 843, -1251, 871, 1550, 105,
50 422, 587, 177, -235, -291, -460, 1574, 1653,
51 -246, 778, 1159, -147, -777, 1483, -602, 1119,
52 -1590, 644, -872, 349, 418, 329, -156, -75,
53 817, 1097, 603, 610, 1322, -1285, -1465, 384,
54 -1215, -136, 1218, -1335, -874, 220, -1187, -1659,
55 -1185, -1530, -1278, 794, -1510, -854, -870, 478,
56 -108, -308, 996, 991, 958, -1460, 1522, 1628
57};
58// clang-format on
59
60/*********************
61 * STATIC FUNCTIONS
62 *********************/
63
67static inline int16_t mldsa_small_montgomery_reduce(int32_t a)
68{
69 int16_t t;
70 t = (int16_t) ((int16_t) a * (int16_t) MLDSA_SMALL_QINV);
71 t = (int16_t) ((a - (int32_t) t * MLDSA_SMALL_Q) >> 16);
72 return t;
73}
74
78static inline int16_t mldsa_small_barrett_reduce(int16_t a)
79{
80 int16_t t;
81 const int16_t v = ((1 << 26) + MLDSA_SMALL_Q / 2) / MLDSA_SMALL_Q;
82 t = (int16_t) (((int32_t) v * a + (1 << 25)) >> 26);
83 t = (int16_t) (t * MLDSA_SMALL_Q);
84 return (int16_t) (a - t);
85}
86
90static inline int16_t mldsa_small_fqmul(int16_t a, int16_t b)
91{
92 return mldsa_small_montgomery_reduce((int32_t) a * b);
93}
94
95/*********************
96 * GLOBAL FUNCTIONS
97 *********************/
98
99void MLDSA_SMALLPOLY_ntt(int16_t r[MLDSA_N])
100{
101 uint32_t len, start, j, k;
102 int16_t t, zeta;
103
104 k = 1U;
105 for (len = 128U; len >= 2U; len >>= 1U) {
106 for (start = 0U; start < MLDSA_N; start = j + len) {
107 zeta = mldsa_small_zetas[k++];
108 for (j = start; j < start + len; j++) {
109 t = mldsa_small_fqmul(zeta, r[j + len]);
110 r[j + len] = (int16_t) (r[j] - t);
111 r[j] = (int16_t) (r[j] + t);
112 }
113 }
114 }
115}
116
117void MLDSA_SMALLPOLY_invntt_tomont(int16_t r[MLDSA_N])
118{
119 uint32_t start, len, j, k;
120 int16_t t, zeta;
121 const int16_t f = 1441; // mont^2 / 128
122
123 k = 127U;
124 for (len = 2U; len <= 128U; len <<= 1U) {
125 for (start = 0U; start < MLDSA_N; start = j + len) {
126 zeta = mldsa_small_zetas[k--];
127 for (j = start; j < start + len; j++) {
128 t = r[j];
129 r[j] = mldsa_small_barrett_reduce((int16_t) (t + r[j + len]));
130 r[j + len] = (int16_t) (r[j + len] - t);
131 r[j + len] = mldsa_small_fqmul(zeta, r[j + len]);
132 }
133 }
134 }
135
136 for (j = 0U; j < MLDSA_N; j++) {
137 r[j] = mldsa_small_barrett_reduce(mldsa_small_fqmul(r[j], f));
138 }
139}
140
144static inline void mldsa_small_basemul(int16_t r[2],
145 const int16_t a[2],
146 const int16_t b[2],
147 int16_t zeta)
148{
149 int16_t a0 = a[0], a1 = a[1];
150 int16_t b0 = b[0];
151
152 r[0] = mldsa_small_fqmul(a1, b[1]);
153 r[0] = mldsa_small_fqmul(r[0], zeta);
154 r[0] = (int16_t) (r[0] + mldsa_small_fqmul(a0, b0));
155 r[1] = mldsa_small_fqmul(a0, b[1]);
156 r[1] = (int16_t) (r[1] + mldsa_small_fqmul(a1, b0));
157}
158
159void MLDSA_SMALLPOLY_ntt_copy(mldsa_smallpoly *out, const mldsa_poly *in)
160{
161 for (uint32_t i = 0U; i < MLDSA_N; i++) {
162 out->coeffs[i] = (int16_t) in->coeffs[i];
163 }
164 MLDSA_SMALLPOLY_ntt(out->coeffs);
165}
166
167void MLDSA_SMALLPOLY_basemul_invntt(mldsa_poly *r,
168 const mldsa_smallpoly *a,
169 const mldsa_smallpoly *b)
170{
171 // Re-use the output buffer as a smallpoly during computation
172 mldsa_smallpoly *tmp = (mldsa_smallpoly *) r;
173
174 // Basemul in NTT domain
175 for (uint32_t i = 0U; i < MLDSA_N / 4U; i++) {
176 mldsa_small_basemul(&tmp->coeffs[4U * i],
177 &a->coeffs[4U * i],
178 &b->coeffs[4U * i],
179 mldsa_small_zetas[64U + i]);
180 mldsa_small_basemul(&tmp->coeffs[4U * i + 2U],
181 &a->coeffs[4U * i + 2U],
182 &b->coeffs[4U * i + 2U],
183 (int16_t) (-mldsa_small_zetas[64U + i]));
184 }
185
186 // Inverse NTT
187 MLDSA_SMALLPOLY_invntt_tomont(tmp->coeffs);
188
189 // Expand int16_t to int32_t in reverse order to avoid clobbering
190 for (int32_t j = (int32_t) MLDSA_N - 1; j >= 0; j--) {
191 r->coeffs[j] = (int32_t) tmp->coeffs[j];
192 }
193}
194
195void MLDSA_SMALLPOLY_unpack_eta(mldsa_smallpoly *r, const uint8_t *a, uint8_t eta)
196{
197 if (eta == 2U) {
198 for (uint32_t i = 0U; i < MLDSA_N / 8U; i++) {
199 r->coeffs[8U * i + 0U] = (int16_t) ((a[3U * i + 0U] >> 0U) & 7U);
200 r->coeffs[8U * i + 1U] = (int16_t) ((a[3U * i + 0U] >> 3U) & 7U);
201 r->coeffs[8U * i + 2U]
202 = (int16_t) (((a[3U * i + 0U] >> 6U) | (a[3U * i + 1U] << 2U)) & 7U);
203 r->coeffs[8U * i + 3U] = (int16_t) ((a[3U * i + 1U] >> 1U) & 7U);
204 r->coeffs[8U * i + 4U] = (int16_t) ((a[3U * i + 1U] >> 4U) & 7U);
205 r->coeffs[8U * i + 5U]
206 = (int16_t) (((a[3U * i + 1U] >> 7U) | (a[3U * i + 2U] << 1U)) & 7U);
207 r->coeffs[8U * i + 6U] = (int16_t) ((a[3U * i + 2U] >> 2U) & 7U);
208 r->coeffs[8U * i + 7U] = (int16_t) ((a[3U * i + 2U] >> 5U) & 7U);
209
210 r->coeffs[8U * i + 0U] = (int16_t) eta - r->coeffs[8U * i + 0U];
211 r->coeffs[8U * i + 1U] = (int16_t) eta - r->coeffs[8U * i + 1U];
212 r->coeffs[8U * i + 2U] = (int16_t) eta - r->coeffs[8U * i + 2U];
213 r->coeffs[8U * i + 3U] = (int16_t) eta - r->coeffs[8U * i + 3U];
214 r->coeffs[8U * i + 4U] = (int16_t) eta - r->coeffs[8U * i + 4U];
215 r->coeffs[8U * i + 5U] = (int16_t) eta - r->coeffs[8U * i + 5U];
216 r->coeffs[8U * i + 6U] = (int16_t) eta - r->coeffs[8U * i + 6U];
217 r->coeffs[8U * i + 7U] = (int16_t) eta - r->coeffs[8U * i + 7U];
218 }
219 }
220 else {
221 // eta == 4
222 for (uint32_t i = 0U; i < MLDSA_N / 2U; i++) {
223 r->coeffs[2U * i + 0U] = (int16_t) (a[i] & 0x0FU);
224 r->coeffs[2U * i + 1U] = (int16_t) (a[i] >> 4U);
225 r->coeffs[2U * i + 0U] = (int16_t) eta - r->coeffs[2U * i + 0U];
226 r->coeffs[2U * i + 1U] = (int16_t) eta - r->coeffs[2U * i + 1U];
227 }
228 }
229}
230
231#endif /* HAVE_MLDSA_OPTIMIZATION */
ML-DSA small polynomial type and NTT mod 3329 (low-RAM optimization).
#define MLDSA_N
Definition lcx_mldsa.h:37
Polynomial with MLDSA_N int32_t coefficients.
int32_t coeffs[MLDSA_N]