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