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 *result = PKA_STATUS_SUCCESS;
852
853 PT_END(&main_protothread);
854}
855/*---------------------------------------------------------------------------*/
856PT_THREAD(ecc_verify(const uint8_t *signature,
857 const uint8_t *message_hash,
858 const uint8_t *public_key,
859 int *const result))
860{
861 static const uintptr_t e_offset =
862 variables_offset;
863 static const uintptr_t r_offset =
864 PKA_NEXT_OFFSET(e_offset, MAX_ELEMENT_WORDS);
865 static const uintptr_t s_offset =
866 PKA_NEXT_OFFSET(r_offset, MAX_ELEMENT_WORDS);
867 static const uintptr_t q_offset =
868 PKA_NEXT_OFFSET(s_offset, MAX_ELEMENT_WORDS);
869 static const uintptr_t u1_offset =
870 PKA_NEXT_OFFSET(q_offset, MAX_POINT_WORDS);
871 static const uintptr_t u2_offset =
872 PKA_NEXT_OFFSET(u1_offset,
873 MAX(MAX_REMAINDER_WORDS, MAX_COORDINATE_WORDS));
874 static const uintptr_t p1_offset =
875 PKA_NEXT_OFFSET(u2_offset,
876 MAX(MAX_REMAINDER_WORDS, MAX_COORDINATE_WORDS));
877 static const uintptr_t p2_offset =
878 PKA_NEXT_OFFSET(p1_offset, MAX_POINT_WORDS);
879 /* PKA_NEXT_OFFSET(p2_offset, MAX_POINT_WORDS); */
880
881 PT_BEGIN(&main_protothread);
882
883 /* copy inputs to PKA RAM */
884 point_to_pka_ram(public_key, q_offset);
885 element_to_pka_ram(signature, r_offset);
886 element_to_pka_ram(signature + curve->bytes, s_offset);
887 element_to_pka_ram(message_hash, e_offset);
888
889 /* reduce hash to an element */
890 PT_SPAWN(&main_protothread,
891 &helper_protothread,
892 reduce_to_element(e_offset, result));
893 if(*result != PKA_STATUS_SUCCESS) {
894 LOG_ERR("Line: %u Error: %u\n", __LINE__, *result);
895 PT_EXIT(&main_protothread);
896 }
897
898 /* ensure that 0 < r < n */
899 PT_SPAWN(&main_protothread,
900 &helper_protothread,
901 check_bounds(r_offset,
902 element_null_offset,
903 curve_n_offset,
904 result));
905 if(*result != PKA_STATUS_SUCCESS) {
906 LOG_ERR("Line: %u Error: %u\n", __LINE__, *result);
907 PT_EXIT(&main_protothread);
908 }
909
910 /* ensure that 0 < s < n */
911 PT_SPAWN(&main_protothread,
912 &helper_protothread,
913 check_bounds(s_offset,
914 element_null_offset,
915 curve_n_offset,
916 result));
917 if(*result != PKA_STATUS_SUCCESS) {
918 LOG_ERR("Line: %u Error: %u\n", __LINE__, *result);
919 PT_EXIT(&main_protothread);
920 }
921
922 /* s := 1 / s */
923 PT_SPAWN(&main_protothread,
924 &helper_protothread,
925 invert_modulo(s_offset, curve_n_offset, s_offset, result));
926 if(*result != PKA_STATUS_SUCCESS) {
927 LOG_ERR("Line: %u Error: %u\n", __LINE__, *result);
928 PT_EXIT(&main_protothread);
929 }
930
931 /* u1 := e / s mod n */
932 PT_SPAWN(&main_protothread,
933 &helper_protothread,
934 add_or_multiply_modulo(PKA_FUNCTION_MULTIPLY,
935 s_offset,
936 e_offset,
937 curve_n_offset,
938 u1_offset,
939 result));
940 if(*result != PKA_STATUS_SUCCESS) {
941 LOG_ERR("Line: %u Error: %u\n", __LINE__, *result);
942 PT_EXIT(&main_protothread);
943 }
944
945 /* p1 := u1 x G */
946 PT_SPAWN(&main_protothread,
947 &helper_protothread,
948 add_or_multiply_point(PKA_FUNCTION_ECCMUL,
949 u1_offset,
950 curve_g_offset,
951 p1_offset,
952 result));
953 if(*result != PKA_STATUS_SUCCESS) {
954 LOG_ERR("Line: %u Error: %u\n", __LINE__, *result);
955 PT_EXIT(&main_protothread);
956 }
957
958 /* u2 := r / s mod n */
959 PT_SPAWN(&main_protothread,
960 &helper_protothread,
961 add_or_multiply_modulo(PKA_FUNCTION_MULTIPLY,
962 s_offset,
963 r_offset,
964 curve_n_offset,
965 u2_offset,
966 result));
967 if(*result != PKA_STATUS_SUCCESS) {
968 LOG_ERR("Line: %u Error: %u\n", __LINE__, *result);
969 PT_EXIT(&main_protothread);
970 }
971
972 /* p2 := u2 x Q */
973 PT_SPAWN(&main_protothread,
974 &helper_protothread,
975 add_or_multiply_point(PKA_FUNCTION_ECCMUL,
976 u2_offset,
977 q_offset,
978 p2_offset,
979 result));
980 if(*result != PKA_STATUS_SUCCESS) {
981 LOG_ERR("Line: %u Error: %u\n", __LINE__, *result);
982 PT_EXIT(&main_protothread);
983 }
984
985 /* p := p1 + p2 */
986 PT_SPAWN(&main_protothread,
987 &helper_protothread,
988 add_or_multiply_point(PKA_FUNCTION_ECCADD,
989 p1_offset,
990 p2_offset,
991 p1_offset,
992 result));
993 if(*result != PKA_STATUS_SUCCESS) {
994 LOG_ERR("Line: %u Error: %u\n", __LINE__, *result);
995 PT_EXIT(&main_protothread);
996 }
997
998 /* verify */
999 PT_SPAWN(&main_protothread,
1000 &helper_protothread,
1001 compare_a_and_b(p1_offset, r_offset, result));
1002 if(*result != PKA_STATUS_A_EQ_B) {
1003 LOG_ERR("Line: %u Error: %u\n", __LINE__, *result);
1004 PT_EXIT(&main_protothread);
1005 }
1006 *result = PKA_STATUS_SUCCESS;
1007
1008 PT_END(&main_protothread);
1009}
1010/*---------------------------------------------------------------------------*/
1011PT_THREAD(ecc_generate_key_pair(uint8_t *public_key,
1012 uint8_t *private_key,
1013 int *const result))
1014{
1015 static const uintptr_t private_key_offset =
1016 variables_offset;
1017 static const uintptr_t public_key_offset =
1018 PKA_NEXT_OFFSET(private_key_offset, MAX_ELEMENT_WORDS);
1019 /* PKA_NEXT_OFFSET(public_key_offset, MAX_POINT_WORDS); */
1020
1021 PT_BEGIN(&main_protothread);
1022
1023 while(1) {
1024 /* generate private key */
1025 if(!csprng_rand(private_key, curve->bytes)) {
1026 LOG_ERR("CSPRNG error\n");
1027 *result = PKA_STATUS_FAILURE;
1028 PT_EXIT(&main_protothread);
1029 }
1030 element_to_pka_ram(private_key, private_key_offset);
1031 PT_SPAWN(&main_protothread,
1032 &helper_protothread,
1033 check_bounds(private_key_offset,
1034 element_null_offset,
1035 curve_n_offset,
1036 result));
1037 if(*result != PKA_STATUS_SUCCESS) {
1038 LOG_WARN("private key was not in [1, n-1]\n");
1039 continue;
1040 }
1041
1042 /* generate public key */
1043 PT_SPAWN(&main_protothread,
1044 &helper_protothread,
1045 add_or_multiply_point(PKA_FUNCTION_ECCMUL,
1046 private_key_offset,
1047 curve_g_offset,
1048 public_key_offset,
1049 result));
1050 if(*result == PKA_SHIFT_POINT_AT_INFINITY) {
1051 LOG_WARN("public key at infinity\n");
1052 continue;
1053 }
1054 if(*result != PKA_STATUS_SUCCESS) {
1055 LOG_ERR("Line: %u Error: %u\n", __LINE__, *result);
1056 PT_EXIT(&main_protothread);
1057 }
1058 break;
1059 }
1060
1061 element_from_pka_ram(private_key, private_key_offset);
1062 point_from_pka_ram(public_key, public_key_offset);
1063
1064 PT_END(&main_protothread);
1065}
1066/*---------------------------------------------------------------------------*/
1067PT_THREAD(ecc_generate_shared_secret(const uint8_t *public_key,
1068 const uint8_t *private_key,
1069 uint8_t *shared_secret,
1070 int *const result))
1071{
1072 static const uintptr_t private_key_offset =
1073 variables_offset;
1074 static const uintptr_t public_key_offset =
1075 PKA_NEXT_OFFSET(private_key_offset, MAX_ELEMENT_WORDS);
1076 static const uintptr_t product_offset =
1077 PKA_NEXT_OFFSET(public_key_offset, MAX_POINT_WORDS);
1078 /* PKA_NEXT_OFFSET(product_offset, MAX_POINT_WORDS); */
1079
1080 PT_BEGIN(&main_protothread);
1081
1082 /* copy inputs to PKA RAM */
1083 element_to_pka_ram(private_key, private_key_offset);
1084 point_to_pka_ram(public_key, public_key_offset);
1085
1086 /* do ECDH */
1087 PT_SPAWN(&main_protothread,
1088 &helper_protothread,
1089 add_or_multiply_point(PKA_FUNCTION_ECCMUL,
1090 private_key_offset,
1091 public_key_offset,
1092 product_offset,
1093 result));
1094 if(*result != PKA_STATUS_SUCCESS) {
1095 LOG_ERR("Line: %u Error: %u\n", __LINE__, *result);
1096 PT_EXIT(&main_protothread);
1097 }
1098 element_from_pka_ram(shared_secret, product_offset);
1099 *result = PKA_STATUS_SUCCESS;
1100
1101 PT_END(&main_protothread);
1102}
1103/*---------------------------------------------------------------------------*/
1104void
1105ecc_disable(void)
1106{
1107 pka_disable();
1108 process_mutex_unlock(&mutex);
1109}
1110/*---------------------------------------------------------------------------*/
1111
1112/** @} */
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.