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