gd32w5xx_crypto_pkc.c
Go to the documentation of this file.
1 /**
2  * @file gd32w5xx_crypto_pkc.c
3  * @brief GD32W5 public-key hardware accelerator (PKCAU)
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.0
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL CRYPTO_TRACE_LEVEL
33 
34 //Dependencies
35 #include "gd32w51x.h"
36 #include "core/crypto.h"
39 #include "pkc/rsa.h"
40 #include "ecc/ec.h"
41 #include "ecc/ec_misc.h"
42 #include "ecc/ecdsa.h"
43 #include "debug.h"
44 
45 //Check crypto library configuration
46 #if (GD32W5XX_CRYPTO_PKC_SUPPORT == ENABLED)
47 
48 
49 /**
50  * @brief PKCAU module initialization
51  * @return Error code
52  **/
53 
55 {
56  //Enable PKCAU peripheral clock
57  rcu_periph_clock_enable(RCU_PKCAU);
58 
59  //Reset the PKCAU peripheral
60  PKCAU_CTL = 0;
61 
62  //Enable the PKCAU peripheral
63  while((PKCAU_CTL & PKCAU_CTL_PKCAUEN) == 0)
64  {
65  PKCAU_CTL = PKCAU_CTL_PKCAUEN;
66  }
67 
68  //Clear flags
69  PKCAU_STATC = PKCAU_STATC_ADDRERRC | PKCAU_STATC_RAMERRC | PKCAU_STATC_ENDC;
70 
71  //Successful processing
72  return NO_ERROR;
73 }
74 
75 
76 /**
77  * @brief Import byte array
78  * @param[in] src Pointer to the byte array
79  * @param[in] srcLen Length of the array to be copied, in bytes
80  * @param[in] destLen Length of the operand, in bits
81  * @param[in] offset PKCAU ram offset
82  **/
83 
84 void pkcauImportArray(const uint8_t *src, size_t srcLen, uint_t destLen,
85  uint_t offset)
86 {
87  uint_t i;
88  uint_t j;
89  uint32_t temp;
90 
91  //Get the length of the operand, in words
92  destLen = (destLen + 31) / 32;
93 
94  //Copy the array to the PKCAU RAM
95  for(i = 0, j = 0; i < srcLen; i++)
96  {
97  switch(i % 4)
98  {
99  case 0:
100  temp = src[srcLen - i - 1];
101  break;
102  case 1:
103  temp |= src[srcLen - i - 1] << 8;
104  break;
105  case 2:
106  temp |= src[srcLen - i - 1] << 16;
107  break;
108  default:
109  temp |= src[srcLen - i - 1] << 24;
110  PKCAU_RAM[offset + j] = temp;
111  j++;
112  break;
113  }
114  }
115 
116  //Pad the operand with zeroes
117  for(; i < (destLen * 4); i++)
118  {
119  switch(i % 4)
120  {
121  case 0:
122  temp = 0;
123  break;
124  case 3:
125  PKCAU_RAM[offset + j] = temp;
126  j++;
127  break;
128  default:
129  break;
130  }
131  }
132 
133  //An additional word with all bits equal to zero must be added
134  PKCAU_RAM[offset + j] = 0;
135 }
136 
137 
138 /**
139  * @brief Import scalar
140  * @param[in] src Pointer to the scalar
141  * @param[in] length Length of the operand, in bits
142  * @param[in] offset PKCAU ram offset
143  **/
144 
145 void pkcauImportScalar(const uint32_t *src, uint_t length, uint_t offset)
146 {
147  uint_t i;
148 
149  //Get the length of the operand, in words
150  length = (length + 31) / 32;
151 
152  //Copy the scalar to the PKCAU RAM
153  for(i = 0; i < length; i++)
154  {
155  PKCAU_RAM[offset + i] = src[i];
156  }
157 
158  //An additional word with all bits equal to zero must be added
159  PKCAU_RAM[offset + i] = 0;
160 }
161 
162 
163 /**
164  * @brief Import multiple-precision integer
165  * @param[in] src Pointer to the multiple-precision integer
166  * @param[in] length Length of the operand, in bits
167  * @param[in] offset PKCAU ram offset
168  **/
169 
170 void pkcauImportMpi(const Mpi *src, uint_t length, uint_t offset)
171 {
172  uint_t i;
173  uint_t n;
174 
175  //Get the length of the operand, in words
176  length = (length + 31) / 32;
177 
178  //Get the actual length of the multiple-precision integer, in words
179  n = mpiGetLength(src);
180 
181  //Copy the multiple-precision integer to the PKCAU RAM
182  for(i = 0; i < n && i < length; i++)
183  {
184  PKCAU_RAM[offset + i] = src->data[i];
185  }
186 
187  //Pad the operand with zeroes
188  for(; i < length; i++)
189  {
190  PKCAU_RAM[offset + i] = 0;
191  }
192 
193  //An additional word with all bits equal to zero must be added
194  PKCAU_RAM[offset + i] = 0;
195 }
196 
197 
198 /**
199  * @brief Export scalar
200  * @param[out] dest Pointer to the scalar
201  * @param[in] length Length of the operand, in bits
202  * @param[in] offset PKCAU ram offset
203  **/
204 
205 void pkcauExportScalar(uint32_t *dest, uint_t length, uint_t offset)
206 {
207  uint_t i;
208 
209  //Get the length of the operand, in words
210  length = (length + 31) / 32;
211 
212  //Copy the scalar from the PKCAU RAM
213  for(i = 0; i < length; i++)
214  {
215  dest[i] = PKCAU_RAM[offset + i];
216  }
217 }
218 
219 
220 /**
221  * @brief Export multiple-precision integer
222  * @param[out] dest Pointer to the multiple-precision integer
223  * @param[in] length Length of the operand, in bits
224  * @param[in] offset PKCAU ram offset
225  * @return Error code
226  **/
227 
229 {
230  error_t error;
231  uint_t i;
232 
233  //Get the length of the operand, in words
234  length = (length + 31) / 32;
235 
236  //Skip trailing zeroes
237  while(length > 0 && PKCAU_RAM[offset + length - 1] == 0)
238  {
239  length--;
240  }
241 
242  //Ajust the size of the multiple precision integer
243  error = mpiGrow(dest, length);
244 
245  //Check status code
246  if(!error)
247  {
248  //Copy the multiple-precision integer from the PKCAU RAM
249  for(i = 0; i < length; i++)
250  {
251  dest->data[i] = PKCAU_RAM[offset + i];
252  }
253 
254  //Pad the resulting value with zeroes
255  for(; i < dest->size; i++)
256  {
257  dest->data[i] = 0;
258  }
259 
260  //Set the sign
261  dest->sign = 1;
262  }
263 
264  //Return status code
265  return error;
266 }
267 
268 
269 #if (MPI_SUPPORT == ENABLED)
270 
271 /**
272  * @brief Modular exponentiation
273  * @param[out] r Resulting integer R = A ^ E mod P
274  * @param[in] a Pointer to a multiple precision integer
275  * @param[in] e Exponent
276  * @param[in] p Modulus
277  * @return Error code
278  **/
279 
280 error_t pkcauModExp(Mpi *r, const Mpi *a, const Mpi *e, const Mpi *p)
281 {
282  error_t error;
283  uint_t modLen;
284  uint_t expLen;
285  uint32_t temp;
286 
287  //Get the length of the modulus, in bits
288  modLen = mpiGetBitLength(p);
289  //Get the length of the exponent, in bits
290  expLen = mpiGetBitLength(e);
291 
292  //Check the length of the operands
293  if(modLen <= PKCAU_MAX_ROS && expLen <= PKCAU_MAX_ROS)
294  {
295  //Reduce the operand first
296  error = mpiMod(r, a, p);
297 
298  //Check status code
299  if(!error)
300  {
301  //Acquire exclusive access to the PKCAU module
303 
304  //Specify the length of the operand, in bits
306  //Specify the length of the exponent, in bits
308 
309  //Load input arguments into the PKCAU internal RAM
313 
314  //Disable interrupts
315  PKCAU_CTL &= ~(PKCAU_CTL_ADDRERRIE | PKCAU_CTL_RAMERRIE | PKCAU_CTL_ENDIE);
316 
317  //Write in the MODESEL field of PKCAU_CTL register, specifying the operation
318  //which is to be executed
319  temp = PKCAU_CTL & ~PKCAU_CTL_MODESEL;
320  PKCAU_CTL = temp | PKCAU_MODE_MOD_EXP;
321 
322  //Then assert the START bit in PKCAU_CTL register
323  PKCAU_CTL |= PKCAU_CTL_START;
324 
325  //Data synchronization barrier
326  __DSB();
327 
328  //Wait until the ENDF bit in the PKCAU_STAT register is set to 1,
329  //indicating that the computation is complete
330  while((PKCAU_STAT & PKCAU_STAT_ENDF) == 0)
331  {
332  }
333 
334  //Read the result data from the PKCAU internal RAM
335  error = pkcauExportMpi(r, modLen, PKCAU_MOD_EXP_OUT_R);
336 
337  //Then clear ENDC bit by setting ENDC bit in PKCAU_STATC
338  PKCAU_STATC = PKCAU_STATC_ENDC;
339 
340  //Release exclusive access to the PKCAU module
342  }
343  }
344  else
345  {
346  //Perform modular exponentiation
347  error = mpiExpMod(r, a, e, p);
348  }
349 
350  //Return status code
351  return error;
352 }
353 
354 #endif
355 #if (RSA_SUPPORT == ENABLED)
356 
357 /**
358  * @brief Modular exponentiation with CRT
359  * @param[in] key RSA public key
360  * @param[in] m Message representative
361  * @param[out] c Ciphertext representative
362  * @return Error code
363  **/
364 
366 {
367  error_t error;
368  uint_t nLen;
369  uint_t pLen;
370  uint_t qLen;
371  uint_t dpLen;
372  uint_t dqLen;
373  uint_t qinvLen;
374  uint32_t temp;
375 
376  //Get the length of the private key
377  nLen = mpiGetBitLength(&key->n);
378  pLen = mpiGetBitLength(&key->p);
379  qLen = mpiGetBitLength(&key->q);
380  dpLen = mpiGetBitLength(&key->dp);
381  dqLen = mpiGetBitLength(&key->dq);
382  qinvLen = mpiGetBitLength(&key->qinv);
383 
384  //Check the length of the operands
385  if(nLen <= PKCAU_MAX_ROS && pLen <= (nLen / 2) && qLen <= (nLen / 2) &&
386  dpLen <= (nLen / 2) && dqLen <= (nLen / 2) && qinvLen <= (nLen / 2))
387  {
388  //Acquire exclusive access to the PKCAU module
390 
391  //Specify the length of the operand, in bits
393 
394  //Load input arguments into the PKCAU internal RAM
395  pkcauImportMpi(&key->p, nLen / 2, PKCAU_RSA_CRT_EXP_IN_P);
396  pkcauImportMpi(&key->q, nLen / 2, PKCAU_RSA_CRT_EXP_IN_Q);
397  pkcauImportMpi(&key->dp, nLen / 2, PKCAU_RSA_CRT_EXP_IN_DP);
398  pkcauImportMpi(&key->dq, nLen / 2, PKCAU_RSA_CRT_EXP_IN_DQ);
401 
402  //Disable interrupts
403  PKCAU_CTL &= ~(PKCAU_CTL_ADDRERRIE | PKCAU_CTL_RAMERRIE | PKCAU_CTL_ENDIE);
404 
405  //Write in the MODESEL field of PKCAU_CTL register, specifying the operation
406  //which is to be executed
407  temp = PKCAU_CTL & ~PKCAU_CTL_MODESEL;
408  PKCAU_CTL = temp | PKCAU_MODE_CRT_EXP;
409 
410  //Then assert the START bit in PKCAU_CTL register
411  PKCAU_CTL |= PKCAU_CTL_START;
412 
413  //Data synchronization barrier
414  __DSB();
415 
416  //Wait until the ENDF bit in the PKCAU_STAT register is set to 1,
417  //indicating that the computation is complete
418  while((PKCAU_STAT & PKCAU_STAT_ENDF) == 0)
419  {
420  }
421 
422  //Read the result data from the PKCAU internal RAM
423  error = pkcauExportMpi(m, nLen, PKCAU_RSA_CRT_EXP_OUT_R);
424 
425  //Then clear ENDC bit by setting ENDC bit in PKCAU_STATC
426  PKCAU_STATC = PKCAU_STATC_ENDC;
427 
428  //Release exclusive access to the PKCAU module
430  }
431  else
432  {
433  Mpi m1;
434  Mpi m2;
435  Mpi h;
436 
437  //Initialize multiple-precision integers
438  mpiInit(&m1);
439  mpiInit(&m2);
440  mpiInit(&h);
441 
442  //Compute m1 = c ^ dP mod p
443  error = pkcauModExp(&m1, c, &key->dp, &key->p);
444 
445  //Check status code
446  if(!error)
447  {
448  //Compute m2 = c ^ dQ mod q
449  error = pkcauModExp(&m2, c, &key->dq, &key->q);
450  }
451 
452  //Check status code
453  if(!error)
454  {
455  //Let h = (m1 - m2) * qInv mod p
456  error = mpiSub(&h, &m1, &m2);
457  }
458 
459  //Check status code
460  if(!error)
461  {
462  error = mpiMulMod(&h, &h, &key->qinv, &key->p);
463  }
464 
465  //Check status code
466  if(!error)
467  {
468  //Let m = m2 + q * h
469  error = mpiMul(m, &key->q, &h);
470  }
471 
472  //Check status code
473  if(!error)
474  {
475  error = mpiAdd(m, m, &m2);
476  }
477 
478  //Free previously allocated memory
479  mpiFree(&m1);
480  mpiFree(&m2);
481  mpiFree(&h);
482  }
483 
484  //Return status code
485  return error;
486 }
487 
488 
489 /**
490  * @brief RSA encryption primitive
491  * @param[in] key RSA public key
492  * @param[in] m Message representative
493  * @param[out] c Ciphertext representative
494  * @return Error code
495  **/
496 
497 error_t rsaep(const RsaPublicKey *key, const Mpi *m, Mpi *c)
498 {
499  size_t nLen;
500  size_t eLen;
501 
502  //Get the length of the public key
503  nLen = mpiGetLength(&key->n);
504  eLen = mpiGetLength(&key->e);
505 
506  //Sanity check
507  if(nLen == 0 || eLen == 0)
509 
510  //The message representative m shall be between 0 and n - 1
511  if(mpiCompInt(m, 0) < 0 || mpiComp(m, &key->n) >= 0)
512  return ERROR_OUT_OF_RANGE;
513 
514  //Perform modular exponentiation (c = m ^ e mod n)
515  return pkcauModExp(c, m, &key->e, &key->n);
516 }
517 
518 
519 /**
520  * @brief RSA decryption primitive
521  * @param[in] key RSA private key
522  * @param[in] c Ciphertext representative
523  * @param[out] m Message representative
524  * @return Error code
525  **/
526 
527 error_t rsadp(const RsaPrivateKey *key, const Mpi *c, Mpi *m)
528 {
529  error_t error;
530 
531  //The ciphertext representative c shall be between 0 and n - 1
532  if(mpiCompInt(c, 0) < 0 || mpiComp(c, &key->n) >= 0)
533  return ERROR_OUT_OF_RANGE;
534 
535  //Use the Chinese remainder algorithm?
536  if(mpiGetLength(&key->n) > 0 && mpiGetLength(&key->p) > 0 &&
537  mpiGetLength(&key->q) > 0 && mpiGetLength(&key->dp) > 0 &&
538  mpiGetLength(&key->dq) > 0 && mpiGetLength(&key->qinv) > 0)
539  {
540  //Perform modular exponentiation (with CRT)
541  error = pkcauRsaCrtExp(key, c, m);
542  }
543  else if(mpiGetLength(&key->n) > 0 && mpiGetLength(&key->d) > 0)
544  {
545  //Perform modular exponentiation (without CRT)
546  error = pkcauModExp(m, c, &key->d, &key->n);
547  }
548  else
549  {
550  //Invalid parameters
551  error = ERROR_INVALID_PARAMETER;
552  }
553 
554  //Return status code
555  return error;
556 }
557 
558 #endif
559 #if (EC_SUPPORT == ENABLED)
560 
561 /**
562  * @brief Scalar multiplication (fast calculation)
563  * @param[in] curve Elliptic curve parameters
564  * @param[out] r Resulting point R = d.S
565  * @param[in] d An integer d such as 0 <= d < p
566  * @param[in] s EC point
567  * @return Error code
568  **/
569 
570 error_t ecMulFast(const EcCurve *curve, EcPoint3 *r, const uint32_t *d,
571  const EcPoint3 *s)
572 {
573  //Compute R = d.S
574  return ecMulRegular(curve, r, d, s);
575 }
576 
577 
578 /**
579  * @brief Scalar multiplication (regular calculation)
580  * @param[in] curve Elliptic curve parameters
581  * @param[out] r Resulting point R = d.S
582  * @param[in] d An integer d such as 0 <= d < q
583  * @param[in] s EC point
584  * @return Error code
585  **/
586 
587 error_t ecMulRegular(const EcCurve *curve, EcPoint3 *r, const uint32_t *d,
588  const EcPoint3 *s)
589 {
590  error_t error;
591  uint_t modLen;
592  uint_t orderLen;
593  uint32_t temp;
594 
595  //Get the length of the modulus, in bits
596  modLen = curve->fieldSize;
597  //Get the length of the order, in bits
598  orderLen = curve->orderSize;
599 
600  //Check the length of the operands
601  if(modLen <= PKCAU_MAX_EOS && orderLen <= PKCAU_MAX_EOS)
602  {
603  //Acquire exclusive access to the PKCAU module
605 
606  //Specify the length of the modulus, in bits
608  //Specify the length of the scalar, in bits
610  //Set the sign of the coefficient A
612 
613  //Load input arguments into the PKCAU internal RAM
614  pkcauImportScalar(curve->p, modLen, PKCAU_ECC_MUL_IN_P);
615  pkcauImportScalar(curve->a, modLen, PKCAU_ECC_MUL_IN_A);
619 
620  //Disable interrupts
621  PKCAU_CTL &= ~(PKCAU_CTL_ADDRERRIE | PKCAU_CTL_RAMERRIE | PKCAU_CTL_ENDIE);
622 
623  //Write in the MODESEL field of PKCAU_CTL register, specifying the operation
624  //which is to be executed
625  temp = PKCAU_CTL & ~PKCAU_CTL_MODESEL;
626  PKCAU_CTL = temp | PKCAU_MODE_ECC_MUL;
627 
628  //Then assert the START bit in PKCAU_CTL register
629  PKCAU_CTL |= PKCAU_CTL_START;
630 
631  //Data synchronization barrier
632  __DSB();
633 
634  //Wait until the ENDF bit in the PKCAU_STAT register is set to 1,
635  //indicating that the computation is complete
636  while((PKCAU_STAT & PKCAU_STAT_ENDF) == 0)
637  {
638  }
639 
640  //Copy the x-coordinate of the result
643 
644  //Copy the y-coordinate of the result
647 
648  //Set the z-coordinate of the result
650 
651  //Then clear ENDC bit by setting ENDC bit in PKCAU_STATC
652  PKCAU_STATC = PKCAU_STATC_ENDC;
653 
654  //Release exclusive access to the PKCAU module
656 
657  //Successful processing
658  error = NO_ERROR;
659  }
660  else
661  {
662  //Report an error
663  error = ERROR_FAILURE;
664  }
665 
666  //Return status code
667  return error;
668 }
669 
670 #endif
671 #if (ECDSA_SUPPORT == ENABLED)
672 
673 /**
674  * @brief ECDSA signature generation
675  * @param[in] prngAlgo PRNG algorithm
676  * @param[in] prngContext Pointer to the PRNG context
677  * @param[in] privateKey Signer's EC private key
678  * @param[in] digest Digest of the message to be signed
679  * @param[in] digestLen Length in octets of the digest
680  * @param[out] signature (R, S) integer pair
681  * @return Error code
682  **/
683 
684 error_t ecdsaGenerateSignature(const PrngAlgo *prngAlgo, void *prngContext,
685  const EcPrivateKey *privateKey, const uint8_t *digest, size_t digestLen,
686  EcdsaSignature *signature)
687 {
688  error_t error;
689  uint_t modLen;
690  uint_t orderLen;
691  uint32_t temp;
692  uint32_t k[EC_MAX_ORDER_SIZE];
693  const EcCurve *curve;
694 
695  //Check parameters
696  if(privateKey == NULL || digest == NULL || signature == NULL)
698 
699  //Invalid elliptic curve?
700  if(privateKey->curve == NULL)
702 
703  //Get elliptic curve parameters
704  curve = privateKey->curve;
705 
706  //Get the length of the modulus, in bits
707  modLen = curve->fieldSize;
708  //Get the length of the order, in bits
709  orderLen = curve->orderSize;
710 
711  //Check the length of the operands
712  if(modLen > PKCAU_MAX_EOS || orderLen > PKCAU_MAX_EOS)
713  return ERROR_FAILURE;
714 
715  //Generate a random number k such as 0 < k < q - 1
716  error = ecScalarRand(curve, k, prngAlgo, prngContext);
717 
718  //Check status code
719  if(!error)
720  {
721  //Acquire exclusive access to the PKCAU module
723 
724  //Specify the length of the modulus, in bits
726  //Specify the length of the base point order, in bits
728  //Set the sign of the coefficient A
730 
731  //Load input arguments into the PKCAU internal RAM
732  pkcauImportScalar(curve->p, modLen, PKCAU_ECDSA_SIGN_IN_P);
733  pkcauImportScalar(curve->a, modLen, PKCAU_ECDSA_SIGN_IN_A);
734  pkcauImportScalar(curve->g.x, modLen, PKCAU_ECDSA_SIGN_IN_GX);
735  pkcauImportScalar(curve->g.y, modLen, PKCAU_ECDSA_SIGN_IN_GY);
736  pkcauImportScalar(curve->q, orderLen, PKCAU_ECDSA_SIGN_IN_N);
737  pkcauImportScalar(privateKey->d, orderLen, PKCAU_ECDSA_SIGN_IN_D);
739 
740  //Keep the leftmost bits of the hash value
741  digestLen = MIN(digestLen, (orderLen + 7) / 8);
742  //Load the hash value into the PKCAU internal RAM
743  pkcauImportArray(digest, digestLen, orderLen, PKCAU_ECDSA_SIGN_IN_Z);
744 
745  //Clear error code
747 
748  //Disable interrupts
749  PKCAU_CTL &= ~(PKCAU_CTL_ADDRERRIE | PKCAU_CTL_RAMERRIE | PKCAU_CTL_ENDIE);
750 
751  //Write in the MODESEL field of PKCAU_CTL register, specifying the operation
752  //which is to be executed
753  temp = PKCAU_CTL & ~PKCAU_CTL_MODESEL;
754  PKCAU_CTL = temp | PKCAU_MODE_ECDSA_SIGN;
755 
756  //Then assert the START bit in PKCAU_CTL register
757  PKCAU_CTL |= PKCAU_CTL_START;
758 
759  //Data synchronization barrier
760  __DSB();
761 
762  //Wait until the ENDF bit in the PKCAU_STAT register is set to 1,
763  //indicating that the computation is complete
764  while((PKCAU_STAT & PKCAU_STAT_ENDF) == 0)
765  {
766  }
767 
768  //Successful computation?
770  {
771  error = NO_ERROR;
772  }
773  else
774  {
775  error = ERROR_FAILURE;
776  }
777 
778  //Check status code
779  if(!error)
780  {
781  //Save elliptic curve parameters
782  signature->curve = curve;
783 
784  //Copy integer R
785  ecScalarSetInt(signature->r, 0, EC_MAX_ORDER_SIZE);
786  pkcauExportScalar(signature->r, orderLen, PKCAU_ECDSA_SIGN_OUT_R);
787 
788  //Copy integer S
789  ecScalarSetInt(signature->s, 0, EC_MAX_ORDER_SIZE);
790  pkcauExportScalar(signature->s, orderLen, PKCAU_ECDSA_SIGN_OUT_S);
791  }
792 
793  //Then clear ENDC bit by setting ENDC bit in PKCAU_STATC
794  PKCAU_STATC = PKCAU_STATC_ENDC;
795 
796  //Release exclusive access to the PKCAU module
798  }
799 
800  //Return status code
801  return error;
802 }
803 
804 
805 /**
806  * @brief ECDSA signature verification
807  * @param[in] publicKey Signer's EC public key
808  * @param[in] digest Digest of the message whose signature is to be verified
809  * @param[in] digestLen Length in octets of the digest
810  * @param[in] signature (R, S) integer pair
811  * @return Error code
812  **/
813 
815  const uint8_t *digest, size_t digestLen, const EcdsaSignature *signature)
816 {
817  error_t error;
818  uint_t modLen;
819  uint_t orderLen;
820  uint32_t temp;
821  const EcCurve *curve;
822 
823  //Check parameters
824  if(publicKey == NULL || digest == NULL || signature == NULL)
826 
827  //Invalid elliptic curve?
828  if(publicKey->curve == NULL)
830 
831  //Verify that the public key is on the curve
832  if(!ecIsPointAffine(publicKey->curve, &publicKey->q))
833  {
835  }
836 
837  //The verifier shall check that 0 < r < q
838  if(ecScalarCompInt(signature->r, 0, EC_MAX_ORDER_SIZE) <= 0 ||
839  ecScalarComp(signature->r, publicKey->curve->q, EC_MAX_ORDER_SIZE) >= 0)
840  {
841  //If the condition is violated, the signature shall be rejected as invalid
843  }
844 
845  //The verifier shall check that 0 < s < q
846  if(ecScalarCompInt(signature->s, 0, EC_MAX_ORDER_SIZE) <= 0 ||
847  ecScalarComp(signature->s, publicKey->curve->q, EC_MAX_ORDER_SIZE) >= 0)
848  {
849  //If the condition is violated, the signature shall be rejected as invalid
851  }
852 
853  //Get elliptic curve parameters
854  curve = publicKey->curve;
855 
856  //Get the length of the modulus, in bits
857  modLen = curve->fieldSize;
858  //Get the length of the order, in bits
859  orderLen = curve->orderSize;
860 
861  //Check the length of the operands
862  if(modLen > PKCAU_MAX_EOS || orderLen > PKCAU_MAX_EOS)
863  return ERROR_FAILURE;
864 
865  //Acquire exclusive access to the PKCAU module
867 
868  //Specify the length of the modulus, in bits
870  //Specify the length of the base point order, in bits
872  //Set the sign of the coefficient A
874 
875  //Load input arguments into the PKCAU internal RAM
876  pkcauImportScalar(curve->p, modLen, PKCAU_ECDSA_VERIF_IN_P);
877  pkcauImportScalar(curve->a, modLen, PKCAU_ECDSA_VERIF_IN_A);
878  pkcauImportScalar(curve->g.x, modLen, PKCAU_ECDSA_VERIF_IN_GX);
879  pkcauImportScalar(curve->g.y, modLen, PKCAU_ECDSA_VERIF_IN_GY);
880  pkcauImportScalar(curve->q, orderLen, PKCAU_ECDSA_VERIF_IN_N);
881  pkcauImportScalar(publicKey->q.x, modLen, PKCAU_ECDSA_VERIF_IN_QX);
882  pkcauImportScalar(publicKey->q.y, modLen, PKCAU_ECDSA_VERIF_IN_QY);
883  pkcauImportScalar(signature->r, orderLen, PKCAU_ECDSA_VERIF_IN_R);
884  pkcauImportScalar(signature->s, orderLen, PKCAU_ECDSA_VERIF_IN_S);
885 
886  //Keep the leftmost bits of the hash value
887  digestLen = MIN(digestLen, (orderLen + 7) / 8);
888  //Load the hash value into the PKCAU internal RAM
889  pkcauImportArray(digest, digestLen, orderLen, PKCAU_ECDSA_VERIF_IN_Z);
890 
891  //Clear result
893 
894  //Disable interrupts
895  PKCAU_CTL &= ~(PKCAU_CTL_ADDRERRIE | PKCAU_CTL_RAMERRIE | PKCAU_CTL_ENDIE);
896 
897  //Write in the MODESEL field of PKCAU_CTL register, specifying the operation
898  //which is to be executed
899  temp = PKCAU_CTL & ~PKCAU_CTL_MODESEL;
900  PKCAU_CTL = temp | PKCAU_MODE_ECDSA_VERIFICATION;
901 
902  //Then assert the START bit in PKCAU_CTL register
903  PKCAU_CTL |= PKCAU_CTL_START;
904 
905  //Data synchronization barrier
906  __DSB();
907 
908  //Wait until the ENDF bit in the PKCAU_STAT register is set to 1,
909  //indicating that the computation is complete
910  while((PKCAU_STAT & PKCAU_STAT_ENDF) == 0)
911  {
912  }
913 
914  //Test if the ECDSA signature is valid
916  {
917  error = NO_ERROR;
918  }
919  else
920  {
921  error = ERROR_INVALID_SIGNATURE;
922  }
923 
924  //Then clear ENDC bit by setting ENDC bit in PKCAU_STATC
925  PKCAU_STATC = PKCAU_STATC_ENDC;
926 
927  //Release exclusive access to the PKCAU module
929 
930  //Return status code
931  return error;
932 }
933 
934 #endif
935 #endif
#define PKCAU_MAX_EOS
ECDSA signature.
Definition: ecdsa.h:63
@ ERROR_OUT_OF_RANGE
Definition: error.h:138
#define PKCAU_ECC_MUL_IN_A_SIGN
Mpi p
First factor.
Definition: rsa.h:72
uint8_t a
Definition: ndp.h:411
Arbitrary precision integer.
Definition: mpi.h:102
#define PKCAU_STATUS_INVALID
#define PrngAlgo
Definition: crypto.h:973
ECDSA (Elliptic Curve Digital Signature Algorithm)
uint8_t p
Definition: ndp.h:300
const EcCurve * curve
Elliptic curve parameters.
Definition: ecdsa.h:64
#define PKCAU_ECC_MUL_IN_A
const EcCurve * curve
Elliptic curve parameters.
Definition: ec.h:433
#define EC_MAX_ORDER_SIZE
Definition: ec.h:315
#define PKCAU_ECDSA_VERIF_IN_R
Mpi n
Modulus.
Definition: rsa.h:69
#define PKCAU_ECC_MUL_OUT_Y
error_t pkcauRsaCrtExp(const RsaPrivateKey *key, const Mpi *c, Mpi *m)
Modular exponentiation with CRT.
error_t ecdsaVerifySignature(const EcPublicKey *publicKey, const uint8_t *digest, size_t digestLen, const EcdsaSignature *signature)
ECDSA signature verification.
#define PKCAU_ECDSA_VERIF_IN_GX
error_t ecMulFast(const EcCurve *curve, EcPoint3 *r, const uint32_t *d, const EcPoint3 *s)
Scalar multiplication (fast calculation)
Mpi e
Public exponent.
Definition: rsa.h:59
uint32_t y[EC_MAX_MODULUS_SIZE]
y-coordinate
Definition: ec.h:400
#define PKCAU_ECDSA_VERIF_IN_MOD_LEN
#define PKCAU_MOD_EXP_IN_OP_LEN
void mpiInit(Mpi *r)
Initialize a multiple precision integer.
Definition: mpi.c:48
GD32W5 public-key hardware accelerator (PKCAU)
Mpi d
Private exponent.
Definition: rsa.h:71
Mpi n
Modulus.
Definition: rsa.h:58
#define PKCAU_ECDSA_VERIF_IN_N
error_t rsaep(const RsaPublicKey *key, const Mpi *m, Mpi *c)
RSA encryption primitive.
#define PKCAU_STATUS_SUCCESS
#define PKCAU_ECC_MUL_IN_MOD_LEN
uint8_t r
Definition: ndp.h:346
#define PKCAU_ECDSA_VERIF_IN_P
#define PKCAU_RSA_CRT_EXP_OUT_R
error_t mpiMod(Mpi *r, const Mpi *a, const Mpi *p)
Modulo operation.
Definition: mpi.c:1587
@ ERROR_INVALID_ELLIPTIC_CURVE
Definition: error.h:134
error_t mpiMul(Mpi *r, const Mpi *a, const Mpi *b)
Multiple precision multiplication.
uint8_t h
Definition: ndp.h:302
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
#define PKCAU_RSA_CRT_EXP_IN_P
OsMutex gd32w5xxCryptoMutex
error_t mpiSub(Mpi *r, const Mpi *a, const Mpi *b)
Multiple precision subtraction.
Definition: mpi.c:969
#define PKCAU_ECDSA_VERIF_IN_A_SIGN
error_t
Error codes.
Definition: error.h:43
#define PKCAU_ECDSA_VERIF_OUT_RES
void pkcauImportMpi(const Mpi *src, uint_t length, uint_t offset)
Import multiple-precision integer.
#define PKCAU_ECDSA_SIGN_IN_MOD_LEN
#define PKCAU_ECDSA_SIGN_IN_K
error_t mpiAdd(Mpi *r, const Mpi *a, const Mpi *b)
Multiple precision addition.
Definition: mpi.c:891
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
void ecScalarSetInt(uint32_t *a, uint32_t b, uint_t n)
Set integer value.
Definition: ec_misc.c:505
#define PKCAU_RAM
Mpi q
Second factor.
Definition: rsa.h:73
Helper routines for ECC.
RSA public key.
Definition: rsa.h:57
#define PKCAU_MOD_EXP_OUT_R
error_t ecMulRegular(const EcCurve *curve, EcPoint3 *r, const uint32_t *d, const EcPoint3 *s)
Scalar multiplication (regular calculation)
uint32_t r[EC_MAX_ORDER_SIZE]
Integer R.
Definition: ecdsa.h:65
General definitions for cryptographic algorithms.
#define PKCAU_MOD_EXP_IN_N
RSA public-key cryptography standard.
EC private key.
Definition: ec.h:432
void pkcauExportScalar(uint32_t *dest, uint_t length, uint_t offset)
Export scalar.
#define PKCAU_ECDSA_SIGN_IN_D
#define PKCAU_RSA_CRT_EXP_IN_A
#define PKCAU_ECDSA_SIGN_OUT_ERROR
uint8_t length
Definition: tcp.h:375
#define PKCAU_ECDSA_SIGN_OUT_S
#define PKCAU_ECC_MUL_IN_Y
#define MIN(a, b)
Definition: os_port.h:63
#define PKCAU_MOD_EXP_IN_E
#define PKCAU_ECDSA_SIGN_IN_N
#define PKCAU_ECDSA_SIGN_IN_Z
uint_t mpiGetBitLength(const Mpi *a)
Get the actual length in bits.
Definition: mpi.c:254
Mpi qinv
CRT coefficient.
Definition: rsa.h:76
Mpi dq
Second factor's CRT exponent.
Definition: rsa.h:75
EC public key.
Definition: ec.h:421
__weak_func bool_t ecIsPointAffine(const EcCurve *curve, const EcPoint *s)
Check whether the affine point S is on the curve.
Definition: ec.c:798
uint_t mpiGetLength(const Mpi *a)
Get the actual length in words.
Definition: mpi.c:188
#define PKCAU_ECDSA_SIGN_IN_P
#define PKCAU_ECDSA_VERIF_IN_QY
#define PKCAU_MOD_EXP_IN_A
#define PKCAU_ECC_MUL_OUT_X
#define PKCAU_MAX_ROS
#define PKCAU_ECC_MUL_IN_K
#define PKCAU_ECC_MUL_IN_SCALAR_LEN
void pkcauImportScalar(const uint32_t *src, uint_t length, uint_t offset)
Import scalar.
error_t pkcauModExp(Mpi *r, const Mpi *a, const Mpi *e, const Mpi *p)
Modular exponentiation.
uint32_t d[EC_MAX_ORDER_SIZE]
Private key.
Definition: ec.h:434
int_t ecScalarCompInt(const uint32_t *a, uint32_t b, uint_t n)
Compare integers.
Definition: ec_misc.c:374
uint8_t m
Definition: ndp.h:304
uint8_t n
RSA private key.
Definition: rsa.h:68
void osAcquireMutex(OsMutex *mutex)
Acquire ownership of the specified mutex object.
uint_t size
Definition: mpi.h:104
error_t pkcauExportMpi(Mpi *dest, uint_t length, uint_t offset)
Export multiple-precision integer.
EC point (projective coordinates)
Definition: ec.h:409
void osReleaseMutex(OsMutex *mutex)
Release ownership of the specified mutex object.
error_t pkcauInit(void)
PKCAU module initialization.
error_t rsadp(const RsaPrivateKey *key, const Mpi *c, Mpi *m)
RSA decryption primitive.
#define PKCAU_RSA_CRT_EXP_IN_Q
#define PKCAU_RSA_CRT_EXP_IN_DP
#define PKCAU_ECDSA_SIGN_IN_GX
GD32W5 hardware cryptographic accelerator.
EcPoint q
Public key.
Definition: ec.h:423
uint32_t s[EC_MAX_ORDER_SIZE]
Integer S.
Definition: ecdsa.h:66
#define PKCAU_RSA_CRT_EXP_IN_QINV
error_t ecdsaGenerateSignature(const PrngAlgo *prngAlgo, void *prngContext, const EcPrivateKey *privateKey, const uint8_t *digest, size_t digestLen, EcdsaSignature *signature)
ECDSA signature generation.
#define PKCAU_ECDSA_VERIF_IN_S
error_t ecScalarRand(const EcCurve *curve, uint32_t *r, const PrngAlgo *prngAlgo, void *prngContext)
Generate a random value.
Definition: ec_misc.c:603
#define PKCAU_ECDSA_SIGN_IN_A_SIGN
#define PKCAU_ECDSA_SIGN_OUT_R
#define PKCAU_RSA_CRT_EXP_IN_MOD_LEN
uint8_t s
Definition: igmp_common.h:234
#define PKCAU_ECDSA_VERIF_IN_QX
#define PKCAU_ECC_MUL_IN_X
#define PKCAU_ECDSA_SIGN_IN_A
#define PKCAU_MOD_EXP_IN_EXP_LEN
void pkcauImportArray(const uint8_t *src, size_t srcLen, uint_t destLen, uint_t offset)
Import byte array.
#define PKCAU_ECDSA_VERIF_IN_GY
#define EcCurve
Definition: ec.h:346
int_t mpiComp(const Mpi *a, const Mpi *b)
Compare two multiple precision integers.
Definition: mpi.c:358
Mpi dp
First factor's CRT exponent.
Definition: rsa.h:74
int_t ecScalarComp(const uint32_t *a, const uint32_t *b, uint_t n)
Compare integers.
Definition: ec_misc.c:337
int_t mpiCompInt(const Mpi *a, mpi_sword_t b)
Compare a multiple precision integer with an integer.
Definition: mpi.c:429
unsigned int uint_t
Definition: compiler_port.h:57
uint32_t x[EC_MAX_MODULUS_SIZE]
x-coordinate
Definition: ec.h:399
error_t mpiMulMod(Mpi *r, const Mpi *a, const Mpi *b, const Mpi *p)
Modular multiplication.
#define PKCAU_RSA_CRT_EXP_IN_DQ
#define PKCAU_ECDSA_VERIF_IN_Z
ECC (Elliptic Curve Cryptography)
@ ERROR_INVALID_SIGNATURE
Definition: error.h:228
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
const EcCurve * curve
Elliptic curve parameters.
Definition: ec.h:422
#define PKCAU_ECDSA_SIGN_IN_GY
#define PKCAU_ECDSA_VERIF_IN_A
error_t mpiExpMod(Mpi *r, const Mpi *a, const Mpi *e, const Mpi *p)
Modular exponentiation.
#define EC_MAX_MODULUS_SIZE
Definition: ec.h:284
@ NO_ERROR
Success.
Definition: error.h:44
uint8_t c
Definition: ndp.h:514
Debugging facilities.
#define PKCAU_ECDSA_SIGN_IN_ORDER_LEN
int_t sign
Definition: mpi.h:103
#define PKCAU_ECDSA_VERIF_IN_ORDER_LEN
#define PKCAU_ECC_MUL_IN_P
void mpiFree(Mpi *r)
Release a multiple precision integer.
Definition: mpi.c:64