miden-crypto/src/dsa/rpo_falcon512/falcon_c/rpo.c
src/dsa/rpo_falcon512/falcon_c/rpo.cRaw
1/*
2 * RPO implementation.
3 */
4
5#include <stdint.h>
6#include <string.h>
7#include <stdlib.h>
8
9/* ================================================================================================
10 * Modular Arithmetic
11 */
12
13#define P 0xFFFFFFFF00000001
14#define M 12289
15
16// From https://github.com/ncw/iprime/blob/master/mod_math_noasm.go
17static uint64_t add_mod_p(uint64_t a, uint64_t b)
18{
19 a = P - a;
20 uint64_t res = b - a;
21 if (b < a)
22 res += P;
23 return res;
24}
25
26static uint64_t sub_mod_p(uint64_t a, uint64_t b)
27{
28 uint64_t r = a - b;
29 if (a < b)
30 r += P;
31 return r;
32}
33
34static uint64_t reduce_mod_p(uint64_t b, uint64_t a)
35{
36 uint32_t d = b >> 32,
37 c = b;
38 if (a >= P)
39 a -= P;
40 a = sub_mod_p(a, c);
41 a = sub_mod_p(a, d);
42 a = add_mod_p(a, ((uint64_t)c) << 32);
43 return a;
44}
45
46static uint64_t mult_mod_p(uint64_t x, uint64_t y)
47{
48 uint32_t a = x,
49 b = x >> 32,
50 c = y,
51 d = y >> 32;
52
53 /* first synthesize the product using 32*32 -> 64 bit multiplies */
54 x = b * (uint64_t)c; /* b*c */
55 y = a * (uint64_t)d; /* a*d */
56 uint64_t e = a * (uint64_t)c, /* a*c */
57 f = b * (uint64_t)d, /* b*d */
58 t;
59
60 x += y; /* b*c + a*d */
61 /* carry? */
62 if (x < y)
63 f += 1LL << 32; /* carry into upper 32 bits - can't overflow */
64
65 t = x << 32;
66 e += t; /* a*c + LSW(b*c + a*d) */
67 /* carry? */
68 if (e < t)
69 f += 1; /* carry into upper 64 bits - can't overflow*/
70 t = x >> 32;
71 f += t; /* b*d + MSW(b*c + a*d) */
72 /* can't overflow */
73
74 /* now reduce: (b*d + MSW(b*c + a*d), a*c + LSW(b*c + a*d)) */
75 return reduce_mod_p(f, e);
76}
77
78/* ================================================================================================
79 * RPO128 Permutation
80 */
81
82static const uint64_t STATE_WIDTH = 12;
83static const uint64_t NUM_ROUNDS = 7;
84
85/*
86 * MDS matrix
87 */
88static const uint64_t MDS[12][12] = {
89 { 7, 23, 8, 26, 13, 10, 9, 7, 6, 22, 21, 8 },
90 { 8, 7, 23, 8, 26, 13, 10, 9, 7, 6, 22, 21 },
91 { 21, 8, 7, 23, 8, 26, 13, 10, 9, 7, 6, 22 },
92 { 22, 21, 8, 7, 23, 8, 26, 13, 10, 9, 7, 6 },
93 { 6, 22, 21, 8, 7, 23, 8, 26, 13, 10, 9, 7 },
94 { 7, 6, 22, 21, 8, 7, 23, 8, 26, 13, 10, 9 },
95 { 9, 7, 6, 22, 21, 8, 7, 23, 8, 26, 13, 10 },
96 { 10, 9, 7, 6, 22, 21, 8, 7, 23, 8, 26, 13 },
97 { 13, 10, 9, 7, 6, 22, 21, 8, 7, 23, 8, 26 },
98 { 26, 13, 10, 9, 7, 6, 22, 21, 8, 7, 23, 8 },
99 { 8, 26, 13, 10, 9, 7, 6, 22, 21, 8, 7, 23 },
100 { 23, 8, 26, 13, 10, 9, 7, 6, 22, 21, 8, 7 },
101};
102
103/*
104 * Round constants.
105 */
106static const uint64_t ARK1[7][12] = {
107 {
108 5789762306288267392ULL,
109 6522564764413701783ULL,
110 17809893479458208203ULL,
111 107145243989736508ULL,
112 6388978042437517382ULL,
113 15844067734406016715ULL,
114 9975000513555218239ULL,
115 3344984123768313364ULL,
116 9959189626657347191ULL,
117 12960773468763563665ULL,
118 9602914297752488475ULL,
119 16657542370200465908ULL,
120 },
121 {
122 12987190162843096997ULL,
123 653957632802705281ULL,
124 4441654670647621225ULL,
125 4038207883745915761ULL,
126 5613464648874830118ULL,
127 13222989726778338773ULL,
128 3037761201230264149ULL,
129 16683759727265180203ULL,
130 8337364536491240715ULL,
131 3227397518293416448ULL,
132 8110510111539674682ULL,
133 2872078294163232137ULL,
134 },
135 {
136 18072785500942327487ULL,
137 6200974112677013481ULL,
138 17682092219085884187ULL,
139 10599526828986756440ULL,
140 975003873302957338ULL,
141 8264241093196931281ULL,
142 10065763900435475170ULL,
143 2181131744534710197ULL,
144 6317303992309418647ULL,
145 1401440938888741532ULL,
146 8884468225181997494ULL,
147 13066900325715521532ULL,
148 },
149 {
150 5674685213610121970ULL,
151 5759084860419474071ULL,
152 13943282657648897737ULL,
153 1352748651966375394ULL,
154 17110913224029905221ULL,
155 1003883795902368422ULL,
156 4141870621881018291ULL,
157 8121410972417424656ULL,
158 14300518605864919529ULL,
159 13712227150607670181ULL,
160 17021852944633065291ULL,
161 6252096473787587650ULL,
162 },
163 {
164 4887609836208846458ULL,
165 3027115137917284492ULL,
166 9595098600469470675ULL,
167 10528569829048484079ULL,
168 7864689113198939815ULL,
169 17533723827845969040ULL,
170 5781638039037710951ULL,
171 17024078752430719006ULL,
172 109659393484013511ULL,
173 7158933660534805869ULL,
174 2955076958026921730ULL,
175 7433723648458773977ULL,
176 },
177 {
178 16308865189192447297ULL,
179 11977192855656444890ULL,
180 12532242556065780287ULL,
181 14594890931430968898ULL,
182 7291784239689209784ULL,
183 5514718540551361949ULL,
184 10025733853830934803ULL,
185 7293794580341021693ULL,
186 6728552937464861756ULL,
187 6332385040983343262ULL,
188 13277683694236792804ULL,
189 2600778905124452676ULL,
190 },
191 {
192 7123075680859040534ULL,
193 1034205548717903090ULL,
194 7717824418247931797ULL,
195 3019070937878604058ULL,
196 11403792746066867460ULL,
197 10280580802233112374ULL,
198 337153209462421218ULL,
199 13333398568519923717ULL,
200 3596153696935337464ULL,
201 8104208463525993784ULL,
202 14345062289456085693ULL,
203 17036731477169661256ULL,
204 }};
205
206const uint64_t ARK2[7][12] = {
207 {
208 6077062762357204287ULL,
209 15277620170502011191ULL,
210 5358738125714196705ULL,
211 14233283787297595718ULL,
212 13792579614346651365ULL,
213 11614812331536767105ULL,
214 14871063686742261166ULL,
215 10148237148793043499ULL,
216 4457428952329675767ULL,
217 15590786458219172475ULL,
218 10063319113072092615ULL,
219 14200078843431360086ULL,
220 },
221 {
222 6202948458916099932ULL,
223 17690140365333231091ULL,
224 3595001575307484651ULL,
225 373995945117666487ULL,
226 1235734395091296013ULL,
227 14172757457833931602ULL,
228 707573103686350224ULL,
229 15453217512188187135ULL,
230 219777875004506018ULL,
231 17876696346199469008ULL,
232 17731621626449383378ULL,
233 2897136237748376248ULL,
234 },
235 {
236 8023374565629191455ULL,
237 15013690343205953430ULL,
238 4485500052507912973ULL,
239 12489737547229155153ULL,
240 9500452585969030576ULL,
241 2054001340201038870ULL,
242 12420704059284934186ULL,
243 355990932618543755ULL,
244 9071225051243523860ULL,
245 12766199826003448536ULL,
246 9045979173463556963ULL,
247 12934431667190679898ULL,
248 },
249 {
250 18389244934624494276ULL,
251 16731736864863925227ULL,
252 4440209734760478192ULL,
253 17208448209698888938ULL,
254 8739495587021565984ULL,
255 17000774922218161967ULL,
256 13533282547195532087ULL,
257 525402848358706231ULL,
258 16987541523062161972ULL,
259 5466806524462797102ULL,
260 14512769585918244983ULL,
261 10973956031244051118ULL,
262 },
263 {
264 6982293561042362913ULL,
265 14065426295947720331ULL,
266 16451845770444974180ULL,
267 7139138592091306727ULL,
268 9012006439959783127ULL,
269 14619614108529063361ULL,
270 1394813199588124371ULL,
271 4635111139507788575ULL,
272 16217473952264203365ULL,
273 10782018226466330683ULL,
274 6844229992533662050ULL,
275 7446486531695178711ULL,
276 },
277 {
278 3736792340494631448ULL,
279 577852220195055341ULL,
280 6689998335515779805ULL,
281 13886063479078013492ULL,
282 14358505101923202168ULL,
283 7744142531772274164ULL,
284 16135070735728404443ULL,
285 12290902521256031137ULL,
286 12059913662657709804ULL,
287 16456018495793751911ULL,
288 4571485474751953524ULL,
289 17200392109565783176ULL,
290 },
291 {
292 17130398059294018733ULL,
293 519782857322261988ULL,
294 9625384390925085478ULL,
295 1664893052631119222ULL,
296 7629576092524553570ULL,
297 3485239601103661425ULL,
298 9755891797164033838ULL,
299 15218148195153269027ULL,
300 16460604813734957368ULL,
301 9643968136937729763ULL,
302 3611348709641382851ULL,
303 18256379591337759196ULL,
304 },
305};
306
307static void apply_sbox(uint64_t *const state)
308{
309 for (uint64_t i = 0; i < STATE_WIDTH; i++)
310 {
311 uint64_t t2 = mult_mod_p(*(state + i), *(state + i));
312 uint64_t t4 = mult_mod_p(t2, t2);
313
314 *(state + i) = mult_mod_p(*(state + i), mult_mod_p(t2, t4));
315 }
316}
317
318static void apply_mds(uint64_t *state)
319{
320 uint64_t res[STATE_WIDTH];
321 for (uint64_t i = 0; i < STATE_WIDTH; i++)
322 {
323 res[i] = 0;
324 }
325 for (uint64_t i = 0; i < STATE_WIDTH; i++)
326 {
327 for (uint64_t j = 0; j < STATE_WIDTH; j++)
328 {
329 res[i] = add_mod_p(res[i], mult_mod_p(MDS[i][j], *(state + j)));
330 }
331 }
332
333 for (uint64_t i = 0; i < STATE_WIDTH; i++)
334 {
335 *(state + i) = res[i];
336 }
337}
338
339static void apply_constants(uint64_t *const state, const uint64_t *ark)
340{
341 for (uint64_t i = 0; i < STATE_WIDTH; i++)
342 {
343 *(state + i) = add_mod_p(*(state + i), *(ark + i));
344 }
345}
346
347static void exp_acc(const uint64_t m, const uint64_t *base, const uint64_t *tail, uint64_t *const res)
348{
349 for (uint64_t i = 0; i < m; i++)
350 {
351 for (uint64_t j = 0; j < STATE_WIDTH; j++)
352 {
353 if (i == 0)
354 {
355 *(res + j) = mult_mod_p(*(base + j), *(base + j));
356 }
357 else
358 {
359 *(res + j) = mult_mod_p(*(res + j), *(res + j));
360 }
361 }
362 }
363
364 for (uint64_t i = 0; i < STATE_WIDTH; i++)
365 {
366 *(res + i) = mult_mod_p(*(res + i), *(tail + i));
367 }
368}
369
370static void apply_inv_sbox(uint64_t *const state)
371{
372 uint64_t t1[STATE_WIDTH];
373 for (uint64_t i = 0; i < STATE_WIDTH; i++)
374 {
375 t1[i] = 0;
376 }
377 for (uint64_t i = 0; i < STATE_WIDTH; i++)
378 {
379 t1[i] = mult_mod_p(*(state + i), *(state + i));
380 }
381
382 uint64_t t2[STATE_WIDTH];
383 for (uint64_t i = 0; i < STATE_WIDTH; i++)
384 {
385 t2[i] = 0;
386 }
387 for (uint64_t i = 0; i < STATE_WIDTH; i++)
388 {
389 t2[i] = mult_mod_p(t1[i], t1[i]);
390 }
391
392 uint64_t t3[STATE_WIDTH];
393 for (uint64_t i = 0; i < STATE_WIDTH; i++)
394 {
395 t3[i] = 0;
396 }
397 exp_acc(3, t2, t2, t3);
398
399 uint64_t t4[STATE_WIDTH];
400 for (uint64_t i = 0; i < STATE_WIDTH; i++)
401 {
402 t4[i] = 0;
403 }
404 exp_acc(6, t3, t3, t4);
405
406 uint64_t tmp[STATE_WIDTH];
407 for (uint64_t i = 0; i < STATE_WIDTH; i++)
408 {
409 tmp[i] = 0;
410 }
411 exp_acc(12, t4, t4, tmp);
412
413 uint64_t t5[STATE_WIDTH];
414 for (uint64_t i = 0; i < STATE_WIDTH; i++)
415 {
416 t5[i] = 0;
417 }
418 exp_acc(6, tmp, t3, t5);
419
420 uint64_t t6[STATE_WIDTH];
421 for (uint64_t i = 0; i < STATE_WIDTH; i++)
422 {
423 t6[i] = 0;
424 }
425 exp_acc(31, t5, t5, t6);
426
427 for (uint64_t i = 0; i < STATE_WIDTH; i++)
428 {
429 uint64_t a = mult_mod_p(mult_mod_p(t6[i], t6[i]), t5[i]);
430 a = mult_mod_p(a, a);
431 a = mult_mod_p(a, a);
432 uint64_t b = mult_mod_p(mult_mod_p(t1[i], t2[i]), *(state + i));
433
434 *(state + i) = mult_mod_p(a, b);
435 }
436}
437
438static void apply_round(uint64_t *const state, const uint64_t round)
439{
440 apply_mds(state);
441 apply_constants(state, ARK1[round]);
442 apply_sbox(state);
443
444 apply_mds(state);
445 apply_constants(state, ARK2[round]);
446 apply_inv_sbox(state);
447}
448
449static void apply_permutation(uint64_t *state)
450{
451 for (uint64_t i = 0; i < NUM_ROUNDS; i++)
452 {
453 apply_round(state, i);
454 }
455}
456
457/* ================================================================================================
458 * RPO128 implementation. This is supposed to substitute SHAKE256 in the hash-to-point algorithm.
459 */
460
461#include "rpo.h"
462
463void rpo128_init(rpo128_context *rc)
464{
465 rc->dptr = 32;
466
467 memset(rc->st.A, 0, sizeof rc->st.A);
468}
469
470void rpo128_absorb(rpo128_context *rc, const uint8_t *in, size_t len)
471{
472 size_t dptr;
473
474 dptr = (size_t)rc->dptr;
475 while (len > 0)
476 {
477 size_t clen, u;
478
479 /* 136 * 8 = 1088 bit for the rate portion in the case of SHAKE256
480 * For RPO, this is 64 * 8 = 512 bits
481 * The capacity for SHAKE256 is at the end while for RPO128 it is at the beginning
482 */
483 clen = 96 - dptr;
484 if (clen > len)
485 {
486 clen = len;
487 }
488
489 for (u = 0; u < clen; u++)
490 {
491 rc->st.dbuf[dptr + u] = in[u];
492 }
493
494 dptr += clen;
495 in += clen;
496 len -= clen;
497 if (dptr == 96)
498 {
499 apply_permutation(rc->st.A);
500 dptr = 32;
501 }
502 }
503 rc->dptr = dptr;
504}
505
506void rpo128_finalize(rpo128_context *rc)
507{
508 // Set dptr to the end of the buffer, so that first call to extract will call the permutation.
509 rc->dptr = 96;
510}
511
512void rpo128_squeeze(rpo128_context *rc, uint8_t *out, size_t len)
513{
514 size_t dptr;
515
516 dptr = (size_t)rc->dptr;
517 while (len > 0)
518 {
519 size_t clen;
520
521 if (dptr == 96)
522 {
523 apply_permutation(rc->st.A);
524 dptr = 32;
525 }
526 clen = 96 - dptr;
527 if (clen > len)
528 {
529 clen = len;
530 }
531 len -= clen;
532
533 memcpy(out, rc->st.dbuf + dptr, clen);
534 dptr += clen;
535 out += clen;
536 }
537 rc->dptr = dptr;
538}
539
540void rpo128_release(rpo128_context *rc)
541{
542 memset(rc->st.A, 0, sizeof rc->st.A);
543 rc->dptr = 32;
544}
545
546/* ================================================================================================
547 * Hash-to-Point algorithm implementation based on RPO128
548 */
549
550void PQCLEAN_FALCON512_CLEAN_hash_to_point_rpo(rpo128_context *rc, uint16_t *x, unsigned logn)
551{
552 /*
553 * This implementation avoids the rejection sampling step needed in the
554 * per-the-spec implementation. It uses a remark in https://falcon-sign.info/falcon.pdf
555 * page 31, which argues that the current variant is secure for the parameters set by NIST.
556 * Avoiding the rejection-sampling step leads to an implementation that is constant-time.
557 * TODO: Check that the current implementation is indeed constant-time.
558 */
559 size_t n;
560
561 n = (size_t)1 << logn;
562 while (n > 0)
563 {
564 uint8_t buf[8];
565 uint64_t w;
566
567 rpo128_squeeze(rc, (void *)buf, sizeof buf);
568 w = ((uint64_t)(buf[7]) << 56) |
569 ((uint64_t)(buf[6]) << 48) |
570 ((uint64_t)(buf[5]) << 40) |
571 ((uint64_t)(buf[4]) << 32) |
572 ((uint64_t)(buf[3]) << 24) |
573 ((uint64_t)(buf[2]) << 16) |
574 ((uint64_t)(buf[1]) << 8) |
575 ((uint64_t)(buf[0]));
576
577 w %= M;
578
579 *x++ = (uint16_t)w;
580 n--;
581 }
582}