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-2026 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.6.6
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  //Initialize variable
92  temp = 0;
93 
94  //Get the length of the operand, in words
95  destLen = (destLen + 31) / 32;
96 
97  //Copy the array to the PKCAU RAM
98  for(i = 0, j = 0; i < srcLen; i++)
99  {
100  switch(i % 4)
101  {
102  case 0:
103  temp = src[srcLen - i - 1];
104  break;
105  case 1:
106  temp |= src[srcLen - i - 1] << 8;
107  break;
108  case 2:
109  temp |= src[srcLen - i - 1] << 16;
110  break;
111  default:
112  temp |= src[srcLen - i - 1] << 24;
113  PKCAU_RAM[offset + j] = temp;
114  j++;
115  break;
116  }
117  }
118 
119  //Pad the operand with zeroes
120  for(; i < (destLen * 4); i++)
121  {
122  switch(i % 4)
123  {
124  case 0:
125  temp = 0;
126  break;
127  case 3:
128  PKCAU_RAM[offset + j] = temp;
129  j++;
130  break;
131  default:
132  break;
133  }
134  }
135 
136  //An additional word with all bits equal to zero must be added
137  PKCAU_RAM[offset + j] = 0;
138 }
139 
140 
141 /**
142  * @brief Import scalar
143  * @param[in] src Pointer to the scalar
144  * @param[in] length Length of the operand, in bits
145  * @param[in] offset PKCAU ram offset
146  **/
147 
148 void pkcauImportScalar(const uint32_t *src, uint_t length, uint_t offset)
149 {
150  uint_t i;
151 
152  //Get the length of the operand, in words
153  length = (length + 31) / 32;
154 
155  //Copy the scalar to the PKCAU RAM
156  for(i = 0; i < length; i++)
157  {
158  PKCAU_RAM[offset + i] = src[i];
159  }
160 
161  //An additional word with all bits equal to zero must be added
162  PKCAU_RAM[offset + i] = 0;
163 }
164 
165 
166 /**
167  * @brief Import multiple-precision integer
168  * @param[in] src Pointer to the multiple-precision integer
169  * @param[in] length Length of the operand, in bits
170  * @param[in] offset PKCAU ram offset
171  **/
172 
173 void pkcauImportMpi(const Mpi *src, uint_t length, uint_t offset)
174 {
175  uint_t i;
176  uint_t n;
177 
178  //Get the length of the operand, in words
179  length = (length + 31) / 32;
180 
181  //Get the actual length of the multiple-precision integer, in words
182  n = mpiGetLength(src);
183 
184  //Copy the multiple-precision integer to the PKCAU RAM
185  for(i = 0; i < n && i < length; i++)
186  {
187  PKCAU_RAM[offset + i] = src->data[i];
188  }
189 
190  //Pad the operand with zeroes
191  for(; i < length; i++)
192  {
193  PKCAU_RAM[offset + i] = 0;
194  }
195 
196  //An additional word with all bits equal to zero must be added
197  PKCAU_RAM[offset + i] = 0;
198 }
199 
200 
201 /**
202  * @brief Export scalar
203  * @param[out] dest Pointer to the scalar
204  * @param[in] length Length of the operand, in bits
205  * @param[in] offset PKCAU ram offset
206  **/
207 
208 void pkcauExportScalar(uint32_t *dest, uint_t length, uint_t offset)
209 {
210  uint_t i;
211 
212  //Get the length of the operand, in words
213  length = (length + 31) / 32;
214 
215  //Copy the scalar from the PKCAU RAM
216  for(i = 0; i < length; i++)
217  {
218  dest[i] = PKCAU_RAM[offset + i];
219  }
220 }
221 
222 
223 /**
224  * @brief Export multiple-precision integer
225  * @param[out] dest Pointer to the multiple-precision integer
226  * @param[in] length Length of the operand, in bits
227  * @param[in] offset PKCAU ram offset
228  * @return Error code
229  **/
230 
232 {
233  error_t error;
234  uint_t i;
235 
236  //Get the length of the operand, in words
237  length = (length + 31) / 32;
238 
239  //Skip trailing zeroes
240  while(length > 0 && PKCAU_RAM[offset + length - 1] == 0)
241  {
242  length--;
243  }
244 
245  //Ajust the size of the multiple precision integer
246  error = mpiGrow(dest, length);
247 
248  //Check status code
249  if(!error)
250  {
251  //Copy the multiple-precision integer from the PKCAU RAM
252  for(i = 0; i < length; i++)
253  {
254  dest->data[i] = PKCAU_RAM[offset + i];
255  }
256 
257  //Pad the resulting value with zeroes
258  for(; i < dest->size; i++)
259  {
260  dest->data[i] = 0;
261  }
262 
263  //Set the sign
264  dest->sign = 1;
265  }
266 
267  //Return status code
268  return error;
269 }
270 
271 
272 #if (MPI_SUPPORT == ENABLED)
273 
274 /**
275  * @brief Modular exponentiation
276  * @param[out] r Resulting integer R = A ^ E mod P
277  * @param[in] a Pointer to a multiple precision integer
278  * @param[in] e Exponent
279  * @param[in] p Modulus
280  * @return Error code
281  **/
282 
283 error_t pkcauModExp(Mpi *r, const Mpi *a, const Mpi *e, const Mpi *p)
284 {
285  error_t error;
286  uint_t modLen;
287  uint_t expLen;
288  uint32_t temp;
289 
290  //Get the length of the modulus, in bits
291  modLen = mpiGetBitLength(p);
292  //Get the length of the exponent, in bits
293  expLen = mpiGetBitLength(e);
294 
295  //Check the length of the operands
296  if(modLen <= PKCAU_MAX_ROS && expLen <= PKCAU_MAX_ROS)
297  {
298  //Reduce the operand first
299  error = mpiMod(r, a, p);
300 
301  //Check status code
302  if(!error)
303  {
304  //Acquire exclusive access to the PKCAU module
306 
307  //Specify the length of the operand, in bits
309  //Specify the length of the exponent, in bits
311 
312  //Load input arguments into the PKCAU internal RAM
316 
317  //Disable interrupts
318  PKCAU_CTL &= ~(PKCAU_CTL_ADDRERRIE | PKCAU_CTL_RAMERRIE | PKCAU_CTL_ENDIE);
319 
320  //Write in the MODESEL field of PKCAU_CTL register, specifying the operation
321  //which is to be executed
322  temp = PKCAU_CTL & ~PKCAU_CTL_MODESEL;
323  PKCAU_CTL = temp | PKCAU_MODE_MOD_EXP;
324 
325  //Then assert the START bit in PKCAU_CTL register
326  PKCAU_CTL |= PKCAU_CTL_START;
327 
328  //Data synchronization barrier
329  __DSB();
330 
331  //Wait until the ENDF bit in the PKCAU_STAT register is set to 1,
332  //indicating that the computation is complete
333  while((PKCAU_STAT & PKCAU_STAT_ENDF) == 0)
334  {
335  }
336 
337  //Read the result data from the PKCAU internal RAM
338  error = pkcauExportMpi(r, modLen, PKCAU_MOD_EXP_OUT_R);
339 
340  //Then clear ENDC bit by setting ENDC bit in PKCAU_STATC
341  PKCAU_STATC = PKCAU_STATC_ENDC;
342 
343  //Release exclusive access to the PKCAU module
345  }
346  }
347  else
348  {
349  //Perform modular exponentiation
350  error = mpiExpMod(r, a, e, p);
351  }
352 
353  //Return status code
354  return error;
355 }
356 
357 #endif
358 #if (RSA_SUPPORT == ENABLED)
359 
360 /**
361  * @brief Modular exponentiation with CRT
362  * @param[in] key RSA public key
363  * @param[in] m Message representative
364  * @param[out] c Ciphertext representative
365  * @return Error code
366  **/
367 
369 {
370  error_t error;
371  uint_t nLen;
372  uint_t pLen;
373  uint_t qLen;
374  uint_t dpLen;
375  uint_t dqLen;
376  uint_t qinvLen;
377  uint32_t temp;
378 
379  //Get the length of the private key
380  nLen = mpiGetBitLength(&key->n);
381  pLen = mpiGetBitLength(&key->p);
382  qLen = mpiGetBitLength(&key->q);
383  dpLen = mpiGetBitLength(&key->dp);
384  dqLen = mpiGetBitLength(&key->dq);
385  qinvLen = mpiGetBitLength(&key->qinv);
386 
387  //Check the length of the operands
388  if(nLen <= PKCAU_MAX_ROS && pLen <= (nLen / 2) && qLen <= (nLen / 2) &&
389  dpLen <= (nLen / 2) && dqLen <= (nLen / 2) && qinvLen <= (nLen / 2))
390  {
391  //Acquire exclusive access to the PKCAU module
393 
394  //Specify the length of the operand, in bits
396 
397  //Load input arguments into the PKCAU internal RAM
398  pkcauImportMpi(&key->p, nLen / 2, PKCAU_RSA_CRT_EXP_IN_P);
399  pkcauImportMpi(&key->q, nLen / 2, PKCAU_RSA_CRT_EXP_IN_Q);
400  pkcauImportMpi(&key->dp, nLen / 2, PKCAU_RSA_CRT_EXP_IN_DP);
401  pkcauImportMpi(&key->dq, nLen / 2, PKCAU_RSA_CRT_EXP_IN_DQ);
404 
405  //Disable interrupts
406  PKCAU_CTL &= ~(PKCAU_CTL_ADDRERRIE | PKCAU_CTL_RAMERRIE | PKCAU_CTL_ENDIE);
407 
408  //Write in the MODESEL field of PKCAU_CTL register, specifying the operation
409  //which is to be executed
410  temp = PKCAU_CTL & ~PKCAU_CTL_MODESEL;
411  PKCAU_CTL = temp | PKCAU_MODE_CRT_EXP;
412 
413  //Then assert the START bit in PKCAU_CTL register
414  PKCAU_CTL |= PKCAU_CTL_START;
415 
416  //Data synchronization barrier
417  __DSB();
418 
419  //Wait until the ENDF bit in the PKCAU_STAT register is set to 1,
420  //indicating that the computation is complete
421  while((PKCAU_STAT & PKCAU_STAT_ENDF) == 0)
422  {
423  }
424 
425  //Read the result data from the PKCAU internal RAM
426  error = pkcauExportMpi(m, nLen, PKCAU_RSA_CRT_EXP_OUT_R);
427 
428  //Then clear ENDC bit by setting ENDC bit in PKCAU_STATC
429  PKCAU_STATC = PKCAU_STATC_ENDC;
430 
431  //Release exclusive access to the PKCAU module
433  }
434  else
435  {
436  Mpi m1;
437  Mpi m2;
438  Mpi h;
439 
440  //Initialize multiple-precision integers
441  mpiInit(&m1);
442  mpiInit(&m2);
443  mpiInit(&h);
444 
445  //Compute m1 = c ^ dP mod p
446  error = pkcauModExp(&m1, c, &key->dp, &key->p);
447 
448  //Check status code
449  if(!error)
450  {
451  //Compute m2 = c ^ dQ mod q
452  error = pkcauModExp(&m2, c, &key->dq, &key->q);
453  }
454 
455  //Check status code
456  if(!error)
457  {
458  //Let h = (m1 - m2) * qInv mod p
459  error = mpiSub(&h, &m1, &m2);
460  }
461 
462  //Check status code
463  if(!error)
464  {
465  error = mpiMulMod(&h, &h, &key->qinv, &key->p);
466  }
467 
468  //Check status code
469  if(!error)
470  {
471  //Let m = m2 + q * h
472  error = mpiMul(m, &key->q, &h);
473  }
474 
475  //Check status code
476  if(!error)
477  {
478  error = mpiAdd(m, m, &m2);
479  }
480 
481  //Free previously allocated memory
482  mpiFree(&m1);
483  mpiFree(&m2);
484  mpiFree(&h);
485  }
486 
487  //Return status code
488  return error;
489 }
490 
491 
492 /**
493  * @brief RSA encryption primitive
494  * @param[in] key RSA public key
495  * @param[in] m Message representative
496  * @param[out] c Ciphertext representative
497  * @return Error code
498  **/
499 
500 error_t rsaep(const RsaPublicKey *key, const Mpi *m, Mpi *c)
501 {
502  size_t nLen;
503  size_t eLen;
504 
505  //Get the length of the public key
506  nLen = mpiGetLength(&key->n);
507  eLen = mpiGetLength(&key->e);
508 
509  //Sanity check
510  if(nLen == 0 || eLen == 0)
512 
513  //The message representative m shall be between 0 and n - 1
514  if(mpiCompInt(m, 0) < 0 || mpiComp(m, &key->n) >= 0)
515  return ERROR_OUT_OF_RANGE;
516 
517  //Perform modular exponentiation (c = m ^ e mod n)
518  return pkcauModExp(c, m, &key->e, &key->n);
519 }
520 
521 
522 /**
523  * @brief RSA decryption primitive
524  * @param[in] key RSA private key
525  * @param[in] c Ciphertext representative
526  * @param[out] m Message representative
527  * @return Error code
528  **/
529 
530 error_t rsadp(const RsaPrivateKey *key, const Mpi *c, Mpi *m)
531 {
532  error_t error;
533 
534  //The ciphertext representative c shall be between 0 and n - 1
535  if(mpiCompInt(c, 0) < 0 || mpiComp(c, &key->n) >= 0)
536  return ERROR_OUT_OF_RANGE;
537 
538  //Use the Chinese remainder algorithm?
539  if(mpiGetLength(&key->p) > 0 && mpiGetLength(&key->q) > 0 &&
540  mpiGetLength(&key->dp) > 0 && mpiGetLength(&key->dq) > 0 &&
541  mpiGetLength(&key->qinv) > 0)
542  {
543  //Perform modular exponentiation (with CRT)
544  error = pkcauRsaCrtExp(key, c, m);
545  }
546  else if(mpiGetLength(&key->n) > 0 && mpiGetLength(&key->d) > 0)
547  {
548  //Perform modular exponentiation (without CRT)
549  error = pkcauModExp(m, c, &key->d, &key->n);
550  }
551  else
552  {
553  //Invalid parameters
554  error = ERROR_INVALID_PARAMETER;
555  }
556 
557  //Return status code
558  return error;
559 }
560 
561 #endif
562 #if (EC_SUPPORT == ENABLED)
563 
564 /**
565  * @brief Scalar multiplication (fast calculation)
566  * @param[in] curve Elliptic curve parameters
567  * @param[out] r Resulting point R = d.S
568  * @param[in] d An integer d such as 0 <= d < p
569  * @param[in] s EC point
570  * @return Error code
571  **/
572 
573 error_t ecMulFast(const EcCurve *curve, EcPoint3 *r, const uint32_t *d,
574  const EcPoint3 *s)
575 {
576  //Compute R = d.S
577  return ecMulRegular(curve, r, d, s);
578 }
579 
580 
581 /**
582  * @brief Scalar multiplication (regular calculation)
583  * @param[in] curve Elliptic curve parameters
584  * @param[out] r Resulting point R = d.S
585  * @param[in] d An integer d such as 0 <= d < q
586  * @param[in] s EC point
587  * @return Error code
588  **/
589 
590 error_t ecMulRegular(const EcCurve *curve, EcPoint3 *r, const uint32_t *d,
591  const EcPoint3 *s)
592 {
593  error_t error;
594  uint_t modLen;
595  uint_t orderLen;
596  uint32_t temp;
597 
598  //Get the length of the modulus, in bits
599  modLen = curve->fieldSize;
600  //Get the length of the order, in bits
601  orderLen = curve->orderSize;
602 
603  //Check the length of the operands
604  if(modLen <= PKCAU_MAX_EOS && orderLen <= PKCAU_MAX_EOS)
605  {
606  //Acquire exclusive access to the PKCAU module
608 
609  //Specify the length of the modulus, in bits
611  //Specify the length of the scalar, in bits
613  //Set the sign of the coefficient A
615 
616  //Load input arguments into the PKCAU internal RAM
617  pkcauImportScalar(curve->p, modLen, PKCAU_ECC_MUL_IN_P);
618  pkcauImportScalar(curve->a, modLen, PKCAU_ECC_MUL_IN_A);
622 
623  //Disable interrupts
624  PKCAU_CTL &= ~(PKCAU_CTL_ADDRERRIE | PKCAU_CTL_RAMERRIE | PKCAU_CTL_ENDIE);
625 
626  //Write in the MODESEL field of PKCAU_CTL register, specifying the operation
627  //which is to be executed
628  temp = PKCAU_CTL & ~PKCAU_CTL_MODESEL;
629  PKCAU_CTL = temp | PKCAU_MODE_ECC_MUL;
630 
631  //Then assert the START bit in PKCAU_CTL register
632  PKCAU_CTL |= PKCAU_CTL_START;
633 
634  //Data synchronization barrier
635  __DSB();
636 
637  //Wait until the ENDF bit in the PKCAU_STAT register is set to 1,
638  //indicating that the computation is complete
639  while((PKCAU_STAT & PKCAU_STAT_ENDF) == 0)
640  {
641  }
642 
643  //Copy the x-coordinate of the result
646 
647  //Copy the y-coordinate of the result
650 
651  //Set the z-coordinate of the result
653 
654  //Then clear ENDC bit by setting ENDC bit in PKCAU_STATC
655  PKCAU_STATC = PKCAU_STATC_ENDC;
656 
657  //Release exclusive access to the PKCAU module
659 
660  //Successful processing
661  error = NO_ERROR;
662  }
663  else
664  {
665  //Report an error
666  error = ERROR_FAILURE;
667  }
668 
669  //Return status code
670  return error;
671 }
672 
673 
674 /**
675  * @brief Twin multiplication
676  * @param[in] curve Elliptic curve parameters
677  * @param[out] r Resulting point R = d0.S + d1.T
678  * @param[in] d0 An integer d such as 0 <= d0 < p
679  * @param[in] s EC point
680  * @param[in] d1 An integer d such as 0 <= d1 < p
681  * @param[in] t EC point
682  * @return Error code
683  **/
684 
685 error_t ecTwinMul(const EcCurve *curve, EcPoint3 *r, const uint32_t *d0,
686  const EcPoint3 *s, const uint32_t *d1, const EcPoint3 *t)
687 {
688  error_t error;
689  EcPoint3 u;
690 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
691  EcState *state;
692 #else
693  EcState state[1];
694 #endif
695 
696 #if (CRYPTO_STATIC_MEM_SUPPORT == DISABLED)
697  //Allocate working state
698  state = cryptoAllocMem(sizeof(EcState));
699  //Failed to allocate memory?
700  if(state == NULL)
701  return ERROR_OUT_OF_MEMORY;
702 #endif
703 
704  //Initialize working state
705  osMemset(state, 0, sizeof(EcState));
706  //Save elliptic curve parameters
707  state->curve = curve;
708 
709  //Compute d0.S
710  error = ecMulFast(curve, r, d0, s);
711 
712  //Check status code
713  if(!error)
714  {
715  //Compute d1.T
716  error = ecMulFast(curve, &u, d1, t);
717  }
718 
719  //Check status code
720  if(!error)
721  {
722  //Compute d0.S + d1.T
723  ecFullAdd(state, r, r, &u);
724  }
725 
726  //Return status code
727  return error;
728 }
729 
730 #endif
731 #if (ECDSA_SUPPORT == ENABLED)
732 
733 /**
734  * @brief ECDSA signature generation
735  * @param[in] prngAlgo PRNG algorithm
736  * @param[in] prngContext Pointer to the PRNG context
737  * @param[in] privateKey Signer's EC private key
738  * @param[in] digest Digest of the message to be signed
739  * @param[in] digestLen Length in octets of the digest
740  * @param[out] signature (R, S) integer pair
741  * @return Error code
742  **/
743 
744 error_t ecdsaGenerateSignature(const PrngAlgo *prngAlgo, void *prngContext,
745  const EcPrivateKey *privateKey, const uint8_t *digest, size_t digestLen,
746  EcdsaSignature *signature)
747 {
748  error_t error;
749  uint_t modLen;
750  uint_t orderLen;
751  uint32_t temp;
752  uint32_t k[EC_MAX_ORDER_SIZE];
753  const EcCurve *curve;
754 
755  //Check parameters
756  if(privateKey == NULL || digest == NULL || signature == NULL)
758 
759  //Invalid elliptic curve?
760  if(privateKey->curve == NULL)
762 
763  //Get elliptic curve parameters
764  curve = privateKey->curve;
765 
766  //Get the length of the modulus, in bits
767  modLen = curve->fieldSize;
768  //Get the length of the order, in bits
769  orderLen = curve->orderSize;
770 
771  //Check the length of the operands
772  if(modLen > PKCAU_MAX_EOS || orderLen > PKCAU_MAX_EOS)
773  return ERROR_FAILURE;
774 
775  //Generate a random number k such as 0 < k < q - 1
776  error = ecScalarRand(curve, k, prngAlgo, prngContext);
777 
778  //Check status code
779  if(!error)
780  {
781  //Acquire exclusive access to the PKCAU module
783 
784  //Specify the length of the modulus, in bits
786  //Specify the length of the base point order, in bits
788  //Set the sign of the coefficient A
790 
791  //Load input arguments into the PKCAU internal RAM
792  pkcauImportScalar(curve->p, modLen, PKCAU_ECDSA_SIGN_IN_P);
793  pkcauImportScalar(curve->a, modLen, PKCAU_ECDSA_SIGN_IN_A);
794  pkcauImportScalar(curve->g.x, modLen, PKCAU_ECDSA_SIGN_IN_GX);
795  pkcauImportScalar(curve->g.y, modLen, PKCAU_ECDSA_SIGN_IN_GY);
796  pkcauImportScalar(curve->q, orderLen, PKCAU_ECDSA_SIGN_IN_N);
797  pkcauImportScalar(privateKey->d, orderLen, PKCAU_ECDSA_SIGN_IN_D);
799 
800  //Keep the leftmost bits of the hash value
801  digestLen = MIN(digestLen, (orderLen + 7) / 8);
802  //Load the hash value into the PKCAU internal RAM
803  pkcauImportArray(digest, digestLen, orderLen, PKCAU_ECDSA_SIGN_IN_Z);
804 
805  //Clear error code
807 
808  //Disable interrupts
809  PKCAU_CTL &= ~(PKCAU_CTL_ADDRERRIE | PKCAU_CTL_RAMERRIE | PKCAU_CTL_ENDIE);
810 
811  //Write in the MODESEL field of PKCAU_CTL register, specifying the operation
812  //which is to be executed
813  temp = PKCAU_CTL & ~PKCAU_CTL_MODESEL;
814  PKCAU_CTL = temp | PKCAU_MODE_ECDSA_SIGN;
815 
816  //Then assert the START bit in PKCAU_CTL register
817  PKCAU_CTL |= PKCAU_CTL_START;
818 
819  //Data synchronization barrier
820  __DSB();
821 
822  //Wait until the ENDF bit in the PKCAU_STAT register is set to 1,
823  //indicating that the computation is complete
824  while((PKCAU_STAT & PKCAU_STAT_ENDF) == 0)
825  {
826  }
827 
828  //Successful computation?
830  {
831  error = NO_ERROR;
832  }
833  else
834  {
835  error = ERROR_FAILURE;
836  }
837 
838  //Check status code
839  if(!error)
840  {
841  //Save elliptic curve parameters
842  signature->curve = curve;
843 
844  //Copy integer R
845  ecScalarSetInt(signature->r, 0, EC_MAX_ORDER_SIZE);
846  pkcauExportScalar(signature->r, orderLen, PKCAU_ECDSA_SIGN_OUT_R);
847 
848  //Copy integer S
849  ecScalarSetInt(signature->s, 0, EC_MAX_ORDER_SIZE);
850  pkcauExportScalar(signature->s, orderLen, PKCAU_ECDSA_SIGN_OUT_S);
851  }
852 
853  //Then clear ENDC bit by setting ENDC bit in PKCAU_STATC
854  PKCAU_STATC = PKCAU_STATC_ENDC;
855 
856  //Release exclusive access to the PKCAU module
858  }
859 
860  //Return status code
861  return error;
862 }
863 
864 
865 /**
866  * @brief ECDSA signature verification
867  * @param[in] publicKey Signer's EC public key
868  * @param[in] digest Digest of the message whose signature is to be verified
869  * @param[in] digestLen Length in octets of the digest
870  * @param[in] signature (R, S) integer pair
871  * @return Error code
872  **/
873 
875  const uint8_t *digest, size_t digestLen, const EcdsaSignature *signature)
876 {
877  error_t error;
878  uint_t modLen;
879  uint_t orderLen;
880  uint32_t temp;
881  const EcCurve *curve;
882 
883  //Check parameters
884  if(publicKey == NULL || digest == NULL || signature == NULL)
886 
887  //Invalid elliptic curve?
888  if(publicKey->curve == NULL)
890 
891  //Verify that the public key is on the curve
892  if(!ecIsPointAffine(publicKey->curve, &publicKey->q))
893  {
895  }
896 
897  //The verifier shall check that 0 < r < q
898  if(ecScalarCompInt(signature->r, 0, EC_MAX_ORDER_SIZE) <= 0 ||
899  ecScalarComp(signature->r, publicKey->curve->q, EC_MAX_ORDER_SIZE) >= 0)
900  {
901  //If the condition is violated, the signature shall be rejected as invalid
903  }
904 
905  //The verifier shall check that 0 < s < q
906  if(ecScalarCompInt(signature->s, 0, EC_MAX_ORDER_SIZE) <= 0 ||
907  ecScalarComp(signature->s, publicKey->curve->q, EC_MAX_ORDER_SIZE) >= 0)
908  {
909  //If the condition is violated, the signature shall be rejected as invalid
911  }
912 
913  //Get elliptic curve parameters
914  curve = publicKey->curve;
915 
916  //Get the length of the modulus, in bits
917  modLen = curve->fieldSize;
918  //Get the length of the order, in bits
919  orderLen = curve->orderSize;
920 
921  //Check the length of the operands
922  if(modLen > PKCAU_MAX_EOS || orderLen > PKCAU_MAX_EOS)
923  return ERROR_FAILURE;
924 
925  //Acquire exclusive access to the PKCAU module
927 
928  //Specify the length of the modulus, in bits
930  //Specify the length of the base point order, in bits
932  //Set the sign of the coefficient A
934 
935  //Load input arguments into the PKCAU internal RAM
936  pkcauImportScalar(curve->p, modLen, PKCAU_ECDSA_VERIF_IN_P);
937  pkcauImportScalar(curve->a, modLen, PKCAU_ECDSA_VERIF_IN_A);
938  pkcauImportScalar(curve->g.x, modLen, PKCAU_ECDSA_VERIF_IN_GX);
939  pkcauImportScalar(curve->g.y, modLen, PKCAU_ECDSA_VERIF_IN_GY);
940  pkcauImportScalar(curve->q, orderLen, PKCAU_ECDSA_VERIF_IN_N);
941  pkcauImportScalar(publicKey->q.x, modLen, PKCAU_ECDSA_VERIF_IN_QX);
942  pkcauImportScalar(publicKey->q.y, modLen, PKCAU_ECDSA_VERIF_IN_QY);
943  pkcauImportScalar(signature->r, orderLen, PKCAU_ECDSA_VERIF_IN_R);
944  pkcauImportScalar(signature->s, orderLen, PKCAU_ECDSA_VERIF_IN_S);
945 
946  //Keep the leftmost bits of the hash value
947  digestLen = MIN(digestLen, (orderLen + 7) / 8);
948  //Load the hash value into the PKCAU internal RAM
949  pkcauImportArray(digest, digestLen, orderLen, PKCAU_ECDSA_VERIF_IN_Z);
950 
951  //Clear result
953 
954  //Disable interrupts
955  PKCAU_CTL &= ~(PKCAU_CTL_ADDRERRIE | PKCAU_CTL_RAMERRIE | PKCAU_CTL_ENDIE);
956 
957  //Write in the MODESEL field of PKCAU_CTL register, specifying the operation
958  //which is to be executed
959  temp = PKCAU_CTL & ~PKCAU_CTL_MODESEL;
960  PKCAU_CTL = temp | PKCAU_MODE_ECDSA_VERIFICATION;
961 
962  //Then assert the START bit in PKCAU_CTL register
963  PKCAU_CTL |= PKCAU_CTL_START;
964 
965  //Data synchronization barrier
966  __DSB();
967 
968  //Wait until the ENDF bit in the PKCAU_STAT register is set to 1,
969  //indicating that the computation is complete
970  while((PKCAU_STAT & PKCAU_STAT_ENDF) == 0)
971  {
972  }
973 
974  //Test if the ECDSA signature is valid
976  {
977  error = NO_ERROR;
978  }
979  else
980  {
981  error = ERROR_INVALID_SIGNATURE;
982  }
983 
984  //Then clear ENDC bit by setting ENDC bit in PKCAU_STATC
985  PKCAU_STATC = PKCAU_STATC_ENDC;
986 
987  //Release exclusive access to the PKCAU module
989 
990  //Return status code
991  return error;
992 }
993 
994 #endif
995 #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:1140
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
uint8_t t
Definition: lldp_ext_med.h:212
void ecFullAdd(EcState *state, EcPoint3 *r, const EcPoint3 *s, const EcPoint3 *t)
Point addition.
Definition: ec.c:1136
#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_OUT_OF_MEMORY
Definition: error.h:63
error_t ecTwinMul(const EcCurve *curve, EcPoint3 *r, const uint32_t *d0, const EcPoint3 *s, const uint32_t *d1, const EcPoint3 *t)
Twin multiplication.
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:49
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:1589
@ 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:971
#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:893
@ 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
uint8_t u
Definition: lldp_ext_med.h:213
#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:255
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:840
uint_t mpiGetLength(const Mpi *a)
Get the actual length in words.
Definition: mpi.c:189
const EcCurve * curve
Definition: ec.h:446
#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
Working state (point addition/subtraction/doubling)
Definition: ec.h:445
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 cryptoAllocMem(size)
Definition: crypto.h:961
#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:359
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:430
unsigned int uint_t
Definition: compiler_port.h:57
uint32_t x[EC_MAX_MODULUS_SIZE]
x-coordinate
Definition: ec.h:399
#define osMemset(p, value, length)
Definition: os_port.h:141
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:103
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:65