esp32_crypto_pkc.c
Go to the documentation of this file.
1 /**
2  * @file esp32_crypto_pkc.c
3  * @brief ESP32 public-key hardware accelerator
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 "soc/hwcrypto_reg.h"
36 #include "soc/dport_access.h"
37 #include "esp_private/periph_ctrl.h"
40 #include "pkc/rsa.h"
41 #include "ecc/curve25519.h"
42 #include "ecc/curve448.h"
43 #include "debug.h"
44 
45 //Check crypto library configuration
46 #if (ESP32_CRYPTO_PKC_SUPPORT == ENABLED)
47 
48 
49 /**
50  * @brief RSA module initialization
51  **/
52 
53 void esp32RsaInit(void)
54 {
55  //Enable RSA module
56  periph_module_enable(PERIPH_RSA_MODULE);
57 
58  //Software should query RSA_CLEAN_REG after being released from reset, and
59  //before writing to any RSA Accelerator memory blocks or registers for the
60  //first time
61  while(DPORT_REG_READ(RSA_CLEAN_REG) == 0)
62  {
63  }
64 }
65 
66 
67 /**
68  * @brief Multiple precision multiplication
69  * @param[out] r Resulting integer R = A * B
70  * @param[in] a First operand A
71  * @param[in] b Second operand B
72  * @return Error code
73  **/
74 
75 error_t mpiMul(Mpi *r, const Mpi *a, const Mpi *b)
76 {
77  error_t error;
78  size_t i;
79  size_t n;
80  size_t aLen;
81  size_t bLen;
82 
83  //Retrieve the length of the first operand, in 32-bit words
84  aLen = mpiGetLength(a);
85  //Retrieve the length of the second operand, in 32-bit words
86  bLen = mpiGetLength(b);
87 
88  //The accelerator supports large-number multiplication up to 2048 bits
89  if(aLen <= 64 && bLen <= 64)
90  {
91  //All numbers in calculation must be of the same length
92  n = 1;
93  n = MAX(n, aLen);
94  n = MAX(n, bLen);
95  n = (n + 7) & ~7U;
96 
97  //Acquire exclusive access to the RSA module
99 
100  //Clear the interrupt flag
101  DPORT_REG_WRITE(RSA_INTERRUPT_REG, 1);
102  //Set mode register
103  DPORT_REG_WRITE(RSA_MULT_MODE_REG, (n / 8) - 1 + 8);
104 
105  //Copy the first operand to RSA_X_MEM
106  for(i = 0; i < n; i++)
107  {
108  if(i < a->size)
109  {
110  DPORT_REG_WRITE(RSA_MEM_X_BLOCK_BASE + i * 4, a->data[i]);
111  }
112  else
113  {
114  DPORT_REG_WRITE(RSA_MEM_X_BLOCK_BASE + i * 4, 0);
115  }
116  }
117 
118  //The second operand will not be written to the base address of the
119  //RSA_Z_MEM memory. This area must be filled with zeroes
120  for(i = 0; i < n; i++)
121  {
122  DPORT_REG_WRITE(RSA_MEM_Z_BLOCK_BASE + i * 4, 0);
123  }
124 
125  //The second operand must be written to the base address of the
126  //RSA_Z_MEM memory plus the address offset 4 * n
127  for(i = 0; i < n; i++)
128  {
129  if(i < b->size)
130  {
131  DPORT_REG_WRITE(RSA_MEM_Z_BLOCK_BASE + (n + i) * 4, b->data[i]);
132  }
133  else
134  {
135  DPORT_REG_WRITE(RSA_MEM_Z_BLOCK_BASE + (n + i) * 4, 0);
136  }
137  }
138 
139  //Start large-number multiplication
140  DPORT_REG_WRITE(RSA_MULT_START_REG, 1);
141 
142  //Wait for the operation to complete
143  while(DPORT_REG_READ(RSA_INTERRUPT_REG) == 0)
144  {
145  }
146 
147  //Set the sign of the result
148  r->sign = (a->sign == b->sign) ? 1 : -1;
149 
150  //The length of the result is 2 x N bits
151  error = mpiGrow(r, n * 2);
152 
153  //Check status code
154  if(!error)
155  {
156  //Disable interrupts only on current CPU
157  DPORT_INTERRUPT_DISABLE();
158 
159  //Read the result from RSA_Z_MEM
160  for(i = 0; i < r->size; i++)
161  {
162  if(i < (n * 2))
163  {
164  r->data[i] = DPORT_SEQUENCE_REG_READ(RSA_MEM_Z_BLOCK_BASE + i * 4);
165  }
166  else
167  {
168  r->data[i] = 0;
169  }
170  }
171 
172  //Restore the previous interrupt level
173  DPORT_INTERRUPT_RESTORE();
174  }
175 
176  //Clear the interrupt flag
177  DPORT_REG_WRITE(RSA_INTERRUPT_REG, 1);
178 
179  //Release exclusive access to the RSA module
181  }
182  else
183  {
184  //Report an error
185  error = ERROR_FAILURE;
186  }
187 
188  //Return status code
189  return error;
190 }
191 
192 
193 /**
194  * @brief Modular exponentiation
195  * @param[out] r Resulting integer R = A ^ E mod P
196  * @param[in] a Pointer to a multiple precision integer
197  * @param[in] e Exponent
198  * @param[in] p Modulus
199  * @return Error code
200  **/
201 
202 error_t mpiExpMod(Mpi *r, const Mpi *a, const Mpi *e, const Mpi *p)
203 {
204  error_t error;
205  size_t i;
206  size_t n;
207  size_t modLen;
208  size_t expLen;
209  uint32_t m;
210  Mpi t;
211  Mpi r2;
212 
213  //Initialize multiple precision integers
214  mpiInit(&t);
215  mpiInit(&r2);
216 
217  //Retrieve the length of the modulus, in 32-bit words
218  modLen = mpiGetLength(p);
219  //Retrieve the length of the exponent, in 32-bit words
220  expLen = mpiGetLength(e);
221 
222  //The accelerator supports operand lengths up to 4096 bits
223  if(modLen > 0 && modLen <= 128 && expLen > 0 && expLen <= 128)
224  {
225  //All numbers in calculation must be of the same length
226  n = MAX(modLen, expLen);
227  n = (n + 15) & ~15U;
228 
229  //Reduce the operand first
230  error = mpiMod(&t, a, p);
231 
232  //Let R = b^n and pre-compute the quantity R^2 mod M
233  if(!error)
234  {
235  error = mpiSetValue(&r2, 1);
236  }
237 
238  if(!error)
239  {
240  error = mpiShiftLeft(&r2, n * 2 * 32);
241  }
242 
243  if(!error)
244  {
245  error = mpiMod(&r2, &r2, p);
246  }
247 
248  //Check status code
249  if(!error)
250  {
251  //Acquire exclusive access to the RSA module
253 
254  //Clear the interrupt flag
255  DPORT_REG_WRITE(RSA_INTERRUPT_REG, 1);
256  //Set mode register
257  DPORT_REG_WRITE(RSA_MODEXP_MODE_REG, (n / 16) - 1);
258 
259  //Copy the operand to RSA_X_MEM
260  for(i = 0; i < n; i++)
261  {
262  if(i < t.size)
263  {
264  DPORT_REG_WRITE(RSA_MEM_X_BLOCK_BASE + i * 4, t.data[i]);
265  }
266  else
267  {
268  DPORT_REG_WRITE(RSA_MEM_X_BLOCK_BASE + i * 4, 0);
269  }
270  }
271 
272  //Copy the exponent to RSA_Y_MEM
273  for(i = 0; i < n; i++)
274  {
275  if(i < e->size)
276  {
277  DPORT_REG_WRITE(RSA_MEM_Y_BLOCK_BASE + i * 4, e->data[i]);
278  }
279  else
280  {
281  DPORT_REG_WRITE(RSA_MEM_Y_BLOCK_BASE + i * 4, 0);
282  }
283  }
284 
285  //Copy the modulus to RSA_M_MEM
286  for(i = 0; i < n; i++)
287  {
288  if(i < p->size)
289  {
290  DPORT_REG_WRITE(RSA_MEM_M_BLOCK_BASE + i * 4, p->data[i]);
291  }
292  else
293  {
294  DPORT_REG_WRITE(RSA_MEM_M_BLOCK_BASE + i * 4, 0);
295  }
296  }
297 
298  //Copy the pre-calculated value of R^2 mod M to RSA_Z_MEM
299  for(i = 0; i < n; i++)
300  {
301  if(i < r2.size)
302  {
303  DPORT_REG_WRITE(RSA_MEM_RB_BLOCK_BASE + i * 4, r2.data[i]);
304  }
305  else
306  {
307  DPORT_REG_WRITE(RSA_MEM_RB_BLOCK_BASE + i * 4, 0);
308  }
309  }
310 
311  //Use Newton's method to compute the inverse of M[0] mod 2^32
312  for(m = 2 - p->data[0], i = 0; i < 4; i++)
313  {
314  m = m * (2 - m * p->data[0]);
315  }
316 
317  //Precompute M' = -1/M[0] mod 2^32;
318  m = ~m + 1;
319 
320  //Write the value of M' to RSA_M_PRIME_REG
321  DPORT_REG_WRITE(RSA_M_DASH_REG, m);
322 
323  //Start modular exponentiation
324  DPORT_REG_WRITE(RSA_MODEXP_START_REG, 1);
325 
326  //Wait for the operation to complete
327  while(DPORT_REG_READ(RSA_INTERRUPT_REG) == 0)
328  {
329  }
330 
331  //Adjust the size of the result if necessary
332  error = mpiGrow(r, n);
333 
334  //Check status code
335  if(!error)
336  {
337  //Disable interrupts only on current CPU
338  DPORT_INTERRUPT_DISABLE();
339 
340  //Read the result from RSA_Z_MEM
341  for(i = 0; i < r->size; i++)
342  {
343  if(i < n)
344  {
345  r->data[i] = DPORT_SEQUENCE_REG_READ(RSA_MEM_Z_BLOCK_BASE + i * 4);
346  }
347  else
348  {
349  r->data[i] = 0;
350  }
351  }
352 
353  //Restore the previous interrupt level
354  DPORT_INTERRUPT_RESTORE();
355  }
356 
357  //Clear the interrupt flag
358  DPORT_REG_WRITE(RSA_INTERRUPT_REG, 1);
359 
360  //Release exclusive access to the RSA module
362  }
363  }
364  else
365  {
366  //Report an error
367  error = ERROR_FAILURE;
368  }
369 
370  //Release previously allocated memory
371  mpiFree(&t);
372  mpiFree(&r2);
373 
374  //Return status code
375  return error;
376 }
377 
378 
379 #if (X25519_SUPPORT == ENABLED || ED25519_SUPPORT == ENABLED)
380 
381 /**
382  * @brief Modular multiplication
383  * @param[out] r Resulting integer R = (A * B) mod p
384  * @param[in] a An integer such as 0 <= A < p
385  * @param[in] b An integer such as 0 <= B < p
386  **/
387 
388 void curve25519Mul(uint32_t *r, const uint32_t *a, const uint32_t *b)
389 {
390  uint_t i;
391  uint64_t temp;
392  uint32_t u[16];
393 
394  //Acquire exclusive access to the RSA module
396 
397  //Clear the interrupt flag
398  DPORT_REG_WRITE(RSA_INTERRUPT_REG, 1);
399  //Set mode register
400  DPORT_REG_WRITE(RSA_MULT_MODE_REG, 8);
401 
402  //Copy the first operand to RSA_X_MEM
403  for(i = 0; i < 8; i++)
404  {
405  DPORT_REG_WRITE(RSA_MEM_X_BLOCK_BASE + i * 4, a[i]);
406  }
407 
408  //The second operand will not be written to the base address of the
409  //RSA_Z_MEM memory. This area must be filled with zeroes
410  for(i = 0; i < 8; i++)
411  {
412  DPORT_REG_WRITE(RSA_MEM_Z_BLOCK_BASE + i * 4, 0);
413  }
414 
415  //The second operand must be written to the base address of the
416  //RSA_Z_MEM memory plus the address offset 32
417  for(i = 0; i < 8; i++)
418  {
419  DPORT_REG_WRITE(RSA_MEM_Z_BLOCK_BASE + 32 + i * 4, b[i]);
420  }
421 
422  //Start large-number multiplication
423  DPORT_REG_WRITE(RSA_MULT_START_REG, 1);
424 
425  //Wait for the operation to complete
426  while(DPORT_REG_READ(RSA_INTERRUPT_REG) == 0)
427  {
428  }
429 
430  //Disable interrupts only on current CPU
431  DPORT_INTERRUPT_DISABLE();
432 
433  //Read the result from RSA_Z_MEM
434  for(i = 0; i < 16; i++)
435  {
436  u[i] = DPORT_SEQUENCE_REG_READ(RSA_MEM_Z_BLOCK_BASE + i * 4);
437  }
438 
439  //Restore the previous interrupt level
440  DPORT_INTERRUPT_RESTORE();
441  //Clear the interrupt flag
442  DPORT_REG_WRITE(RSA_INTERRUPT_REG, 1);
443 
444  //Release exclusive access to the RSA module
446 
447  //Reduce bit 255 (2^255 = 19 mod p)
448  temp = (u[7] >> 31) * 19;
449  //Mask the most significant bit
450  u[7] &= 0x7FFFFFFF;
451 
452  //Perform fast modular reduction (first pass)
453  for(i = 0; i < 8; i++)
454  {
455  temp += u[i];
456  temp += (uint64_t) u[i + 8] * 38;
457  u[i] = temp & 0xFFFFFFFF;
458  temp >>= 32;
459  }
460 
461  //Reduce bit 256 (2^256 = 38 mod p)
462  temp *= 38;
463  //Reduce bit 255 (2^255 = 19 mod p)
464  temp += (u[7] >> 31) * 19;
465  //Mask the most significant bit
466  u[7] &= 0x7FFFFFFF;
467 
468  //Perform fast modular reduction (second pass)
469  for(i = 0; i < 8; i++)
470  {
471  temp += u[i];
472  u[i] = temp & 0xFFFFFFFF;
473  temp >>= 32;
474  }
475 
476  //Reduce non-canonical values
477  curve25519Red(r, u);
478 }
479 
480 #endif
481 #if (X448_SUPPORT == ENABLED || ED448_SUPPORT == ENABLED)
482 
483 /**
484  * @brief Modular multiplication
485  * @param[out] r Resulting integer R = (A * B) mod p
486  * @param[in] a An integer such as 0 <= A < p
487  * @param[in] b An integer such as 0 <= B < p
488  **/
489 
490 void curve448Mul(uint32_t *r, const uint32_t *a, const uint32_t *b)
491 {
492  uint_t i;
493 
494  //Acquire exclusive access to the RSA module
496 
497  //Clear the interrupt flag
498  DPORT_REG_WRITE(RSA_INTERRUPT_REG, 1);
499  //Set mode register
500  DPORT_REG_WRITE(RSA_MULT_MODE_REG, 0);
501 
502  //Copy the first operand to RSA_X_MEM
503  for(i = 0; i < 14; i++)
504  {
505  DPORT_REG_WRITE(RSA_MEM_X_BLOCK_BASE + i * 4, a[i]);
506  }
507 
508  //Pad the first operand with zeroes
509  DPORT_REG_WRITE(RSA_MEM_X_BLOCK_BASE + 56, 0);
510  DPORT_REG_WRITE(RSA_MEM_X_BLOCK_BASE + 60, 0);
511 
512  //Copy the modulus to RSA_M_MEM
513  DPORT_REG_WRITE(RSA_MEM_M_BLOCK_BASE, 0xFFFFFFFF);
514  DPORT_REG_WRITE(RSA_MEM_M_BLOCK_BASE + 4, 0xFFFFFFFF);
515  DPORT_REG_WRITE(RSA_MEM_M_BLOCK_BASE + 8, 0xFFFFFFFF);
516  DPORT_REG_WRITE(RSA_MEM_M_BLOCK_BASE + 12, 0xFFFFFFFF);
517  DPORT_REG_WRITE(RSA_MEM_M_BLOCK_BASE + 16, 0xFFFFFFFF);
518  DPORT_REG_WRITE(RSA_MEM_M_BLOCK_BASE + 20, 0xFFFFFFFF);
519  DPORT_REG_WRITE(RSA_MEM_M_BLOCK_BASE + 24, 0xFFFFFFFF);
520  DPORT_REG_WRITE(RSA_MEM_M_BLOCK_BASE + 28, 0xFFFFFFFE);
521  DPORT_REG_WRITE(RSA_MEM_M_BLOCK_BASE + 32, 0xFFFFFFFF);
522  DPORT_REG_WRITE(RSA_MEM_M_BLOCK_BASE + 36, 0xFFFFFFFF);
523  DPORT_REG_WRITE(RSA_MEM_M_BLOCK_BASE + 40, 0xFFFFFFFF);
524  DPORT_REG_WRITE(RSA_MEM_M_BLOCK_BASE + 44, 0xFFFFFFFF);
525  DPORT_REG_WRITE(RSA_MEM_M_BLOCK_BASE + 48, 0xFFFFFFFF);
526  DPORT_REG_WRITE(RSA_MEM_M_BLOCK_BASE + 52, 0xFFFFFFFF);
527  DPORT_REG_WRITE(RSA_MEM_M_BLOCK_BASE + 56, 0x00000000);
528  DPORT_REG_WRITE(RSA_MEM_M_BLOCK_BASE + 60, 0x00000000);
529 
530  //Copy the pre-calculated value of R^2 mod M to RSA_Z_MEM
531  DPORT_REG_WRITE(RSA_MEM_RB_BLOCK_BASE, 0x00000000);
532  DPORT_REG_WRITE(RSA_MEM_RB_BLOCK_BASE + 4, 0x00000000);
533  DPORT_REG_WRITE(RSA_MEM_RB_BLOCK_BASE + 8, 0x00000000);
534  DPORT_REG_WRITE(RSA_MEM_RB_BLOCK_BASE + 12, 0x00000000);
535  DPORT_REG_WRITE(RSA_MEM_RB_BLOCK_BASE + 16, 0x00000002);
536  DPORT_REG_WRITE(RSA_MEM_RB_BLOCK_BASE + 20, 0x00000000);
537  DPORT_REG_WRITE(RSA_MEM_RB_BLOCK_BASE + 24, 0x00000000);
538  DPORT_REG_WRITE(RSA_MEM_RB_BLOCK_BASE + 28, 0x00000000);
539  DPORT_REG_WRITE(RSA_MEM_RB_BLOCK_BASE + 32, 0x00000000);
540  DPORT_REG_WRITE(RSA_MEM_RB_BLOCK_BASE + 36, 0x00000000);
541  DPORT_REG_WRITE(RSA_MEM_RB_BLOCK_BASE + 40, 0x00000000);
542  DPORT_REG_WRITE(RSA_MEM_RB_BLOCK_BASE + 44, 0x00000003);
543  DPORT_REG_WRITE(RSA_MEM_RB_BLOCK_BASE + 48, 0x00000000);
544  DPORT_REG_WRITE(RSA_MEM_RB_BLOCK_BASE + 52, 0x00000000);
545  DPORT_REG_WRITE(RSA_MEM_RB_BLOCK_BASE + 56, 0x00000000);
546  DPORT_REG_WRITE(RSA_MEM_RB_BLOCK_BASE + 60, 0x00000000);
547 
548  //Write the value of M' to RSA_M_PRIME_REG
549  DPORT_REG_WRITE(RSA_M_DASH_REG, 0x00000001);
550  //Start the first round of the operation
551  DPORT_REG_WRITE(RSA_MULT_START_REG, 1);
552 
553  //Wait for the first round to complete
554  while(DPORT_REG_READ(RSA_INTERRUPT_REG) == 0)
555  {
556  }
557 
558  //Clear the interrupt flag
559  DPORT_REG_WRITE(RSA_INTERRUPT_REG, 1);
560 
561  //Copy the second operand to RSA_X_MEM
562  for(i = 0; i < 14; i++)
563  {
564  DPORT_REG_WRITE(RSA_MEM_X_BLOCK_BASE + i * 4, b[i]);
565  }
566 
567  //Pad the second operand with zeroes
568  DPORT_REG_WRITE(RSA_MEM_X_BLOCK_BASE + 56, 0);
569  DPORT_REG_WRITE(RSA_MEM_X_BLOCK_BASE + 60, 0);
570 
571  //Start the second round of the operation
572  DPORT_REG_WRITE(RSA_MULT_START_REG, 1);
573 
574  //Wait for the second round to complete
575  while(DPORT_REG_READ(RSA_INTERRUPT_REG) == 0)
576  {
577  }
578 
579  //Disable interrupts only on current CPU
580  DPORT_INTERRUPT_DISABLE();
581 
582  //Read the result from RSA_Z_MEM
583  for(i = 0; i < 14; i++)
584  {
585  r[i] = DPORT_SEQUENCE_REG_READ(RSA_MEM_Z_BLOCK_BASE + i * 4);
586  }
587 
588  //Restore the previous interrupt level
589  DPORT_INTERRUPT_RESTORE();
590  //Clear the interrupt flag
591  DPORT_REG_WRITE(RSA_INTERRUPT_REG, 1);
592 
593  //Release exclusive access to the RSA module
595 }
596 
597 #endif
598 #endif
error_t mpiShiftLeft(Mpi *r, uint_t n)
Left shift operation.
Definition: mpi.c:1111
Curve448 elliptic curve (constant-time implementation)
uint8_t b
Definition: nbns_common.h:104
uint8_t a
Definition: ndp.h:411
Arbitrary precision integer.
Definition: mpi.h:80
uint8_t p
Definition: ndp.h:300
uint8_t t
Definition: lldp_ext_med.h:212
error_t mpiSetValue(Mpi *r, int_t a)
Set the value of a multiple precision integer.
Definition: mpi.c:484
void mpiInit(Mpi *r)
Initialize a multiple precision integer.
Definition: mpi.c:48
ESP32 hardware cryptographic accelerator.
void curve448Mul(uint32_t *r, const uint32_t *a, const uint32_t *b)
Modular multiplication.
uint8_t r
Definition: ndp.h:346
error_t mpiMod(Mpi *r, const Mpi *a, const Mpi *p)
Modulo operation.
Definition: mpi.c:1444
OsMutex esp32CryptoMutex
Definition: esp32_crypto.c:45
error_t mpiMul(Mpi *r, const Mpi *a, const Mpi *b)
Multiple precision multiplication.
error_t
Error codes.
Definition: error.h:43
void curve25519Red(uint32_t *r, const uint32_t *a)
Modular reduction.
Definition: curve25519.c:352
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
void esp32RsaInit(void)
RSA module initialization.
RSA public-key cryptography standard.
uint8_t u
Definition: lldp_ext_med.h:213
uint_t * data
Definition: mpi.h:84
ESP32 public-key hardware accelerator.
#define MAX(a, b)
Definition: os_port.h:67
uint_t mpiGetLength(const Mpi *a)
Get the actual length in words.
Definition: mpi.c:168
uint8_t m
Definition: ndp.h:304
uint8_t n
void osAcquireMutex(OsMutex *mutex)
Acquire ownership of the specified mutex object.
uint_t size
Definition: mpi.h:82
void osReleaseMutex(OsMutex *mutex)
Release ownership of the specified mutex object.
Curve25519 elliptic curve (constant-time implementation)
unsigned int uint_t
Definition: compiler_port.h:50
error_t mpiGrow(Mpi *r, uint_t size)
Adjust the size of multiple precision integer.
Definition: mpi.c:94
void curve25519Mul(uint32_t *r, const uint32_t *a, const uint32_t *b)
Modular multiplication.
error_t mpiExpMod(Mpi *r, const Mpi *a, const Mpi *e, const Mpi *p)
Modular exponentiation.
Debugging facilities.
void mpiFree(Mpi *r)
Release a multiple precision integer.
Definition: mpi.c:64