initial commit

This commit is contained in:
2022-10-23 23:45:43 -07:00
commit e190fa5193
6450 changed files with 8626944 additions and 0 deletions
@@ -0,0 +1,208 @@
micro-ecc
==========
A small and fast ECDH and ECDSA implementation for 8-bit, 32-bit, and 64-bit processors.
The old version of micro-ecc can be found in the "old" branch.
Features
--------
* Resistant to known side-channel attacks.
* Written in C, with optional GCC inline assembly for AVR, ARM and Thumb platforms.
* Supports 8, 32, and 64-bit architectures.
* Small code size.
* No dynamic memory allocation.
* Support for 4 standard curves: secp160r1, secp192r1, secp256r1, and secp256k1.
* BSD 2-clause license.
Usage Notes
-----------
### Point Representation ###
Compressed points are represented in the standard format as defined in http://www.secg.org/collateral/sec1_final.pdf; uncompressed points are represented in standard format, but without the `0x04` prefix. `uECC_make_key()`, `uECC_shared_secret()`, `uECC_sign()`, and `uECC_verify()` only handle uncompressed points; you can use `uECC_compress()` and `uECC_decompress()` to convert between compressed and uncompressed point representations.
Private keys are represented in the standard format.
### Using the Code ###
I recommend just copying (or symlink) uECC.h, uECC.c, and the appropriate asm\_<arch>\_.inc (if any) into your project. Then just `#include "uECC.h"` to use the micro-ecc functions.
For use with Arduino, you can just create a symlink to the `uECC` directory in your Arduino `libraries` directory. You can then use uECC just like any other Arduino library (uECC should show up in the **Sketch**=>**Import Library** submenu).
See uECC.h for documentation for each function.
### Compilation Notes ###
* Should compile with any C/C++ compiler that supports stdint.h (this includes Visual Studio 2013).
* If you want to change the defaults for `uECC_CURVE` and `uECC_ASM`, you must change them in your Makefile or similar so that uECC.c is compiled with the desired values (ie, compile uECC.c with `-DuECC_CURVE=uECC_secp256r1` or whatever).
* When compiling for a Thumb-1 platform with inline assembly enabled (ie, `uECC_ASM` is defined to `uECC_asm_small` or `uECC_asm_fast`), you must use the `-fomit-frame-pointer` GCC option (this is enabled by default when compiling with `-O1` or higher).
* When compiling for an ARM/Thumb-2 platform with fast inline assembly enabled (ie, `uECC_ASM` is defined to `uECC_asm_fast`), you must use the `-fomit-frame-pointer` GCC option (this is enabled by default when compiling with `-O1` or higher).
* When compiling for AVR with inline assembly enabled, you must have optimizations enabled (compile with `-O1` or higher).
* When building for Windows, you will need to link in the `advapi32.lib` system library.
ARM Performance
---------------
All tests were built using gcc 4.8.2 with `-O3`, and were run on a Raspberry Pi B+. `uECC_ASM` was defined to `uECC_asm_fast` and `ECC_SQUARE_FUNC` was defined to `1` in all cases. All times are in milliseconds.
<table>
<tr>
<th></th>
<th>secp160r1</th>
<th>secp192r1</th>
<th>secp256r1</th>
<th>secp256k1</th>
</tr>
<tr>
<td><em>ECDH:</em></td>
<td>2.3</td>
<td>2.7</td>
<td>7.9</td>
<td>6.5</td>
</tr>
<tr>
<td><em>ECDSA sign:</em></td>
<td>2.8</td>
<td>3.1</td>
<td>8.6</td>
<td>7.2</td>
</tr>
<tr>
<td><em>ECDSA verify:</em></td>
<td>2.7</td>
<td>3.2</td>
<td>9.2</td>
<td>7.0</td>
</tr>
</table>
AVR Performance
---------------
All tests were built using avr-gcc 4.8.1 with `-Os`, and were run on a 16 MHz ATmega256RFR2. Code size refers to the space used by micro-ecc code and data.
#### ECDH (fast) ####
In these tests, `uECC_ASM` was defined to `uECC_asm_fast` and `ECC_SQUARE_FUNC` was defined to `1` in all cases.
<table>
<tr>
<th></th>
<th>secp160r1</th>
<th>secp192r1</th>
<th>secp256r1</th>
<th>secp256k1</th>
</tr>
<tr>
<td><em>ECDH time (ms):</em></td>
<td>470</td>
<td>810</td>
<td>2220</td>
<td>1615</td>
</tr>
<tr>
<td><em>Code size (bytes):</em></td>
<td>10768</td>
<td>13112</td>
<td>20886</td>
<td>21126</td>
</tr>
</table>
#### ECDH (small) ####
In these tests, `uECC_ASM` was defined to `uECC_asm_small` and `ECC_SQUARE_FUNC` was defined to `0` in all cases.
<table>
<tr>
<th></th>
<th>secp160r1</th>
<th>secp192r1</th>
<th>secp256r1</th>
<th>secp256k1</th>
</tr>
<tr>
<td><em>ECDH time (ms):</em></td>
<td>1250</td>
<td>1810</td>
<td>4790</td>
<td>4700</td>
</tr>
<tr>
<td><em>Code size (bytes):</em></td>
<td>3244</td>
<td>3400</td>
<td>5274</td>
<td>3426</td>
</tr>
</table>
#### ECDSA (fast) ####
In these tests, `uECC_ASM` was defined to `uECC_asm_fast` and `ECC_SQUARE_FUNC` was defined to `1` in all cases.
<table>
<tr>
<th></th>
<th>secp160r1</th>
<th>secp192r1</th>
<th>secp256r1</th>
<th>secp256k1</th>
</tr>
<tr>
<td><em>ECDSA sign time (ms):</em></td>
<td>555</td>
<td>902</td>
<td>2386</td>
<td>1773</td>
</tr>
<tr>
<td><em>ECDSA verify time (ms):</em></td>
<td>590</td>
<td>990</td>
<td>2650</td>
<td>1800</td>
</tr>
<tr>
<td><em>Code size (bytes):</em></td>
<td>13246</td>
<td>14798</td>
<td>22594</td>
<td>22826</td>
</tr>
</table>
#### ECDSA (small) ####
In these tests, `uECC_ASM` was defined to `uECC_asm_small` and `ECC_SQUARE_FUNC` was defined to `0` in all cases.
<table>
<tr>
<th></th>
<th>secp160r1</th>
<th>secp192r1</th>
<th>secp256r1</th>
<th>secp256k1</th>
</tr>
<tr>
<td><em>ECDSA sign time (ms):</em></td>
<td>1359</td>
<td>1931</td>
<td>4998</td>
<td>4904</td>
</tr>
<tr>
<td><em>ECDSA verify time (ms):</em></td>
<td>1515</td>
<td>2160</td>
<td>5700</td>
<td>5220</td>
</tr>
<tr>
<td><em>Code size (bytes):</em></td>
<td>5690</td>
<td>5054</td>
<td>6980</td>
<td>5080</td>
</tr>
</table>
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,21 @@
Copyright (c) 2014, Kenneth MacKay
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
File diff suppressed because it is too large Load Diff
+301
View File
@@ -0,0 +1,301 @@
/* Copyright 2014, Kenneth MacKay. Licensed under the BSD 2-clause license. */
#ifndef _MICRO_ECC_H_
#define _MICRO_ECC_H_
#include "wsf_types.h"
/* Platform selection options.
If uECC_PLATFORM is not defined, the code will try to guess it based on compiler macros.
Possible values for uECC_PLATFORM are defined below: */
#define uECC_arch_other 0
#define uECC_x86 1
#define uECC_x86_64 2
#define uECC_arm 3
#define uECC_arm_thumb 4
#define uECC_avr 5
#define uECC_arm_thumb2 6
/* If desired, you can define uECC_WORD_SIZE as appropriate for your platform (1, 4, or 8 bytes).
If uECC_WORD_SIZE is not explicitly defined then it will be automatically set based on your
platform. */
/* Inline assembly options.
uECC_asm_none - Use standard C99 only.
uECC_asm_small - Use GCC inline assembly for the target platform (if available), optimized for
minimum size.
uECC_asm_fast - Use GCC inline assembly optimized for maximum speed. */
#define uECC_asm_none 0
#define uECC_asm_small 1
#define uECC_asm_fast 2
#ifndef uECC_ASM
#define uECC_ASM uECC_asm_fast
#endif
/* Curve selection options. */
#define uECC_secp160r1 1
#define uECC_secp192r1 2
#define uECC_secp256r1 3
#define uECC_secp256k1 4
#define uECC_secp224r1 5
#ifndef uECC_CURVE
#define uECC_CURVE uECC_secp256r1
#endif
/* uECC_SQUARE_FUNC - If enabled (defined as nonzero), this will cause a specific function to be
used for (scalar) squaring instead of the generic multiplication function. This will make things
faster by about 8% but increases the code size. */
#ifndef uECC_SQUARE_FUNC
#define uECC_SQUARE_FUNC 1
#endif
#define uECC_CONCAT1(a, b) a##b
#define uECC_CONCAT(a, b) uECC_CONCAT1(a, b)
#define uECC_size_1 20 /* secp160r1 */
#define uECC_size_2 24 /* secp192r1 */
#define uECC_size_3 32 /* secp256r1 */
#define uECC_size_4 32 /* secp256k1 */
#define uECC_size_5 28 /* secp224r1 */
#define uECC_BYTES uECC_CONCAT(uECC_size_, uECC_CURVE)
#ifdef __cplusplus
extern "C"
{
#endif
/* uECC_RNG_Function type
The RNG function should fill 'size' random bytes into 'dest'. It should return 1 if
'dest' was filled with random data, or 0 if the random data could not be generated.
The filled-in values should be either truly random, or from a cryptographically-secure PRNG.
A correctly functioning RNG function must be set (using uECC_set_rng()) before calling
uECC_make_key() or uECC_sign().
Setting a correctly functioning RNG function improves the resistance to side-channel attacks
for uECC_shared_secret() and uECC_sign_deterministic().
A correct RNG function is set by default when building for Windows, Linux, or OS X.
If you are building on another POSIX-compliant system that supports /dev/random or /dev/urandom,
you can define uECC_POSIX to use the predefined RNG. For embedded platforms there is no predefined
RNG function; you must provide your own.
*/
typedef int (*uECC_RNG_Function)(uint8_t *dest, unsigned size);
/* uECC_set_rng() function.
Set the function that will be used to generate random bytes. The RNG function should
return 1 if the random data was generated, or 0 if the random data could not be generated.
On platforms where there is no predefined RNG function (eg embedded platforms), this must
be called before uECC_make_key() or uECC_sign() are used.
Inputs:
rng_function - The function that will be used to generate random bytes.
*/
void uECC_set_rng(uECC_RNG_Function rng_function);
/* uECC_make_key() function.
Create a public/private key pair.
Outputs:
public_key - Will be filled in with the public key.
private_key - Will be filled in with the private key.
Returns 1 if the key pair was generated successfully, 0 if an error occurred.
*/
int uECC_make_key(uint8_t public_key[uECC_BYTES*2], uint8_t private_key[uECC_BYTES]);
/* uECC_shared_secret() function.
Compute a shared secret given your secret key and someone else's public key.
Note: It is recommended that you hash the result of uECC_shared_secret() before using it for
symmetric encryption or HMAC.
Inputs:
public_key - The public key of the remote party.
private_key - Your private key.
Outputs:
secret - Will be filled in with the shared secret value.
Returns 1 if the shared secret was generated successfully, 0 if an error occurred.
*/
int uECC_shared_secret(const uint8_t public_key[uECC_BYTES*2],
const uint8_t private_key[uECC_BYTES],
uint8_t secret[uECC_BYTES]);
/* uECC_sign() function.
Generate an ECDSA signature for a given hash value.
Usage: Compute a hash of the data you wish to sign (SHA-2 is recommended) and pass it in to
this function along with your private key.
Inputs:
private_key - Your private key.
message_hash - The hash of the message to sign.
Outputs:
signature - Will be filled in with the signature value.
Returns 1 if the signature generated successfully, 0 if an error occurred.
*/
int uECC_sign(const uint8_t private_key[uECC_BYTES],
const uint8_t message_hash[uECC_BYTES],
uint8_t signature[uECC_BYTES*2]);
/* uECC_HashContext structure.
This is used to pass in an arbitrary hash function to uECC_sign_deterministic().
The structure will be used for multiple hash computations; each time a new hash
is computed, init_hash() will be called, followed by one or more calls to
update_hash(), and finally a call to finish_hash() to prudoce the resulting hash.
The intention is that you will create a structure that includes uECC_HashContext
followed by any hash-specific data. For example:
typedef struct SHA256_HashContext {
uECC_HashContext uECC;
SHA256_CTX ctx;
} SHA256_HashContext;
void init_SHA256(uECC_HashContext *base) {
SHA256_HashContext *context = (SHA256_HashContext *)base;
SHA256_Init(&context->ctx);
}
void update_SHA256(uECC_HashContext *base,
const uint8_t *message,
unsigned message_size) {
SHA256_HashContext *context = (SHA256_HashContext *)base;
SHA256_Update(&context->ctx, message, message_size);
}
void finish_SHA256(uECC_HashContext *base, uint8_t *hash_result) {
SHA256_HashContext *context = (SHA256_HashContext *)base;
SHA256_Final(hash_result, &context->ctx);
}
... when signing ...
{
uint8_t tmp[32 + 32 + 64];
SHA256_HashContext ctx = {{&init_SHA256, &update_SHA256, &finish_SHA256, 64, 32, tmp}};
uECC_sign_deterministic(key, message_hash, &ctx.uECC, signature);
}
*/
typedef struct uECC_HashContext {
void (*init_hash)(struct uECC_HashContext *context);
void (*update_hash)(struct uECC_HashContext *context,
const uint8_t *message,
unsigned message_size);
void (*finish_hash)(struct uECC_HashContext *context, uint8_t *hash_result);
unsigned block_size; /* Hash function block size in bytes, eg 64 for SHA-256. */
unsigned result_size; /* Hash function result size in bytes, eg 32 for SHA-256. */
uint8_t *tmp; /* Must point to a buffer of at least (2 * result_size + block_size) bytes. */
} uECC_HashContext;
/* uECC_sign_deterministic() function.
Generate an ECDSA signature for a given hash value, using a deterministic algorithm
(see RFC 6979). You do not need to set the RNG using uECC_set_rng() before calling
this function; however, if the RNG is defined it will improve resistance to side-channel
attacks.
Usage: Compute a hash of the data you wish to sign (SHA-2 is recommended) and pass it in to
this function along with your private key and a hash context.
Inputs:
private_key - Your private key.
message_hash - The hash of the message to sign.
hash_context - A hash context to use.
Outputs:
signature - Will be filled in with the signature value.
Returns 1 if the signature generated successfully, 0 if an error occurred.
*/
int uECC_sign_deterministic(const uint8_t private_key[uECC_BYTES],
const uint8_t message_hash[uECC_BYTES],
uECC_HashContext *hash_context,
uint8_t signature[uECC_BYTES*2]);
/* uECC_verify() function.
Verify an ECDSA signature.
Usage: Compute the hash of the signed data using the same hash as the signer and
pass it to this function along with the signer's public key and the signature values (r and s).
Inputs:
public_key - The signer's public key
hash - The hash of the signed data.
signature - The signature value.
Returns 1 if the signature is valid, 0 if it is invalid.
*/
int uECC_verify(const uint8_t private_key[uECC_BYTES*2],
const uint8_t hash[uECC_BYTES],
const uint8_t signature[uECC_BYTES*2]);
/* uECC_compress() function.
Compress a public key.
Inputs:
public_key - The public key to compress.
Outputs:
compressed - Will be filled in with the compressed public key.
*/
void uECC_compress(const uint8_t public_key[uECC_BYTES*2], uint8_t compressed[uECC_BYTES+1]);
/* uECC_decompress() function.
Decompress a compressed public key.
Inputs:
compressed - The compressed public key.
Outputs:
public_key - Will be filled in with the decompressed public key.
*/
void uECC_decompress(const uint8_t compressed[uECC_BYTES+1], uint8_t public_key[uECC_BYTES*2]);
/* uECC_valid_public_key() function.
Check to see if a public key is valid.
Note that you are not required to check for a valid public key before using any other uECC
functions. However, you may wish to avoid spending CPU time computing a shared secret or
verifying a signature using an invalid public key.
Inputs:
public_key - The public key to check.
Returns 1 if the public key is valid, 0 if it is invalid.
*/
int uECC_valid_public_key(const uint8_t public_key[uECC_BYTES*2]);
/* uECC_compute_public_key() function.
Compute the corresponding public key for a private key.
Inputs:
private_key - The private key to compute the public key for
Outputs:
public_key - Will be filled in with the corresponding public key
Returns 1 if the key was computed successfully, 0 if an error occurred.
*/
int uECC_compute_public_key(const uint8_t private_key[uECC_BYTES],
uint8_t public_key[uECC_BYTES * 2]);
/* uECC_bytes() function.
Returns the value of uECC_BYTES. Helpful for foreign-interfaces to higher-level languages.
*/
int uECC_bytes(void);
/* uECC_curve() function.
Returns the value of uECC_CURVE. Helpful for foreign-interfaces to higher-level languages.
*/
int uECC_curve(void);
#ifdef __cplusplus
} /* end of extern "C" */
#endif
#endif /* _MICRO_ECC_H_ */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,148 @@
/* Copyright 2014, Kenneth MacKay. Licensed under the BSD 2-clause license. */
#ifndef _MICRO_ECC_LL_H_
#define _MICRO_ECC_LL_H_
#include "wsf_types.h"
/* Platform selection options.
If uECC_PLATFORM is not defined, the code will try to guess it based on compiler macros.
Possible values for uECC_PLATFORM are defined below: */
#define uECC_arch_other 0
#define uECC_x86 1
#define uECC_x86_64 2
#define uECC_arm 3
#define uECC_arm_thumb 4
#define uECC_avr 5
#define uECC_arm_thumb2 6
/* If desired, you can define uECC_WORD_SIZE as appropriate for your platform (1, 4, or 8 bytes).
If uECC_WORD_SIZE is not explicitly defined then it will be automatically set based on your
platform. */
/* Inline assembly options.
uECC_asm_none - Use standard C99 only.
uECC_asm_small - Use GCC inline assembly for the target platform (if available), optimized for
minimum size.
uECC_asm_fast - Use GCC inline assembly optimized for maximum speed. */
#define uECC_asm_none 0
#define uECC_asm_small 1
#define uECC_asm_fast 2
#ifndef uECC_ASM
#define uECC_ASM uECC_asm_fast
#endif
/* Curve selection options. */
#define uECC_secp160r1 1
#define uECC_secp192r1 2
#define uECC_secp256r1 3
#define uECC_secp256k1 4
#define uECC_secp224r1 5
#ifndef uECC_CURVE
#define uECC_CURVE uECC_secp256r1
#endif
/* uECC_SQUARE_FUNC - If enabled (defined as nonzero), this will cause a specific function to be
used for (scalar) squaring instead of the generic multiplication function. This will make things
faster by about 8% but increases the code size. */
#ifndef uECC_SQUARE_FUNC
#define uECC_SQUARE_FUNC 1
#endif
#define uECC_CONCAT1(a, b) a##b
#define uECC_CONCAT(a, b) uECC_CONCAT1(a, b)
#define uECC_size_1 20 /* secp160r1 */
#define uECC_size_2 24 /* secp192r1 */
#define uECC_size_3 32 /* secp256r1 */
#define uECC_size_4 32 /* secp256k1 */
#define uECC_size_5 28 /* secp224r1 */
#define uECC_BYTES uECC_CONCAT(uECC_size_, uECC_CURVE)
#ifdef __cplusplus
extern "C"
{
#endif
/* uECC_RNG_Function type
The RNG function should fill 'size' random bytes into 'dest'. It should return 1 if
'dest' was filled with random data, or 0 if the random data could not be generated.
The filled-in values should be either truly random, or from a cryptographically-secure PRNG.
A correctly functioning RNG function must be set (using uECC_set_rng()) before calling
uECC_make_key() or uECC_sign().
Setting a correctly functioning RNG function improves the resistance to side-channel attacks
for uECC_shared_secret() and uECC_sign_deterministic().
A correct RNG function is set by default when building for Windows, Linux, or OS X.
If you are building on another POSIX-compliant system that supports /dev/random or /dev/urandom,
you can define uECC_POSIX to use the predefined RNG. For embedded platforms there is no predefined
RNG function; you must provide your own.
*/
typedef int (*uECC_RNG_Function)(uint8_t *dest, unsigned size);
/* uECC_set_rng() function.
Set the function that will be used to generate random bytes. The RNG function should
return 1 if the random data was generated, or 0 if the random data could not be generated.
On platforms where there is no predefined RNG function (eg embedded platforms), this must
be called before uECC_make_key() or uECC_sign() are used.
Inputs:
rng_function - The function that will be used to generate random bytes.
*/
void uECC_set_rng_ll(uECC_RNG_Function rng_function);
/* uECC_make_key() function.
Create a public/private key pair.
Outputs:
public_key - Will be filled in with the public key.
private_key - Will be filled in with the private key.
Returns 1 if the key pair was generated successfully, 0 if an error occurred.
*/
void uECC_make_key_start(const uint8_t private_key[uECC_BYTES]);
int uECC_make_key_continue(void);
void uECC_make_key_complete(uint8_t public_key[uECC_BYTES*2], uint8_t private_key[uECC_BYTES]);
/* uECC_valid_public_key() function.
Check to see if a public key is valid.
Note that you are not required to check for a valid public key before using any other uECC
functions. However, you may wish to avoid spending CPU time computing a shared secret or
verifying a signature using an invalid public key.
Inputs:
public_key - The public key to check.
Returns 1 if the public key is valid, 0 if it is invalid.
*/
int uECC_valid_public_key_ll(const uint8_t public_key[uECC_BYTES*2]);
/* uECC_shared_secret() function.
Compute a shared secret given your secret key and someone else's public key.
Note: It is recommended that you hash the result of uECC_shared_secret() before using it for
symmetric encryption or HMAC.
Inputs:
public_key - The public key of the remote party.
private_key - Your private key.
Outputs:
secret - Will be filled in with the shared secret value.
Returns 1 if the shared secret was generated successfully, 0 if an error occurred.
*/
void uECC_shared_secret_start(const uint8_t public_key[uECC_BYTES*2],
const uint8_t private_key[uECC_BYTES]);
int uECC_shared_secret_continue(void);
void uECC_shared_secret_complete(uint8_t secret[uECC_BYTES]);
#ifdef __cplusplus
} /* end of extern "C" */
#endif
#endif /* _MICRO_ECC_LL_H_ */