48#define LOG_MODULE "ECC"
49#define LOG_LEVEL LOG_LEVEL_NONE
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))))))
69static const uint32_t element_null[MAX_ELEMENT_WORDS];
70static const uint32_t element_one[MAX_ELEMENT_WORDS] = { 1 };
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;
92static struct pt main_protothread;
93static struct pt helper_protothread;
107 return element[bit >> 5] & ((uint32_t)1 << (bit & 0x1F));
111element_to_pka_ram(
const uint8_t *bytes, uintptr_t offset)
117element_from_pka_ram(uint8_t *bytes, uintptr_t offset)
123point_to_pka_ram(
const uint8_t *bytes, uintptr_t offset)
125 element_to_pka_ram(bytes, offset);
126 element_to_pka_ram(bytes + curve->
bytes,
131point_from_pka_ram(uint8_t *bytes, uintptr_t offset)
133 element_from_pka_ram(bytes, offset);
134 element_from_pka_ram(bytes + curve->
bytes,
139PT_THREAD(compare_a_and_b(uintptr_t a_offset,
155 *result = PKA_STATUS_A_EQ_B;
158 PT_END(&helper_protothread);
162PT_THREAD(check_bounds(uintptr_t x_offset,
191 PT_END(&helper_protothread);
195PT_THREAD(invert_modulo(uintptr_t number_offset,
196 uintptr_t modulus_offset,
197 uintptr_t result_offset,
226 PT_END(&helper_protothread);
230PT_THREAD(add_or_multiply_modulo(uint32_t function,
233 uintptr_t modulus_offset,
234 uintptr_t result_offset,
258 - scratchpad_offset + 1);
266 PT_END(&helper_protothread);
272 uintptr_t result_offset))
292 PT_END(&helper_protothread);
296PT_THREAD(reduce_to_element(uintptr_t hash_offset,
337 PT_END(&helper_protothread);
341PT_THREAD(add_or_multiply_point(uint32_t function,
344 uintptr_t result_offset,
360 if(REG(
PKA_SHIFT) == PKA_SHIFT_POINT_AT_INFINITY) {
361 *result = PKA_STATUS_POINT_AT_INFINITY;
364 if(REG(
PKA_SHIFT) != PKA_SHIFT_SUCCESS) {
378 PT_END(&helper_protothread);
401 element_null_offset);
436ecc_get_protothread(
void)
438 return &main_protothread;
441PT_THREAD(ecc_validate_public_key(
const uint8_t *public_key,
444 static const uintptr_t public_key_x_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);
457 element_to_pka_ram(public_key, public_key_x_offset);
458 element_to_pka_ram(public_key + curve->
bytes, public_key_y_offset);
463 check_bounds(public_key_x_offset,
474 check_bounds(public_key_y_offset,
550 compare_a_and_b(tmp1_offset, tmp2_offset, result));
551 if(*result != PKA_STATUS_A_EQ_B) {
557 PT_END(&main_protothread);
561ecc_compress_public_key(
const uint8_t *public_key,
562 uint8_t *compressed_public_key)
564 memcpy(compressed_public_key + 1, public_key, curve->
bytes);
565 compressed_public_key[0] = 2 + (public_key[curve->
bytes * 2 - 1] & 0x01);
568PT_THREAD(ecc_decompress_public_key(
const uint8_t *compressed_public_key,
569 uint8_t *uncompressed_public_key,
572 static const uintptr_t public_key_x_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));
581 static uint8_t compression_info;
587 compression_info = compressed_public_key[0];
588 element_to_pka_ram(compressed_public_key + 1, public_key_x_offset);
679 != (compression_info & 0x01)) {
682 subtract(curve_prime_offset, mod_sqrt_offset, mod_sqrt_offset));
685 element_from_pka_ram(uncompressed_public_key, public_key_x_offset);
686 element_from_pka_ram(uncompressed_public_key + curve->
bytes,
690 PT_END(&main_protothread);
693PT_THREAD(ecc_sign(
const uint8_t *message_hash,
694 const uint8_t *private_key,
698 static const uintptr_t e_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);
709 uint8_t k[MAX_ELEMENT_BYTES];
714 element_to_pka_ram(private_key, d_offset);
715 element_to_pka_ram(message_hash, e_offset);
720 reduce_to_element(e_offset, result));
722 LOG_ERR(
"Line: %u Error: %u\n", __LINE__, *result);
729 LOG_ERR(
"CSPRNG error\n");
733 element_to_pka_ram(k, k_offset);
736 check_bounds(k_offset,
741 LOG_WARN(
"k was not in [1, n-1]\n");
748 add_or_multiply_point(PKA_FUNCTION_ECCMUL,
753 if(*result == PKA_STATUS_POINT_AT_INFINITY) {
754 LOG_WARN(
"k x G is at infinity\n");
758 LOG_ERR(
"Line: %u Error: %u\n", __LINE__, *result);
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");
781 LOG_WARN(
"rd mod n was zero\n");
785 LOG_ERR(
"Line: %u Error: %u\n", __LINE__, *result);
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");
808 LOG_WARN(
"e + rd mod n was zero\n");
812 LOG_ERR(
"Line: %u Error: %u\n", __LINE__, *result);
819 invert_modulo(k_offset, curve_n_offset, k_offset, result));
821 LOG_WARN(
"inverse of k was zero\n");
825 LOG_ERR(
"Line: %u Error: %u\n", __LINE__, *result);
839 LOG_WARN(
"s is zero\n");
843 LOG_ERR(
"Line: %u Error: %u\n", __LINE__, *result);
849 element_from_pka_ram(signature, r_offset);
850 element_from_pka_ram(signature + curve->
bytes, s_offset);
853 PT_END(&main_protothread);
856PT_THREAD(ecc_verify(
const uint8_t *signature,
857 const uint8_t *message_hash,
858 const uint8_t *public_key,
861 static const uintptr_t e_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);
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);
892 reduce_to_element(e_offset, result));
894 LOG_ERR(
"Line: %u Error: %u\n", __LINE__, *result);
901 check_bounds(r_offset,
906 LOG_ERR(
"Line: %u Error: %u\n", __LINE__, *result);
913 check_bounds(s_offset,
918 LOG_ERR(
"Line: %u Error: %u\n", __LINE__, *result);
925 invert_modulo(s_offset, curve_n_offset, s_offset, result));
927 LOG_ERR(
"Line: %u Error: %u\n", __LINE__, *result);
941 LOG_ERR(
"Line: %u Error: %u\n", __LINE__, *result);
948 add_or_multiply_point(PKA_FUNCTION_ECCMUL,
954 LOG_ERR(
"Line: %u Error: %u\n", __LINE__, *result);
968 LOG_ERR(
"Line: %u Error: %u\n", __LINE__, *result);
975 add_or_multiply_point(PKA_FUNCTION_ECCMUL,
981 LOG_ERR(
"Line: %u Error: %u\n", __LINE__, *result);
988 add_or_multiply_point(PKA_FUNCTION_ECCADD,
994 LOG_ERR(
"Line: %u Error: %u\n", __LINE__, *result);
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);
1008 PT_END(&main_protothread);
1011PT_THREAD(ecc_generate_key_pair(uint8_t *public_key,
1012 uint8_t *private_key,
1015 static const uintptr_t private_key_offset =
1017 static const uintptr_t public_key_offset =
1018 PKA_NEXT_OFFSET(private_key_offset, MAX_ELEMENT_WORDS);
1026 LOG_ERR(
"CSPRNG error\n");
1030 element_to_pka_ram(private_key, private_key_offset);
1032 &helper_protothread,
1033 check_bounds(private_key_offset,
1034 element_null_offset,
1038 LOG_WARN(
"private key was not in [1, n-1]\n");
1044 &helper_protothread,
1045 add_or_multiply_point(PKA_FUNCTION_ECCMUL,
1050 if(*result == PKA_SHIFT_POINT_AT_INFINITY) {
1051 LOG_WARN(
"public key at infinity\n");
1055 LOG_ERR(
"Line: %u Error: %u\n", __LINE__, *result);
1061 element_from_pka_ram(private_key, private_key_offset);
1062 point_from_pka_ram(public_key, public_key_offset);
1064 PT_END(&main_protothread);
1067PT_THREAD(ecc_generate_shared_secret(
const uint8_t *public_key,
1068 const uint8_t *private_key,
1069 uint8_t *shared_secret,
1072 static const uintptr_t private_key_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);
1083 element_to_pka_ram(private_key, private_key_offset);
1084 point_to_pka_ram(public_key, public_key_offset);
1088 &helper_protothread,
1089 add_or_multiply_point(PKA_FUNCTION_ECCMUL,
1095 LOG_ERR(
"Line: %u Error: %u\n", __LINE__, *result);
1098 element_from_pka_ram(shared_secret, product_offset);
1101 PT_END(&main_protothread);
An OFB-AES-128-based CSPRNG.
#define PKA_CPTR
PKA vector C address During execution of basic PKCP operations, this register is double buffered and ...
uint32_t pka_word_from_pka_ram(uintptr_t offset)
Retrieves a word from the PKA RAM.
void pka_run_function(uint32_t function)
Initiates the given PKA function.
#define PKA_FUNCTION_ADD
Perform add operation.
#define PKA_STATUS_A_LT_B
Big number compare return status if the first big num is less than the second.
#define PKA_COMPARE_A_LESS_THAN_B
Vector_A is less than Vector_B.
#define PKA_DPTR
PKA vector D address During execution of basic PKCP operations, this register is double buffered and ...
static bool test_bit(const uint32_t *element, size_t bit)
Tells if a bit in a little-endian element is set.
#define PKA_STATUS_A_GR_B
Big number compare return status if the first big num is greater than the second.
#define PKA_FUNCTION_MULTIPLY
Perform multiply operation.
#define PKA_MSW
PKA most-significant-word of result vector This register indicates the (word) address in the PKA RAM ...
#define PKA_FUNCTION_COMPARE
Perform compare operation.
#define PKA_MSW_MSW_ADDRESS_M
Address of the most-significant nonzero 32-bit word of the result vector in PKA RAM.
#define PKA_BLENGTH
PKA vector B length During execution of basic PKCP operations, this register is double buffered and c...
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.
#define PKA_ALENGTH
PKA vector A length During execution of basic PKCP operations, this register is double buffered and c...
#define PKA_APTR
PKA vector A address During execution of basic PKCP operations, this register is double buffered and ...
void pka_disable(void)
Disables the PKA engine.
#define PKA_FUNCTION_RSHIFT
Perform right shift operation.
void pka_init(void)
Enables and resets the PKA engine.
void pka_enable(void)
Enables the PKA engine.
#define PKA_FUNCTION_COPY
Perform copy operation.
#define PKA_STATUS_FAILURE
Failure.
#define PKA_FUNCTION_MODULO
Perform modulo operation.
#define PKA_COMPARE
PKA compare result This register provides the result of a basic PKCP compare operation.
#define PKA_COMPARE_A_GREATER_THAN_B
Vector_A is greater than Vector_B.
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.
#define PKA_MSW_RESULT_IS_ZERO
The result vector is all zeroes, ignore the address returned in bits [10:0].
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.
#define PKA_STATUS_RESULT_0
Result is all zeros.
#define PKA_COORDINATE_WORDS(len)
Table 22-21.
#define PKA_BPTR
PKA vector B address During execution of basic PKCP operations, this register is double buffered and ...
#define PKA_FUNCTION_SUBTRACT
Perform subtract operation.
#define PKA_SHIFT
PKA bit shift value For basic PKCP operations, modifying the contents of this register is made imposs...
#define PKA_STATUS_SUCCESS
Success.
bool pka_check_status(void)
Checks the status of the PKA engine operation.
bool csprng_rand(uint8_t *result, size_t len)
Generates a cryptographic random number.
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.
#define PT_THREAD(name_args)
Declaration of a protothread.
#define PT_END(pt)
Declare the end of a protothread.
#define PT_EXIT(pt)
Exit the protothread.
#define PT_SPAWN(pt, child, thread)
Spawn a child protothread and wait until it exits.
#define PT_YIELD_UNTIL(pt, cond)
Yield from the protothread until a condition occurs.
Header file for the logging system.
Header file for the cc2538 PKA engine driver.
Parameters of an ECC curve in little-endian word order.
const size_t words
Size of the curve in 32-bit words.
const uint32_t * b
Coefficient b of the equation.
const size_t binary_length_of_p_plus_one
Length of the binary representation of p + 1.
const uint32_t * x
x coordinate of the generator point.
const uint32_t * p
The prime that defines the field of the curve.
const uint32_t * y
y coordinate of the generator point.
const size_t binary_length_of_n
Length of the binary representation of n.
const uint32_t * n
Order of the curve.
const size_t bytes
Size of the curve in bytes.
const uint32_t * a
Coefficient a of the equation.
const uint32_t * p_plus_one
Precomputed value of p + 1.
Structure of a process mutex.