same54_crypto_pkc.c
Go to the documentation of this file.
1 /**
2  * @file same54_crypto_pkc.c
3  * @brief SAME54 public-key hardware accelerator (PUKCC)
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 "sam.h"
36 #include "pukcc/CryptoLib_typedef_pb.h"
37 #include "pukcc/CryptoLib_Headers_pb.h"
38 #include "core/crypto.h"
41 #include "pkc/rsa.h"
42 #include "ecc/ec.h"
43 #include "ecc/ec_misc.h"
44 #include "ecc/ecdsa.h"
45 #include "mpi/mpi.h"
46 #include "debug.h"
47 
48 //Check crypto library configuration
49 #if (SAME54_CRYPTO_PKC_SUPPORT == ENABLED)
50 
51 //Global variables
52 PPUKCL_PARAM pvPUKCLParam;
53 PUKCL_PARAM PUKCLParam;
54 
55 
56 /**
57  * @brief Initialize PUKCC module
58  **/
59 
61 {
62  //Enable PUKCC clock
63  MCLK_REGS->MCLK_AHBMASK |= MCLK_AHBMASK_PUKCC_Msk;
64 
65  //Clear PUKCLParam structure
66  osMemset(&PUKCLParam, 0, sizeof(PUKCL_PARAM));
68 
69  //Initialize PUKCC
70  vPUKCL_Process(SelfTest, pvPUKCLParam);
71 
72  //Check status code
73  if(PUKCL(u2Status) != PUKCL_OK)
74  return ERROR_FAILURE;
75 
76  //Check version number
77  if(pvPUKCLParam->P.PUKCL_SelfTest.u4Version != PUKCL_VERSION)
78  return ERROR_FAILURE;
79 
80  //The return values from the SelfTest service must be compared against
81  //known values mentioned in the service description
82  if(pvPUKCLParam->P.PUKCL_SelfTest.u4CheckNum1 != 0x6E70DDD2)
83  return ERROR_FAILURE;
84 
85  if(pvPUKCLParam->P.PUKCL_SelfTest.u4CheckNum2 != 0x25C8D64F)
86  return ERROR_FAILURE;
87 
88  //Successful initialization
89  return NO_ERROR;
90 }
91 
92 
93 /**
94  * @brief Import byte array
95  * @param[in,out] dest Pointer to the crypto memory
96  * @param[in] src Pointer to the byte array
97  * @param[in] srcLen Length of the array to be copied
98  * @param[in] totalLen Desired length of the area, in bytes
99  * @return Pointer to the initialized area
100  **/
101 
102 uint8_t *pukccImportArray(uint8_t **dest, const uint8_t *src, size_t srcLen,
103  size_t totalLen)
104 {
105  size_t i;
106  uint8_t *p;
107 
108  //Point to the crypto memory
109  p = *dest;
110 
111  //Copy the byte array to the crypto memory
112  for(i = 0; i < srcLen; i++)
113  {
114  p[i] = src[srcLen - 1 - i];
115  }
116 
117  //Pad the data with zeroes
118  while(i < totalLen)
119  {
120  p[i++] = 0;
121  }
122 
123  //Advance data pointer
124  *dest = p + i;
125 
126  //Return a pointer to the initialized area
127  return p;
128 }
129 
130 
131 /**
132  * @brief Import scalar
133  * @param[in,out] dest Pointer to the crypto memory
134  * @param[in] src Pointer to the scalar
135  * @param[in] totalLen Desired length of the area, in bytes
136  * @return Pointer to the initialized area
137  **/
138 
139 uint8_t *pukccImportScalar(uint8_t **dest, const uint32_t *src, size_t totalLen)
140 {
141  uint8_t *p;
142 
143  //Point to the crypto memory
144  p = *dest;
145 
146  //Copy the scalar to the crypto memory
147  ecScalarExport(src, (totalLen - 1) / 4, p, totalLen, EC_SCALAR_FORMAT_LITTLE_ENDIAN);
148 
149  //Advance data pointer
150  *dest = p + totalLen;
151 
152  //Return a pointer to the initialized area
153  return p;
154 }
155 
156 
157 /**
158  * @brief Import multiple-precision integer
159  * @param[in,out] dest Pointer to the crypto memory
160  * @param[in] src Pointer to the multiple-precision integer
161  * @param[in] totalLen Desired length of the area, in bytes
162  * @return Pointer to the initialized area
163  **/
164 
165 uint8_t *pukccImportMpi(uint8_t **dest, const Mpi *src, size_t totalLen)
166 {
167  uint8_t *p;
168 
169  //Point to the crypto memory
170  p = *dest;
171 
172  //Copy the multiple-precision integer to the crypto memory
173  mpiExport(src, p, totalLen, MPI_FORMAT_LITTLE_ENDIAN);
174 
175  //Advance data pointer
176  *dest = p + totalLen;
177 
178  //Return a pointer to the initialized area
179  return p;
180 }
181 
182 
183 /**
184  * @brief Initialize workspace area
185  * @param[in,out] dest Pointer to the crypto memory
186  * @param[in] totalLen Desired length of the area, in bytes
187  * @return Pointer to the initialized area
188  **/
189 
190 uint8_t *pukccWorkspace(uint8_t **dest, size_t totalLen)
191 {
192  size_t i;
193  uint8_t *p;
194 
195  //Point to the crypto memory
196  p = *dest;
197 
198  //Initialize workspace area
199  for(i = 0; i < totalLen; i++)
200  {
201  p[i] = 0;
202  }
203 
204  //Advance data pointer
205  *dest = p + i;
206 
207  //Return a pointer to the initialized area
208  return p;
209 }
210 
211 
212 #if (MPI_SUPPORT == ENABLED)
213 
214 /**
215  * @brief Multiple precision multiplication
216  * @param[out] r Resulting integer R = A * B
217  * @param[in] a First operand A
218  * @param[in] b Second operand B
219  * @return Error code
220  **/
221 
222 error_t mpiMul(Mpi *r, const Mpi *a, const Mpi *b)
223 {
224  error_t error;
225  size_t m;
226  size_t n;
227  uint8_t *pos;
228  PukccFmultParams params = {0};
229 
230  //Get the length of the input integer, in bytes
231  m = mpiGetByteLength(a);
232  m = (m + 3U) & ~3U;
233 
234  //Get the length of the modulus, in bytes
235  n = mpiGetByteLength(b);
236  n = (n + 3U) & ~3U;
237 
238  //Acquire exclusive access to the PUKCC accelerator
240 
241  //Point to the crypto memory
242  pos = (uint8_t *) PUKCC_CRYPTO_RAM_BASE;
243 
244  //Copy input integer X
245  params.x = pukccImportMpi(&pos, a, m);
246  //Copy input integer Y
247  params.y = pukccImportMpi(&pos, b, n);
248 
249  //Unused parameters
250  params.z = 0;
251  params.mod = 0;
252  params.cns = 0;
253 
254  //Initialize output integer R
255  params.r = pukccWorkspace(&pos, m + n);
256 
257  //Set Fmult service parameters
258  PUKCL(u2Option) = SET_MULTIPLIEROPTION(PUKCL_FMULT_ONLY) |
259  SET_CARRYOPTION(CARRY_NONE);
260  PUKCL(Specific).CarryIn = 0;
261  PUKCL(Specific).Gf2n = 0;
262  PUKCL_Fmult(u2ModLength) = 0;
263  PUKCL_Fmult(nu1ModBase) = PUKCC_FAR_TO_NEAR(params.mod);
264  PUKCL_Fmult(nu1CnsBase) = PUKCC_FAR_TO_NEAR(params.cns);
265  PUKCL_Fmult(u2XLength) = m;
266  PUKCL_Fmult(nu1XBase) = PUKCC_FAR_TO_NEAR(params.x);
267  PUKCL_Fmult(u2YLength) = n;
268  PUKCL_Fmult(nu1YBase) = PUKCC_FAR_TO_NEAR(params.y);
269  PUKCL_Fmult(nu1ZBase) = PUKCC_FAR_TO_NEAR(params.z);
270  PUKCL_Fmult(nu1RBase) = PUKCC_FAR_TO_NEAR(params.r);
271 
272  //Perform multiplication
273  vPUKCL_Process(Fmult, pvPUKCLParam);
274 
275  //Check status code
276  if(PUKCL(u2Status) == PUKCL_OK)
277  {
278  //If FMult is without reduction, R is filled with the final result
279  error = mpiImport(r, params.r, m + n, MPI_FORMAT_LITTLE_ENDIAN);
280 
281  //Check status code
282  if(!error)
283  {
284  //Set the sign of the result
285  r->sign = (a->sign == b->sign) ? 1 : -1;
286  }
287  }
288  else
289  {
290  //Report an error
291  error = ERROR_FAILURE;
292  }
293 
294  //Release exclusive access to the PUKCC accelerator
296 
297  //Return error code
298  return error;
299 }
300 
301 
302 /**
303  * @brief Modulo operation
304  * @param[out] r Resulting integer R = A mod P
305  * @param[in] a The multiple precision integer to be reduced
306  * @param[in] p The modulus P
307  * @return Error code
308  **/
309 
310 error_t mpiMod2(Mpi *r, const Mpi *a, const Mpi *p)
311 {
312  error_t error;
313  size_t n;
314  size_t modLen;
315  uint8_t *pos;
316  PukccRedModParams params = {0};
317 
318  //Get the length of the input integer, in bytes
319  n = mpiGetByteLength(a);
320 
321  //Get the length of the modulus, in bytes
322  modLen = mpiGetByteLength(p);
323  modLen = (modLen + 3U) & ~3U;
324 
325  //Check the length of the input integer
326  if(n > (2 * modLen + 4))
327  return ERROR_INVALID_LENGTH;
328 
329  //Acquire exclusive access to the PUKCC accelerator
331 
332  //Point to the crypto memory
333  pos = (uint8_t *) PUKCC_CRYPTO_RAM_BASE;
334 
335  //Copy modulus
336  params.mod = pukccImportMpi(&pos, p, modLen + 4);
337  //Initialize workspace CNS
338  params.cns = pukccWorkspace(&pos, 68);
339  //Initialize output integer R
340  params.r = pukccWorkspace(&pos, modLen + 4);
341  //Copy input integer X
342  params.x = pukccImportMpi(&pos, a, 2 * modLen + 8);
343 
344  //Set RedMod service parameters
345  PUKCL(u2Option) = PUKCL_REDMOD_REDUCTION | PUKCL_REDMOD_USING_DIVISION;
346  PUKCL(Specific).CarryIn = 0;
347  PUKCL(Specific).Gf2n = 0;
348  PUKCL_RedMod(u2ModLength) = modLen;
349  PUKCL_RedMod(nu1ModBase) = PUKCC_FAR_TO_NEAR(params.mod);
350  PUKCL_RedMod(nu1CnsBase) = PUKCC_FAR_TO_NEAR(params.cns);
351  PUKCL_RedMod(nu1RBase) = PUKCC_FAR_TO_NEAR(params.r);
352  PUKCL_RedMod(nu1XBase) = PUKCC_FAR_TO_NEAR(params.x);
353 
354  //Perform modular reduction setup
355  vPUKCL_Process(RedMod, pvPUKCLParam);
356 
357  //Check status code
358  if(PUKCL(u2Status) == PUKCL_OK)
359  {
360  //If FMult is without reduction, R is filled with the final result
361  error = mpiImport(r, params.r, modLen, MPI_FORMAT_LITTLE_ENDIAN);
362  }
363  else
364  {
365  //Report an error
366  error = ERROR_FAILURE;
367  }
368 
369  //Release exclusive access to the PUKCC accelerator
371 
372  //Return error code
373  return error;
374 }
375 
376 
377 /**
378  * @brief Modular inverse
379  * @param[out] r Resulting integer R = A^-1 mod P
380  * @param[in] a The multiple precision integer A
381  * @param[in] p The modulus P
382  * @return Error code
383  **/
384 
385 error_t mpiInvMod(Mpi *r, const Mpi *a, const Mpi *p)
386 {
387  error_t error;
388  size_t m;
389  size_t n;
390  uint8_t *pos;
391  PukccGcdParams params = {0};
392 
393  //Get the length of the input integer, in bytes
394  m = mpiGetByteLength(a);
395  //Get the length of the modulus, in bytes
396  n = mpiGetByteLength(p);
397 
398  //Compute the length of the areas X, Y, A and Z
399  n = MAX(n, m);
400  n = (n + 7U) & ~3U;
401 
402  //Acquire exclusive access to the PUKCC accelerator
404 
405  //Point to the crypto memory
406  pos = (uint8_t *) PUKCC_CRYPTO_RAM_BASE;
407 
408  //Copy input integer
409  params.x = pukccImportMpi(&pos, a, n);
410  //Copy modulus
411  params.y = pukccImportMpi(&pos, p, n);
412  //Initialize output integer A
413  params.a = pukccWorkspace(&pos, n);
414  //Initialize output integer Z
415  params.z = pukccWorkspace(&pos, n + 4);
416  //Initialize workspace >
417  params.w = pukccWorkspace(&pos, 32);
418 
419  //Set GCD service parameters
420  PUKCL(Specific).Gf2n = 0;
421  PUKCL_GCD(nu1XBase) = PUKCC_FAR_TO_NEAR(params.x);
422  PUKCL_GCD(nu1YBase) = PUKCC_FAR_TO_NEAR(params.y);
423  PUKCL_GCD(nu1ABase) = PUKCC_FAR_TO_NEAR(params.a);
424  PUKCL_GCD(nu1ZBase) = PUKCC_FAR_TO_NEAR(params.z);
425  PUKCL_GCD(nu1WorkSpace) = PUKCC_FAR_TO_NEAR(params.w);
426  PUKCL_GCD(u2Length) = n;
427 
428  //Calculate the modular inverse
429  vPUKCL_Process(GCD, pvPUKCLParam);
430 
431  //Check status code
432  if(PUKCL(u2Status) == PUKCL_OK)
433  {
434  //Copy output integer Z
435  error = mpiImport(r, params.a, n, MPI_FORMAT_LITTLE_ENDIAN);
436  }
437  else
438  {
439  //Report an error
440  error = ERROR_FAILURE;
441  }
442 
443  //Release exclusive access to the PUKCC accelerator
445 
446  //Return error code
447  return error;
448 }
449 
450 
451 /**
452  * @brief Modular exponentiation
453  * @param[out] r Resulting integer R = A ^ E mod P
454  * @param[in] a Pointer to a multiple precision integer
455  * @param[in] e Exponent
456  * @param[in] p Modulus
457  * @return Error code
458  **/
459 
460 error_t mpiExpMod(Mpi *r, const Mpi *a, const Mpi *e, const Mpi *p)
461 {
462  error_t error;
463  size_t n;
464  size_t modLen;
465  size_t expLen;
466  uint8_t *pos;
467  PukccExpModParams params = {0};
468 
469  //Get the length of the input integer, in bytes
470  n = mpiGetByteLength(a);
471 
472  //Get the length of the modulus, in bytes
473  modLen = mpiGetByteLength(p);
474  modLen = (modLen + 3U) & ~3U;
475 
476  //Get the length of the exponent, in bytes
477  expLen = mpiGetByteLength(e);
478  expLen = (expLen + 3U) & ~3U;
479 
480  //Check the length of the input integer
481  if(n > (2 * modLen + 4))
482  return ERROR_INVALID_LENGTH;
483 
484  //Acquire exclusive access to the PUKCC accelerator
486 
487  //Point to the crypto memory
488  pos = (uint8_t *) PUKCC_CRYPTO_RAM_BASE;
489 
490  //Copy modulus
491  params.mod = pukccImportMpi(&pos, p, modLen + 4);
492  //Initialize reduction constant
493  params.cns = pukccWorkspace(&pos, modLen + 12);
494  //Initialize workspace R
495  params.r = pukccWorkspace(&pos, 64);
496  //Initialize workspace X
497  params.x = pukccWorkspace(&pos, 2 * modLen + 8);
498 
499  //Set RedMod service parameters
500  PUKCL(u2Option) = PUKCL_REDMOD_SETUP;
501  PUKCL(Specific).CarryIn = 0;
502  PUKCL(Specific).Gf2n = 0;
503  PUKCL_RedMod(u2ModLength) = modLen;
504  PUKCL_RedMod(nu1ModBase) = PUKCC_FAR_TO_NEAR(params.mod);
505  PUKCL_RedMod(nu1CnsBase) = PUKCC_FAR_TO_NEAR(params.cns);
506  PUKCL_RedMod(nu1RBase) = PUKCC_FAR_TO_NEAR(params.r);
507  PUKCL_RedMod(nu1XBase) = PUKCC_FAR_TO_NEAR(params.x);
508 
509  //Perform modular reduction setup
510  vPUKCL_Process(RedMod, pvPUKCLParam);
511 
512  //Check status code
513  if(PUKCL(u2Status) == PUKCL_OK)
514  {
515  //Point to the crypto memory
516  pos = params.r;
517 
518  //Copy input number
519  params.x = pukccImportMpi(&pos, a, 2 * modLen + 8);
520 
521  //Set RedMod service parameters
522  PUKCL(u2Option) = PUKCL_REDMOD_REDUCTION | PUKCL_REDMOD_USING_FASTRED;
523  PUKCL(Specific).CarryIn = 0;
524  PUKCL(Specific).Gf2n = 0;
525  PUKCL_RedMod(u2ModLength) = modLen;
526  PUKCL_RedMod(nu1ModBase) = PUKCC_FAR_TO_NEAR(params.mod);
527  PUKCL_RedMod(nu1CnsBase) = PUKCC_FAR_TO_NEAR(params.cns);
528  PUKCL_RedMod(nu1RBase) = PUKCC_FAR_TO_NEAR(params.x);
529  PUKCL_RedMod(nu1XBase) = PUKCC_FAR_TO_NEAR(params.x);
530 
531  //Perform fast modular reduction
532  vPUKCL_Process(RedMod, pvPUKCLParam);
533  }
534 
535  //Check status code
536  if(PUKCL(u2Status) == PUKCL_OK)
537  {
538  //Set RedMod service parameters
539  PUKCL(u2Option) = PUKCL_REDMOD_NORMALIZE;
540  PUKCL(Specific).CarryIn = 0;
541  PUKCL(Specific).Gf2n = 0;
542  PUKCL_RedMod(u2ModLength) = modLen;
543  PUKCL_RedMod(nu1ModBase) = PUKCC_FAR_TO_NEAR(params.mod);
544  PUKCL_RedMod(nu1CnsBase) = PUKCC_FAR_TO_NEAR(params.cns);
545  PUKCL_RedMod(nu1RBase) = PUKCC_FAR_TO_NEAR(params.x);
546  PUKCL_RedMod(nu1XBase) = PUKCC_FAR_TO_NEAR(params.x);
547 
548  //Normalize the result
549  vPUKCL_Process(RedMod, pvPUKCLParam);
550  }
551 
552  //Check status code
553  if(PUKCL(u2Status) == PUKCL_OK)
554  {
555  //The number to be exponentiated is followed by four 32-bit words
556  //that are used during the computations as a workspace
557  pos = params.x + modLen;
558  pukccWorkspace(&pos, 16);
559 
560  //The exponent must be given with a supplemental word on the LSB
561  //side (low addresses). This word shall be set to zero
562  params.exp = pukccWorkspace(&pos, 4);
563  pukccImportMpi(&pos, e, expLen);
564 
565  //Initialize workspace
566  params.w = pukccWorkspace(&pos, 3 * (modLen + 4) + 8);
567 
568  //Set ExpMod service parameters
569  PUKCL(u2Option) = PUKCL_EXPMOD_REGULARRSA | PUKCL_EXPMOD_WINDOWSIZE_1 |
570  PUKCL_EXPMOD_EXPINPUKCCRAM;
571  PUKCL_ExpMod(u2ModLength) = modLen;
572  PUKCL_ExpMod(nu1ModBase) = PUKCC_FAR_TO_NEAR(params.mod);
573  PUKCL_ExpMod(nu1CnsBase) = PUKCC_FAR_TO_NEAR(params.cns);
574  PUKCL_ExpMod(nu1XBase) = PUKCC_FAR_TO_NEAR(params.x);
575  PUKCL_ExpMod(nu1PrecompBase) = PUKCC_FAR_TO_NEAR(params.w);
576  PUKCL_ExpMod(u2ExpLength) = expLen;
577  PUKCL_ExpMod(pfu1ExpBase) = params.exp;
578  PUKCL_ExpMod(u1Blinding) = 0;
579 
580  //Perform modular exponentiation
581  vPUKCL_Process(ExpMod, pvPUKCLParam);
582  }
583 
584  //Check status code
585  if(PUKCL(u2Status) == PUKCL_OK)
586  {
587  //Copy resulting integer
588  error = mpiImport(r, params.x, modLen, MPI_FORMAT_LITTLE_ENDIAN);
589  }
590  else
591  {
592  //Report an error
593  error = ERROR_FAILURE;
594  }
595 
596  //Release exclusive access to the PUKCC accelerator
598 
599  //Return error code
600  return error;
601 }
602 
603 
604 /**
605  * @brief Test whether a number is probable prime
606  * @param[in] a Pointer to a multiple precision integer
607  * @return Error code
608  **/
609 
611 {
612  error_t error;
613  uint_t k;
614  size_t n;
615  uint8_t *pos;
616  PukccPrimeGenParams params = {0};
617 
618  //Get the length of the input integer, in bits
619  n = mpiGetBitLength(a);
620 
621  //Prime numbers of a size lower than 96 bits cannot be tested by this
622  //service
623  if(n < 96)
624  return ERROR_INVALID_LENGTH;
625 
626  //The number of repetitions controls the error probability
627  if(n >= 1300)
628  {
629  k = 2;
630  }
631  else if(n >= 850)
632  {
633  k = 3;
634  }
635  else if(n >= 650)
636  {
637  k = 4;
638  }
639  else if(n >= 550)
640  {
641  k = 5;
642  }
643  else if(n >= 450)
644  {
645  k = 6;
646  }
647  else if(n >= 400)
648  {
649  k = 7;
650  }
651  else if(n >= 350)
652  {
653  k = 8;
654  }
655  else if(n >= 300)
656  {
657  k = 9;
658  }
659  else if(n >= 250)
660  {
661  k = 12;
662  }
663  else if(n >= 200)
664  {
665  k = 15;
666  }
667  else if(n >= 150)
668  {
669  k = 18;
670  }
671  else
672  {
673  k = 27;
674  }
675 
676  //Get the length of the input integer, in bytes
677  n = mpiGetByteLength(a);
678  n = (n + 3U) & ~3U;
679 
680  //Acquire exclusive access to the PUKCC accelerator
682 
683  //Point to the crypto memory
684  pos = (uint8_t *) PUKCC_CRYPTO_RAM_BASE;
685 
686  //One additional word is used on the LSB side of the NBase parameter. As
687  //a consequence, the parameter nu1NBase must never be at the beginning of
688  //the crypto RAM, but at least at one word from the beginning
689  pukccWorkspace(&pos, 4);
690 
691  //Copy the number to test
692  params.n = pukccImportMpi(&pos, a, n + 4);
693  //Cns is used as a workspace
694  params.cns = pukccWorkspace(&pos, n + 12);
695  //Rnd is used as a workspace
696  params.rnd = pukccWorkspace(&pos, MAX(n + 16, 64));
697  //Precomp is used as a precomputation workspace
698  params.w = pukccWorkspace(&pos, MAX(3 * (n + 4), n + 72) + 8);
699  //Exp is used as a workspace
700  params.exp = pukccWorkspace(&pos, n + 4);
701 
702  //Unused parameter
703  params.r = 0;
704 
705  //Set PrimeGen service parameters
706  PUKCL(u2Option) = PUKCL_PRIMEGEN_TEST | PUKCL_EXPMOD_FASTRSA |
707  PUKCL_EXPMOD_WINDOWSIZE_1;
708  PUKCL_PrimeGen(u2NLength) = n;
709  PUKCL_PrimeGen(nu1NBase) = PUKCC_FAR_TO_NEAR(params.n);
710  PUKCL_PrimeGen(nu1CnsBase) = PUKCC_FAR_TO_NEAR(params.cns);
711  PUKCL_PrimeGen(nu1RndBase) = PUKCC_FAR_TO_NEAR(params.rnd);
712  PUKCL_PrimeGen(nu1PrecompBase) = PUKCC_FAR_TO_NEAR(params.w);
713  PUKCL_PrimeGen(nu1RBase) = PUKCC_FAR_TO_NEAR(params.r);
714  PUKCL_PrimeGen(nu1ExpBase) = PUKCC_FAR_TO_NEAR(params.exp);
715  PUKCL_PrimeGen(u1MillerRabinIterations) = k;
716  PUKCL_PrimeGen(u2MaxIncrement) = 1;
717 
718  //Perform probable prime testing
719  vPUKCL_Process(PrimeGen, pvPUKCLParam);
720 
721  //Check status code
722  switch(PUKCL(u2Status))
723  {
724  case PUKCL_NUMBER_IS_PRIME:
725  //The number is probably prime
726  error = NO_ERROR;
727  break;
728  case PUKCL_NUMBER_IS_NOT_PRIME:
729  //The number is not prime
730  error = ERROR_INVALID_VALUE;
731  break;
732  default:
733  //Report an error
734  error = ERROR_FAILURE;
735  break;
736  }
737 
738  //Release exclusive access to the PUKCC accelerator
740 
741  //Return error code
742  return error;
743 }
744 
745 #endif
746 #if (RSA_SUPPORT == ENABLED)
747 
748 /**
749  * @brief RSA decryption primitive
750  * @param[in] key RSA private key
751  * @param[in] c Ciphertext representative
752  * @param[out] m Message representative
753  * @return Error code
754  **/
755 
756 error_t rsadp(const RsaPrivateKey *key, const Mpi *c, Mpi *m)
757 {
758  error_t error;
759  size_t nLen;
760  size_t dLen;
761  size_t pLen;
762  size_t qLen;
763  size_t dpLen;
764  size_t dqLen;
765  size_t qinvLen;
766 
767  //Get the length of the private key
768  nLen = mpiGetByteLength(&key->n);
769  dLen = mpiGetByteLength(&key->d);
770  pLen = mpiGetByteLength(&key->p);
771  qLen = mpiGetByteLength(&key->q);
772  dpLen = mpiGetByteLength(&key->dp);
773  dqLen = mpiGetByteLength(&key->dq);
774  qinvLen = mpiGetByteLength(&key->qinv);
775 
776  //Sanity check
777  if(nLen == 0)
779 
780  //The ciphertext representative c shall be between 0 and n - 1
781  if(mpiCompInt(c, 0) < 0 || mpiComp(c, &key->n) >= 0)
782  return ERROR_OUT_OF_RANGE;
783 
784  //Use the Chinese remainder algorithm?
785  if(nLen > 0 && pLen > 0 && qLen > 0 && dpLen > 0 && dqLen > 0 && qinvLen > 0)
786  {
787  size_t cLen;
788  size_t modLen;
789  size_t expLen;
790  uint8_t *pos;
791  PukccCrtParams params = {0};
792 
793  //Get the length of the ciphertext, in bytes
794  cLen = mpiGetByteLength(c);
795 
796  //Get the length of the modulus, in bytes
797  modLen = MAX(pLen, qLen);
798  modLen = MAX(modLen, 12);
799  modLen = (modLen + 3U) & ~3U;
800 
801  //Get the length of the reduced exponents, in bytes
802  expLen = MAX(dpLen, dqLen);
803  expLen = (expLen + 3U) & ~3U;
804 
805  //Check the length of the ciphertext
806  if(cLen > (2 * modLen))
807  return ERROR_INVALID_LENGTH;
808 
809  //Acquire exclusive access to the PUKCC accelerator
811 
812  //Point to the crypto memory
813  pos = (uint8_t *) PUKCC_CRYPTO_RAM_BASE;
814 
815  //Copy primes
816  params.q = pukccImportMpi(&pos, &key->q, modLen + 4);
817  params.p = pukccImportMpi(&pos, &key->p, modLen + 4);
818 
819  //Copy input number
820  params.x = pukccImportMpi(&pos, c, 2 * modLen + 16);
821 
822  //The reduced exponents must be given with a supplemental word on the
823  //LSB side (low addresses). This word shall be set to zero
824  params.dq = pukccWorkspace(&pos, 4);
825  pukccImportMpi(&pos, &key->dq, expLen);
826  params.dp = pukccWorkspace(&pos, 4);
827  pukccImportMpi(&pos, &key->dp, expLen);
828 
829  //Copy R value
830  params.r = pukccImportMpi(&pos, &key->qinv, modLen + 4);
831  //Initialize workspace
832  pukccWorkspace(&pos, 3 * (modLen + 4) + MAX(64, 1 * (modLen + 4)) + 8);
833 
834  //Set CRT service parameters
835  PUKCL(u2Option) = PUKCL_EXPMOD_REGULARRSA | PUKCL_EXPMOD_WINDOWSIZE_1 |
836  PUKCL_EXPMOD_EXPINPUKCCRAM;
837  PUKCL_CRT(u2ModLength) = modLen;
838  PUKCL_CRT(nu1ModBase) = PUKCC_FAR_TO_NEAR(params.q);
839  PUKCL_CRT(nu1XBase) = PUKCC_FAR_TO_NEAR(params.x);
840  PUKCL_CRT(nu1PrecompBase) = PUKCC_FAR_TO_NEAR(params.r);
841  PUKCL_CRT(u2ExpLength) = expLen;
842  PUKCL_CRT(pfu1ExpBase) = params.dq;
843  PUKCL_CRT(u1Blinding) = 0;
844 
845  //Perform modular exponentiation (with CRT)
846  vPUKCL_Process(CRT, pvPUKCLParam);
847 
848  //Check status code
849  if(PUKCL(u2Status) == PUKCL_OK)
850  {
851  //Copy resulting integer
852  error = mpiImport(m, params.x, 2 * modLen, MPI_FORMAT_LITTLE_ENDIAN);
853  }
854  else
855  {
856  //Report an error
857  error = ERROR_FAILURE;
858  }
859 
860  //Release exclusive access to the PUKCC accelerator
862  }
863  else if(nLen > 0 && dLen > 0)
864  {
865  //Perform modular exponentiation (without CRT)
866  error = mpiExpMod(m, c, &key->d, &key->n);
867  }
868  else
869  {
870  //Invalid parameters
871  error = ERROR_INVALID_PARAMETER;
872  }
873 
874  //Return status code
875  return error;
876 }
877 
878 #endif
879 #if (EC_SUPPORT == ENABLED)
880 
881 /**
882  * @brief Check whether the affine point S is on the curve
883  * @param[in] curve Elliptic curve parameters
884  * @param[in] s Affine representation of the point
885  * @return TRUE if the affine point S is on the curve, else FALSE
886  **/
887 
888 bool_t ecIsPointAffine(const EcCurve *curve, const EcPoint *s)
889 {
890  bool_t valid;
891  size_t modLen;
892  uint8_t *pos;
893  PukccZpEcPointIsOnCurveParams params = {0};
894 
895  //Get the length of the modulus, in bytes
896  modLen = (curve->fieldSize + 7) /8;
897  modLen = (modLen + 3U) & ~3U;
898 
899  //Acquire exclusive access to the PUKCC accelerator
901 
902  //Point to the crypto memory
903  pos = (uint8_t *) PUKCC_CRYPTO_RAM_BASE;
904 
905  //Copy modulus
906  params.mod = pukccImportScalar(&pos, curve->p, modLen + 4);
907  //Initialize reduction constant
908  params.cns = pukccWorkspace(&pos, modLen + 12);
909  //Initialize workspace R
910  params.r = pukccWorkspace(&pos, 64);
911  //Initialize workspace X
912  params.x = pukccWorkspace(&pos, 2 * modLen + 8);
913 
914  //Set RedMod service parameters
915  PUKCL(u2Option) = PUKCL_REDMOD_SETUP;
916  PUKCL(Specific).CarryIn = 0;
917  PUKCL(Specific).Gf2n = 0;
918  PUKCL_RedMod(u2ModLength) = modLen;
919  PUKCL_RedMod(nu1ModBase) = PUKCC_FAR_TO_NEAR(params.mod);
920  PUKCL_RedMod(nu1CnsBase) = PUKCC_FAR_TO_NEAR(params.cns);
921  PUKCL_RedMod(nu1RBase) = PUKCC_FAR_TO_NEAR(params.r);
922  PUKCL_RedMod(nu1XBase) = PUKCC_FAR_TO_NEAR(params.x);
923 
924  //Perform modular reduction setup
925  vPUKCL_Process(RedMod, pvPUKCLParam);
926 
927  //Check status code
928  if(PUKCL(u2Status) == PUKCL_OK)
929  {
930  //Point to the crypto memory
931  pos = params.r;
932 
933  //Copy point coordinates
934  params.point.x = pukccImportScalar(&pos, s->x, modLen + 4);
935  params.point.y = pukccImportScalar(&pos, s->y, modLen + 4);
936  params.point.z = pukccWorkspace(&pos, modLen + 4);
937  params.point.z[0] = 1;
938 
939  //Copy curve parameter a
940  params.a = pukccImportScalar(&pos, curve->a, modLen + 4);
941  //Copy curve parameter b
942  params.b = pukccImportScalar(&pos, curve->b, modLen + 4);
943  //Initialize workspace
944  params.w = pukccWorkspace(&pos, 4 * modLen + 28);
945 
946  //Set ZpEcPointIsOnCurve service parameters
947  PUKCL_ZpEcPointIsOnCurve(u2ModLength) = modLen;
948  PUKCL_ZpEcPointIsOnCurve(nu1ModBase) = PUKCC_FAR_TO_NEAR(params.mod);
949  PUKCL_ZpEcPointIsOnCurve(nu1CnsBase) = PUKCC_FAR_TO_NEAR(params.cns);
950  PUKCL_ZpEcPointIsOnCurve(nu1PointBase) = PUKCC_FAR_TO_NEAR(params.point.x);
951  PUKCL_ZpEcPointIsOnCurve(nu1AParam) = PUKCC_FAR_TO_NEAR(params.a);
952  PUKCL_ZpEcPointIsOnCurve(nu1BParam) = PUKCC_FAR_TO_NEAR(params.b);
953  PUKCL_ZpEcPointIsOnCurve(nu1Workspace) = PUKCC_FAR_TO_NEAR(params.w);
954 
955  //Test whether the point is on the curve
956  vPUKCL_Process(ZpEcPointIsOnCurve, pvPUKCLParam);
957  }
958 
959  //Check status code
960  if(PUKCL(u2Status) == PUKCL_OK)
961  {
962  //The point S is on the elliptic curve
963  valid = TRUE;
964  }
965  else
966  {
967  //The point S is not on the elliptic curve
968  valid = FALSE;
969  }
970 
971  //Release exclusive access to the PUKCC accelerator
973 
974  //Return TRUE if the affine point S is on the curve, else FALSE
975  return valid;
976 }
977 
978 
979 /**
980  * @brief Recover affine representation
981  * @param[in] curve Elliptic curve parameters
982  * @param[out] r Affine representation of the point
983  * @param[in] s Projective representation of the point
984  * @return Error code
985  **/
986 
987 error_t ecAffinify(const EcCurve *curve, EcPoint3 *r, const EcPoint3 *s)
988 {
989  error_t error;
990  size_t modLen;
991  uint8_t *pos;
992  PukccZpEcConvProjToAffineParams params = {0};
993 
994  //Get the length of the modulus, in bytes
995  modLen = (curve->fieldSize + 7) / 8;
996  modLen = (modLen + 3U) & ~3U;
997 
998  //Acquire exclusive access to the PUKCC accelerator
1000 
1001  //Point to the crypto memory
1002  pos = (uint8_t *) PUKCC_CRYPTO_RAM_BASE;
1003 
1004  //Copy modulus
1005  params.mod = pukccImportScalar(&pos, curve->p, modLen + 4);
1006  //Initialize reduction constant
1007  params.cns = pukccWorkspace(&pos, modLen + 12);
1008  //Initialize workspace R
1009  params.r = pukccWorkspace(&pos, 64);
1010  //Initialize workspace X
1011  params.x = pukccWorkspace(&pos, 2 * modLen + 8);
1012 
1013  //Set RedMod service parameters
1014  PUKCL(u2Option) = PUKCL_REDMOD_SETUP;
1015  PUKCL(Specific).CarryIn = 0;
1016  PUKCL(Specific).Gf2n = 0;
1017  PUKCL_RedMod(u2ModLength) = modLen;
1018  PUKCL_RedMod(nu1ModBase) = PUKCC_FAR_TO_NEAR(params.mod);
1019  PUKCL_RedMod(nu1CnsBase) = PUKCC_FAR_TO_NEAR(params.cns);
1020  PUKCL_RedMod(nu1RBase) = PUKCC_FAR_TO_NEAR(params.r);
1021  PUKCL_RedMod(nu1XBase) = PUKCC_FAR_TO_NEAR(params.x);
1022 
1023  //Perform modular reduction setup
1024  vPUKCL_Process(RedMod, pvPUKCLParam);
1025 
1026  //Check status code
1027  if(PUKCL(u2Status) == PUKCL_OK)
1028  {
1029  //Point to the crypto memory
1030  pos = params.r;
1031 
1032  //Copy point coordinates
1033  params.point.x = pukccImportScalar(&pos, s->x, modLen + 4);
1034  params.point.y = pukccImportScalar(&pos, s->y, modLen + 4);
1035  params.point.z = pukccImportScalar(&pos, s->z, modLen + 4);
1036  //Initialize workspace
1037  params.w = pukccWorkspace(&pos, 4 * modLen + 48);
1038 
1039  //Set ZpEccConvAffineToProjective service parameters
1040  PUKCL_ZpEcConvProjToAffine(u2ModLength) = modLen;
1041  PUKCL_ZpEcConvProjToAffine(nu1ModBase) = PUKCC_FAR_TO_NEAR(params.mod);
1042  PUKCL_ZpEcConvProjToAffine(nu1CnsBase) = PUKCC_FAR_TO_NEAR(params.cns);
1043  PUKCL_ZpEcConvProjToAffine(nu1PointABase) = PUKCC_FAR_TO_NEAR(params.point.x);
1044  PUKCL_ZpEcConvProjToAffine(nu1Workspace) = PUKCC_FAR_TO_NEAR(params.w);
1045 
1046  //Convert point coordinates from projective to affine representation
1047  vPUKCL_Process(ZpEcConvProjToAffine, pvPUKCLParam);
1048  }
1049 
1050  //Check status code
1051  if(PUKCL(u2Status) == PUKCL_OK)
1052  {
1053  //Copy the x-coordinate of the result
1054  error = ecScalarImport(r->x, EC_MAX_MODULUS_SIZE, params.point.x, modLen,
1056 
1057  //Check error code
1058  if(!error)
1059  {
1060  //Copy the y-coordinate of the result
1061  error = ecScalarImport(r->y, EC_MAX_MODULUS_SIZE, params.point.y, modLen,
1063  }
1064 
1065  //Check error code
1066  if(!error)
1067  {
1068  //Copy the z-coordinate of the result
1069  error = ecScalarImport(r->z, EC_MAX_MODULUS_SIZE, params.point.z, modLen,
1071  }
1072  }
1073  else
1074  {
1075  //Report an error
1076  error = ERROR_FAILURE;
1077  }
1078 
1079  //Release exclusive access to the PUKCC accelerator
1081 
1082  //Return error code
1083  return error;
1084 }
1085 
1086 
1087 /**
1088  * @brief Scalar multiplication (fast calculation)
1089  * @param[in] curve Elliptic curve parameters
1090  * @param[out] r Resulting point R = d.S
1091  * @param[in] d An integer d such as 0 <= d < p
1092  * @param[in] s EC point
1093  * @return Error code
1094  **/
1095 
1096 error_t ecMulFast(const EcCurve *curve, EcPoint3 *r, const uint32_t *d,
1097  const EcPoint3 *s)
1098 {
1099  //Compute R = d.S
1100  return ecMulRegular(curve, r, d, s);
1101 }
1102 
1103 
1104 /**
1105  * @brief Scalar multiplication (regular calculation)
1106  * @param[in] curve Elliptic curve parameters
1107  * @param[out] r Resulting point R = d.S
1108  * @param[in] d An integer d such as 0 <= d < q
1109  * @param[in] s EC point
1110  * @return Error code
1111  **/
1112 
1113 error_t ecMulRegular(const EcCurve *curve, EcPoint3 *r, const uint32_t *d,
1114  const EcPoint3 *s)
1115 {
1116  error_t error;
1117  size_t modLen;
1118  size_t orderLen;
1119  uint8_t *pos;
1120  PukccZpEccMulParams params = {0};
1121 
1122  //Get the length of the modulus, in bytes
1123  modLen = (curve->fieldSize + 7) / 8;
1124  modLen = (modLen + 3U) & ~3U;
1125 
1126  //Get the length of the order, in bytes
1127  orderLen = (curve->orderSize + 7) / 8;
1128  orderLen = (orderLen + 3U) & ~3U;
1129 
1130  //Acquire exclusive access to the PUKCC accelerator
1132 
1133  //Point to the crypto memory
1134  pos = (uint8_t *) PUKCC_CRYPTO_RAM_BASE;
1135 
1136  //Copy modulus
1137  params.mod = pukccImportScalar(&pos, curve->p, modLen + 4);
1138  //Initialize reduction constant
1139  params.cns = pukccWorkspace(&pos, modLen + 12);
1140  //Initialize workspace R
1141  params.r = pukccWorkspace(&pos, 64);
1142  //Initialize workspace X
1143  params.x = pukccWorkspace(&pos, 2 * modLen + 8);
1144 
1145  //Set RedMod service parameters
1146  PUKCL(u2Option) = PUKCL_REDMOD_SETUP;
1147  PUKCL(Specific).CarryIn = 0;
1148  PUKCL(Specific).Gf2n = 0;
1149  PUKCL_RedMod(u2ModLength) = modLen;
1150  PUKCL_RedMod(nu1ModBase) = PUKCC_FAR_TO_NEAR(params.mod);
1151  PUKCL_RedMod(nu1CnsBase) = PUKCC_FAR_TO_NEAR(params.cns);
1152  PUKCL_RedMod(nu1RBase) = PUKCC_FAR_TO_NEAR(params.r);
1153  PUKCL_RedMod(nu1XBase) = PUKCC_FAR_TO_NEAR(params.x);
1154 
1155  //Perform modular reduction setup
1156  vPUKCL_Process(RedMod, pvPUKCLParam);
1157 
1158  //Check status code
1159  if(PUKCL(u2Status) == PUKCL_OK)
1160  {
1161  //Point to the crypto memory
1162  pos = params.r;
1163 
1164  //Copy scalar number
1165  params.k = pukccImportScalar(&pos, d, orderLen + 4);
1166 
1167  //Copy point coordinates
1168  params.point.x = pukccImportScalar(&pos, s->x, modLen + 4);
1169  params.point.y = pukccImportScalar(&pos, s->y, modLen + 4);
1170  params.point.z = pukccWorkspace(&pos, modLen + 4);
1171  params.point.z[0] = 1;
1172 
1173  //Copy curve parameter a
1174  params.a = pukccImportScalar(&pos, curve->a, modLen + 4);
1175  //Initialize workspace
1176  params.w = pukccWorkspace(&pos, 8 * modLen + 44);
1177 
1178  //Set ZpEccMulFast service parameters
1179  PUKCL_ZpEccMul(u2ModLength) = modLen;
1180  PUKCL_ZpEccMul(nu1ModBase) = PUKCC_FAR_TO_NEAR(params.mod);
1181  PUKCL_ZpEccMul(nu1CnsBase) = PUKCC_FAR_TO_NEAR(params.cns);
1182  PUKCL_ZpEccMul(u2KLength) = orderLen;
1183  PUKCL_ZpEccMul(nu1KBase) = PUKCC_FAR_TO_NEAR(params.k);
1184  PUKCL_ZpEccMul(nu1PointBase) = PUKCC_FAR_TO_NEAR(params.point.x);
1185  PUKCL_ZpEccMul(nu1ABase) = PUKCC_FAR_TO_NEAR(params.a);
1186  PUKCL_ZpEccMul(nu1Workspace) = PUKCC_FAR_TO_NEAR(params.w);
1187 
1188  //Perform scalar multiplication over GF(p)
1189  vPUKCL_Process(ZpEccMulFast, pvPUKCLParam);
1190  }
1191 
1192  //Check status code
1193  if(PUKCL(u2Status) == PUKCL_OK)
1194  {
1195  //Copy the x-coordinate of the result
1196  error = ecScalarImport(r->x, EC_MAX_MODULUS_SIZE, params.point.x, modLen,
1198 
1199  //Check error code
1200  if(!error)
1201  {
1202  //Copy the y-coordinate of the result
1203  error = ecScalarImport(r->y, EC_MAX_MODULUS_SIZE, params.point.y, modLen,
1205  }
1206 
1207  //Check error code
1208  if(!error)
1209  {
1210  //Copy the z-coordinate of the result
1211  error = ecScalarImport(r->z, EC_MAX_MODULUS_SIZE, params.point.z, modLen,
1213  }
1214  }
1215  else
1216  {
1217  //Report an error
1218  error = ERROR_FAILURE;
1219  }
1220 
1221  //Release exclusive access to the PUKCC accelerator
1223 
1224  //Return error code
1225  return error;
1226 }
1227 
1228 #endif
1229 #if (ECDSA_SUPPORT == ENABLED)
1230 
1231 /**
1232  * @brief ECDSA signature generation
1233  * @param[in] prngAlgo PRNG algorithm
1234  * @param[in] prngContext Pointer to the PRNG context
1235  * @param[in] privateKey Signer's EC private key
1236  * @param[in] digest Digest of the message to be signed
1237  * @param[in] digestLen Length in octets of the digest
1238  * @param[out] signature (R, S) integer pair
1239  * @return Error code
1240  **/
1241 
1242 error_t ecdsaGenerateSignature(const PrngAlgo *prngAlgo, void *prngContext,
1243  const EcPrivateKey *privateKey, const uint8_t *digest, size_t digestLen,
1244  EcdsaSignature *signature)
1245 {
1246  error_t error;
1247  size_t modLen;
1248  size_t orderLen;
1249  uint8_t *pos;
1250  uint32_t k[EC_MAX_ORDER_SIZE];
1251  const EcCurve *curve;
1252  PukccZpEcDsaGenerateParams params = {0};
1253 
1254  //Check parameters
1255  if(privateKey == NULL || digest == NULL || signature == NULL)
1256  return ERROR_INVALID_PARAMETER;
1257 
1258  //Invalid elliptic curve?
1259  if(privateKey->curve == NULL)
1261 
1262  //Get elliptic curve parameters
1263  curve = privateKey->curve;
1264 
1265  //Get the length of the modulus, in bytes
1266  modLen = (curve->fieldSize + 7) / 8;
1267  modLen = (modLen + 3U) & ~3U;
1268 
1269  //Get the length of the order, in bytes
1270  orderLen = (curve->orderSize + 7) / 8;
1271  orderLen = (orderLen + 3U) & ~3U;
1272 
1273  //Keep the leftmost bits of the hash value
1274  digestLen = MIN(digestLen, (curve->orderSize + 7) / 8);
1275 
1276  //Generate a random number k such as 0 < k < q - 1
1277  error = ecScalarRand(curve, k, prngAlgo, prngContext);
1278 
1279  //Acquire exclusive access to the PUKCC accelerator
1281 
1282  //Check error code
1283  if(!error)
1284  {
1285  //Point to the crypto memory
1286  pos = (uint8_t *) PUKCC_CRYPTO_RAM_BASE;
1287 
1288  //Copy modulus
1289  params.mod = pukccImportScalar(&pos, curve->p, modLen + 4);
1290  //Initialize reduction constant
1291  params.cns = pukccWorkspace(&pos, orderLen + 12);
1292  //Initialize workspace R
1293  params.r = pukccWorkspace(&pos, 64);
1294  //Initialize workspace X
1295  params.x = pukccWorkspace(&pos, 2 * modLen + 8);
1296 
1297  //Set RedMod service parameters
1298  PUKCL(u2Option) = PUKCL_REDMOD_SETUP;
1299  PUKCL(Specific).CarryIn = 0;
1300  PUKCL(Specific).Gf2n = 0;
1301  PUKCL_RedMod(u2ModLength) = modLen;
1302  PUKCL_RedMod(nu1ModBase) = PUKCC_FAR_TO_NEAR(params.mod);
1303  PUKCL_RedMod(nu1CnsBase) = PUKCC_FAR_TO_NEAR(params.cns);
1304  PUKCL_RedMod(nu1RBase) = PUKCC_FAR_TO_NEAR(params.r);
1305  PUKCL_RedMod(nu1XBase) = PUKCC_FAR_TO_NEAR(params.x);
1306 
1307  //Perform modular reduction setup
1308  vPUKCL_Process(RedMod, pvPUKCLParam);
1309 
1310  //Check status code
1311  if(PUKCL(u2Status) != PUKCL_OK)
1312  error = ERROR_FAILURE;
1313  }
1314 
1315  //Check error code
1316  if(!error)
1317  {
1318  //Point to the crypto memory
1319  pos = params.r;
1320 
1321  //Copy base point coordinates
1322  params.basePoint.x = pukccImportScalar(&pos, curve->g.x, modLen + 4);
1323  params.basePoint.y = pukccImportScalar(&pos, curve->g.y, modLen + 4);
1324  params.basePoint.z = pukccImportScalar(&pos, curve->g.z, modLen + 4);
1325 
1326  //Copy base point order
1327  params.order = pukccImportScalar(&pos, curve->q, orderLen + 4);
1328  //Copy curve parameter a
1329  params.a = pukccImportScalar(&pos, curve->a, modLen + 4);
1330  //Copy private key
1331  params.privateKey = pukccImportScalar(&pos, privateKey->d, orderLen + 4);
1332  //Copy random scalar
1333  params.k = pukccImportScalar(&pos, k, orderLen + 4);
1334  //Copy digest
1335  params.h = pukccImportArray(&pos, digest, digestLen, orderLen + 4);
1336  //Initialize workspace
1337  params.w = pukccWorkspace(&pos, 8 * modLen + 44);
1338 
1339  //Set ZpEcDsaGenerateFast service parameters
1340  PUKCL_ZpEcDsaGenerate(u2ModLength) = modLen;
1341  PUKCL_ZpEcDsaGenerate(nu1ModBase) = PUKCC_FAR_TO_NEAR(params.mod);
1342  PUKCL_ZpEcDsaGenerate(nu1CnsBase) = PUKCC_FAR_TO_NEAR(params.cns);
1343  PUKCL_ZpEcDsaGenerate(nu1PointABase) = PUKCC_FAR_TO_NEAR(params.basePoint.x);
1344  PUKCL_ZpEcDsaGenerate(nu1OrderPointBase) = PUKCC_FAR_TO_NEAR(params.order);
1345  PUKCL_ZpEcDsaGenerate(nu1ABase) = PUKCC_FAR_TO_NEAR(params.a);
1346  PUKCL_ZpEcDsaGenerate(nu1PrivateKey) = PUKCC_FAR_TO_NEAR(params.privateKey);
1347  PUKCL_ZpEcDsaGenerate(u2ScalarLength) = orderLen;
1348  PUKCL_ZpEcDsaGenerate(nu1ScalarNumber) = PUKCC_FAR_TO_NEAR(params.k);
1349  PUKCL_ZpEcDsaGenerate(nu1HashBase) = PUKCC_FAR_TO_NEAR(params.h);
1350  PUKCL_ZpEcDsaGenerate(nu1Workspace) = PUKCC_FAR_TO_NEAR(params.w);
1351 
1352  //Perform ECDSA signature generation
1353  vPUKCL_Process(ZpEcDsaGenerateFast, pvPUKCLParam);
1354 
1355  //Check status code
1356  if(PUKCL(u2Status) != PUKCL_OK)
1357  error = ERROR_FAILURE;
1358  }
1359 
1360  //Check error code
1361  if(!error)
1362  {
1363  //Save elliptic curve parameters
1364  signature->curve = curve;
1365 
1366  //Copy the first part of the ECDSA signature
1367  error = ecScalarImport(signature->r, EC_MAX_ORDER_SIZE,
1368  params.basePoint.x, orderLen, EC_SCALAR_FORMAT_LITTLE_ENDIAN);
1369  }
1370 
1371  //Check error code
1372  if(!error)
1373  {
1374  //Copy the second part of the ECDSA signature
1375  error = ecScalarImport(signature->s, EC_MAX_ORDER_SIZE,
1376  params.basePoint.x + orderLen + 4, orderLen,
1378  }
1379 
1380  //Release exclusive access to the PUKCC accelerator
1382 
1383  //Return error code
1384  return error;
1385 }
1386 
1387 
1388 /**
1389  * @brief ECDSA signature verification
1390  * @param[in] publicKey Signer's EC public key
1391  * @param[in] digest Digest of the message whose signature is to be verified
1392  * @param[in] digestLen Length in octets of the digest
1393  * @param[in] signature (R, S) integer pair
1394  * @return Error code
1395  **/
1396 
1398  const uint8_t *digest, size_t digestLen, const EcdsaSignature *signature)
1399 {
1400  error_t error;
1401  size_t modLen;
1402  size_t orderLen;
1403  uint8_t *pos;
1404  const EcCurve *curve;
1405  PukccZpEcDsaVerifyParams params = {0};
1406 
1407  //Check parameters
1408  if(publicKey == NULL || digest == NULL || signature == NULL)
1409  return ERROR_INVALID_PARAMETER;
1410 
1411  //Invalid elliptic curve?
1412  if(publicKey->curve == NULL)
1414 
1415  //Verify that the public key is on the curve
1416  if(!ecIsPointAffine(publicKey->curve, &publicKey->q))
1417  {
1418  return ERROR_INVALID_SIGNATURE;
1419  }
1420 
1421  //The verifier shall check that 0 < r < q
1422  if(ecScalarCompInt(signature->r, 0, EC_MAX_ORDER_SIZE) <= 0 ||
1423  ecScalarComp(signature->r, publicKey->curve->q, EC_MAX_ORDER_SIZE) >= 0)
1424  {
1425  //If the condition is violated, the signature shall be rejected as invalid
1426  return ERROR_INVALID_SIGNATURE;
1427  }
1428 
1429  //The verifier shall check that 0 < s < q
1430  if(ecScalarCompInt(signature->s, 0, EC_MAX_ORDER_SIZE) <= 0 ||
1431  ecScalarComp(signature->s, publicKey->curve->q, EC_MAX_ORDER_SIZE) >= 0)
1432  {
1433  //If the condition is violated, the signature shall be rejected as invalid
1434  return ERROR_INVALID_SIGNATURE;
1435  }
1436 
1437  //Get elliptic curve parameters
1438  curve = publicKey->curve;
1439 
1440  //Get the length of the modulus, in bytes
1441  modLen = (curve->fieldSize + 7) / 8;
1442  modLen = (modLen + 3U) & ~3U;
1443 
1444  //Get the length of the order, in bytes
1445  orderLen = (curve->orderSize + 7) / 8;
1446  orderLen = (orderLen + 3U) & ~3U;
1447 
1448  //Keep the leftmost bits of the hash value
1449  digestLen = MIN(digestLen, (curve->orderSize + 7) / 8);
1450 
1451  //Acquire exclusive access to the PUKCC accelerator
1453 
1454  //Point to the crypto memory
1455  pos = (uint8_t *) PUKCC_CRYPTO_RAM_BASE;
1456 
1457  //Copy modulus
1458  params.mod = pukccImportScalar(&pos, curve->p, modLen + 4);
1459  //Initialize reduction constant
1460  params.cns = pukccWorkspace(&pos, orderLen + 12);
1461  //Initialize workspace R
1462  params.r = pukccWorkspace(&pos, 64);
1463  //Initialize workspace X
1464  params.x = pukccWorkspace(&pos, 2 * modLen + 8);
1465 
1466  //Set RedMod service parameters
1467  PUKCL(u2Option) = PUKCL_REDMOD_SETUP;
1468  PUKCL(Specific).CarryIn = 0;
1469  PUKCL(Specific).Gf2n = 0;
1470  PUKCL_RedMod(u2ModLength) = modLen;
1471  PUKCL_RedMod(nu1ModBase) = PUKCC_FAR_TO_NEAR(params.mod);
1472  PUKCL_RedMod(nu1CnsBase) = PUKCC_FAR_TO_NEAR(params.cns);
1473  PUKCL_RedMod(nu1RBase) = PUKCC_FAR_TO_NEAR(params.r);
1474  PUKCL_RedMod(nu1XBase) = PUKCC_FAR_TO_NEAR(params.x);
1475 
1476  //Perform modular reduction setup
1477  vPUKCL_Process(RedMod, pvPUKCLParam);
1478 
1479  //Check status code
1480  if(PUKCL(u2Status) == PUKCL_OK)
1481  {
1482  //Point to the crypto memory
1483  pos = params.r;
1484 
1485  //Copy base point coordinates
1486  params.basePoint.x = pukccImportScalar(&pos, curve->g.x, modLen + 4);
1487  params.basePoint.y = pukccImportScalar(&pos, curve->g.y, modLen + 4);
1488  params.basePoint.z = pukccImportScalar(&pos, curve->g.z, modLen + 4);
1489 
1490  //Copy base point order
1491  params.order = pukccImportScalar(&pos, curve->q, orderLen + 4);
1492  //Copy curve parameter a
1493  params.a = pukccImportScalar(&pos, curve->a, modLen + 4);
1494 
1495  //Copy public key
1496  params.publicKey.x = pukccImportScalar(&pos, publicKey->q.x, modLen + 4);
1497  params.publicKey.y = pukccImportScalar(&pos, publicKey->q.y, modLen + 4);
1498  params.publicKey.z = pukccWorkspace(&pos, modLen + 4);
1499  params.publicKey.z[0] = 1;
1500 
1501  //Copy digest
1502  params.h = pukccImportArray(&pos, digest, digestLen, orderLen + 4);
1503 
1504  //Copy signature
1505  params.r = pukccImportScalar(&pos, signature->r, orderLen + 4);
1506  params.s = pukccImportScalar(&pos, signature->s, orderLen + 4);
1507 
1508  //Initialize workspace
1509  params.w = pukccWorkspace(&pos, 8 * modLen + 44);
1510 
1511  //Set ZpEcDsaVerifyFast service parameters
1512  PUKCL(u2Option) = 0;
1513  PUKCL_ZpEcDsaVerify(u2ModLength) = modLen;
1514  PUKCL_ZpEcDsaVerify(nu1ModBase) = PUKCC_FAR_TO_NEAR(params.mod);
1515  PUKCL_ZpEcDsaVerify(nu1CnsBase) = PUKCC_FAR_TO_NEAR(params.cns);
1516  PUKCL_ZpEcDsaVerify(nu1PointABase) = PUKCC_FAR_TO_NEAR(params.basePoint.x);
1517  PUKCL_ZpEcDsaVerify(nu1OrderPointBase) = PUKCC_FAR_TO_NEAR(params.order);
1518  PUKCL_ZpEcDsaVerify(nu1ABase) = PUKCC_FAR_TO_NEAR(params.a);
1519  PUKCL_ZpEcDsaVerify(nu1PointPublicKeyGen) = PUKCC_FAR_TO_NEAR(params.publicKey.x);
1520  PUKCL_ZpEcDsaVerify(u2ScalarLength) = orderLen;
1521  PUKCL_ZpEcDsaVerify(nu1HashBase) = PUKCC_FAR_TO_NEAR(params.h);
1522  PUKCL_ZpEcDsaVerify(nu1PointSignature) = PUKCC_FAR_TO_NEAR(params.r);
1523  PUKCL_ZpEcDsaVerify(nu1Workspace) = PUKCC_FAR_TO_NEAR(params.w);
1524 
1525  //Perform ECDSA signature verification
1526  vPUKCL_Process(ZpEcDsaVerifyFast, pvPUKCLParam);
1527  }
1528 
1529  //Check status code
1530  if(PUKCL(u2Status) == PUKCL_OK)
1531  {
1532  //The ECDSA signature is valid
1533  error = NO_ERROR;
1534  }
1535  else if(PUKCL(u2Status) == PUKCL_WRONG_SIGNATURE)
1536  {
1537  //The ECDSA signature is not valid
1538  error = ERROR_INVALID_SIGNATURE;
1539  }
1540  else
1541  {
1542  //Report an error
1543  error = ERROR_FAILURE;
1544  }
1545 
1546  //Release exclusive access to the PUKCC accelerator
1548 
1549  //Return status code
1550  return error;
1551 }
1552 
1553 #endif
1554 #endif
error_t ecScalarImport(uint32_t *r, uint_t n, const uint8_t *input, size_t length, EcScalarFormat format)
Octet string to integer conversion.
Definition: ec_misc.c:54
error_t pukccInit(void)
Initialize PUKCC module.
ECDSA signature.
Definition: ecdsa.h:63
ZpEccMul service parameters.
OsMutex same54CryptoMutex
Definition: same54_crypto.c:45
ZpEcPointIsOnCurve service parameters.
int bool_t
Definition: compiler_port.h:61
uint8_t b
Definition: nbns_common.h:104
@ ERROR_OUT_OF_RANGE
Definition: error.h:138
Mpi p
First factor.
Definition: rsa.h:72
uint8_t a
Definition: ndp.h:411
SAME54 public-key hardware accelerator (PUKCC)
error_t ecScalarExport(const uint32_t *a, uint_t n, uint8_t *output, size_t length, EcScalarFormat format)
Integer to octet string conversion.
Definition: ec_misc.c:150
#define PUKCC_CRYPTO_RAM_BASE
Arbitrary precision integer.
Definition: mpi.h:102
#define PrngAlgo
Definition: crypto.h:973
PrimeGen service parameters.
ECDSA (Elliptic Curve Digital Signature Algorithm)
uint8_t p
Definition: ndp.h:300
const EcCurve * curve
Elliptic curve parameters.
Definition: ecdsa.h:64
const EcCurve * curve
Elliptic curve parameters.
Definition: ec.h:433
#define TRUE
Definition: os_port.h:50
#define EC_MAX_ORDER_SIZE
Definition: ec.h:315
PPUKCL_PARAM pvPUKCLParam
Mpi n
Modulus.
Definition: rsa.h:69
error_t ecMulFast(const EcCurve *curve, EcPoint3 *r, const uint32_t *d, const EcPoint3 *s)
Scalar multiplication (fast calculation)
error_t rsadp(const RsaPrivateKey *key, const Mpi *c, Mpi *m)
RSA decryption primitive.
Fmult service parameters.
uint32_t y[EC_MAX_MODULUS_SIZE]
y-coordinate
Definition: ec.h:400
ExpMod service parameters.
#define PUKCC_FAR_TO_NEAR(p)
Mpi d
Private exponent.
Definition: rsa.h:71
uint8_t r
Definition: ndp.h:346
@ ERROR_INVALID_ELLIPTIC_CURVE
Definition: error.h:134
#define FALSE
Definition: os_port.h:46
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
@ MPI_FORMAT_LITTLE_ENDIAN
Definition: mpi.h:92
error_t
Error codes.
Definition: error.h:43
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
error_t ecAffinify(const EcCurve *curve, EcPoint3 *r, const EcPoint3 *s)
Recover affine representation.
error_t ecdsaVerifySignature(const EcPublicKey *publicKey, const uint8_t *digest, size_t digestLen, const EcdsaSignature *signature)
ECDSA signature verification.
Mpi q
Second factor.
Definition: rsa.h:73
Helper routines for ECC.
ZpEcConvProjToAffine service parameters.
error_t mpiImport(Mpi *r, const uint8_t *input, size_t length, MpiFormat format)
Octet string to integer conversion.
Definition: mpi.c:712
ZpEcDsaVerify service parameters.
uint32_t r[EC_MAX_ORDER_SIZE]
Integer R.
Definition: ecdsa.h:65
MPI (Multiple Precision Integer Arithmetic)
@ ERROR_INVALID_LENGTH
Definition: error.h:111
@ EC_SCALAR_FORMAT_LITTLE_ENDIAN
Definition: ec_misc.h:50
General definitions for cryptographic algorithms.
RSA public-key cryptography standard.
EC private key.
Definition: ec.h:432
error_t mpiExport(const Mpi *a, uint8_t *output, size_t length, MpiFormat format)
Integer to octet string conversion.
Definition: mpi.c:809
EC point (affine coordinates)
Definition: ec.h:398
#define MIN(a, b)
Definition: os_port.h:63
error_t mpiCheckProbablePrime(const Mpi *a)
Test whether a number is probable prime.
RedMod service parameters.
uint_t mpiGetBitLength(const Mpi *a)
Get the actual length in bits.
Definition: mpi.c:254
Mpi qinv
CRT coefficient.
Definition: rsa.h:76
uint8_t * pukccImportArray(uint8_t **dest, const uint8_t *src, size_t srcLen, size_t totalLen)
Import byte array.
Mpi dq
Second factor's CRT exponent.
Definition: rsa.h:75
error_t mpiMul(Mpi *r, const Mpi *a, const Mpi *b)
Multiple precision multiplication.
EC public key.
Definition: ec.h:421
#define MAX(a, b)
Definition: os_port.h:67
GCD service parameters.
CRT service parameters.
@ ERROR_INVALID_VALUE
Definition: error.h:116
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 * pukccImportScalar(uint8_t **dest, const uint32_t *src, size_t totalLen)
Import scalar.
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.
EC point (projective coordinates)
Definition: ec.h:409
void osReleaseMutex(OsMutex *mutex)
Release ownership of the specified mutex object.
error_t ecMulRegular(const EcCurve *curve, EcPoint3 *r, const uint32_t *d, const EcPoint3 *s)
Scalar multiplication (regular calculation)
EcPoint q
Public key.
Definition: ec.h:423
ZpEcDsaGenerate service parameters.
uint32_t s[EC_MAX_ORDER_SIZE]
Integer S.
Definition: ecdsa.h:66
error_t ecScalarRand(const EcCurve *curve, uint32_t *r, const PrngAlgo *prngAlgo, void *prngContext)
Generate a random value.
Definition: ec_misc.c:603
uint8_t s
Definition: igmp_common.h:234
PUKCL_PARAM PUKCLParam
SAME54 hardware cryptographic accelerator.
#define EcCurve
Definition: ec.h:346
error_t mpiInvMod(Mpi *r, const Mpi *a, const Mpi *p)
Modular inverse.
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
error_t mpiExpMod(Mpi *r, const Mpi *a, const Mpi *e, const Mpi *p)
Modular exponentiation.
uint8_t * pukccWorkspace(uint8_t **dest, size_t totalLen)
Initialize workspace area.
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
#define osMemset(p, value, length)
Definition: os_port.h:138
ECC (Elliptic Curve Cryptography)
bool_t ecIsPointAffine(const EcCurve *curve, const EcPoint *s)
Check whether the affine point S is on the curve.
@ ERROR_INVALID_SIGNATURE
Definition: error.h:228
error_t mpiMod2(Mpi *r, const Mpi *a, const Mpi *p)
Modulo operation.
const EcCurve * curve
Elliptic curve parameters.
Definition: ec.h:422
#define EC_MAX_MODULUS_SIZE
Definition: ec.h:284
@ NO_ERROR
Success.
Definition: error.h:44
uint8_t c
Definition: ndp.h:514
uint8_t * pukccImportMpi(uint8_t **dest, const Mpi *src, size_t totalLen)
Import multiple-precision integer.
Debugging facilities.
error_t ecdsaGenerateSignature(const PrngAlgo *prngAlgo, void *prngContext, const EcPrivateKey *privateKey, const uint8_t *digest, size_t digestLen, EcdsaSignature *signature)
ECDSA signature generation.
uint_t mpiGetByteLength(const Mpi *a)
Get the actual length in bytes.
Definition: mpi.c:215