curve448.c
Go to the documentation of this file.
1 /**
2  * @file curve448.c
3  * @brief Curve448 elliptic curve (constant-time implementation)
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2024 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneCRYPTO Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.4.4
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL CRYPTO_TRACE_LEVEL
33 
34 //Dependencies
35 #include "core/crypto.h"
36 #include "ecc/ec_curves.h"
37 #include "ecc/curve448.h"
38 #include "debug.h"
39 
40 //Check crypto library configuration
41 #if (X448_SUPPORT == ENABLED || ED448_SUPPORT == ENABLED)
42 
43 
44 /**
45  * @brief Set integer value
46  * @param[out] a Pointer to the integer to be initialized
47  * @param[in] b Initial value
48  **/
49 
50 void curve448SetInt(uint32_t *a, uint32_t b)
51 {
52  uint_t i;
53 
54  //Set the value of the least significant word
55  a[0] = b;
56 
57  //Initialize the rest of the integer
58  for(i = 1; i < 14; i++)
59  {
60  a[i] = 0;
61  }
62 }
63 
64 
65 /**
66  * @brief Modular addition
67  * @param[out] r Resulting integer R = (A + B) mod p
68  * @param[in] a An integer such as 0 <= A < p
69  * @param[in] b An integer such as 0 <= B < p
70  **/
71 
72 void curve448Add(uint32_t *r, const uint32_t *a, const uint32_t *b)
73 {
74  uint_t i;
75  uint64_t temp;
76 
77  //Compute R = A + B
78  for(temp = 0, i = 0; i < 14; i++)
79  {
80  temp += a[i];
81  temp += b[i];
82  r[i] = temp & 0xFFFFFFFF;
83  temp >>= 32;
84  }
85 
86  //Perform modular reduction
87  curve448Red(r, r, (uint32_t) temp);
88 }
89 
90 
91 /**
92  * @brief Modular addition
93  * @param[out] r Resulting integer R = (A + B) mod p
94  * @param[in] a An integer such as 0 <= A < p
95  * @param[in] b An integer such as 0 <= B < (2^32 - 1)
96  **/
97 
98 void curve448AddInt(uint32_t *r, const uint32_t *a, uint32_t b)
99 {
100  uint_t i;
101  uint64_t temp;
102 
103  //Compute R = A + B
104  for(temp = b, i = 0; i < 14; i++)
105  {
106  temp += a[i];
107  r[i] = temp & 0xFFFFFFFF;
108  temp >>= 32;
109  }
110 
111  //Perform modular reduction
112  curve448Red(r, r, (uint32_t) temp);
113 }
114 
115 
116 /**
117  * @brief Modular subtraction
118  * @param[out] r Resulting integer R = (A - B) mod p
119  * @param[in] a An integer such as 0 <= A < p
120  * @param[in] b An integer such as 0 <= B < p
121  **/
122 
123 void curve448Sub(uint32_t *r, const uint32_t *a, const uint32_t *b)
124 {
125  uint_t i;
126  int64_t temp;
127 
128  //Compute R = A + (2^448 - 2^224 - 1) - B
129  for(temp = -1, i = 0; i < 7; i++)
130  {
131  temp += a[i];
132  temp -= b[i];
133  r[i] = temp & 0xFFFFFFFF;
134  temp >>= 32;
135  }
136 
137  for(temp -= 1, i = 7; i < 14; i++)
138  {
139  temp += a[i];
140  temp -= b[i];
141  r[i] = temp & 0xFFFFFFFF;
142  temp >>= 32;
143  }
144 
145  //Compute the highest term of the result
146  temp += 1;
147 
148  //Perform modular reduction
149  curve448Red(r, r, (uint32_t) temp);
150 }
151 
152 
153 /**
154  * @brief Modular subtraction
155  * @param[out] r Resulting integer R = (A - B) mod p
156  * @param[in] a An integer such as 0 <= A < p
157  * @param[in] b An integer such as 0 <= B < (2^32 - 1)
158  **/
159 
160 void curve448SubInt(uint32_t *r, const uint32_t *a, uint32_t b)
161 {
162  uint_t i;
163  int64_t temp;
164 
165  //Set initial value
166  temp = -1;
167  temp -= b;
168 
169  //Compute R = A + (2^448 - 2^224 - 1) - B
170  for(i = 0; i < 7; i++)
171  {
172  temp += a[i];
173  r[i] = temp & 0xFFFFFFFF;
174  temp >>= 32;
175  }
176 
177  for(temp -= 1, i = 7; i < 14; i++)
178  {
179  temp += a[i];
180  r[i] = temp & 0xFFFFFFFF;
181  temp >>= 32;
182  }
183 
184  //Compute the highest term of the result
185  temp += 1;
186 
187  //Perform modular reduction
188  curve448Red(r, r, (uint32_t) temp);
189 }
190 
191 
192 /**
193  * @brief Modular multiplication
194  * @param[out] r Resulting integer R = (A * B) mod p
195  * @param[in] a An integer such as 0 <= A < p
196  * @param[in] b An integer such as 0 <= B < p
197  **/
198 
199 __weak_func void curve448Mul(uint32_t *r, const uint32_t *a, const uint32_t *b)
200 {
201  uint_t i;
202  uint_t j;
203  uint64_t c;
204  uint64_t temp;
205  uint32_t u[28];
206 
207  //Initialize variables
208  temp = 0;
209  c = 0;
210 
211  //Comba's method is used to perform multiplication
212  for(i = 0; i < 28; i++)
213  {
214  //The algorithm computes the products, column by column
215  if(i < 14)
216  {
217  //Inner loop
218  for(j = 0; j <= i; j++)
219  {
220  temp += (uint64_t) a[j] * b[i - j];
221  c += temp >> 32;
222  temp &= 0xFFFFFFFF;
223  }
224  }
225  else
226  {
227  //Inner loop
228  for(j = i - 13; j < 14; j++)
229  {
230  temp += (uint64_t) a[j] * b[i - j];
231  c += temp >> 32;
232  temp &= 0xFFFFFFFF;
233  }
234  }
235 
236  //At the bottom of each column, the final result is written to memory
237  u[i] = temp & 0xFFFFFFFF;
238 
239  //Propagate the carry upwards
240  temp = c & 0xFFFFFFFF;
241  c >>= 32;
242  }
243 
244  //Perform fast modular reduction (first pass)
245  for(temp = 0, i = 0; i < 7; i++)
246  {
247  temp += u[i];
248  temp += u[i + 14];
249  temp += u[i + 21];
250  u[i] = temp & 0xFFFFFFFF;
251  temp >>= 32;
252  }
253 
254  for(i = 7; i < 14; i++)
255  {
256  temp += u[i];
257  temp += u[i + 7];
258  temp += (uint64_t) u[i + 14] << 1;
259  u[i] = temp & 0xFFFFFFFF;
260  temp >>= 32;
261  }
262 
263  //Perform fast modular reduction (second pass)
264  for(c = temp, i = 0; i < 7; i++)
265  {
266  temp += u[i];
267  u[i] = temp & 0xFFFFFFFF;
268  temp >>= 32;
269  }
270 
271  for(temp += c, i = 7; i < 14; i++)
272  {
273  temp += u[i];
274  u[i] = temp & 0xFFFFFFFF;
275  temp >>= 32;
276  }
277 
278  //Reduce non-canonical values
279  curve448Red(r, u, (uint32_t) temp);
280 }
281 
282 
283 /**
284  * @brief Modular multiplication
285  * @param[out] r Resulting integer R = (A * B) mod p
286  * @param[in] a An integer such as 0 <= A < p
287  * @param[in] b An integer such as 0 <= B < (2^32 - 1)
288  **/
289 
290 void curve448MulInt(uint32_t *r, const uint32_t *a, uint32_t b)
291 {
292  int_t i;
293  uint64_t c;
294  uint64_t temp;
295  uint32_t u[14];
296 
297  //Compute R = A * B
298  for(temp = 0, i = 0; i < 14; i++)
299  {
300  temp += (uint64_t) a[i] * b;
301  u[i] = temp & 0xFFFFFFFF;
302  temp >>= 32;
303  }
304 
305  //Perform fast modular reduction
306  for(c = temp, i = 0; i < 7; i++)
307  {
308  temp += u[i];
309  u[i] = temp & 0xFFFFFFFF;
310  temp >>= 32;
311  }
312 
313  for(temp += c, i = 7; i < 14; i++)
314  {
315  temp += u[i];
316  u[i] = temp & 0xFFFFFFFF;
317  temp >>= 32;
318  }
319 
320  //Reduce non-canonical values
321  curve448Red(r, u, (uint32_t) temp);
322 }
323 
324 
325 /**
326  * @brief Modular squaring
327  * @param[out] r Resulting integer R = (A ^ 2) mod p
328  * @param[in] a An integer such as 0 <= A < p
329  **/
330 
331 void curve448Sqr(uint32_t *r, const uint32_t *a)
332 {
333  //Compute R = (A ^ 2) mod p
334  curve448Mul(r, a, a);
335 }
336 
337 
338 /**
339  * @brief Raise an integer to power 2^n
340  * @param[out] r Resulting integer R = (A ^ (2^n)) mod p
341  * @param[in] a An integer such as 0 <= A < p
342  * @param[in] n An integer such as n >= 1
343  **/
344 
345 void curve448Pwr2(uint32_t *r, const uint32_t *a, uint_t n)
346 {
347  uint_t i;
348 
349  //Pre-compute (A ^ 2) mod p
350  curve448Sqr(r, a);
351 
352  //Compute R = (A ^ (2^n)) mod p
353  for(i = 1; i < n; i++)
354  {
355  curve448Sqr(r, r);
356  }
357 }
358 
359 
360 /**
361  * @brief Modular reduction
362  * @param[out] r Resulting integer R = A mod p
363  * @param[in] a An integer such as 0 <= A < (2 * p)
364  * @param[in] h The highest term of A
365  **/
366 
367 void curve448Red(uint32_t *r, const uint32_t *a, uint32_t h)
368 {
369  uint_t i;
370  uint64_t temp;
371  uint32_t b[14];
372 
373  //Compute B = A - (2^448 - 2^224 - 1)
374  for(temp = 1, i = 0; i < 7; i++)
375  {
376  temp += a[i];
377  b[i] = temp & 0xFFFFFFFF;
378  temp >>= 32;
379  }
380 
381  for(temp += 1, i = 7; i < 14; i++)
382  {
383  temp += a[i];
384  b[i] = temp & 0xFFFFFFFF;
385  temp >>= 32;
386  }
387 
388  //Compute the highest term of the result
389  h += (uint32_t) temp - 1;
390 
391  //If B < (2^448 - 2^224 + 1) then R = B, else R = A
392  curve448Select(r, b, a, h & 1);
393 }
394 
395 
396 /**
397  * @brief Modular multiplicative inverse
398  * @param[out] r Resulting integer R = A^-1 mod p
399  * @param[in] a An integer such as 0 <= A < p
400  **/
401 
402 void curve448Inv(uint32_t *r, const uint32_t *a)
403 {
404  uint32_t u[14];
405  uint32_t v[14];
406 
407  //Since GF(p) is a prime field, the Fermat's little theorem can be
408  //used to find the multiplicative inverse of A modulo p
409  curve448Sqr(u, a);
410  curve448Mul(u, u, a); //A^(2^2 - 1)
411  curve448Sqr(u, u);
412  curve448Mul(v, u, a); //A^(2^3 - 1)
413  curve448Pwr2(u, v, 3);
414  curve448Mul(v, u, v); //A^(2^6 - 1)
415  curve448Pwr2(u, v, 6);
416  curve448Mul(u, u, v); //A^(2^12 - 1)
417  curve448Sqr(u, u);
418  curve448Mul(v, u, a); //A^(2^13 - 1)
419  curve448Pwr2(u, v, 13);
420  curve448Mul(u, u, v); //A^(2^26 - 1)
421  curve448Sqr(u, u);
422  curve448Mul(v, u, a); //A^(2^27 - 1)
423  curve448Pwr2(u, v, 27);
424  curve448Mul(u, u, v); //A^(2^54 - 1)
425  curve448Sqr(u, u);
426  curve448Mul(v, u, a); //A^(2^55 - 1)
427  curve448Pwr2(u, v, 55);
428  curve448Mul(u, u, v); //A^(2^110 - 1)
429  curve448Sqr(u, u);
430  curve448Mul(v, u, a); //A^(2^111 - 1)
431  curve448Pwr2(u, v, 111);
432  curve448Mul(v, u, v); //A^(2^222 - 1)
433  curve448Sqr(u, v);
434  curve448Mul(u, u, a); //A^(2^223 - 1)
435  curve448Pwr2(u, u, 223);
436  curve448Mul(u, u, v); //A^(2^446 - 2^222 - 1)
437  curve448Sqr(u, u);
438  curve448Sqr(u, u);
439  curve448Mul(r, u, a); //A^(2^448 - 2^224 - 3)
440 }
441 
442 
443 /**
444  * @brief Compute the square root of (A / B) modulo p
445  * @param[out] r Resulting integer R = (A / B)^(1 / 2) mod p
446  * @param[in] a An integer such as 0 <= A < p
447  * @param[in] b An integer such as 0 < B < p
448  * @return The function returns 0 if the square root exists, else 1
449  **/
450 
451 uint32_t curve448Sqrt(uint32_t *r, const uint32_t *a, const uint32_t *b)
452 {
453  uint32_t res;
454  uint32_t c[14];
455  uint32_t u[14];
456  uint32_t v[14];
457 
458  //Compute the candidate root (A / B)^((p + 1) / 4). This can be done
459  //with the following trick, using a single modular powering for both the
460  //inversion of B and the square root: A^3 * B * (A^5 * B^3)^((p - 3) / 4)
461  curve448Sqr(u, a);
462  curve448Sqr(u, u);
463  curve448Mul(u, u, a);
464  curve448Sqr(v, b);
465  curve448Mul(v, v, b);
466 
467  //Compute C = A^5 * B^3
468  curve448Mul(c, u, v);
469 
470  //Compute U = C^((p - 3) / 4)
471  curve448Sqr(u, c);
472  curve448Mul(u, u, c); //C^(2^2 - 1)
473  curve448Sqr(u, u);
474  curve448Mul(v, u, c); //C^(2^3 - 1)
475  curve448Pwr2(u, v, 3);
476  curve448Mul(v, u, v); //C^(2^6 - 1)
477  curve448Pwr2(u, v, 6);
478  curve448Mul(u, u, v); //C^(2^12 - 1)
479  curve448Sqr(u, u);
480  curve448Mul(v, u, c); //C^(2^13 - 1)
481  curve448Pwr2(u, v, 13);
482  curve448Mul(u, u, v); //C^(2^26 - 1)
483  curve448Sqr(u, u);
484  curve448Mul(v, u, c); //C^(2^27 - 1)
485  curve448Pwr2(u, v, 27);
486  curve448Mul(u, u, v); //C^(2^54 - 1)
487  curve448Sqr(u, u);
488  curve448Mul(v, u, c); //C^(2^55 - 1)
489  curve448Pwr2(u, v, 55);
490  curve448Mul(u, u, v); //C^(2^110 - 1)
491  curve448Sqr(u, u);
492  curve448Mul(v, u, c); //C^(2^111 - 1)
493  curve448Pwr2(u, v, 111);
494  curve448Mul(v, u, v); //C^(2^222 - 1)
495  curve448Sqr(u, v);
496  curve448Mul(u, u, c); //C^(2^223 - 1)
497  curve448Pwr2(u, u, 223);
498  curve448Mul(u, u, v); //C^(2^446 - 2^222 - 1)
499 
500  //The candidate root is U = A^3 * B * (A^5 * B^3)^((p - 3) / 4)
501  curve448Sqr(v, a);
502  curve448Mul(v, v, a);
503  curve448Mul(u, u, v);
504  curve448Mul(u, u, b);
505 
506  //Calculate C = B * U^2
507  curve448Sqr(c, u);
508  curve448Mul(c, c, b);
509 
510  //Check whether B * U^2 = A
511  res = curve448Comp(c, a);
512 
513  //Copy the candidate root
514  curve448Copy(r, u);
515 
516  //Return 0 if the square root exists
517  return res;
518 }
519 
520 
521 /**
522  * @brief Copy an integer
523  * @param[out] a Pointer to the destination integer
524  * @param[in] b Pointer to the source integer
525  **/
526 
527 void curve448Copy(uint32_t *a, const uint32_t *b)
528 {
529  uint_t i;
530 
531  //Copy the value of the integer
532  for(i = 0; i < 14; i++)
533  {
534  a[i] = b[i];
535  }
536 }
537 
538 
539 /**
540  * @brief Conditional swap
541  * @param[in,out] a Pointer to the first integer
542  * @param[in,out] b Pointer to the second integer
543  * @param[in] c Condition variable
544  **/
545 
546 void curve448Swap(uint32_t *a, uint32_t *b, uint32_t c)
547 {
548  uint_t i;
549  uint32_t mask;
550  uint32_t dummy;
551 
552  //The mask is the all-1 or all-0 word
553  mask = ~c + 1;
554 
555  //Conditional swap
556  for(i = 0; i < 14; i++)
557  {
558  //Constant time implementation
559  dummy = mask & (a[i] ^ b[i]);
560  a[i] ^= dummy;
561  b[i] ^= dummy;
562  }
563 }
564 
565 
566 /**
567  * @brief Select an integer
568  * @param[out] r Pointer to the destination integer
569  * @param[in] a Pointer to the first source integer
570  * @param[in] b Pointer to the second source integer
571  * @param[in] c Condition variable
572  **/
573 
574 void curve448Select(uint32_t *r, const uint32_t *a, const uint32_t *b,
575  uint32_t c)
576 {
577  uint_t i;
578  uint32_t mask;
579 
580  //The mask is the all-1 or all-0 word
581  mask = c - 1;
582 
583  //Select between A and B
584  for(i = 0; i < 14; i++)
585  {
586  //Constant time implementation
587  r[i] = (a[i] & mask) | (b[i] & ~mask);
588  }
589 }
590 
591 
592 /**
593  * @brief Compare integers
594  * @param[in] a Pointer to the first integer
595  * @param[in] b Pointer to the second integer
596  * @return The function returns 0 if the A = B, else 1
597  **/
598 
599 uint32_t curve448Comp(const uint32_t *a, const uint32_t *b)
600 {
601  uint_t i;
602  uint32_t mask;
603 
604  //Initialize mask
605  mask = 0;
606 
607  //Compare A and B
608  for(i = 0; i < 14; i++)
609  {
610  //Constant time implementation
611  mask |= a[i] ^ b[i];
612  }
613 
614  //Return 0 if A = B, else 1
615  return ((uint32_t) (mask | (~mask + 1))) >> 31;
616 }
617 
618 
619 /**
620  * @brief Import an octet string
621  * @param[out] a Pointer to resulting integer
622  * @param[in] data Octet string to be converted
623  **/
624 
625 void curve448Import(uint32_t *a, const uint8_t *data)
626 {
627  uint_t i;
628 
629  //Import the octet string
630  osMemcpy(a, data, 56);
631 
632  //Convert from little-endian byte order to host byte order
633  for(i = 0; i < 14; i++)
634  {
635  a[i] = letoh32(a[i]);
636  }
637 }
638 
639 
640 /**
641  * @brief Export an octet string
642  * @param[in] a Pointer to the integer to be exported
643  * @param[out] data Octet string resulting from the conversion
644  **/
645 
646 void curve448Export(uint32_t *a, uint8_t *data)
647 {
648  uint_t i;
649 
650  //Convert from host byte order to little-endian byte order
651  for(i = 0; i < 14; i++)
652  {
653  a[i] = htole32(a[i]);
654  }
655 
656  //Export the octet string
657  osMemcpy(data, a, 56);
658 }
659 
660 #endif
Curve448 elliptic curve (constant-time implementation)
uint8_t b
Definition: nbns_common.h:104
uint8_t a
Definition: ndp.h:411
signed int int_t
Definition: compiler_port.h:49
void curve448Select(uint32_t *r, const uint32_t *a, const uint32_t *b, uint32_t c)
Select an integer.
Definition: curve448.c:574
void curve448Export(uint32_t *a, uint8_t *data)
Export an octet string.
Definition: curve448.c:646
uint8_t data[]
Definition: ethernet.h:222
void curve448Copy(uint32_t *a, const uint32_t *b)
Copy an integer.
Definition: curve448.c:527
void curve448MulInt(uint32_t *r, const uint32_t *a, uint32_t b)
Modular multiplication.
Definition: curve448.c:290
void curve448SubInt(uint32_t *r, const uint32_t *a, uint32_t b)
Modular subtraction.
Definition: curve448.c:160
const uint8_t res[]
uint8_t r
Definition: ndp.h:346
#define letoh32(value)
Definition: cpu_endian.h:438
uint8_t h
Definition: ndp.h:302
#define osMemcpy(dest, src, length)
Definition: os_port.h:141
#define htole32(value)
Definition: cpu_endian.h:430
void curve448Import(uint32_t *a, const uint8_t *data)
Import an octet string.
Definition: curve448.c:625
void curve448Inv(uint32_t *r, const uint32_t *a)
Modular multiplicative inverse.
Definition: curve448.c:402
void curve448Pwr2(uint32_t *r, const uint32_t *a, uint_t n)
Raise an integer to power 2^n.
Definition: curve448.c:345
void curve448Sqr(uint32_t *r, const uint32_t *a)
Modular squaring.
Definition: curve448.c:331
General definitions for cryptographic algorithms.
uint8_t mask
Definition: web_socket.h:319
uint8_t u
Definition: lldp_ext_med.h:213
void curve448SetInt(uint32_t *a, uint32_t b)
Set integer value.
Definition: curve448.c:50
void curve448Swap(uint32_t *a, uint32_t *b, uint32_t c)
Conditional swap.
Definition: curve448.c:546
uint32_t curve448Sqrt(uint32_t *r, const uint32_t *a, const uint32_t *b)
Compute the square root of (A / B) modulo p.
Definition: curve448.c:451
uint8_t n
void curve448Add(uint32_t *r, const uint32_t *a, const uint32_t *b)
Modular addition.
Definition: curve448.c:72
void curve448Sub(uint32_t *r, const uint32_t *a, const uint32_t *b)
Modular subtraction.
Definition: curve448.c:123
void curve448Red(uint32_t *r, const uint32_t *a, uint32_t h)
Modular reduction.
Definition: curve448.c:367
void curve448AddInt(uint32_t *r, const uint32_t *a, uint32_t b)
Modular addition.
Definition: curve448.c:98
unsigned int uint_t
Definition: compiler_port.h:50
Elliptic curves.
uint32_t curve448Comp(const uint32_t *a, const uint32_t *b)
Compare integers.
Definition: curve448.c:599
__weak_func void curve448Mul(uint32_t *r, const uint32_t *a, const uint32_t *b)
Modular multiplication.
Definition: curve448.c:199
uint8_t c
Definition: ndp.h:514
Debugging facilities.