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-2025 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.5.2
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL CRYPTO_TRACE_LEVEL
33 
34 //Dependencies
35 #include "esp_crypto_lock.h"
36 #include "soc/hwcrypto_reg.h"
37 #include "soc/dport_access.h"
38 #include "esp_private/periph_ctrl.h"
41 #include "pkc/rsa.h"
42 #include "ecc/ec.h"
43 #include "ecc/ec_misc.h"
44 #include "debug.h"
45 
46 //Check crypto library configuration
47 #if (ESP32_CRYPTO_PKC_SUPPORT == ENABLED)
48 
49 
50 /**
51  * @brief RSA module initialization
52  **/
53 
54 void esp32RsaInit(void)
55 {
56  //Enable RSA module
57  periph_module_enable(PERIPH_RSA_MODULE);
58 
59  //Software should query RSA_CLEAN_REG after being released from reset, and
60  //before writing to any RSA Accelerator memory blocks or registers for the
61  //first time
62  while(DPORT_REG_READ(RSA_CLEAN_REG) == 0)
63  {
64  }
65 }
66 
67 
68 #if (MPI_SUPPORT == ENABLED)
69 
70 /**
71  * @brief Multiple precision multiplication
72  * @param[out] r Resulting integer R = A * B
73  * @param[in] a First operand A
74  * @param[in] b Second operand B
75  * @return Error code
76  **/
77 
78 error_t mpiMul(Mpi *r, const Mpi *a, const Mpi *b)
79 {
80  error_t error;
81  size_t i;
82  size_t n;
83  size_t aLen;
84  size_t bLen;
85 
86  //Get the length of the first operand, in 32-bit words
87  aLen = mpiGetLength(a);
88  //Get the length of the second operand, in 32-bit words
89  bLen = mpiGetLength(b);
90 
91  //The accelerator supports large-number multiplication up to 2048 bits
92  if(aLen <= 64 && bLen <= 64)
93  {
94  //All numbers in calculation must be of the same length
95  n = 1;
96  n = MAX(n, aLen);
97  n = MAX(n, bLen);
98  n = (n + 7) & ~7U;
99 
100  //Acquire exclusive access to the RSA module
101  esp_crypto_mpi_lock_acquire();
102 
103  //Clear the interrupt flag
104  DPORT_REG_WRITE(RSA_INTERRUPT_REG, 1);
105  //Set mode register
106  DPORT_REG_WRITE(RSA_MULT_MODE_REG, (n / 8) - 1 + 8);
107 
108  //Copy the first operand to RSA_X_MEM
109  for(i = 0; i < n; i++)
110  {
111  if(i < a->size)
112  {
113  DPORT_REG_WRITE(RSA_MEM_X_BLOCK_BASE + i * 4, a->data[i]);
114  }
115  else
116  {
117  DPORT_REG_WRITE(RSA_MEM_X_BLOCK_BASE + i * 4, 0);
118  }
119  }
120 
121  //The second operand will not be written to the base address of the
122  //RSA_Z_MEM memory. This area must be filled with zeroes
123  for(i = 0; i < n; i++)
124  {
125  DPORT_REG_WRITE(RSA_MEM_Z_BLOCK_BASE + i * 4, 0);
126  }
127 
128  //The second operand must be written to the base address of the RSA_Z_MEM
129  //memory plus the address offset N
130  for(i = 0; i < n; i++)
131  {
132  if(i < b->size)
133  {
134  DPORT_REG_WRITE(RSA_MEM_Z_BLOCK_BASE + (n + i) * 4, b->data[i]);
135  }
136  else
137  {
138  DPORT_REG_WRITE(RSA_MEM_Z_BLOCK_BASE + (n + i) * 4, 0);
139  }
140  }
141 
142  //Start large-number multiplication
143  DPORT_REG_WRITE(RSA_MULT_START_REG, 1);
144 
145  //Wait for the operation to complete
146  while(DPORT_REG_READ(RSA_INTERRUPT_REG) == 0)
147  {
148  }
149 
150  //Set the sign of the result
151  r->sign = (a->sign == b->sign) ? 1 : -1;
152 
153  //The length of the result is 2 x N bits
154  error = mpiGrow(r, n * 2);
155 
156  //Check status code
157  if(!error)
158  {
159  //Disable interrupts only on current CPU
160  DPORT_INTERRUPT_DISABLE();
161 
162  //Read the result from RSA_Z_MEM
163  for(i = 0; i < r->size; i++)
164  {
165  if(i < (n * 2))
166  {
167  r->data[i] = DPORT_SEQUENCE_REG_READ(RSA_MEM_Z_BLOCK_BASE + i * 4);
168  }
169  else
170  {
171  r->data[i] = 0;
172  }
173  }
174 
175  //Restore the previous interrupt level
176  DPORT_INTERRUPT_RESTORE();
177  }
178 
179  //Clear the interrupt flag
180  DPORT_REG_WRITE(RSA_INTERRUPT_REG, 1);
181 
182  //Release exclusive access to the RSA module
183  esp_crypto_mpi_lock_release();
184  }
185  else
186  {
187  //Report an error
188  error = ERROR_FAILURE;
189  }
190 
191  //Return status code
192  return error;
193 }
194 
195 
196 /**
197  * @brief Modular exponentiation
198  * @param[out] r Resulting integer R = A ^ E mod P
199  * @param[in] a Pointer to a multiple precision integer
200  * @param[in] e Exponent
201  * @param[in] p Modulus
202  * @return Error code
203  **/
204 
205 error_t mpiExpMod(Mpi *r, const Mpi *a, const Mpi *e, const Mpi *p)
206 {
207  error_t error;
208  size_t i;
209  size_t n;
210  size_t modLen;
211  size_t expLen;
212  uint32_t m;
213  Mpi t;
214  Mpi r2;
215 
216  //Initialize multiple precision integers
217  mpiInit(&t);
218  mpiInit(&r2);
219 
220  //Get the length of the modulus, in 32-bit words
221  modLen = mpiGetLength(p);
222  //Get the length of the exponent, in 32-bit words
223  expLen = mpiGetLength(e);
224 
225  //The accelerator supports operand lengths up to 4096 bits
226  if(modLen > 0 && modLen <= 128 && expLen > 0 && expLen <= 128)
227  {
228  //All numbers in calculation must be of the same length
229  n = MAX(modLen, expLen);
230  n = (n + 15) & ~15U;
231 
232  //Reduce the operand first
233  error = mpiMod(&t, a, p);
234 
235  //Let R = b^n and pre-compute the quantity R^2 mod M
236  if(!error)
237  {
238  error = mpiSetValue(&r2, 1);
239  }
240 
241  if(!error)
242  {
243  error = mpiShiftLeft(&r2, n * 2 * 32);
244  }
245 
246  if(!error)
247  {
248  error = mpiMod(&r2, &r2, p);
249  }
250 
251  //Check status code
252  if(!error)
253  {
254  //Acquire exclusive access to the RSA module
255  esp_crypto_mpi_lock_acquire();
256 
257  //Clear the interrupt flag
258  DPORT_REG_WRITE(RSA_INTERRUPT_REG, 1);
259  //Set mode register
260  DPORT_REG_WRITE(RSA_MODEXP_MODE_REG, (n / 16) - 1);
261 
262  //Copy the operand to RSA_X_MEM
263  for(i = 0; i < n; i++)
264  {
265  if(i < t.size)
266  {
267  DPORT_REG_WRITE(RSA_MEM_X_BLOCK_BASE + i * 4, t.data[i]);
268  }
269  else
270  {
271  DPORT_REG_WRITE(RSA_MEM_X_BLOCK_BASE + i * 4, 0);
272  }
273  }
274 
275  //Copy the exponent to RSA_Y_MEM
276  for(i = 0; i < n; i++)
277  {
278  if(i < e->size)
279  {
280  DPORT_REG_WRITE(RSA_MEM_Y_BLOCK_BASE + i * 4, e->data[i]);
281  }
282  else
283  {
284  DPORT_REG_WRITE(RSA_MEM_Y_BLOCK_BASE + i * 4, 0);
285  }
286  }
287 
288  //Copy the modulus to RSA_M_MEM
289  for(i = 0; i < n; i++)
290  {
291  if(i < p->size)
292  {
293  DPORT_REG_WRITE(RSA_MEM_M_BLOCK_BASE + i * 4, p->data[i]);
294  }
295  else
296  {
297  DPORT_REG_WRITE(RSA_MEM_M_BLOCK_BASE + i * 4, 0);
298  }
299  }
300 
301  //Copy the pre-calculated value of R^2 mod M to RSA_Z_MEM
302  for(i = 0; i < n; i++)
303  {
304  if(i < r2.size)
305  {
306  DPORT_REG_WRITE(RSA_MEM_RB_BLOCK_BASE + i * 4, r2.data[i]);
307  }
308  else
309  {
310  DPORT_REG_WRITE(RSA_MEM_RB_BLOCK_BASE + i * 4, 0);
311  }
312  }
313 
314  //Use Newton's method to compute the inverse of M[0] mod 2^32
315  for(m = p->data[0], i = 0; i < 4; i++)
316  {
317  m = m * (2U - m * p->data[0]);
318  }
319 
320  //Precompute M' = -1/M[0] mod 2^32;
321  m = ~m + 1U;
322 
323  //Write the value of M' to RSA_M_PRIME_REG
324  DPORT_REG_WRITE(RSA_M_DASH_REG, m);
325 
326  //Start modular exponentiation
327  DPORT_REG_WRITE(RSA_MODEXP_START_REG, 1);
328 
329  //Wait for the operation to complete
330  while(DPORT_REG_READ(RSA_INTERRUPT_REG) == 0)
331  {
332  }
333 
334  //Adjust the size of the result if necessary
335  error = mpiGrow(r, n);
336 
337  //Check status code
338  if(!error)
339  {
340  //Disable interrupts only on current CPU
341  DPORT_INTERRUPT_DISABLE();
342 
343  //Read the result from RSA_Z_MEM
344  for(i = 0; i < r->size; i++)
345  {
346  if(i < n)
347  {
348  r->data[i] = DPORT_SEQUENCE_REG_READ(RSA_MEM_Z_BLOCK_BASE + i * 4);
349  }
350  else
351  {
352  r->data[i] = 0;
353  }
354  }
355 
356  //Restore the previous interrupt level
357  DPORT_INTERRUPT_RESTORE();
358  }
359 
360  //Clear the interrupt flag
361  DPORT_REG_WRITE(RSA_INTERRUPT_REG, 1);
362 
363  //Release exclusive access to the RSA module
364  esp_crypto_mpi_lock_release();
365  }
366  }
367  else
368  {
369  //Report an error
370  error = ERROR_FAILURE;
371  }
372 
373  //Release previously allocated memory
374  mpiFree(&t);
375  mpiFree(&r2);
376 
377  //Return status code
378  return error;
379 }
380 
381 #endif
382 #if (EC_SUPPORT == ENABLED)
383 
384 /**
385  * @brief Multiplication of two integers
386  * @param[out] rl Low part of the result R = (A * B) mod (2^32)^n
387  * @param[out] rh High part of the result R = (A * B) / (2^32)^n
388  * @param[in] a An integer such as 0 <= A < (2^32)^n
389  * @param[in] b An integer such as 0 <= B < (2^32)^n
390  * @param[in] n Size of the operands, in words
391  **/
392 
393 void ecScalarMul(uint32_t *rl, uint32_t *rh, const uint32_t *a,
394  const uint32_t *b, uint_t n)
395 {
396  uint_t i;
397  uint_t m;
398 
399  //The accelerator supports large-number multiplication with only four
400  //operand lengths
401  m = (n + 7) & ~7U;
402 
403  //Acquire exclusive access to the RSA module
404  esp_crypto_mpi_lock_acquire();
405 
406  //Clear the interrupt flag
407  DPORT_REG_WRITE(RSA_INTERRUPT_REG, 1);
408  //Set mode register
409  DPORT_REG_WRITE(RSA_MULT_MODE_REG, (m / 8) - 1 + 8);
410 
411  //Copy the first operand to RSA_X_MEM
412  for(i = 0; i < m; i++)
413  {
414  if(i < n)
415  {
416  DPORT_REG_WRITE(RSA_MEM_X_BLOCK_BASE + i * 4, a[i]);
417  }
418  else
419  {
420  DPORT_REG_WRITE(RSA_MEM_X_BLOCK_BASE + i * 4, 0);
421  }
422  }
423 
424  //The second operand will not be written to the base address of the
425  //RSA_Z_MEM memory. This area must be filled with zeroes
426  for(i = 0; i < m; i++)
427  {
428  DPORT_REG_WRITE(RSA_MEM_Z_BLOCK_BASE + i * 4, 0);
429  }
430 
431  //The second operand must be written to the base address of the RSA_Z_MEM
432  //memory plus the address offset N
433  for(i = 0; i < m; i++)
434  {
435  if(i < n)
436  {
437  DPORT_REG_WRITE(RSA_MEM_Z_BLOCK_BASE + (m + i) * 4, b[i]);
438  }
439  else
440  {
441  DPORT_REG_WRITE(RSA_MEM_Z_BLOCK_BASE + (m + i) * 4, 0);
442  }
443  }
444 
445  //Start large-number multiplication
446  DPORT_REG_WRITE(RSA_MULT_START_REG, 1);
447 
448  //Wait for the operation to complete
449  while(DPORT_REG_READ(RSA_INTERRUPT_REG) == 0)
450  {
451  }
452 
453  //Disable interrupts only on current CPU
454  DPORT_INTERRUPT_DISABLE();
455 
456  //Check whether the low part of the multiplication should be calculated
457  if(rl != NULL)
458  {
459  //Read the result from RSA_Z_MEM
460  for(i = 0; i < n; i++)
461  {
462  rl[i] = DPORT_SEQUENCE_REG_READ(RSA_MEM_Z_BLOCK_BASE + i * 4);
463  }
464  }
465 
466  //Check whether the high part of the multiplication should be calculated
467  if(rh != NULL)
468  {
469  //Read the result from RSA_Z_MEM
470  for(i = 0; i < n; i++)
471  {
472  rh[i] = DPORT_SEQUENCE_REG_READ(RSA_MEM_Z_BLOCK_BASE + (n + i) * 4);
473  }
474  }
475 
476  //Restore the previous interrupt level
477  DPORT_INTERRUPT_RESTORE();
478  //Clear the interrupt flag
479  DPORT_REG_WRITE(RSA_INTERRUPT_REG, 1);
480 
481  //Release exclusive access to the RSA module
482  esp_crypto_mpi_lock_release();
483 }
484 
485 
486 /**
487  * @brief Squaring operation
488  * @param[out] r Result R = A ^ 2
489  * @param[in] a An integer such as 0 <= A < (2^32)^n
490  * @param[in] n Size of the integer A, in words
491  **/
492 
493 void ecScalarSqr(uint32_t *r, const uint32_t *a, uint_t n)
494 {
495  //Compute R = A ^ 2
496  ecScalarMul(r, r + n, a, a, n);
497 }
498 
499 #endif
500 #endif
error_t mpiShiftLeft(Mpi *r, uint_t n)
Left shift operation.
Definition: mpi.c:1243
uint8_t b
Definition: nbns_common.h:104
uint8_t a
Definition: ndp.h:411
Arbitrary precision integer.
Definition: mpi.h:102
uint8_t p
Definition: ndp.h:300
uint8_t t
Definition: lldp_ext_med.h:212
void mpiInit(Mpi *r)
Initialize a multiple precision integer.
Definition: mpi.c:48
ESP32 hardware cryptographic accelerator.
uint8_t r
Definition: ndp.h:346
error_t mpiMod(Mpi *r, const Mpi *a, const Mpi *p)
Modulo operation.
Definition: mpi.c:1587
error_t mpiMul(Mpi *r, const Mpi *a, const Mpi *b)
Multiple precision multiplication.
error_t
Error codes.
Definition: error.h:43
error_t mpiSetValue(Mpi *r, mpi_sword_t a)
Set the value of a multiple precision integer.
Definition: mpi.c:562
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
void esp32RsaInit(void)
RSA module initialization.
Helper routines for ECC.
void ecScalarMul(uint32_t *rl, uint32_t *rh, const uint32_t *a, const uint32_t *b, uint_t n)
Multiplication of two integers.
RSA public-key cryptography standard.
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:188
uint8_t m
Definition: ndp.h:304
uint8_t n
uint_t size
Definition: mpi.h:104
void ecScalarSqr(uint32_t *r, const uint32_t *a, uint_t n)
Squaring operation.
unsigned int uint_t
Definition: compiler_port.h:57
ECC (Elliptic Curve Cryptography)
mpi_word_t * data
Definition: mpi.h:106
error_t mpiGrow(Mpi *r, uint_t size)
Adjust the size of multiple precision integer.
Definition: mpi.c:102
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