-
Notifications
You must be signed in to change notification settings - Fork 6
/
p256-cortex-m4.h
254 lines (229 loc) · 11.5 KB
/
p256-cortex-m4.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
/*
* Copyright (c) 2017-2021 Emil Lenngren
* Copyright (c) 2021 Shortcut Labs AB
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef P256_CORTEX_M4_H
#define P256_CORTEX_M4_H
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include "p256-cortex-m4-config.h"
/*
Implementation of P-256 Elliptic Curve operations for 32-bit ARMv7E-M processors or later.
The functions below have the following conventions:
- Arrays of type uint32_t represent 256-bit integers, stored using little endian byte order on a 4-byte alignment.
- Pointer/array parameters are input parameters when they are const and output parameters when they are not
const, unless otherwise stated.
- All functions that take a public key as parameter will validate that the public key corresponds to a valid
point and return false if validation fails.
- When a function returns false, the output parameters, if any, will not contain valid data and should hence
not be inspected.
- There are no checks for null pointers, unaligned uint32_t-pointers, invalid private keys etc.
If there is a need to convert a big endian byte string to an array of little endian uint32_t integers or vice
versa, the p256_convert_endianness function may be used for this purpose.
Note: code that processes secret data runs in constant time, in order to mitigate side channel attacks.
*/
/**
* Converts endianness by reversing the input value.
*
* The output and input pointers may refer to the same location and have no alignment requirements.
*/
void p256_convert_endianness(void* output, const void* input, size_t byte_len);
#if include_p256_verify
/**
* Verifies an ECDSA signature.
*
* Returns true if the signature is valid for the given input, otherwise false.
*/
bool p256_verify(const uint32_t public_key_x[8], const uint32_t public_key_y[8],
const uint8_t* hash, uint32_t hashlen_in_bytes,
const uint32_t r[8], const uint32_t s[8])
__attribute__((warn_unused_result));
#endif
#if include_p256_sign
/**
* Creates an ECDSA signature.
*
* The parameter "k" shall consist of a 256-bit random integer value. This random value MUST be generated from
* a cryptographically secure random number generator, and MUST be unique for every pair of message hash and
* private key.
*
* With a small probability (~ 2^-32), this function will fail and return false for the given "k" and this
* function MUST in that case be called again with a new random "k", until true is returned. This is in line
* with the ECDSA standard.
*
* As an alternative to using a random "k", "k" might be derived deterministically from the input, using a
* sophisticated hash construction such as RFC 6979, or e.g. by hashing the private key, message hash and a
* retry counter, using a secure hash function such as SHA-256.
*/
bool p256_sign(uint32_t r[8], uint32_t s[8],
const uint8_t* hash, uint32_t hashlen_in_bytes,
const uint32_t private_key[8], const uint32_t k[8])
__attribute__((warn_unused_result));
/**
* Sign precomputation state.
*
* The content shall be treated as opaque to the API user and shall not be inspected or modified.
*/
struct SignPrecomp {
uint32_t r[8];
uint32_t k_inv[8];
};
/**
* Creates an ECDSA signature, using a two-step procedure.
*
* This function performs the first of two steps, and accounts for 99% of the time spent for generating an
* ECDSA signature.
*
* By splitting up into two steps, most of the work could be spent before deciding what message to sign, or
* which private key to use.
*
* The parameter "k" shall consist of a 256-bit random integer value. This random value MUST be generated from
* a cryptographically secure random number generator, and MUST be unique for every pair of message hash and
* private key.
*
* With a small probability (~ 2^-32), this function will fail and return false for the given "k" and this
* function MUST in that case be called again with a new random "k", until true is returned. This is in line
* with the ECDSA standard.
*
* As an alternative to using a random "k", "k" might be derived deterministically from the input, using a
* sophisticated hash construction such as RFC 6979, or e.g. by hashing the private key, message hash and a
* retry counter, using a secure hash function such as SHA-256.
*
* The "result" parameter will contain the computed state, that is later to be passed to p256_sign_step2.
* A result state MUST NOT be reused for generating multiple signatures.
*/
bool p256_sign_step1(struct SignPrecomp *result, const uint32_t k[8]) __attribute__((warn_unused_result));
/**
* Second step of creating an ECDSA signature, using a two-step procedure.
*
* This function performs the second of two steps, and accounts for the last 1% of the time spent for generating
* an ECDSA signature.
*
* The "sign_precomp" parameter shall contain a pointer to a state generated by p256_sign_step1.
*
* With a small probability (~ 2^-256), this function will fail, due to the given "k" from the first step is
* not compatible with the rest of the input, and return false. In this case, the procedure MUST be started
* over from step 1 with a new random "k". This is in line with the ECDSA standard. Otherwise true is returned
* and the signature is placed in "r" and "s".
*
* When this function returns, "sign_precomp" is also zeroed out and may hence not be reused.
*/
bool p256_sign_step2(uint32_t r[8], uint32_t s[8], const uint8_t* hash, uint32_t hashlen_in_bytes,
const uint32_t private_key[8], struct SignPrecomp *sign_precomp)
__attribute__((warn_unused_result));
#endif
#if include_p256_keygen
/**
* Calculates the public key from a given private key for use by either ECDSA or ECDH.
*
* The private key shall be taken from a random value that MUST have been generated by a cryptographically
* secure random number generator that generates 256 random bits. This function validates that the private key
* lies in the accepted range 1 to n-1, where n is the order of the elliptic curve, and returns true only if
* this validation succeeds. If random value is out of that range, false is returned and in this case a new
* random value needs to be generated and this function MUST be called again until true is returned.
*
* The public key is created by performing a scalar multiplication of the private key and the base point of
* the curve.
*
* Only use a keypair for either ECDSA or ECDH, not both, and don't use the private key for any other purposes.
*/
bool p256_keygen(uint32_t public_key_x[8], uint32_t public_key_y[8],
const uint32_t private_key[8])
__attribute__((warn_unused_result));
#endif
#if include_p256_ecdh
/**
* Generates the shared secret according to the ECDH standard.
*
* The shared secret parameter will contain the big endian encoding for the x coordinate of the scalar
* multiplication of the private key and the input point (other's public key), if the function succeeds.
*
* If the other's public key point does not lie on the curve, this function fails and false is returned.
* Otherwise, shared secret is calculated and true is returned.
*
* NOTE: The return value MUST be checked since the other's public key point cannot generally be trusted.
*/
bool p256_ecdh_calc_shared_secret(uint8_t shared_secret[32], const uint32_t private_key[8],
const uint32_t others_public_key_x[8], const uint32_t others_public_key_y[8])
__attribute__((warn_unused_result));
#endif
#if include_p256_raw_scalarmult_base
/**
* Raw scalar multiplication by the base point of the elliptic curve.
*
* This function can be used to implement custom algorithms using the P-256 curve.
*
* This function validates that the scalar lies in the accepted range 1 to n-1, where n is the order of the
* elliptic curve, and returns true only if this validation succeeds. Otherwise false is returned.
*/
bool p256_scalarmult_base(uint32_t result_x[8], uint32_t result_y[8], const uint32_t scalar[8]);
#endif
#if include_p256_raw_scalarmult_generic
/**
* Raw scalar multiplication by any point on the elliptic curve.
*
* This function can be used to implement custom algorithms using the P-256 curve.
*
* This function validates all inputs and proceeds only if the scalar is within the range 1 to n-1, where n
* is the order of the elliptic curve, and the input point's coordinates are each less than the order of
* the prime field. If validation succeeds, true is returned. Otherwise false is returned.
*/
bool p256_scalarmult_generic(uint32_t result_x[8], uint32_t result_y[8],
const uint32_t scalar[8], const uint32_t in_x[8], const uint32_t in_y[8]);
#endif
// These functions create a big endian octet string representation of a point according to the X.92 standard.
#if include_p256_to_octet_string_uncompressed
/**
* Uncompressed encoding: "04 || Px || Py".
*/
void p256_point_to_octet_string_uncompressed(uint8_t out[65], const uint32_t x[8], const uint32_t y[8]);
#endif
#if include_p256_to_octet_string_compressed
/**
* Compressed encoding: "02 || Px" if Py is even and "03 || Px" if Py is odd.
*/
void p256_point_to_octet_string_compressed(uint8_t out[33], const uint32_t x[8], const uint32_t y[8]);
#endif
#if include_p256_to_octet_string_hybrid
/**
* Hybrid encoding: "06 || Px || Py" if Py is even and "07 || Px || Py" if Py is odd (a pretty useless encoding).
*/
void p256_point_to_octet_string_hybrid(uint8_t out[65], const uint32_t x[8], const uint32_t y[8]);
#endif
#if include_p256_decode_point || include_p256_decompress_point
/**
* Decodes a point according to the three encodings above.
*
* include_p256_decode_point: first byte is "04", "06" or "07" and input length is 65 bytes
* include_p256_decompress_point: first byte is "02" or "03" and input length is 33 bytes
*
* Returns true if the input string confirms to a valid encoding and the point lies on the curve,
* otherwise false.
*
* NOTE: The return value MUST be checked in case the point is not guaranteed to lie on the curve (e.g. if it
* is received from an untrusted party).
*/
bool p256_octet_string_to_point(uint32_t x[8], uint32_t y[8],
const uint8_t* input, uint32_t input_len_in_bytes)
__attribute__((warn_unused_result));
#endif
#endif