Contiki-NG
Loading...
Searching...
No Matches
cc2538-ecc.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2021, Uppsala universitet.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holder nor the names of its
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28 * OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31/**
32 * \addtogroup cc2538-pka
33 * @{
34 *
35 * \file
36 * Implementation of PKA-accelerated ECDH and ECDSA.
37 * \author
38 * Konrad Krentz <konrad.krentz@gmail.com>
39 */
40
41#include "lib/ecc.h"
42#include "lib/csprng.h"
43#include "dev/pka.h"
44#include <stdbool.h>
45
46/* Log configuration */
47#include "sys/log.h"
48#define LOG_MODULE "ECC"
49#define LOG_LEVEL LOG_LEVEL_NONE
50
51/* maximum sizes */
52#define MAX_ELEMENT_WORDS (8)
53#define MAX_ELEMENT_BYTES (MAX_ELEMENT_WORDS * sizeof(uint32_t))
54#define MAX_REMAINDER_WORDS \
55 PKA_REMAINDER_WORDS(MAX_ELEMENT_WORDS)
56#define MAX_COORDINATE_WORDS \
57 PKA_COORDINATE_WORDS(MAX_ELEMENT_WORDS)
58#define MAX_POINT_WORDS \
59 PKA_POINT_WORDS(MAX_ELEMENT_WORDS)
60#define SCRATCHPAD_WORDS \
61 MAX(PKA_MULTIPLY_SCRATCHPAD_WORDS(MAX_ELEMENT_WORDS, MAX_ELEMENT_WORDS), \
62 MAX(PKA_ADD_SCRATCHPAD_WORDS(MAX_ELEMENT_WORDS, MAX_ELEMENT_WORDS), \
63 MAX(PKA_SUBTRACT_SCRATCHPAD_WORDS(MAX_ELEMENT_WORDS, MAX_ELEMENT_WORDS), \
64 MAX(PKA_ECC_ADD_SCRATCHPAD_WORDS(MAX_ELEMENT_WORDS), \
65 MAX(PKA_ECC_MUL_SCRATCHPAD_WORDS(MAX_ELEMENT_WORDS), \
66 PKA_MOD_INV_SCRATCHPAD_WORDS(MAX_ELEMENT_WORDS, MAX_ELEMENT_WORDS))))))
67
68/* useful elements */
69static const uint32_t element_null[MAX_ELEMENT_WORDS];
70static const uint32_t element_one[MAX_ELEMENT_WORDS] = { 1 };
71
72/* offsets into PKA RAM */
73static const uintptr_t element_null_offset = 0;
74static const uintptr_t element_one_offset =
75 PKA_NEXT_OFFSET(element_null_offset, MAX_ELEMENT_WORDS);
76static const uintptr_t curve_g_offset =
77 PKA_NEXT_OFFSET(element_one_offset, MAX_ELEMENT_WORDS);
78static const uintptr_t curve_pab_offset =
79 PKA_NEXT_OFFSET(curve_g_offset, MAX_POINT_WORDS);
80static const uintptr_t curve_n_offset =
81 PKA_NEXT_OFFSET(curve_pab_offset, 3 * MAX_COORDINATE_WORDS);
82static const uintptr_t curve_a_offset =
83 PKA_NEXT_OFFSET(curve_n_offset, MAX_ELEMENT_WORDS);
84static const uintptr_t curve_b_offset =
85 PKA_NEXT_OFFSET(curve_a_offset, MAX_ELEMENT_WORDS);
86static const uintptr_t scratchpad_offset =
87 PKA_NEXT_OFFSET(curve_b_offset, MAX_ELEMENT_WORDS);
88static const uintptr_t variables_offset =
89 PKA_NEXT_OFFSET(scratchpad_offset, SCRATCHPAD_WORDS);
90static const uintptr_t curve_prime_offset = curve_pab_offset;
91
92static struct pt main_protothread;
93static struct pt helper_protothread;
94static const ecc_curve_t *curve;
95static process_mutex_t mutex;
96
97/*---------------------------------------------------------------------------*/
98/**
99 * \brief Tells if a bit in a little-endian element is set.
100 * \param element Little-endian element.
101 * \param bit Index of the bit; the least significant bit has index 0.
102 * \return True if the bit is set.
103 */
104static bool
105test_bit(const uint32_t *element, size_t bit)
106{
107 return element[bit >> 5] & ((uint32_t)1 << (bit & 0x1F));
108}
109/*---------------------------------------------------------------------------*/
110static void
111element_to_pka_ram(const uint8_t *bytes, uintptr_t offset)
112{
113 pka_big_endian_to_pka_ram(bytes, curve->bytes, offset);
114}
115/*---------------------------------------------------------------------------*/
116static void
117element_from_pka_ram(uint8_t *bytes, uintptr_t offset)
118{
119 pka_big_endian_from_pka_ram(bytes, curve->words, offset);
120}
121/*---------------------------------------------------------------------------*/
122static void
123point_to_pka_ram(const uint8_t *bytes, uintptr_t offset)
124{
125 element_to_pka_ram(bytes, offset);
126 element_to_pka_ram(bytes + curve->bytes,
127 offset + PKA_COORDINATE_WORDS(curve->words));
128}
129/*---------------------------------------------------------------------------*/
130static void
131point_from_pka_ram(uint8_t *bytes, uintptr_t offset)
132{
133 element_from_pka_ram(bytes, offset);
134 element_from_pka_ram(bytes + curve->bytes,
135 offset + PKA_COORDINATE_WORDS(curve->words));
136}
137/*---------------------------------------------------------------------------*/
138static
139PT_THREAD(compare_a_and_b(uintptr_t a_offset,
140 uintptr_t b_offset,
141 int *const result))
142{
143 PT_BEGIN(&helper_protothread);
144
145 REG(PKA_APTR) = a_offset;
146 REG(PKA_ALENGTH) = curve->words;
147 REG(PKA_BPTR) = b_offset;
149 PT_YIELD_UNTIL(&helper_protothread, pka_check_status());
151 *result = PKA_STATUS_A_GR_B;
152 } else if(REG(PKA_COMPARE) == PKA_COMPARE_A_LESS_THAN_B) {
153 *result = PKA_STATUS_A_LT_B;
154 } else {
155 *result = PKA_STATUS_A_EQ_B;
156 }
157
158 PT_END(&helper_protothread);
159}
160/*---------------------------------------------------------------------------*/
161static
162PT_THREAD(check_bounds(uintptr_t x_offset,
163 uintptr_t a_offset,
164 uintptr_t b_offset,
165 int *const result))
166{
167 PT_BEGIN(&helper_protothread);
168
169 /* check whether x > a */
170 REG(PKA_APTR) = x_offset;
171 REG(PKA_ALENGTH) = curve->words;
172 REG(PKA_BPTR) = a_offset;
174 PT_YIELD_UNTIL(&helper_protothread, pka_check_status());
176 *result = PKA_STATUS_FAILURE;
177 PT_EXIT(&helper_protothread);
178 }
179
180 /* check whether x < b */
181 REG(PKA_BPTR) = b_offset;
183 PT_YIELD_UNTIL(&helper_protothread, pka_check_status());
185 *result = PKA_STATUS_FAILURE;
186 PT_EXIT(&helper_protothread);
187 }
188
189 *result = PKA_STATUS_SUCCESS;
190
191 PT_END(&helper_protothread);
192}
193/*---------------------------------------------------------------------------*/
194static
195PT_THREAD(invert_modulo(uintptr_t number_offset,
196 uintptr_t modulus_offset,
197 uintptr_t result_offset,
198 int *const result))
199{
200 PT_BEGIN(&helper_protothread);
201
202 /* invert number */
203 REG(PKA_APTR) = number_offset;
204 REG(PKA_ALENGTH) = curve->words;
205 REG(PKA_BPTR) = modulus_offset;
206 REG(PKA_BLENGTH) = curve->words;
207 REG(PKA_DPTR) = scratchpad_offset;
208 pka_run_function(PKA_FUNCTION_INVMOD);
209 PT_YIELD_UNTIL(&helper_protothread, pka_check_status());
210
211 /* check result */
213 *result = PKA_STATUS_RESULT_0;
214 PT_EXIT(&helper_protothread);
215 }
216
217 /* copy result */
218 REG(PKA_APTR) = scratchpad_offset;
219 REG(PKA_ALENGTH) = curve->words;
220 REG(PKA_CPTR) = result_offset;
222 PT_YIELD_UNTIL(&helper_protothread, pka_check_status());
223
224 *result = PKA_STATUS_SUCCESS;
225
226 PT_END(&helper_protothread);
227}
228/*---------------------------------------------------------------------------*/
229static
230PT_THREAD(add_or_multiply_modulo(uint32_t function,
231 uintptr_t a_offset,
232 uintptr_t b_offset,
233 uintptr_t modulus_offset,
234 uintptr_t result_offset,
235 int *const result))
236{
237 PT_BEGIN(&helper_protothread);
238
239 /* add or multiply */
240 REG(PKA_APTR) = a_offset;
241 REG(PKA_ALENGTH) = curve->words;
242 REG(PKA_BPTR) = b_offset;
243 REG(PKA_BLENGTH) = curve->words;
244 REG(PKA_CPTR) = scratchpad_offset;
245 pka_run_function(function);
246 PT_YIELD_UNTIL(&helper_protothread, pka_check_status());
247
248 /* check result */
250 *result = PKA_STATUS_RESULT_0;
251 PT_EXIT(&helper_protothread);
252 }
253
254 /* compute modulus */
255 REG(PKA_APTR) = scratchpad_offset;
256 REG(PKA_ALENGTH) = MAX(curve->words,
258 - scratchpad_offset + 1);
259 REG(PKA_BPTR) = modulus_offset;
260 REG(PKA_CPTR) = result_offset;
262 PT_YIELD_UNTIL(&helper_protothread, pka_check_status());
263
264 *result = PKA_STATUS_SUCCESS;
265
266 PT_END(&helper_protothread);
267}
268/*---------------------------------------------------------------------------*/
269static
270PT_THREAD(subtract(uintptr_t a_offset,
271 uintptr_t b_offset,
272 uintptr_t result_offset))
273{
274 PT_BEGIN(&helper_protothread);
275
276 /* subtract */
277 REG(PKA_APTR) = a_offset;
278 REG(PKA_ALENGTH) = curve->words;
279 REG(PKA_BPTR) = b_offset;
280 REG(PKA_BLENGTH) = curve->words;
281 REG(PKA_CPTR) = scratchpad_offset;
283 PT_YIELD_UNTIL(&helper_protothread, pka_check_status());
284
285 /* copy result */
286 REG(PKA_APTR) = scratchpad_offset;
287 REG(PKA_ALENGTH) = curve->words;
288 REG(PKA_CPTR) = result_offset;
290 PT_YIELD_UNTIL(&helper_protothread, pka_check_status());
291
292 PT_END(&helper_protothread);
293}
294/*---------------------------------------------------------------------------*/
295static
296PT_THREAD(reduce_to_element(uintptr_t hash_offset,
297 int *const result))
298{
299 PT_BEGIN(&helper_protothread);
300
301 if((curve->bytes * 8) < curve->binary_length_of_n) {
302 *result = PKA_STATUS_SUCCESS;
303 PT_EXIT(&helper_protothread);
304 }
305
306 /* right shift to binary length of n */
307 REG(PKA_APTR) = hash_offset;
308 REG(PKA_ALENGTH) = curve->words;
309 REG(PKA_CPTR) = scratchpad_offset;
310 REG(PKA_SHIFT) = (curve->bytes * 8) - curve->binary_length_of_n;
312 PT_YIELD_UNTIL(&helper_protothread, pka_check_status());
313
314 /* check whether hash < n */
315 REG(PKA_APTR) = scratchpad_offset;
316 REG(PKA_BPTR) = curve_n_offset;
318 PT_YIELD_UNTIL(&helper_protothread, pka_check_status());
319
321 /* subtract n */
322 REG(PKA_APTR) = scratchpad_offset;
323 REG(PKA_BPTR) = curve_n_offset;
324 REG(PKA_BLENGTH) = curve->words;
325 REG(PKA_CPTR) = hash_offset;
327 } else {
328 /* copy result */
329 REG(PKA_APTR) = scratchpad_offset;
330 REG(PKA_CPTR) = hash_offset;
332 }
333 PT_YIELD_UNTIL(&helper_protothread, pka_check_status());
334
335 *result = PKA_STATUS_SUCCESS;
336
337 PT_END(&helper_protothread);
338}
339/*---------------------------------------------------------------------------*/
340static
341PT_THREAD(add_or_multiply_point(uint32_t function,
342 uintptr_t a_offset,
343 uintptr_t c_offset,
344 uintptr_t result_offset,
345 int *const result))
346{
347 PT_BEGIN(&helper_protothread);
348
349 /* add or multiply point */
350 REG(PKA_APTR) = a_offset;
351 REG(PKA_ALENGTH) = curve->words;
352 REG(PKA_BPTR) = curve_pab_offset;
353 REG(PKA_BLENGTH) = curve->words;
354 REG(PKA_CPTR) = c_offset;
355 REG(PKA_DPTR) = scratchpad_offset;
356 pka_run_function(function);
357 PT_YIELD_UNTIL(&helper_protothread, pka_check_status());
358
359 /* check result */
360 if(REG(PKA_SHIFT) == PKA_SHIFT_POINT_AT_INFINITY) {
361 *result = PKA_STATUS_POINT_AT_INFINITY;
362 PT_EXIT(&helper_protothread);
363 }
364 if(REG(PKA_SHIFT) != PKA_SHIFT_SUCCESS) {
365 *result = PKA_STATUS_FAILURE;
366 PT_EXIT(&helper_protothread);
367 }
368
369 /* copy result */
370 REG(PKA_APTR) = scratchpad_offset;
371 REG(PKA_ALENGTH) = PKA_POINT_WORDS(curve->words);
372 REG(PKA_CPTR) = result_offset;
374 PT_YIELD_UNTIL(&helper_protothread, pka_check_status());
375
376 *result = PKA_STATUS_SUCCESS;
377
378 PT_END(&helper_protothread);
379}
380/*---------------------------------------------------------------------------*/
381void
382ecc_init(void)
383{
384 process_mutex_init(&mutex);
385 pka_init();
386}
387/*---------------------------------------------------------------------------*/
389ecc_get_mutex(void)
390{
391 return &mutex;
392}
393/*---------------------------------------------------------------------------*/
394int
395ecc_enable(const ecc_curve_t *c)
396{
397 curve = c;
398 pka_enable();
399 pka_little_endian_to_pka_ram(element_null,
400 c->words,
401 element_null_offset);
403 c->words,
404 element_one_offset);
406 c->words,
407 curve_g_offset);
409 c->words,
410 curve_g_offset
413 c->words,
414 curve_pab_offset);
416 c->words,
417 curve_pab_offset
420 c->words,
421 curve_pab_offset
422 + (PKA_COORDINATE_WORDS(c->words) * 2));
424 c->words,
425 curve_n_offset);
427 c->words,
428 curve_a_offset);
430 c->words,
431 curve_b_offset);
432 return 0;
433}
434/*---------------------------------------------------------------------------*/
435struct pt *
436ecc_get_protothread(void)
437{
438 return &main_protothread;
439}
440/*---------------------------------------------------------------------------*/
441PT_THREAD(ecc_validate_public_key(const uint8_t *public_key,
442 int *const result))
443{
444 static const uintptr_t public_key_x_offset =
445 variables_offset;
446 static const uintptr_t public_key_y_offset =
447 PKA_NEXT_OFFSET(public_key_x_offset, MAX_ELEMENT_WORDS);
448 static const uintptr_t tmp1_offset =
449 PKA_NEXT_OFFSET(public_key_y_offset, MAX_ELEMENT_WORDS);
450 static const uintptr_t tmp2_offset =
451 PKA_NEXT_OFFSET(tmp1_offset, MAX_REMAINDER_WORDS);
452 /* PKA_NEXT_OFFSET(tmp2_offset, MAX_REMAINDER_WORDS); */
453
454 PT_BEGIN(&main_protothread);
455
456 /* copy inputs to PKA RAM */
457 element_to_pka_ram(public_key, public_key_x_offset);
458 element_to_pka_ram(public_key + curve->bytes, public_key_y_offset);
459
460 /* ensure that 0 < x < prime */
461 PT_SPAWN(&main_protothread,
462 &helper_protothread,
463 check_bounds(public_key_x_offset,
464 element_null_offset,
465 curve_prime_offset,
466 result));
467 if(*result != PKA_STATUS_SUCCESS) {
468 PT_EXIT(&main_protothread);
469 }
470
471 /* ensure that 0 < y < prime */
472 PT_SPAWN(&main_protothread,
473 &helper_protothread,
474 check_bounds(public_key_y_offset,
475 element_null_offset,
476 curve_prime_offset,
477 result));
478 if(*result != PKA_STATUS_SUCCESS) {
479 PT_EXIT(&main_protothread);
480 }
481
482 /* ensure that y^2 = x^3 + ax + b */
483 /* tmp1 = y^2 */
484 PT_SPAWN(&main_protothread,
485 &helper_protothread,
486 add_or_multiply_modulo(PKA_FUNCTION_MULTIPLY,
487 public_key_y_offset,
488 public_key_y_offset,
489 curve_prime_offset,
490 tmp1_offset,
491 result));
492 if(*result != PKA_STATUS_SUCCESS) {
493 PT_EXIT(&main_protothread);
494 }
495
496 /* tmp2 = x^2 */
497 PT_SPAWN(&main_protothread,
498 &helper_protothread,
499 add_or_multiply_modulo(PKA_FUNCTION_MULTIPLY,
500 public_key_x_offset,
501 public_key_x_offset,
502 curve_prime_offset,
503 tmp2_offset,
504 result));
505 if(*result != PKA_STATUS_SUCCESS) {
506 PT_EXIT(&main_protothread);
507 }
508
509 /* tmp2 = x^2 + a */
510 PT_SPAWN(&main_protothread,
511 &helper_protothread,
512 add_or_multiply_modulo(PKA_FUNCTION_ADD,
513 tmp2_offset,
514 curve_a_offset,
515 curve_prime_offset,
516 tmp2_offset,
517 result));
518 if(*result != PKA_STATUS_SUCCESS) {
519 PT_EXIT(&main_protothread);
520 }
521
522 /* tmp2 = x^3 + ax */
523 PT_SPAWN(&main_protothread,
524 &helper_protothread,
525 add_or_multiply_modulo(PKA_FUNCTION_MULTIPLY,
526 tmp2_offset,
527 public_key_x_offset,
528 curve_prime_offset,
529 tmp2_offset,
530 result));
531 if(*result != PKA_STATUS_SUCCESS) {
532 PT_EXIT(&main_protothread);
533 }
534
535 /* tmp2 = x^3 + ax + b */
536 PT_SPAWN(&main_protothread,
537 &helper_protothread,
538 add_or_multiply_modulo(PKA_FUNCTION_ADD,
539 tmp2_offset,
540 curve_b_offset,
541 curve_prime_offset,
542 tmp2_offset,
543 result));
544 if(*result != PKA_STATUS_SUCCESS) {
545 PT_EXIT(&main_protothread);
546 }
547
548 PT_SPAWN(&main_protothread,
549 &helper_protothread,
550 compare_a_and_b(tmp1_offset, tmp2_offset, result));
551 if(*result != PKA_STATUS_A_EQ_B) {
552 PT_EXIT(&main_protothread);
553 }
554
555 *result = PKA_STATUS_SUCCESS;
556
557 PT_END(&main_protothread);
558}
559/*---------------------------------------------------------------------------*/
560void
561ecc_compress_public_key(const uint8_t *public_key,
562 uint8_t *compressed_public_key)
563{
564 memcpy(compressed_public_key + 1, public_key, curve->bytes);
565 compressed_public_key[0] = 2 + (public_key[curve->bytes * 2 - 1] & 0x01);
566}
567/*---------------------------------------------------------------------------*/
568PT_THREAD(ecc_decompress_public_key(const uint8_t *compressed_public_key,
569 uint8_t *uncompressed_public_key,
570 int *const result))
571{
572 static const uintptr_t public_key_x_offset =
573 variables_offset;
574 static const uintptr_t public_key_y_offset =
575 PKA_NEXT_OFFSET(public_key_x_offset, MAX_ELEMENT_WORDS);
576 static const uintptr_t mod_sqrt_offset =
577 PKA_NEXT_OFFSET(public_key_y_offset,
578 MAX(MAX_ELEMENT_WORDS, MAX_REMAINDER_WORDS));
579 /* PKA_NEXT_OFFSET(mod_sqrt_offset,
580 MAX(MAX_ELEMENT_WORDS, MAX_REMAINDER_WORDS)); */
581 static uint8_t compression_info;
582 static size_t i;
583
584 PT_BEGIN(&main_protothread);
585
586 /* save inputs */
587 compression_info = compressed_public_key[0];
588 element_to_pka_ram(compressed_public_key + 1, public_key_x_offset);
589
590 /* y = x^2 */
591 PT_SPAWN(&main_protothread,
592 &helper_protothread,
593 add_or_multiply_modulo(PKA_FUNCTION_MULTIPLY,
594 public_key_x_offset,
595 public_key_x_offset,
596 curve_prime_offset,
597 public_key_y_offset,
598 result));
599 if(*result != PKA_STATUS_SUCCESS) {
600 PT_EXIT(&main_protothread);
601 }
602
603 /* y = x^2 + a */
604 PT_SPAWN(&main_protothread,
605 &helper_protothread,
606 add_or_multiply_modulo(PKA_FUNCTION_ADD,
607 public_key_y_offset,
608 curve_a_offset,
609 curve_prime_offset,
610 public_key_y_offset,
611 result));
612 if(*result != PKA_STATUS_SUCCESS) {
613 PT_EXIT(&main_protothread);
614 }
615
616 /* y = x^3 + ax */
617 PT_SPAWN(&main_protothread,
618 &helper_protothread,
619 add_or_multiply_modulo(PKA_FUNCTION_MULTIPLY,
620 public_key_y_offset,
621 public_key_x_offset,
622 curve_prime_offset,
623 public_key_y_offset,
624 result));
625 if(*result != PKA_STATUS_SUCCESS) {
626 PT_EXIT(&main_protothread);
627 }
628
629 /* y = x^3 + ax + b */
630 PT_SPAWN(&main_protothread,
631 &helper_protothread,
632 add_or_multiply_modulo(PKA_FUNCTION_ADD,
633 public_key_y_offset,
634 curve_b_offset,
635 curve_prime_offset,
636 public_key_y_offset,
637 result));
638 if(*result != PKA_STATUS_SUCCESS) {
639 PT_EXIT(&main_protothread);
640 }
641
642 /* compute mod sqrt of y */
643
644 /* copy element 1 */
645 REG(PKA_APTR) = element_one_offset;
646 REG(PKA_ALENGTH) = curve->words;
647 REG(PKA_CPTR) = mod_sqrt_offset;
649 PT_YIELD_UNTIL(&main_protothread, pka_check_status());
650
651 for(i = curve->binary_length_of_p_plus_one - 1; i > 1; i--) {
652 PT_SPAWN(&main_protothread,
653 &helper_protothread,
654 add_or_multiply_modulo(PKA_FUNCTION_MULTIPLY,
655 mod_sqrt_offset,
656 mod_sqrt_offset,
657 curve_prime_offset,
658 mod_sqrt_offset,
659 result));
660 if(*result != PKA_STATUS_SUCCESS) {
661 PT_EXIT(&main_protothread);
662 }
663 if(test_bit(curve->p_plus_one, i)) {
664 PT_SPAWN(&main_protothread,
665 &helper_protothread,
666 add_or_multiply_modulo(PKA_FUNCTION_MULTIPLY,
667 mod_sqrt_offset,
668 public_key_y_offset,
669 curve_prime_offset,
670 mod_sqrt_offset,
671 result));
672 if(*result != PKA_STATUS_SUCCESS) {
673 PT_EXIT(&main_protothread);
674 }
675 }
676 }
677
678 if((pka_word_from_pka_ram(mod_sqrt_offset) & 0x01)
679 != (compression_info & 0x01)) {
680 PT_SPAWN(&main_protothread,
681 &helper_protothread,
682 subtract(curve_prime_offset, mod_sqrt_offset, mod_sqrt_offset));
683 }
684
685 element_from_pka_ram(uncompressed_public_key, public_key_x_offset);
686 element_from_pka_ram(uncompressed_public_key + curve->bytes,
687 mod_sqrt_offset);
688 *result = PKA_STATUS_SUCCESS;
689
690 PT_END(&main_protothread);
691}
692/*---------------------------------------------------------------------------*/
693PT_THREAD(ecc_sign(const uint8_t *message_hash,
694 const uint8_t *private_key,
695 uint8_t *signature,
696 int *const result))
697{
698 static const uintptr_t e_offset =
699 variables_offset;
700 static const uintptr_t d_offset =
701 PKA_NEXT_OFFSET(e_offset, MAX_REMAINDER_WORDS);
702 static const uintptr_t k_offset =
703 PKA_NEXT_OFFSET(d_offset, MAX_ELEMENT_WORDS);
704 static const uintptr_t r_offset =
705 PKA_NEXT_OFFSET(k_offset, MAX_COORDINATE_WORDS);
706 static const uintptr_t s_offset =
707 PKA_NEXT_OFFSET(r_offset, MAX_POINT_WORDS);
708 /* PKA_NEXT_OFFSET(s_offset, MAX_REMAINDER_WORDS); */
709 uint8_t k[MAX_ELEMENT_BYTES];
710
711 PT_BEGIN(&main_protothread);
712
713 /* copy inputs to PKA RAM */
714 element_to_pka_ram(private_key, d_offset);
715 element_to_pka_ram(message_hash, e_offset);
716
717 /* reduce hash to an element */
718 PT_SPAWN(&main_protothread,
719 &helper_protothread,
720 reduce_to_element(e_offset, result));
721 if(*result != PKA_STATUS_SUCCESS) {
722 LOG_ERR("Line: %u Error: %u\n", __LINE__, *result);
723 PT_EXIT(&main_protothread);
724 }
725
726 while(1) {
727 /* generate k */
728 if(!csprng_rand(k, sizeof(k))) {
729 LOG_ERR("CSPRNG error\n");
730 *result = PKA_STATUS_FAILURE;
731 PT_EXIT(&main_protothread);
732 }
733 element_to_pka_ram(k, k_offset);
734 PT_SPAWN(&main_protothread,
735 &helper_protothread,
736 check_bounds(k_offset,
737 element_null_offset,
738 curve_n_offset,
739 result));
740 if(*result != PKA_STATUS_SUCCESS) {
741 LOG_WARN("k was not in [1, n-1]\n");
742 continue;
743 }
744
745 /* calculate k x G = (r, ignore) */
746 PT_SPAWN(&main_protothread,
747 &helper_protothread,
748 add_or_multiply_point(PKA_FUNCTION_ECCMUL,
749 k_offset,
750 curve_g_offset,
751 r_offset,
752 result));
753 if(*result == PKA_STATUS_POINT_AT_INFINITY) {
754 LOG_WARN("k x G is at infinity\n");
755 continue;
756 }
757 if(*result != PKA_STATUS_SUCCESS) {
758 LOG_ERR("Line: %u Error: %u\n", __LINE__, *result);
759 PT_EXIT(&main_protothread);
760 }
761
762 /* ensure that r != 0 */
763 PT_SPAWN(&main_protothread,
764 &helper_protothread,
765 compare_a_and_b(element_null_offset, r_offset, result));
766 if(*result == PKA_STATUS_A_EQ_B) {
767 LOG_WARN("r is zero\n");
768 continue;
769 }
770
771 /* s := rd mod n */
772 PT_SPAWN(&main_protothread,
773 &helper_protothread,
774 add_or_multiply_modulo(PKA_FUNCTION_MULTIPLY,
775 d_offset,
776 r_offset,
777 curve_n_offset,
778 s_offset,
779 result));
780 if(*result == PKA_STATUS_RESULT_0) {
781 LOG_WARN("rd mod n was zero\n");
782 continue;
783 }
784 if(*result != PKA_STATUS_SUCCESS) {
785 LOG_ERR("Line: %u Error: %u\n", __LINE__, *result);
786 PT_EXIT(&main_protothread);
787 }
788
789 /* ensure that rd and e don't coincide */
790 PT_SPAWN(&main_protothread,
791 &helper_protothread,
792 compare_a_and_b(e_offset, s_offset, result));
793 if(*result == PKA_STATUS_A_EQ_B) {
794 LOG_WARN("rd and e coincide\n");
795 continue;
796 }
797
798 /* s := e + rd mod n */
799 PT_SPAWN(&main_protothread,
800 &helper_protothread,
801 add_or_multiply_modulo(PKA_FUNCTION_ADD,
802 e_offset,
803 s_offset,
804 curve_n_offset,
805 s_offset,
806 result));
807 if(*result == PKA_STATUS_RESULT_0) {
808 LOG_WARN("e + rd mod n was zero\n");
809 continue;
810 }
811 if(*result != PKA_STATUS_SUCCESS) {
812 LOG_ERR("Line: %u Error: %u\n", __LINE__, *result);
813 PT_EXIT(&main_protothread);
814 }
815
816 /* k := 1 / k */
817 PT_SPAWN(&main_protothread,
818 &helper_protothread,
819 invert_modulo(k_offset, curve_n_offset, k_offset, result));
820 if(*result == PKA_STATUS_RESULT_0) {
821 LOG_WARN("inverse of k was zero\n");
822 continue;
823 }
824 if(*result != PKA_STATUS_SUCCESS) {
825 LOG_ERR("Line: %u Error: %u\n", __LINE__, *result);
826 PT_EXIT(&main_protothread);
827 }
828
829 /* s := (e + r*d) / k mod n */
830 PT_SPAWN(&main_protothread,
831 &helper_protothread,
832 add_or_multiply_modulo(PKA_FUNCTION_MULTIPLY,
833 k_offset,
834 s_offset,
835 curve_n_offset,
836 s_offset,
837 result));
838 if(*result == PKA_STATUS_RESULT_0) {
839 LOG_WARN("s is zero\n");
840 continue;
841 }
842 if(*result != PKA_STATUS_SUCCESS) {
843 LOG_ERR("Line: %u Error: %u\n", __LINE__, *result);
844 PT_EXIT(&main_protothread);
845 }
846 break;
847 }
848
849 element_from_pka_ram(signature, r_offset);
850 element_from_pka_ram(signature + curve->bytes, s_offset);
851
852 PT_END(&main_protothread);
853}
854/*---------------------------------------------------------------------------*/
855PT_THREAD(ecc_verify(const uint8_t *signature,
856 const uint8_t *message_hash,
857 const uint8_t *public_key,
858 int *const result))
859{
860 static const uintptr_t e_offset =
861 variables_offset;
862 static const uintptr_t r_offset =
863 PKA_NEXT_OFFSET(e_offset, MAX_ELEMENT_WORDS);
864 static const uintptr_t s_offset =
865 PKA_NEXT_OFFSET(r_offset, MAX_ELEMENT_WORDS);
866 static const uintptr_t q_offset =
867 PKA_NEXT_OFFSET(s_offset, MAX_ELEMENT_WORDS);
868 static const uintptr_t u1_offset =
869 PKA_NEXT_OFFSET(q_offset, MAX_POINT_WORDS);
870 static const uintptr_t u2_offset =
871 PKA_NEXT_OFFSET(u1_offset,
872 MAX(MAX_REMAINDER_WORDS, MAX_COORDINATE_WORDS));
873 static const uintptr_t p1_offset =
874 PKA_NEXT_OFFSET(u2_offset,
875 MAX(MAX_REMAINDER_WORDS, MAX_COORDINATE_WORDS));
876 static const uintptr_t p2_offset =
877 PKA_NEXT_OFFSET(p1_offset, MAX_POINT_WORDS);
878 /* PKA_NEXT_OFFSET(p2_offset, MAX_POINT_WORDS); */
879
880 PT_BEGIN(&main_protothread);
881
882 /* copy inputs to PKA RAM */
883 point_to_pka_ram(public_key, q_offset);
884 element_to_pka_ram(signature, r_offset);
885 element_to_pka_ram(signature + curve->bytes, s_offset);
886 element_to_pka_ram(message_hash, e_offset);
887
888 /* reduce hash to an element */
889 PT_SPAWN(&main_protothread,
890 &helper_protothread,
891 reduce_to_element(e_offset, result));
892 if(*result != PKA_STATUS_SUCCESS) {
893 LOG_ERR("Line: %u Error: %u\n", __LINE__, *result);
894 PT_EXIT(&main_protothread);
895 }
896
897 /* ensure that 0 < r < n */
898 PT_SPAWN(&main_protothread,
899 &helper_protothread,
900 check_bounds(r_offset,
901 element_null_offset,
902 curve_n_offset,
903 result));
904 if(*result != PKA_STATUS_SUCCESS) {
905 LOG_ERR("Line: %u Error: %u\n", __LINE__, *result);
906 PT_EXIT(&main_protothread);
907 }
908
909 /* ensure that 0 < s < n */
910 PT_SPAWN(&main_protothread,
911 &helper_protothread,
912 check_bounds(s_offset,
913 element_null_offset,
914 curve_n_offset,
915 result));
916 if(*result != PKA_STATUS_SUCCESS) {
917 LOG_ERR("Line: %u Error: %u\n", __LINE__, *result);
918 PT_EXIT(&main_protothread);
919 }
920
921 /* s := 1 / s */
922 PT_SPAWN(&main_protothread,
923 &helper_protothread,
924 invert_modulo(s_offset, curve_n_offset, s_offset, result));
925 if(*result != PKA_STATUS_SUCCESS) {
926 LOG_ERR("Line: %u Error: %u\n", __LINE__, *result);
927 PT_EXIT(&main_protothread);
928 }
929
930 /* u1 := e / s mod n */
931 PT_SPAWN(&main_protothread,
932 &helper_protothread,
933 add_or_multiply_modulo(PKA_FUNCTION_MULTIPLY,
934 s_offset,
935 e_offset,
936 curve_n_offset,
937 u1_offset,
938 result));
939 if(*result != PKA_STATUS_SUCCESS) {
940 LOG_ERR("Line: %u Error: %u\n", __LINE__, *result);
941 PT_EXIT(&main_protothread);
942 }
943
944 /* p1 := u1 x G */
945 PT_SPAWN(&main_protothread,
946 &helper_protothread,
947 add_or_multiply_point(PKA_FUNCTION_ECCMUL,
948 u1_offset,
949 curve_g_offset,
950 p1_offset,
951 result));
952 if(*result != PKA_STATUS_SUCCESS) {
953 LOG_ERR("Line: %u Error: %u\n", __LINE__, *result);
954 PT_EXIT(&main_protothread);
955 }
956
957 /* u2 := r / s mod n */
958 PT_SPAWN(&main_protothread,
959 &helper_protothread,
960 add_or_multiply_modulo(PKA_FUNCTION_MULTIPLY,
961 s_offset,
962 r_offset,
963 curve_n_offset,
964 u2_offset,
965 result));
966 if(*result != PKA_STATUS_SUCCESS) {
967 LOG_ERR("Line: %u Error: %u\n", __LINE__, *result);
968 PT_EXIT(&main_protothread);
969 }
970
971 /* p2 := u2 x Q */
972 PT_SPAWN(&main_protothread,
973 &helper_protothread,
974 add_or_multiply_point(PKA_FUNCTION_ECCMUL,
975 u2_offset,
976 q_offset,
977 p2_offset,
978 result));
979 if(*result != PKA_STATUS_SUCCESS) {
980 LOG_ERR("Line: %u Error: %u\n", __LINE__, *result);
981 PT_EXIT(&main_protothread);
982 }
983
984 /* p := p1 + p2 */
985 PT_SPAWN(&main_protothread,
986 &helper_protothread,
987 add_or_multiply_point(PKA_FUNCTION_ECCADD,
988 p1_offset,
989 p2_offset,
990 p1_offset,
991 result));
992 if(*result != PKA_STATUS_SUCCESS) {
993 LOG_ERR("Line: %u Error: %u\n", __LINE__, *result);
994 PT_EXIT(&main_protothread);
995 }
996
997 /* verify */
998 PT_SPAWN(&main_protothread,
999 &helper_protothread,
1000 compare_a_and_b(p1_offset, r_offset, result));
1001 if(*result != PKA_STATUS_A_EQ_B) {
1002 LOG_ERR("Line: %u Error: %u\n", __LINE__, *result);
1003 PT_EXIT(&main_protothread);
1004 }
1005 *result = PKA_STATUS_SUCCESS;
1006
1007 PT_END(&main_protothread);
1008}
1009/*---------------------------------------------------------------------------*/
1010PT_THREAD(ecc_generate_key_pair(uint8_t *public_key,
1011 uint8_t *private_key,
1012 int *const result))
1013{
1014 static const uintptr_t private_key_offset =
1015 variables_offset;
1016 static const uintptr_t public_key_offset =
1017 PKA_NEXT_OFFSET(private_key_offset, MAX_ELEMENT_WORDS);
1018 /* PKA_NEXT_OFFSET(public_key_offset, MAX_POINT_WORDS); */
1019
1020 PT_BEGIN(&main_protothread);
1021
1022 while(1) {
1023 /* generate private key */
1024 if(!csprng_rand(private_key, curve->bytes)) {
1025 LOG_ERR("CSPRNG error\n");
1026 *result = PKA_STATUS_FAILURE;
1027 PT_EXIT(&main_protothread);
1028 }
1029 element_to_pka_ram(private_key, private_key_offset);
1030 PT_SPAWN(&main_protothread,
1031 &helper_protothread,
1032 check_bounds(private_key_offset,
1033 element_null_offset,
1034 curve_n_offset,
1035 result));
1036 if(*result != PKA_STATUS_SUCCESS) {
1037 LOG_WARN("private key was not in [1, n-1]\n");
1038 continue;
1039 }
1040
1041 /* generate public key */
1042 PT_SPAWN(&main_protothread,
1043 &helper_protothread,
1044 add_or_multiply_point(PKA_FUNCTION_ECCMUL,
1045 private_key_offset,
1046 curve_g_offset,
1047 public_key_offset,
1048 result));
1049 if(*result == PKA_STATUS_POINT_AT_INFINITY) {
1050 LOG_WARN("public key at infinity\n");
1051 continue;
1052 }
1053 if(*result != PKA_STATUS_SUCCESS) {
1054 LOG_ERR("Line: %u Error: %u\n", __LINE__, *result);
1055 PT_EXIT(&main_protothread);
1056 }
1057 break;
1058 }
1059
1060 element_from_pka_ram(private_key, private_key_offset);
1061 point_from_pka_ram(public_key, public_key_offset);
1062
1063 PT_END(&main_protothread);
1064}
1065/*---------------------------------------------------------------------------*/
1066PT_THREAD(ecc_generate_shared_secret(const uint8_t *public_key,
1067 const uint8_t *private_key,
1068 uint8_t *shared_secret,
1069 int *const result))
1070{
1071 static const uintptr_t private_key_offset =
1072 variables_offset;
1073 static const uintptr_t public_key_offset =
1074 PKA_NEXT_OFFSET(private_key_offset, MAX_ELEMENT_WORDS);
1075 static const uintptr_t product_offset =
1076 PKA_NEXT_OFFSET(public_key_offset, MAX_POINT_WORDS);
1077 /* PKA_NEXT_OFFSET(product_offset, MAX_POINT_WORDS); */
1078
1079 PT_BEGIN(&main_protothread);
1080
1081 /* copy inputs to PKA RAM */
1082 element_to_pka_ram(private_key, private_key_offset);
1083 point_to_pka_ram(public_key, public_key_offset);
1084
1085 /* do ECDH */
1086 PT_SPAWN(&main_protothread,
1087 &helper_protothread,
1088 add_or_multiply_point(PKA_FUNCTION_ECCMUL,
1089 private_key_offset,
1090 public_key_offset,
1091 product_offset,
1092 result));
1093 if(*result != PKA_STATUS_SUCCESS) {
1094 LOG_ERR("Line: %u Error: %u\n", __LINE__, *result);
1095 PT_EXIT(&main_protothread);
1096 }
1097 element_from_pka_ram(shared_secret, product_offset);
1098
1099 PT_END(&main_protothread);
1100}
1101/*---------------------------------------------------------------------------*/
1102void
1103ecc_disable(void)
1104{
1105 pka_disable();
1106 process_mutex_unlock(&mutex);
1107}
1108/*---------------------------------------------------------------------------*/
1109
1110/** @} */
An OFB-AES-128-based CSPRNG.
Header file of ECC.
#define PKA_CPTR
PKA vector C address During execution of basic PKCP operations, this register is double buffered and ...
Definition pka.h:101
uint32_t pka_word_from_pka_ram(uintptr_t offset)
Retrieves a word from the PKA RAM.
Definition pka.c:145
void pka_run_function(uint32_t function)
Initiates the given PKA function.
Definition pka.c:116
#define PKA_FUNCTION_ADD
Perform add operation.
Definition pka.h:514
#define PKA_STATUS_A_LT_B
Big number compare return status if the first big num is less than the second.
Definition pka.h:838
#define PKA_COMPARE_A_LESS_THAN_B
Vector_A is less than Vector_B.
Definition pka.h:550
#define PKA_DPTR
PKA vector D address During execution of basic PKCP operations, this register is double buffered and ...
Definition pka.h:116
static bool test_bit(const uint32_t *element, size_t bit)
Tells if a bit in a little-endian element is set.
Definition cc2538-ecc.c:105
#define PKA_STATUS_A_GR_B
Big number compare return status if the first big num is greater than the second.
Definition pka.h:835
#define PKA_FUNCTION_MULTIPLY
Perform multiply operation.
Definition pka.h:531
#define PKA_MSW
PKA most-significant-word of result vector This register indicates the (word) address in the PKA RAM ...
Definition pka.h:207
#define PKA_FUNCTION_COMPARE
Perform compare operation.
Definition pka.h:496
#define PKA_MSW_MSW_ADDRESS_M
Address of the most-significant nonzero 32-bit word of the result vector in PKA RAM.
Definition pka.h:579
#define PKA_BLENGTH
PKA vector B length During execution of basic PKCP operations, this register is double buffered and c...
Definition pka.h:146
void pka_big_endian_from_pka_ram(uint8_t *bytes, size_t num_words, uintptr_t offset)
Retrieves a big-endian sequence of bytes from the PKA RAM.
Definition pka.c:170
#define PKA_ALENGTH
PKA vector A length During execution of basic PKCP operations, this register is double buffered and c...
Definition pka.h:131
#define PKA_APTR
PKA vector A address During execution of basic PKCP operations, this register is double buffered and ...
Definition pka.h:71
void pka_disable(void)
Disables the PKA engine.
Definition pka.c:95
#define PKA_FUNCTION_RSHIFT
Perform right shift operation.
Definition pka.h:508
void pka_init(void)
Enables and resets the PKA engine.
Definition pka.c:80
void pka_enable(void)
Enables the PKA engine.
Definition pka.c:86
#define PKA_FUNCTION_COPY
Perform copy operation.
Definition pka.h:493
#define PKA_STATUS_FAILURE
Failure.
Definition pka.h:831
#define PKA_FUNCTION_MODULO
Perform modulo operation.
Definition pka.h:499
#define PKA_COMPARE
PKA compare result This register provides the result of a basic PKCP compare operation.
Definition pka.h:198
#define PKA_COMPARE_A_GREATER_THAN_B
Vector_A is greater than Vector_B.
Definition pka.h:543
void pka_little_endian_to_pka_ram(const uint32_t *words, size_t num_words, uintptr_t offset)
Copies a little-endian sequence of words to the PKA RAM.
Definition pka.c:125
#define PKA_MSW_RESULT_IS_ZERO
The result vector is all zeroes, ignore the address returned in bits [10:0].
Definition pka.h:573
void pka_big_endian_to_pka_ram(const uint8_t *bytes, size_t num_bytes, uintptr_t offset)
Copies a big-endian sequence of bytes to the PKA RAM.
Definition pka.c:153
#define PKA_STATUS_RESULT_0
Result is all zeros.
Definition pka.h:834
#define PKA_COORDINATE_WORDS(len)
Table 22-21.
Definition pka.h:872
#define PKA_BPTR
PKA vector B address During execution of basic PKCP operations, this register is double buffered and ...
Definition pka.h:86
#define PKA_FUNCTION_SUBTRACT
Perform subtract operation.
Definition pka.h:511
#define PKA_SHIFT
PKA bit shift value For basic PKCP operations, modifying the contents of this register is made imposs...
Definition pka.h:161
#define PKA_STATUS_SUCCESS
Success.
Definition pka.h:830
bool pka_check_status(void)
Checks the status of the PKA engine operation.
Definition pka.c:104
bool csprng_rand(uint8_t *result, size_t len)
Generates a cryptographic random number.
Definition csprng.c:81
void process_mutex_init(process_mutex_t *mutex)
Initializes a process mutex.
void process_mutex_unlock(process_mutex_t *mutex)
Unlocks a process mutex.
#define PT_BEGIN(pt)
Declare the start of a protothread inside the C function implementing the protothread.
Definition pt.h:280
#define PT_THREAD(name_args)
Declaration of a protothread.
Definition pt.h:265
#define PT_END(pt)
Declare the end of a protothread.
Definition pt.h:292
#define PT_EXIT(pt)
Exit the protothread.
Definition pt.h:411
#define PT_SPAWN(pt, child, thread)
Spawn a child protothread and wait until it exits.
Definition pt.h:371
#define PT_YIELD_UNTIL(pt, cond)
Yield from the protothread until a condition occurs.
Definition pt.h:475
Header file for the logging system.
Header file for the cc2538 PKA engine driver.
Parameters of an ECC curve in little-endian word order.
Definition ecc-curve.h:53
const size_t words
Size of the curve in 32-bit words.
Definition ecc-curve.h:58
const uint32_t * b
Coefficient b of the equation.
Definition ecc-curve.h:82
const size_t binary_length_of_p_plus_one
Length of the binary representation of p + 1.
Definition ecc-curve.h:70
const uint32_t * x
x coordinate of the generator point.
Definition ecc-curve.h:85
const uint32_t * p
The prime that defines the field of the curve.
Definition ecc-curve.h:64
const uint32_t * y
y coordinate of the generator point.
Definition ecc-curve.h:88
const size_t binary_length_of_n
Length of the binary representation of n.
Definition ecc-curve.h:76
const uint32_t * n
Order of the curve.
Definition ecc-curve.h:73
const size_t bytes
Size of the curve in bytes.
Definition ecc-curve.h:61
const uint32_t * a
Coefficient a of the equation.
Definition ecc-curve.h:79
const uint32_t * p_plus_one
Precomputed value of p + 1.
Definition ecc-curve.h:67
Structure of a process mutex.