add ECDSA verification
This commit is contained in:
parent
748d5953fa
commit
cdbce138b7
6
.project
6
.project
|
@ -5,6 +5,11 @@
|
||||||
<projects>
|
<projects>
|
||||||
</projects>
|
</projects>
|
||||||
<buildSpec>
|
<buildSpec>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.python.pydev.PyDevBuilder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
<buildCommand>
|
<buildCommand>
|
||||||
<name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
|
<name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
|
||||||
<triggers>clean,full,incremental,</triggers>
|
<triggers>clean,full,incremental,</triggers>
|
||||||
|
@ -23,5 +28,6 @@
|
||||||
<nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
|
<nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
|
||||||
<nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
|
<nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
|
||||||
<nature>fr.ac6.mcu.ide.core.MCUProjectNature</nature>
|
<nature>fr.ac6.mcu.ide.core.MCUProjectNature</nature>
|
||||||
|
<nature>org.python.pydev.pythonNature</nature>
|
||||||
</natures>
|
</natures>
|
||||||
</projectDescription>
|
</projectDescription>
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<?eclipse-pydev version="1.0"?><pydev_project>
|
||||||
|
<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
|
||||||
|
<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python interpreter</pydev_property>
|
||||||
|
</pydev_project>
|
|
@ -7,7 +7,7 @@
|
||||||
#define FW_MAGIC 0x46574853
|
#define FW_MAGIC 0x46574853
|
||||||
|
|
||||||
// The constants below define the memory layout documented in the README.md file
|
// The constants below define the memory layout documented in the README.md file
|
||||||
#define BOOTLOADER_SIZE 0x1000
|
#define BOOTLOADER_SIZE 0x2000
|
||||||
#define FIRMWARE_SIZE ((FLASH_BANK_SIZE - BOOTLOADER_SIZE) / 2)
|
#define FIRMWARE_SIZE ((FLASH_BANK_SIZE - BOOTLOADER_SIZE) / 2)
|
||||||
#define FIRMWARE_HEADER_SIZE 0x200
|
#define FIRMWARE_HEADER_SIZE 0x200
|
||||||
#define FIRMWARE_FIRST_PAGE (BOOTLOADER_SIZE / FLASH_PAGE_SIZE)
|
#define FIRMWARE_FIRST_PAGE (BOOTLOADER_SIZE / FLASH_PAGE_SIZE)
|
||||||
|
|
|
@ -0,0 +1,123 @@
|
||||||
|
/* Copyright 2014, Kenneth MacKay. Licensed under the BSD 2-clause license. */
|
||||||
|
|
||||||
|
#ifndef _UECC_H_
|
||||||
|
#define _UECC_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define uECC_ENABLE_VLI_API 0
|
||||||
|
#define uECC_OPTIMIZATION_LEVEL 2
|
||||||
|
#define uECC_SUPPORT_COMPRESSED_POINT 0
|
||||||
|
|
||||||
|
/* 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_arm_thumb2 5
|
||||||
|
#define uECC_arm64 6
|
||||||
|
#define uECC_avr 7
|
||||||
|
|
||||||
|
/* 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. */
|
||||||
|
|
||||||
|
/* Optimization level; trade speed for code size.
|
||||||
|
Larger values produce code that is faster but larger.
|
||||||
|
Currently supported values are 0 - 4; 0 is unusably slow for most applications.
|
||||||
|
Optimization level 4 currently only has an effect ARM platforms where more than one
|
||||||
|
curve is enabled. */
|
||||||
|
#ifndef uECC_OPTIMIZATION_LEVEL
|
||||||
|
#define uECC_OPTIMIZATION_LEVEL 2
|
||||||
|
#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 can make things
|
||||||
|
faster somewhat faster, but increases the code size. */
|
||||||
|
#ifndef uECC_SQUARE_FUNC
|
||||||
|
#define uECC_SQUARE_FUNC 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* uECC_VLI_NATIVE_LITTLE_ENDIAN - If enabled (defined as nonzero), this will switch to native
|
||||||
|
little-endian format for *all* arrays passed in and out of the public API. This includes public
|
||||||
|
and private keys, shared secrets, signatures and message hashes.
|
||||||
|
Using this switch reduces the amount of call stack memory used by uECC, since less intermediate
|
||||||
|
translations are required.
|
||||||
|
Note that this will *only* work on native little-endian processors and it will treat the uint8_t
|
||||||
|
arrays passed into the public API as word arrays, therefore requiring the provided byte arrays
|
||||||
|
to be word aligned on architectures that do not support unaligned accesses.
|
||||||
|
IMPORTANT: Keys and signatures generated with uECC_VLI_NATIVE_LITTLE_ENDIAN=1 are incompatible
|
||||||
|
with keys and signatures generated with uECC_VLI_NATIVE_LITTLE_ENDIAN=0; all parties must use
|
||||||
|
the same endianness. */
|
||||||
|
#ifndef uECC_VLI_NATIVE_LITTLE_ENDIAN
|
||||||
|
#define uECC_VLI_NATIVE_LITTLE_ENDIAN 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Curve support selection. Set to 0 to remove that curve. */
|
||||||
|
#ifndef uECC_SUPPORTS_secp160r1
|
||||||
|
#define uECC_SUPPORTS_secp160r1 0
|
||||||
|
#endif
|
||||||
|
#ifndef uECC_SUPPORTS_secp192r1
|
||||||
|
#define uECC_SUPPORTS_secp192r1 0
|
||||||
|
#endif
|
||||||
|
#ifndef uECC_SUPPORTS_secp224r1
|
||||||
|
#define uECC_SUPPORTS_secp224r1 0
|
||||||
|
#endif
|
||||||
|
#ifndef uECC_SUPPORTS_secp256r1
|
||||||
|
#define uECC_SUPPORTS_secp256r1 0
|
||||||
|
#endif
|
||||||
|
#ifndef uECC_SUPPORTS_secp256k1
|
||||||
|
#define uECC_SUPPORTS_secp256k1 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Specifies whether compressed point format is supported.
|
||||||
|
Set to 0 to disable point compression/decompression functions. */
|
||||||
|
#ifndef uECC_SUPPORT_COMPRESSED_POINT
|
||||||
|
#define uECC_SUPPORT_COMPRESSED_POINT 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct uECC_Curve_t;
|
||||||
|
typedef const struct uECC_Curve_t * uECC_Curve;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
uECC_Curve uECC_secp256k1(void);
|
||||||
|
|
||||||
|
/* uECC_curve_public_key_size() function.
|
||||||
|
|
||||||
|
Returns the size of a public key for the curve in bytes.
|
||||||
|
*/
|
||||||
|
int uECC_curve_public_key_size(uECC_Curve curve);
|
||||||
|
|
||||||
|
/* 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.
|
||||||
|
message_hash - The hash of the signed data.
|
||||||
|
hash_size - The size of message_hash in bytes.
|
||||||
|
signature - The signature value.
|
||||||
|
|
||||||
|
Returns 1 if the signature is valid, 0 if it is invalid.
|
||||||
|
*/
|
||||||
|
int uECC_verify(const uint8_t *public_key,
|
||||||
|
const uint8_t *message_hash,
|
||||||
|
unsigned hash_size,
|
||||||
|
const uint8_t *signature,
|
||||||
|
uECC_Curve curve);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* end of extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _UECC_H_ */
|
|
@ -0,0 +1,225 @@
|
||||||
|
/* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */
|
||||||
|
|
||||||
|
#ifndef _UECC_ASM_ARM_H_
|
||||||
|
#define _UECC_ASM_ARM_H_
|
||||||
|
|
||||||
|
#if (uECC_SUPPORTS_secp256r1 || uECC_SUPPORTS_secp256k1)
|
||||||
|
#define uECC_MIN_WORDS 8
|
||||||
|
#endif
|
||||||
|
#if uECC_SUPPORTS_secp224r1
|
||||||
|
#undef uECC_MIN_WORDS
|
||||||
|
#define uECC_MIN_WORDS 7
|
||||||
|
#endif
|
||||||
|
#if uECC_SUPPORTS_secp192r1
|
||||||
|
#undef uECC_MIN_WORDS
|
||||||
|
#define uECC_MIN_WORDS 6
|
||||||
|
#endif
|
||||||
|
#if uECC_SUPPORTS_secp160r1
|
||||||
|
#undef uECC_MIN_WORDS
|
||||||
|
#define uECC_MIN_WORDS 5
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (uECC_PLATFORM == uECC_arm_thumb)
|
||||||
|
#define REG_RW "+l"
|
||||||
|
#define REG_WRITE "=l"
|
||||||
|
#else
|
||||||
|
#define REG_RW "+r"
|
||||||
|
#define REG_WRITE "=r"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (uECC_PLATFORM == uECC_arm_thumb || uECC_PLATFORM == uECC_arm_thumb2)
|
||||||
|
#define REG_RW_LO "+l"
|
||||||
|
#define REG_WRITE_LO "=l"
|
||||||
|
#else
|
||||||
|
#define REG_RW_LO "+r"
|
||||||
|
#define REG_WRITE_LO "=r"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (uECC_PLATFORM == uECC_arm_thumb2)
|
||||||
|
#define RESUME_SYNTAX
|
||||||
|
#else
|
||||||
|
#define RESUME_SYNTAX ".syntax divided \n\t"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (uECC_OPTIMIZATION_LEVEL >= 2)
|
||||||
|
|
||||||
|
uECC_VLI_API uECC_word_t uECC_vli_add(uECC_word_t *result,
|
||||||
|
const uECC_word_t *left,
|
||||||
|
const uECC_word_t *right,
|
||||||
|
wordcount_t num_words) {
|
||||||
|
#if (uECC_MAX_WORDS != uECC_MIN_WORDS)
|
||||||
|
#if (uECC_PLATFORM == uECC_arm_thumb) || (uECC_PLATFORM == uECC_arm_thumb2)
|
||||||
|
uint32_t jump = (uECC_MAX_WORDS - num_words) * 4 * 2 + 1;
|
||||||
|
#else /* ARM */
|
||||||
|
uint32_t jump = (uECC_MAX_WORDS - num_words) * 4 * 4;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
uint32_t carry;
|
||||||
|
uint32_t left_word;
|
||||||
|
uint32_t right_word;
|
||||||
|
|
||||||
|
__asm__ volatile (
|
||||||
|
".syntax unified \n\t"
|
||||||
|
"movs %[carry], #0 \n\t"
|
||||||
|
#if (uECC_MAX_WORDS != uECC_MIN_WORDS)
|
||||||
|
"adr %[left], 1f \n\t"
|
||||||
|
".align 4 \n\t"
|
||||||
|
"adds %[jump], %[left] \n\t"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
"ldmia %[lptr]!, {%[left]} \n\t"
|
||||||
|
"ldmia %[rptr]!, {%[right]} \n\t"
|
||||||
|
"adds %[left], %[right] \n\t"
|
||||||
|
"stmia %[dptr]!, {%[left]} \n\t"
|
||||||
|
|
||||||
|
#if (uECC_MAX_WORDS != uECC_MIN_WORDS)
|
||||||
|
"bx %[jump] \n\t"
|
||||||
|
#endif
|
||||||
|
"1: \n\t"
|
||||||
|
REPEAT(DEC(uECC_MAX_WORDS),
|
||||||
|
"ldmia %[lptr]!, {%[left]} \n\t"
|
||||||
|
"ldmia %[rptr]!, {%[right]} \n\t"
|
||||||
|
"adcs %[left], %[right] \n\t"
|
||||||
|
"stmia %[dptr]!, {%[left]} \n\t")
|
||||||
|
|
||||||
|
"adcs %[carry], %[carry] \n\t"
|
||||||
|
RESUME_SYNTAX
|
||||||
|
: [dptr] REG_RW_LO (result), [lptr] REG_RW_LO (left), [rptr] REG_RW_LO (right),
|
||||||
|
#if (uECC_MAX_WORDS != uECC_MIN_WORDS)
|
||||||
|
[jump] REG_RW_LO (jump),
|
||||||
|
#endif
|
||||||
|
[carry] REG_WRITE_LO (carry), [left] REG_WRITE_LO (left_word),
|
||||||
|
[right] REG_WRITE_LO (right_word)
|
||||||
|
:
|
||||||
|
: "cc", "memory"
|
||||||
|
);
|
||||||
|
return carry;
|
||||||
|
}
|
||||||
|
#define asm_add 1
|
||||||
|
|
||||||
|
uECC_VLI_API uECC_word_t uECC_vli_sub(uECC_word_t *result,
|
||||||
|
const uECC_word_t *left,
|
||||||
|
const uECC_word_t *right,
|
||||||
|
wordcount_t num_words) {
|
||||||
|
#if (uECC_MAX_WORDS != uECC_MIN_WORDS)
|
||||||
|
#if (uECC_PLATFORM == uECC_arm_thumb) || (uECC_PLATFORM == uECC_arm_thumb2)
|
||||||
|
uint32_t jump = (uECC_MAX_WORDS - num_words) * 4 * 2 + 1;
|
||||||
|
#else /* ARM */
|
||||||
|
uint32_t jump = (uECC_MAX_WORDS - num_words) * 4 * 4;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
uint32_t carry;
|
||||||
|
uint32_t left_word;
|
||||||
|
uint32_t right_word;
|
||||||
|
|
||||||
|
__asm__ volatile (
|
||||||
|
".syntax unified \n\t"
|
||||||
|
"movs %[carry], #0 \n\t"
|
||||||
|
#if (uECC_MAX_WORDS != uECC_MIN_WORDS)
|
||||||
|
"adr %[left], 1f \n\t"
|
||||||
|
".align 4 \n\t"
|
||||||
|
"adds %[jump], %[left] \n\t"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
"ldmia %[lptr]!, {%[left]} \n\t"
|
||||||
|
"ldmia %[rptr]!, {%[right]} \n\t"
|
||||||
|
"subs %[left], %[right] \n\t"
|
||||||
|
"stmia %[dptr]!, {%[left]} \n\t"
|
||||||
|
|
||||||
|
#if (uECC_MAX_WORDS != uECC_MIN_WORDS)
|
||||||
|
"bx %[jump] \n\t"
|
||||||
|
#endif
|
||||||
|
"1: \n\t"
|
||||||
|
REPEAT(DEC(uECC_MAX_WORDS),
|
||||||
|
"ldmia %[lptr]!, {%[left]} \n\t"
|
||||||
|
"ldmia %[rptr]!, {%[right]} \n\t"
|
||||||
|
"sbcs %[left], %[right] \n\t"
|
||||||
|
"stmia %[dptr]!, {%[left]} \n\t")
|
||||||
|
|
||||||
|
"adcs %[carry], %[carry] \n\t"
|
||||||
|
RESUME_SYNTAX
|
||||||
|
: [dptr] REG_RW_LO (result), [lptr] REG_RW_LO (left), [rptr] REG_RW_LO (right),
|
||||||
|
#if (uECC_MAX_WORDS != uECC_MIN_WORDS)
|
||||||
|
[jump] REG_RW_LO (jump),
|
||||||
|
#endif
|
||||||
|
[carry] REG_WRITE_LO (carry), [left] REG_WRITE_LO (left_word),
|
||||||
|
[right] REG_WRITE_LO (right_word)
|
||||||
|
:
|
||||||
|
: "cc", "memory"
|
||||||
|
);
|
||||||
|
return !carry; /* Note that on ARM, carry flag set means "no borrow" when subtracting
|
||||||
|
(for some reason...) */
|
||||||
|
}
|
||||||
|
#define asm_sub 1
|
||||||
|
|
||||||
|
#endif /* (uECC_OPTIMIZATION_LEVEL >= 2) */
|
||||||
|
|
||||||
|
/* ---- "Small" implementations ---- */
|
||||||
|
|
||||||
|
#if !asm_mult
|
||||||
|
uECC_VLI_API void uECC_vli_mult(uECC_word_t *result,
|
||||||
|
const uECC_word_t *left,
|
||||||
|
const uECC_word_t *right,
|
||||||
|
wordcount_t num_words) {
|
||||||
|
uint32_t c0 = 0;
|
||||||
|
uint32_t c1 = 0;
|
||||||
|
uint32_t c2 = 0;
|
||||||
|
uint32_t k = 0;
|
||||||
|
uint32_t i;
|
||||||
|
uint32_t t0, t1;
|
||||||
|
|
||||||
|
__asm__ volatile (
|
||||||
|
".syntax unified \n\t"
|
||||||
|
|
||||||
|
"1: \n\t" /* outer loop (k < num_words) */
|
||||||
|
"movs %[i], #0 \n\t" /* i = 0 */
|
||||||
|
"b 3f \n\t"
|
||||||
|
|
||||||
|
"2: \n\t" /* outer loop (k >= num_words) */
|
||||||
|
"movs %[i], %[k] \n\t" /* i = k */
|
||||||
|
"subs %[i], %[last_word] \n\t" /* i = k - (num_words - 1) (times 4) */
|
||||||
|
|
||||||
|
"3: \n\t" /* inner loop */
|
||||||
|
"subs %[t0], %[k], %[i] \n\t" /* t0 = k-i */
|
||||||
|
|
||||||
|
"ldr %[t1], [%[right], %[t0]] \n\t" /* t1 = right[k - i] */
|
||||||
|
"ldr %[t0], [%[left], %[i]] \n\t" /* t0 = left[i] */
|
||||||
|
|
||||||
|
"umull %[t0], %[t1], %[t0], %[t1] \n\t" /* (t0, t1) = left[i] * right[k - i] */
|
||||||
|
|
||||||
|
"adds %[c0], %[c0], %[t0] \n\t" /* add low word to c0 */
|
||||||
|
"adcs %[c1], %[c1], %[t1] \n\t" /* add high word to c1, including carry */
|
||||||
|
"adcs %[c2], %[c2], #0 \n\t" /* add carry to c2 */
|
||||||
|
|
||||||
|
"adds %[i], #4 \n\t" /* i += 4 */
|
||||||
|
"cmp %[i], %[last_word] \n\t" /* i > (num_words - 1) (times 4)? */
|
||||||
|
"bgt 4f \n\t" /* if so, exit the loop */
|
||||||
|
"cmp %[i], %[k] \n\t" /* i <= k? */
|
||||||
|
"ble 3b \n\t" /* if so, continue looping */
|
||||||
|
|
||||||
|
"4: \n\t" /* end inner loop */
|
||||||
|
|
||||||
|
"str %[c0], [%[result], %[k]] \n\t" /* result[k] = c0 */
|
||||||
|
"mov %[c0], %[c1] \n\t" /* c0 = c1 */
|
||||||
|
"mov %[c1], %[c2] \n\t" /* c1 = c2 */
|
||||||
|
"movs %[c2], #0 \n\t" /* c2 = 0 */
|
||||||
|
"adds %[k], #4 \n\t" /* k += 4 */
|
||||||
|
"cmp %[k], %[last_word] \n\t" /* k <= (num_words - 1) (times 4) ? */
|
||||||
|
"ble 1b \n\t" /* if so, loop back, start with i = 0 */
|
||||||
|
"cmp %[k], %[last_word], lsl #1 \n\t" /* k <= (num_words * 2 - 2) (times 4) ? */
|
||||||
|
"ble 2b \n\t" /* if so, loop back, start with i = (k + 1) - num_words */
|
||||||
|
/* end outer loop */
|
||||||
|
|
||||||
|
"str %[c0], [%[result], %[k]] \n\t" /* result[num_words * 2 - 1] = c0 */
|
||||||
|
RESUME_SYNTAX
|
||||||
|
: [c0] "+r" (c0), [c1] "+r" (c1), [c2] "+r" (c2),
|
||||||
|
[k] "+r" (k), [i] "=&r" (i), [t0] "=&r" (t0), [t1] "=&r" (t1)
|
||||||
|
: [result] "r" (result), [left] "r" (left), [right] "r" (right),
|
||||||
|
[last_word] "r" ((num_words - 1) * 4)
|
||||||
|
: "cc", "memory"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
#define asm_mult 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _UECC_ASM_ARM_H_ */
|
|
@ -0,0 +1,138 @@
|
||||||
|
/* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */
|
||||||
|
|
||||||
|
#ifndef _UECC_CURVE_SPECIFIC_H_
|
||||||
|
#define _UECC_CURVE_SPECIFIC_H_
|
||||||
|
|
||||||
|
#define num_bytes_secp256k1 32
|
||||||
|
#define num_words_secp256k1 8
|
||||||
|
|
||||||
|
#define BYTES_TO_WORDS_8(a, b, c, d, e, f, g, h) 0x##d##c##b##a, 0x##h##g##f##e
|
||||||
|
#define BYTES_TO_WORDS_4(a, b, c, d) 0x##d##c##b##a
|
||||||
|
|
||||||
|
static void double_jacobian_secp256k1(uECC_word_t * X1,
|
||||||
|
uECC_word_t * Y1,
|
||||||
|
uECC_word_t * Z1,
|
||||||
|
uECC_Curve curve);
|
||||||
|
static void x_side_secp256k1(uECC_word_t *result, const uECC_word_t *x, uECC_Curve curve);
|
||||||
|
static void vli_mmod_fast_secp256k1(uECC_word_t *result, uECC_word_t *product);
|
||||||
|
|
||||||
|
static const struct uECC_Curve_t curve_secp256k1 = {
|
||||||
|
num_words_secp256k1,
|
||||||
|
num_bytes_secp256k1,
|
||||||
|
256, /* num_n_bits */
|
||||||
|
{ BYTES_TO_WORDS_8(2F, FC, FF, FF, FE, FF, FF, FF),
|
||||||
|
BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF),
|
||||||
|
BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF),
|
||||||
|
BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF) },
|
||||||
|
{ BYTES_TO_WORDS_8(41, 41, 36, D0, 8C, 5E, D2, BF),
|
||||||
|
BYTES_TO_WORDS_8(3B, A0, 48, AF, E6, DC, AE, BA),
|
||||||
|
BYTES_TO_WORDS_8(FE, FF, FF, FF, FF, FF, FF, FF),
|
||||||
|
BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF) },
|
||||||
|
{ BYTES_TO_WORDS_8(98, 17, F8, 16, 5B, 81, F2, 59),
|
||||||
|
BYTES_TO_WORDS_8(D9, 28, CE, 2D, DB, FC, 9B, 02),
|
||||||
|
BYTES_TO_WORDS_8(07, 0B, 87, CE, 95, 62, A0, 55),
|
||||||
|
BYTES_TO_WORDS_8(AC, BB, DC, F9, 7E, 66, BE, 79),
|
||||||
|
|
||||||
|
BYTES_TO_WORDS_8(B8, D4, 10, FB, 8F, D0, 47, 9C),
|
||||||
|
BYTES_TO_WORDS_8(19, 54, 85, A6, 48, B4, 17, FD),
|
||||||
|
BYTES_TO_WORDS_8(A8, 08, 11, 0E, FC, FB, A4, 5D),
|
||||||
|
BYTES_TO_WORDS_8(65, C4, A3, 26, 77, DA, 3A, 48) },
|
||||||
|
{ BYTES_TO_WORDS_8(07, 00, 00, 00, 00, 00, 00, 00),
|
||||||
|
BYTES_TO_WORDS_8(00, 00, 00, 00, 00, 00, 00, 00),
|
||||||
|
BYTES_TO_WORDS_8(00, 00, 00, 00, 00, 00, 00, 00),
|
||||||
|
BYTES_TO_WORDS_8(00, 00, 00, 00, 00, 00, 00, 00) },
|
||||||
|
&double_jacobian_secp256k1,
|
||||||
|
&x_side_secp256k1,
|
||||||
|
&vli_mmod_fast_secp256k1
|
||||||
|
};
|
||||||
|
|
||||||
|
uECC_Curve uECC_secp256k1(void) { return &curve_secp256k1; }
|
||||||
|
|
||||||
|
|
||||||
|
/* Double in place */
|
||||||
|
static void double_jacobian_secp256k1(uECC_word_t * X1,
|
||||||
|
uECC_word_t * Y1,
|
||||||
|
uECC_word_t * Z1,
|
||||||
|
uECC_Curve curve) {
|
||||||
|
/* t1 = X, t2 = Y, t3 = Z */
|
||||||
|
uECC_word_t t4[num_words_secp256k1];
|
||||||
|
uECC_word_t t5[num_words_secp256k1];
|
||||||
|
|
||||||
|
if (uECC_vli_isZero(Z1, num_words_secp256k1)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uECC_vli_modSquare_fast(t5, Y1, curve); /* t5 = y1^2 */
|
||||||
|
uECC_vli_modMult_fast(t4, X1, t5, curve); /* t4 = x1*y1^2 = A */
|
||||||
|
uECC_vli_modSquare_fast(X1, X1, curve); /* t1 = x1^2 */
|
||||||
|
uECC_vli_modSquare_fast(t5, t5, curve); /* t5 = y1^4 */
|
||||||
|
uECC_vli_modMult_fast(Z1, Y1, Z1, curve); /* t3 = y1*z1 = z3 */
|
||||||
|
|
||||||
|
uECC_vli_modAdd(Y1, X1, X1, curve->p, num_words_secp256k1); /* t2 = 2*x1^2 */
|
||||||
|
uECC_vli_modAdd(Y1, Y1, X1, curve->p, num_words_secp256k1); /* t2 = 3*x1^2 */
|
||||||
|
if (uECC_vli_testBit(Y1, 0)) {
|
||||||
|
uECC_word_t carry = uECC_vli_add(Y1, Y1, curve->p, num_words_secp256k1);
|
||||||
|
uECC_vli_rshift1(Y1, num_words_secp256k1);
|
||||||
|
Y1[num_words_secp256k1 - 1] |= carry << (uECC_WORD_BITS - 1);
|
||||||
|
} else {
|
||||||
|
uECC_vli_rshift1(Y1, num_words_secp256k1);
|
||||||
|
}
|
||||||
|
/* t2 = 3/2*(x1^2) = B */
|
||||||
|
|
||||||
|
uECC_vli_modSquare_fast(X1, Y1, curve); /* t1 = B^2 */
|
||||||
|
uECC_vli_modSub(X1, X1, t4, curve->p, num_words_secp256k1); /* t1 = B^2 - A */
|
||||||
|
uECC_vli_modSub(X1, X1, t4, curve->p, num_words_secp256k1); /* t1 = B^2 - 2A = x3 */
|
||||||
|
|
||||||
|
uECC_vli_modSub(t4, t4, X1, curve->p, num_words_secp256k1); /* t4 = A - x3 */
|
||||||
|
uECC_vli_modMult_fast(Y1, Y1, t4, curve); /* t2 = B * (A - x3) */
|
||||||
|
uECC_vli_modSub(Y1, Y1, t5, curve->p, num_words_secp256k1); /* t2 = B * (A - x3) - y1^4 = y3 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Computes result = x^3 + b. result must not overlap x. */
|
||||||
|
static void x_side_secp256k1(uECC_word_t *result, const uECC_word_t *x, uECC_Curve curve) {
|
||||||
|
uECC_vli_modSquare_fast(result, x, curve); /* r = x^2 */
|
||||||
|
uECC_vli_modMult_fast(result, result, x, curve); /* r = x^3 */
|
||||||
|
uECC_vli_modAdd(result, result, curve->b, curve->p, num_words_secp256k1); /* r = x^3 + b */
|
||||||
|
}
|
||||||
|
|
||||||
|
static void omega_mult_secp256k1(uECC_word_t *result, const uECC_word_t *right);
|
||||||
|
static void vli_mmod_fast_secp256k1(uECC_word_t *result, uECC_word_t *product) {
|
||||||
|
uECC_word_t tmp[2 * num_words_secp256k1];
|
||||||
|
uECC_word_t carry;
|
||||||
|
|
||||||
|
uECC_vli_clear(tmp, num_words_secp256k1);
|
||||||
|
uECC_vli_clear(tmp + num_words_secp256k1, num_words_secp256k1);
|
||||||
|
|
||||||
|
omega_mult_secp256k1(tmp, product + num_words_secp256k1); /* (Rq, q) = q * c */
|
||||||
|
|
||||||
|
carry = uECC_vli_add(result, product, tmp, num_words_secp256k1); /* (C, r) = r + q */
|
||||||
|
uECC_vli_clear(product, num_words_secp256k1);
|
||||||
|
omega_mult_secp256k1(product, tmp + num_words_secp256k1); /* Rq*c */
|
||||||
|
carry += uECC_vli_add(result, result, product, num_words_secp256k1); /* (C1, r) = r + Rq*c */
|
||||||
|
|
||||||
|
while (carry > 0) {
|
||||||
|
--carry;
|
||||||
|
uECC_vli_sub(result, result, curve_secp256k1.p, num_words_secp256k1);
|
||||||
|
}
|
||||||
|
if (uECC_vli_cmp_unsafe(result, curve_secp256k1.p, num_words_secp256k1) > 0) {
|
||||||
|
uECC_vli_sub(result, result, curve_secp256k1.p, num_words_secp256k1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void omega_mult_secp256k1(uint32_t * result, const uint32_t * right) {
|
||||||
|
/* Multiply by (2^9 + 2^8 + 2^7 + 2^6 + 2^4 + 1). */
|
||||||
|
uint32_t carry = 0;
|
||||||
|
wordcount_t k;
|
||||||
|
|
||||||
|
for (k = 0; k < num_words_secp256k1; ++k) {
|
||||||
|
uint64_t p = (uint64_t)0x3D1 * right[k] + carry;
|
||||||
|
result[k] = (uint32_t) p;
|
||||||
|
carry = p >> 32;
|
||||||
|
}
|
||||||
|
result[num_words_secp256k1] = carry;
|
||||||
|
/* add the 2^32 multiple */
|
||||||
|
result[1 + num_words_secp256k1] =
|
||||||
|
uECC_vli_add(result + 1, result + 1, right, num_words_secp256k1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* _UECC_CURVE_SPECIFIC_H_ */
|
|
@ -0,0 +1,78 @@
|
||||||
|
/* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */
|
||||||
|
|
||||||
|
#ifndef _UECC_TYPES_H_
|
||||||
|
#define _UECC_TYPES_H_
|
||||||
|
|
||||||
|
#define uECC_PLATFORM uECC_arm_thumb2
|
||||||
|
|
||||||
|
#ifndef uECC_PLATFORM
|
||||||
|
#if __AVR__
|
||||||
|
#define uECC_PLATFORM uECC_avr
|
||||||
|
#elif defined(__thumb2__) || defined(_M_ARMT) /* I think MSVC only supports Thumb-2 targets */
|
||||||
|
#define uECC_PLATFORM uECC_arm_thumb2
|
||||||
|
#elif defined(__thumb__)
|
||||||
|
#define uECC_PLATFORM uECC_arm_thumb
|
||||||
|
#elif defined(__arm__) || defined(_M_ARM)
|
||||||
|
#define uECC_PLATFORM uECC_arm
|
||||||
|
#elif defined(__aarch64__)
|
||||||
|
#define uECC_PLATFORM uECC_arm64
|
||||||
|
#elif defined(__i386__) || defined(_M_IX86) || defined(_X86_) || defined(__I86__)
|
||||||
|
#define uECC_PLATFORM uECC_x86
|
||||||
|
#elif defined(__amd64__) || defined(_M_X64)
|
||||||
|
#define uECC_PLATFORM uECC_x86_64
|
||||||
|
#else
|
||||||
|
#define uECC_PLATFORM uECC_arch_other
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef uECC_ARM_USE_UMAAL
|
||||||
|
#if (uECC_PLATFORM == uECC_arm) && (__ARM_ARCH >= 6)
|
||||||
|
#define uECC_ARM_USE_UMAAL 1
|
||||||
|
#elif (uECC_PLATFORM == uECC_arm_thumb2) && (__ARM_ARCH >= 6) && !__ARM_ARCH_7M__
|
||||||
|
#define uECC_ARM_USE_UMAAL 1
|
||||||
|
#else
|
||||||
|
#define uECC_ARM_USE_UMAAL 0
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef uECC_WORD_SIZE
|
||||||
|
#if uECC_PLATFORM == uECC_avr
|
||||||
|
#define uECC_WORD_SIZE 1
|
||||||
|
#elif (uECC_PLATFORM == uECC_x86_64 || uECC_PLATFORM == uECC_arm64)
|
||||||
|
#define uECC_WORD_SIZE 8
|
||||||
|
#else
|
||||||
|
#define uECC_WORD_SIZE 4
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (uECC_WORD_SIZE != 1) && (uECC_WORD_SIZE != 4) && (uECC_WORD_SIZE != 8)
|
||||||
|
#error "Unsupported value for uECC_WORD_SIZE"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ((uECC_PLATFORM == uECC_avr) && (uECC_WORD_SIZE != 1))
|
||||||
|
#pragma message ("uECC_WORD_SIZE must be 1 for AVR")
|
||||||
|
#undef uECC_WORD_SIZE
|
||||||
|
#define uECC_WORD_SIZE 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ((uECC_PLATFORM == uECC_arm || uECC_PLATFORM == uECC_arm_thumb || \
|
||||||
|
uECC_PLATFORM == uECC_arm_thumb2) && \
|
||||||
|
(uECC_WORD_SIZE != 4))
|
||||||
|
#pragma message ("uECC_WORD_SIZE must be 4 for ARM")
|
||||||
|
#undef uECC_WORD_SIZE
|
||||||
|
#define uECC_WORD_SIZE 4
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef int8_t wordcount_t;
|
||||||
|
typedef int16_t bitcount_t;
|
||||||
|
typedef int8_t cmpresult_t;
|
||||||
|
|
||||||
|
typedef uint32_t uECC_word_t;
|
||||||
|
typedef uint64_t uECC_dword_t;
|
||||||
|
|
||||||
|
#define HIGH_BIT_SET 0x80000000
|
||||||
|
#define uECC_WORD_BITS 32
|
||||||
|
#define uECC_WORD_BITS_SHIFT 5
|
||||||
|
#define uECC_WORD_BITS_MASK 0x01F
|
||||||
|
|
||||||
|
#endif /* _UECC_TYPES_H_ */
|
24
Src/main.c
24
Src/main.c
|
@ -1,6 +1,9 @@
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "flash.h"
|
#include "flash.h"
|
||||||
#include "sha256.h"
|
#include "sha256.h"
|
||||||
|
#include "uECC.h"
|
||||||
|
|
||||||
|
uint8_t fw_public_key[] = { 0xfe, 0xcb, 0x28, 0xb9, 0x50, 0xdd, 0x8b, 0x2f, 0xc7, 0x34, 0xd3, 0x60, 0x5b, 0x1a, 0xc6, 0xed, 0x02, 0x50, 0xf2, 0x4a, 0xc4, 0x75, 0xd1, 0x28, 0x7f, 0x7c, 0xb5, 0xce, 0x61, 0xd6, 0x95, 0xb9, 0xb5, 0x27, 0x0b, 0x52, 0x77, 0x42, 0x4b, 0xf3, 0xb4, 0x3c, 0xef, 0xcb, 0x56, 0xd1, 0x98, 0x22, 0x11, 0xc2, 0xe5, 0xd3, 0xf0, 0x22, 0x87, 0xb9, 0xe8, 0x20, 0xdc, 0xee, 0x9f, 0xc2, 0xad, 0x22, };
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
if (!check_firmware(UPGRADE_FW_START)) {
|
if (!check_firmware(UPGRADE_FW_START)) {
|
||||||
|
@ -17,14 +20,21 @@ int check_firmware(uintptr_t addr) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
cf_sha256_context ctx;
|
uint32_t fw_size = UINT32_PTR(addr)[1];
|
||||||
cf_sha256_init(&ctx);
|
|
||||||
cf_sha256_update(&ctx, UINT8_PTR(addr), UINT32_PTR(addr)[1]);
|
|
||||||
uint8_t hash[CF_SHA256_HASHSZ];
|
|
||||||
cf_sha256_digest(&ctx, hash);
|
|
||||||
//TODO: verify signature!!!
|
|
||||||
|
|
||||||
return 0;
|
if (fw_size > FIRMWARE_SIZE) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t hash[CF_SHA256_HASHSZ];
|
||||||
|
cf_sha256_context ctx;
|
||||||
|
uECC_Curve ec_curve = uECC_secp256k1();
|
||||||
|
|
||||||
|
cf_sha256_init(&ctx);
|
||||||
|
cf_sha256_update(&ctx, UINT8_PTR(addr + FIRMWARE_HEADER_SIZE), fw_size);
|
||||||
|
cf_sha256_digest(&ctx, hash);
|
||||||
|
|
||||||
|
return uECC_verify(fw_public_key, hash, CF_SHA256_HASHSZ, UINT8_PTR(addr + 8), ec_curve) != 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,621 @@
|
||||||
|
/* Copyright 2014, Kenneth MacKay. Licensed under the BSD 2-clause license. */
|
||||||
|
|
||||||
|
#include "uECC.h"
|
||||||
|
#include "uECC_types.h"
|
||||||
|
|
||||||
|
#ifndef uECC_RNG_MAX_TRIES
|
||||||
|
#define uECC_RNG_MAX_TRIES 64
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if uECC_ENABLE_VLI_API
|
||||||
|
#define uECC_VLI_API
|
||||||
|
#else
|
||||||
|
#define uECC_VLI_API static
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define CONCATX(a, ...) a ## __VA_ARGS__
|
||||||
|
#define CONCAT(a, ...) CONCATX(a, __VA_ARGS__)
|
||||||
|
|
||||||
|
#define STRX(a) #a
|
||||||
|
#define STR(a) STRX(a)
|
||||||
|
|
||||||
|
#define EVAL(...) EVAL1(EVAL1(EVAL1(EVAL1(__VA_ARGS__))))
|
||||||
|
#define EVAL1(...) EVAL2(EVAL2(EVAL2(EVAL2(__VA_ARGS__))))
|
||||||
|
#define EVAL2(...) EVAL3(EVAL3(EVAL3(EVAL3(__VA_ARGS__))))
|
||||||
|
#define EVAL3(...) EVAL4(EVAL4(EVAL4(EVAL4(__VA_ARGS__))))
|
||||||
|
#define EVAL4(...) __VA_ARGS__
|
||||||
|
|
||||||
|
#define DEC_1 0
|
||||||
|
#define DEC_2 1
|
||||||
|
#define DEC_3 2
|
||||||
|
#define DEC_4 3
|
||||||
|
#define DEC_5 4
|
||||||
|
#define DEC_6 5
|
||||||
|
#define DEC_7 6
|
||||||
|
#define DEC_8 7
|
||||||
|
#define DEC_9 8
|
||||||
|
#define DEC_10 9
|
||||||
|
#define DEC_11 10
|
||||||
|
#define DEC_12 11
|
||||||
|
#define DEC_13 12
|
||||||
|
#define DEC_14 13
|
||||||
|
#define DEC_15 14
|
||||||
|
#define DEC_16 15
|
||||||
|
#define DEC_17 16
|
||||||
|
#define DEC_18 17
|
||||||
|
#define DEC_19 18
|
||||||
|
#define DEC_20 19
|
||||||
|
#define DEC_21 20
|
||||||
|
#define DEC_22 21
|
||||||
|
#define DEC_23 22
|
||||||
|
#define DEC_24 23
|
||||||
|
#define DEC_25 24
|
||||||
|
#define DEC_26 25
|
||||||
|
#define DEC_27 26
|
||||||
|
#define DEC_28 27
|
||||||
|
#define DEC_29 28
|
||||||
|
#define DEC_30 29
|
||||||
|
#define DEC_31 30
|
||||||
|
#define DEC_32 31
|
||||||
|
|
||||||
|
#define DEC(N) CONCAT(DEC_, N)
|
||||||
|
|
||||||
|
#define SECOND_ARG(_, val, ...) val
|
||||||
|
#define SOME_CHECK_0 ~, 0
|
||||||
|
#define GET_SECOND_ARG(...) SECOND_ARG(__VA_ARGS__, SOME,)
|
||||||
|
#define SOME_OR_0(N) GET_SECOND_ARG(CONCAT(SOME_CHECK_, N))
|
||||||
|
|
||||||
|
#define EMPTY(...)
|
||||||
|
#define DEFER(...) __VA_ARGS__ EMPTY()
|
||||||
|
|
||||||
|
#define REPEAT_NAME_0() REPEAT_0
|
||||||
|
#define REPEAT_NAME_SOME() REPEAT_SOME
|
||||||
|
#define REPEAT_0(...)
|
||||||
|
#define REPEAT_SOME(N, stuff) DEFER(CONCAT(REPEAT_NAME_, SOME_OR_0(DEC(N))))()(DEC(N), stuff) stuff
|
||||||
|
#define REPEAT(N, stuff) EVAL(REPEAT_SOME(N, stuff))
|
||||||
|
|
||||||
|
#define REPEATM_NAME_0() REPEATM_0
|
||||||
|
#define REPEATM_NAME_SOME() REPEATM_SOME
|
||||||
|
#define REPEATM_0(...)
|
||||||
|
#define REPEATM_SOME(N, macro) macro(N) \
|
||||||
|
DEFER(CONCAT(REPEATM_NAME_, SOME_OR_0(DEC(N))))()(DEC(N), macro)
|
||||||
|
#define REPEATM(N, macro) EVAL(REPEATM_SOME(N, macro))
|
||||||
|
|
||||||
|
|
||||||
|
#define uECC_MAX_WORDS 8
|
||||||
|
|
||||||
|
#define BITS_TO_WORDS(num_bits) ((num_bits + ((uECC_WORD_SIZE * 8) - 1)) / (uECC_WORD_SIZE * 8))
|
||||||
|
#define BITS_TO_BYTES(num_bits) ((num_bits + 7) / 8)
|
||||||
|
|
||||||
|
struct uECC_Curve_t {
|
||||||
|
wordcount_t num_words;
|
||||||
|
wordcount_t num_bytes;
|
||||||
|
bitcount_t num_n_bits;
|
||||||
|
uECC_word_t p[uECC_MAX_WORDS];
|
||||||
|
uECC_word_t n[uECC_MAX_WORDS];
|
||||||
|
uECC_word_t G[uECC_MAX_WORDS * 2];
|
||||||
|
uECC_word_t b[uECC_MAX_WORDS];
|
||||||
|
void (*double_jacobian)(uECC_word_t * X1,
|
||||||
|
uECC_word_t * Y1,
|
||||||
|
uECC_word_t * Z1,
|
||||||
|
uECC_Curve curve);
|
||||||
|
void (*x_side)(uECC_word_t *result, const uECC_word_t *x, uECC_Curve curve);
|
||||||
|
void (*mmod_fast)(uECC_word_t *result, uECC_word_t *product);
|
||||||
|
};
|
||||||
|
|
||||||
|
static cmpresult_t uECC_vli_cmp_unsafe(const uECC_word_t *left,
|
||||||
|
const uECC_word_t *right,
|
||||||
|
wordcount_t num_words);
|
||||||
|
|
||||||
|
#if (uECC_PLATFORM == uECC_arm || uECC_PLATFORM == uECC_arm_thumb || \
|
||||||
|
uECC_PLATFORM == uECC_arm_thumb2)
|
||||||
|
#include "uECC_asm_arm.inc"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int uECC_curve_private_key_size(uECC_Curve curve) {
|
||||||
|
return BITS_TO_BYTES(curve->num_n_bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
int uECC_curve_public_key_size(uECC_Curve curve) {
|
||||||
|
return 2 * curve->num_bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !asm_clear
|
||||||
|
uECC_VLI_API void uECC_vli_clear(uECC_word_t *vli, wordcount_t num_words) {
|
||||||
|
wordcount_t i;
|
||||||
|
for (i = 0; i < num_words; ++i) {
|
||||||
|
vli[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* !asm_clear */
|
||||||
|
|
||||||
|
/* Constant-time comparison to zero - secure way to compare long integers */
|
||||||
|
/* Returns 1 if vli == 0, 0 otherwise. */
|
||||||
|
uECC_VLI_API uECC_word_t uECC_vli_isZero(const uECC_word_t *vli, wordcount_t num_words) {
|
||||||
|
uECC_word_t bits = 0;
|
||||||
|
wordcount_t i;
|
||||||
|
for (i = 0; i < num_words; ++i) {
|
||||||
|
bits |= vli[i];
|
||||||
|
}
|
||||||
|
return (bits == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns nonzero if bit 'bit' of vli is set. */
|
||||||
|
uECC_VLI_API uECC_word_t uECC_vli_testBit(const uECC_word_t *vli, bitcount_t bit) {
|
||||||
|
return (vli[bit >> uECC_WORD_BITS_SHIFT] & ((uECC_word_t)1 << (bit & uECC_WORD_BITS_MASK)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Counts the number of words in vli. */
|
||||||
|
static wordcount_t vli_numDigits(const uECC_word_t *vli, const wordcount_t max_words) {
|
||||||
|
wordcount_t i;
|
||||||
|
/* Search from the end until we find a non-zero digit.
|
||||||
|
We do it in reverse because we expect that most digits will be nonzero. */
|
||||||
|
for (i = max_words - 1; i >= 0 && vli[i] == 0; --i) {
|
||||||
|
}
|
||||||
|
|
||||||
|
return (i + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Counts the number of bits required to represent vli. */
|
||||||
|
uECC_VLI_API bitcount_t uECC_vli_numBits(const uECC_word_t *vli, const wordcount_t max_words) {
|
||||||
|
uECC_word_t i;
|
||||||
|
uECC_word_t digit;
|
||||||
|
|
||||||
|
wordcount_t num_digits = vli_numDigits(vli, max_words);
|
||||||
|
if (num_digits == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
digit = vli[num_digits - 1];
|
||||||
|
for (i = 0; digit; ++i) {
|
||||||
|
digit >>= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (((bitcount_t)(num_digits - 1) << uECC_WORD_BITS_SHIFT) + i);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sets dest = src. */
|
||||||
|
#if !asm_set
|
||||||
|
uECC_VLI_API void uECC_vli_set(uECC_word_t *dest, const uECC_word_t *src, wordcount_t num_words) {
|
||||||
|
wordcount_t i;
|
||||||
|
for (i = 0; i < num_words; ++i) {
|
||||||
|
dest[i] = src[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* !asm_set */
|
||||||
|
|
||||||
|
/* Returns sign of left - right. */
|
||||||
|
static cmpresult_t uECC_vli_cmp_unsafe(const uECC_word_t *left,
|
||||||
|
const uECC_word_t *right,
|
||||||
|
wordcount_t num_words) {
|
||||||
|
wordcount_t i;
|
||||||
|
for (i = num_words - 1; i >= 0; --i) {
|
||||||
|
if (left[i] > right[i]) {
|
||||||
|
return 1;
|
||||||
|
} else if (left[i] < right[i]) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Constant-time comparison function - secure way to compare long integers */
|
||||||
|
/* Returns one if left == right, zero otherwise. */
|
||||||
|
uECC_VLI_API uECC_word_t uECC_vli_equal(const uECC_word_t *left,
|
||||||
|
const uECC_word_t *right,
|
||||||
|
wordcount_t num_words) {
|
||||||
|
uECC_word_t diff = 0;
|
||||||
|
wordcount_t i;
|
||||||
|
for (i = num_words - 1; i >= 0; --i) {
|
||||||
|
diff |= (left[i] ^ right[i]);
|
||||||
|
}
|
||||||
|
return (diff == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Computes vli = vli >> 1. */
|
||||||
|
#if !asm_rshift1
|
||||||
|
uECC_VLI_API void uECC_vli_rshift1(uECC_word_t *vli, wordcount_t num_words) {
|
||||||
|
uECC_word_t *end = vli;
|
||||||
|
uECC_word_t carry = 0;
|
||||||
|
|
||||||
|
vli += num_words;
|
||||||
|
while (vli-- > end) {
|
||||||
|
uECC_word_t temp = *vli;
|
||||||
|
*vli = (temp >> 1) | carry;
|
||||||
|
carry = temp << (uECC_WORD_BITS - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* !asm_rshift1 */
|
||||||
|
|
||||||
|
/* Computes result = (left + right) % mod.
|
||||||
|
Assumes that left < mod and right < mod, and that result does not overlap mod. */
|
||||||
|
uECC_VLI_API void uECC_vli_modAdd(uECC_word_t *result,
|
||||||
|
const uECC_word_t *left,
|
||||||
|
const uECC_word_t *right,
|
||||||
|
const uECC_word_t *mod,
|
||||||
|
wordcount_t num_words) {
|
||||||
|
uECC_word_t carry = uECC_vli_add(result, left, right, num_words);
|
||||||
|
if (carry || uECC_vli_cmp_unsafe(mod, result, num_words) != 1) {
|
||||||
|
/* result > mod (result = mod + remainder), so subtract mod to get remainder. */
|
||||||
|
uECC_vli_sub(result, result, mod, num_words);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Computes result = (left - right) % mod.
|
||||||
|
Assumes that left < mod and right < mod, and that result does not overlap mod. */
|
||||||
|
uECC_VLI_API void uECC_vli_modSub(uECC_word_t *result,
|
||||||
|
const uECC_word_t *left,
|
||||||
|
const uECC_word_t *right,
|
||||||
|
const uECC_word_t *mod,
|
||||||
|
wordcount_t num_words) {
|
||||||
|
uECC_word_t l_borrow = uECC_vli_sub(result, left, right, num_words);
|
||||||
|
if (l_borrow) {
|
||||||
|
/* In this case, result == -diff == (max int) - diff. Since -x % d == d - x,
|
||||||
|
we can get the correct result from result + mod (with overflow). */
|
||||||
|
uECC_vli_add(result, result, mod, num_words);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Computes result = product % mod, where product is 2N words long. */
|
||||||
|
/* Currently only designed to work for curve_p or curve_n. */
|
||||||
|
uECC_VLI_API void uECC_vli_mmod(uECC_word_t *result,
|
||||||
|
uECC_word_t *product,
|
||||||
|
const uECC_word_t *mod,
|
||||||
|
wordcount_t num_words) {
|
||||||
|
uECC_word_t mod_multiple[2 * uECC_MAX_WORDS];
|
||||||
|
uECC_word_t tmp[2 * uECC_MAX_WORDS];
|
||||||
|
uECC_word_t *v[2] = {tmp, product};
|
||||||
|
uECC_word_t index;
|
||||||
|
|
||||||
|
/* Shift mod so its highest set bit is at the maximum position. */
|
||||||
|
bitcount_t shift = (num_words * 2 * uECC_WORD_BITS) - uECC_vli_numBits(mod, num_words);
|
||||||
|
wordcount_t word_shift = shift / uECC_WORD_BITS;
|
||||||
|
wordcount_t bit_shift = shift % uECC_WORD_BITS;
|
||||||
|
uECC_word_t carry = 0;
|
||||||
|
uECC_vli_clear(mod_multiple, word_shift);
|
||||||
|
if (bit_shift > 0) {
|
||||||
|
for(index = 0; index < (uECC_word_t)num_words; ++index) {
|
||||||
|
mod_multiple[word_shift + index] = (mod[index] << bit_shift) | carry;
|
||||||
|
carry = mod[index] >> (uECC_WORD_BITS - bit_shift);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
uECC_vli_set(mod_multiple + word_shift, mod, num_words);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (index = 1; shift >= 0; --shift) {
|
||||||
|
uECC_word_t borrow = 0;
|
||||||
|
wordcount_t i;
|
||||||
|
for (i = 0; i < num_words * 2; ++i) {
|
||||||
|
uECC_word_t diff = v[index][i] - mod_multiple[i] - borrow;
|
||||||
|
if (diff != v[index][i]) {
|
||||||
|
borrow = (diff > v[index][i]);
|
||||||
|
}
|
||||||
|
v[1 - index][i] = diff;
|
||||||
|
}
|
||||||
|
index = !(index ^ borrow); /* Swap the index if there was no borrow */
|
||||||
|
uECC_vli_rshift1(mod_multiple, num_words);
|
||||||
|
mod_multiple[num_words - 1] |= mod_multiple[num_words] << (uECC_WORD_BITS - 1);
|
||||||
|
uECC_vli_rshift1(mod_multiple + num_words, num_words);
|
||||||
|
}
|
||||||
|
uECC_vli_set(result, v[index], num_words);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Computes result = (left * right) % mod. */
|
||||||
|
uECC_VLI_API void uECC_vli_modMult(uECC_word_t *result,
|
||||||
|
const uECC_word_t *left,
|
||||||
|
const uECC_word_t *right,
|
||||||
|
const uECC_word_t *mod,
|
||||||
|
wordcount_t num_words) {
|
||||||
|
uECC_word_t product[2 * uECC_MAX_WORDS];
|
||||||
|
uECC_vli_mult(product, left, right, num_words);
|
||||||
|
uECC_vli_mmod(result, product, mod, num_words);
|
||||||
|
}
|
||||||
|
|
||||||
|
uECC_VLI_API void uECC_vli_modMult_fast(uECC_word_t *result,
|
||||||
|
const uECC_word_t *left,
|
||||||
|
const uECC_word_t *right,
|
||||||
|
uECC_Curve curve) {
|
||||||
|
uECC_word_t product[2 * uECC_MAX_WORDS];
|
||||||
|
uECC_vli_mult(product, left, right, curve->num_words);
|
||||||
|
curve->mmod_fast(result, product);
|
||||||
|
}
|
||||||
|
|
||||||
|
uECC_VLI_API void uECC_vli_modSquare_fast(uECC_word_t *result,
|
||||||
|
const uECC_word_t *left,
|
||||||
|
uECC_Curve curve) {
|
||||||
|
uECC_vli_modMult_fast(result, left, left, curve);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define EVEN(vli) (!(vli[0] & 1))
|
||||||
|
static void vli_modInv_update(uECC_word_t *uv,
|
||||||
|
const uECC_word_t *mod,
|
||||||
|
wordcount_t num_words) {
|
||||||
|
uECC_word_t carry = 0;
|
||||||
|
if (!EVEN(uv)) {
|
||||||
|
carry = uECC_vli_add(uv, uv, mod, num_words);
|
||||||
|
}
|
||||||
|
uECC_vli_rshift1(uv, num_words);
|
||||||
|
if (carry) {
|
||||||
|
uv[num_words - 1] |= HIGH_BIT_SET;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Computes result = (1 / input) % mod. All VLIs are the same size.
|
||||||
|
See "From Euclid's GCD to Montgomery Multiplication to the Great Divide" */
|
||||||
|
uECC_VLI_API void uECC_vli_modInv(uECC_word_t *result,
|
||||||
|
const uECC_word_t *input,
|
||||||
|
const uECC_word_t *mod,
|
||||||
|
wordcount_t num_words) {
|
||||||
|
uECC_word_t a[uECC_MAX_WORDS], b[uECC_MAX_WORDS], u[uECC_MAX_WORDS], v[uECC_MAX_WORDS];
|
||||||
|
cmpresult_t cmpResult;
|
||||||
|
|
||||||
|
if (uECC_vli_isZero(input, num_words)) {
|
||||||
|
uECC_vli_clear(result, num_words);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uECC_vli_set(a, input, num_words);
|
||||||
|
uECC_vli_set(b, mod, num_words);
|
||||||
|
uECC_vli_clear(u, num_words);
|
||||||
|
u[0] = 1;
|
||||||
|
uECC_vli_clear(v, num_words);
|
||||||
|
while ((cmpResult = uECC_vli_cmp_unsafe(a, b, num_words)) != 0) {
|
||||||
|
if (EVEN(a)) {
|
||||||
|
uECC_vli_rshift1(a, num_words);
|
||||||
|
vli_modInv_update(u, mod, num_words);
|
||||||
|
} else if (EVEN(b)) {
|
||||||
|
uECC_vli_rshift1(b, num_words);
|
||||||
|
vli_modInv_update(v, mod, num_words);
|
||||||
|
} else if (cmpResult > 0) {
|
||||||
|
uECC_vli_sub(a, a, b, num_words);
|
||||||
|
uECC_vli_rshift1(a, num_words);
|
||||||
|
if (uECC_vli_cmp_unsafe(u, v, num_words) < 0) {
|
||||||
|
uECC_vli_add(u, u, mod, num_words);
|
||||||
|
}
|
||||||
|
uECC_vli_sub(u, u, v, num_words);
|
||||||
|
vli_modInv_update(u, mod, num_words);
|
||||||
|
} else {
|
||||||
|
uECC_vli_sub(b, b, a, num_words);
|
||||||
|
uECC_vli_rshift1(b, num_words);
|
||||||
|
if (uECC_vli_cmp_unsafe(v, u, num_words) < 0) {
|
||||||
|
uECC_vli_add(v, v, mod, num_words);
|
||||||
|
}
|
||||||
|
uECC_vli_sub(v, v, u, num_words);
|
||||||
|
vli_modInv_update(v, mod, num_words);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uECC_vli_set(result, u, num_words);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------ Point operations ------ */
|
||||||
|
|
||||||
|
#include "uECC_curve-specific.inc"
|
||||||
|
|
||||||
|
/* Returns 1 if 'point' is the point at infinity, 0 otherwise. */
|
||||||
|
#define EccPoint_isZero(point, curve) uECC_vli_isZero((point), (curve)->num_words * 2)
|
||||||
|
|
||||||
|
/* Point multiplication algorithm using Montgomery's ladder with co-Z coordinates.
|
||||||
|
From http://eprint.iacr.org/2011/338.pdf
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Modify (x1, y1) => (x1 * z^2, y1 * z^3) */
|
||||||
|
static void apply_z(uECC_word_t * X1,
|
||||||
|
uECC_word_t * Y1,
|
||||||
|
const uECC_word_t * const Z,
|
||||||
|
uECC_Curve curve) {
|
||||||
|
uECC_word_t t1[uECC_MAX_WORDS];
|
||||||
|
|
||||||
|
uECC_vli_modSquare_fast(t1, Z, curve); /* z^2 */
|
||||||
|
uECC_vli_modMult_fast(X1, X1, t1, curve); /* x1 * z^2 */
|
||||||
|
uECC_vli_modMult_fast(t1, t1, Z, curve); /* z^3 */
|
||||||
|
uECC_vli_modMult_fast(Y1, Y1, t1, curve); /* y1 * z^3 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Input P = (x1, y1, Z), Q = (x2, y2, Z)
|
||||||
|
Output P' = (x1', y1', Z3), P + Q = (x3, y3, Z3)
|
||||||
|
or P => P', Q => P + Q
|
||||||
|
*/
|
||||||
|
static void XYcZ_add(uECC_word_t * X1,
|
||||||
|
uECC_word_t * Y1,
|
||||||
|
uECC_word_t * X2,
|
||||||
|
uECC_word_t * Y2,
|
||||||
|
uECC_Curve curve) {
|
||||||
|
/* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */
|
||||||
|
uECC_word_t t5[uECC_MAX_WORDS];
|
||||||
|
wordcount_t num_words = curve->num_words;
|
||||||
|
|
||||||
|
uECC_vli_modSub(t5, X2, X1, curve->p, num_words); /* t5 = x2 - x1 */
|
||||||
|
uECC_vli_modSquare_fast(t5, t5, curve); /* t5 = (x2 - x1)^2 = A */
|
||||||
|
uECC_vli_modMult_fast(X1, X1, t5, curve); /* t1 = x1*A = B */
|
||||||
|
uECC_vli_modMult_fast(X2, X2, t5, curve); /* t3 = x2*A = C */
|
||||||
|
uECC_vli_modSub(Y2, Y2, Y1, curve->p, num_words); /* t4 = y2 - y1 */
|
||||||
|
uECC_vli_modSquare_fast(t5, Y2, curve); /* t5 = (y2 - y1)^2 = D */
|
||||||
|
|
||||||
|
uECC_vli_modSub(t5, t5, X1, curve->p, num_words); /* t5 = D - B */
|
||||||
|
uECC_vli_modSub(t5, t5, X2, curve->p, num_words); /* t5 = D - B - C = x3 */
|
||||||
|
uECC_vli_modSub(X2, X2, X1, curve->p, num_words); /* t3 = C - B */
|
||||||
|
uECC_vli_modMult_fast(Y1, Y1, X2, curve); /* t2 = y1*(C - B) */
|
||||||
|
uECC_vli_modSub(X2, X1, t5, curve->p, num_words); /* t3 = B - x3 */
|
||||||
|
uECC_vli_modMult_fast(Y2, Y2, X2, curve); /* t4 = (y2 - y1)*(B - x3) */
|
||||||
|
uECC_vli_modSub(Y2, Y2, Y1, curve->p, num_words); /* t4 = y3 */
|
||||||
|
|
||||||
|
uECC_vli_set(X2, t5, num_words);
|
||||||
|
}
|
||||||
|
|
||||||
|
uECC_VLI_API void uECC_vli_bytesToNative(uECC_word_t *native,
|
||||||
|
const uint8_t *bytes,
|
||||||
|
int num_bytes) {
|
||||||
|
wordcount_t i;
|
||||||
|
uECC_vli_clear(native, (num_bytes + (uECC_WORD_SIZE - 1)) / uECC_WORD_SIZE);
|
||||||
|
for (i = 0; i < num_bytes; ++i) {
|
||||||
|
unsigned b = num_bytes - 1 - i;
|
||||||
|
native[b / uECC_WORD_SIZE] |=
|
||||||
|
(uECC_word_t)bytes[i] << (8 * (b % uECC_WORD_SIZE));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int uECC_valid_point(const uECC_word_t *point, uECC_Curve curve) {
|
||||||
|
uECC_word_t tmp1[uECC_MAX_WORDS];
|
||||||
|
uECC_word_t tmp2[uECC_MAX_WORDS];
|
||||||
|
wordcount_t num_words = curve->num_words;
|
||||||
|
|
||||||
|
/* The point at infinity is invalid. */
|
||||||
|
if (EccPoint_isZero(point, curve)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* x and y must be smaller than p. */
|
||||||
|
if (uECC_vli_cmp_unsafe(curve->p, point, num_words) != 1 ||
|
||||||
|
uECC_vli_cmp_unsafe(curve->p, point + num_words, num_words) != 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uECC_vli_modSquare_fast(tmp1, point + num_words, curve);
|
||||||
|
curve->x_side(tmp2, point, curve); /* tmp2 = x^3 + ax + b */
|
||||||
|
|
||||||
|
/* Make sure that y^2 == x^3 + ax + b */
|
||||||
|
return (int)(uECC_vli_equal(tmp1, tmp2, num_words));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------- ECDSA code -------- */
|
||||||
|
|
||||||
|
static void bits2int(uECC_word_t *native,
|
||||||
|
const uint8_t *bits,
|
||||||
|
unsigned bits_size,
|
||||||
|
uECC_Curve curve) {
|
||||||
|
unsigned num_n_bytes = BITS_TO_BYTES(curve->num_n_bits);
|
||||||
|
unsigned num_n_words = BITS_TO_WORDS(curve->num_n_bits);
|
||||||
|
int shift;
|
||||||
|
uECC_word_t carry;
|
||||||
|
uECC_word_t *ptr;
|
||||||
|
|
||||||
|
if (bits_size > num_n_bytes) {
|
||||||
|
bits_size = num_n_bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
uECC_vli_clear(native, num_n_words);
|
||||||
|
uECC_vli_bytesToNative(native, bits, bits_size);
|
||||||
|
|
||||||
|
if (bits_size * 8 <= (unsigned)curve->num_n_bits) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
shift = bits_size * 8 - curve->num_n_bits;
|
||||||
|
carry = 0;
|
||||||
|
ptr = native + num_n_words;
|
||||||
|
while (ptr-- > native) {
|
||||||
|
uECC_word_t temp = *ptr;
|
||||||
|
*ptr = (temp >> shift) | carry;
|
||||||
|
carry = temp << (uECC_WORD_BITS - shift);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reduce mod curve_n */
|
||||||
|
if (uECC_vli_cmp_unsafe(curve->n, native, num_n_words) != 1) {
|
||||||
|
uECC_vli_sub(native, native, curve->n, num_n_words);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bitcount_t smax(bitcount_t a, bitcount_t b) {
|
||||||
|
return (a > b ? a : b);
|
||||||
|
}
|
||||||
|
|
||||||
|
int uECC_verify(const uint8_t *public_key,
|
||||||
|
const uint8_t *message_hash,
|
||||||
|
unsigned hash_size,
|
||||||
|
const uint8_t *signature,
|
||||||
|
uECC_Curve curve) {
|
||||||
|
uECC_word_t u1[uECC_MAX_WORDS], u2[uECC_MAX_WORDS];
|
||||||
|
uECC_word_t z[uECC_MAX_WORDS];
|
||||||
|
uECC_word_t sum[uECC_MAX_WORDS * 2];
|
||||||
|
uECC_word_t rx[uECC_MAX_WORDS];
|
||||||
|
uECC_word_t ry[uECC_MAX_WORDS];
|
||||||
|
uECC_word_t tx[uECC_MAX_WORDS];
|
||||||
|
uECC_word_t ty[uECC_MAX_WORDS];
|
||||||
|
uECC_word_t tz[uECC_MAX_WORDS];
|
||||||
|
const uECC_word_t *points[4];
|
||||||
|
const uECC_word_t *point;
|
||||||
|
bitcount_t num_bits;
|
||||||
|
bitcount_t i;
|
||||||
|
uECC_word_t _public[uECC_MAX_WORDS * 2];
|
||||||
|
uECC_word_t r[uECC_MAX_WORDS], s[uECC_MAX_WORDS];
|
||||||
|
wordcount_t num_words = curve->num_words;
|
||||||
|
wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits);
|
||||||
|
|
||||||
|
rx[num_n_words - 1] = 0;
|
||||||
|
r[num_n_words - 1] = 0;
|
||||||
|
s[num_n_words - 1] = 0;
|
||||||
|
|
||||||
|
uECC_vli_bytesToNative(_public, public_key, curve->num_bytes);
|
||||||
|
uECC_vli_bytesToNative(_public + num_words, public_key + curve->num_bytes, curve->num_bytes);
|
||||||
|
uECC_vli_bytesToNative(r, signature, curve->num_bytes);
|
||||||
|
uECC_vli_bytesToNative(s, signature + curve->num_bytes, curve->num_bytes);
|
||||||
|
|
||||||
|
/* r, s must not be 0. */
|
||||||
|
if (uECC_vli_isZero(r, num_words) || uECC_vli_isZero(s, num_words)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* r, s must be < n. */
|
||||||
|
if (uECC_vli_cmp_unsafe(curve->n, r, num_n_words) != 1 ||
|
||||||
|
uECC_vli_cmp_unsafe(curve->n, s, num_n_words) != 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Calculate u1 and u2. */
|
||||||
|
uECC_vli_modInv(z, s, curve->n, num_n_words); /* z = 1/s */
|
||||||
|
u1[num_n_words - 1] = 0;
|
||||||
|
bits2int(u1, message_hash, hash_size, curve);
|
||||||
|
uECC_vli_modMult(u1, u1, z, curve->n, num_n_words); /* u1 = e/s */
|
||||||
|
uECC_vli_modMult(u2, r, z, curve->n, num_n_words); /* u2 = r/s */
|
||||||
|
|
||||||
|
/* Calculate sum = G + Q. */
|
||||||
|
uECC_vli_set(sum, _public, num_words);
|
||||||
|
uECC_vli_set(sum + num_words, _public + num_words, num_words);
|
||||||
|
uECC_vli_set(tx, curve->G, num_words);
|
||||||
|
uECC_vli_set(ty, curve->G + num_words, num_words);
|
||||||
|
uECC_vli_modSub(z, sum, tx, curve->p, num_words); /* z = x2 - x1 */
|
||||||
|
XYcZ_add(tx, ty, sum, sum + num_words, curve);
|
||||||
|
uECC_vli_modInv(z, z, curve->p, num_words); /* z = 1/z */
|
||||||
|
apply_z(sum, sum + num_words, z, curve);
|
||||||
|
|
||||||
|
/* Use Shamir's trick to calculate u1*G + u2*Q */
|
||||||
|
points[0] = 0;
|
||||||
|
points[1] = curve->G;
|
||||||
|
points[2] = _public;
|
||||||
|
points[3] = sum;
|
||||||
|
num_bits = smax(uECC_vli_numBits(u1, num_n_words),
|
||||||
|
uECC_vli_numBits(u2, num_n_words));
|
||||||
|
|
||||||
|
point = points[(!!uECC_vli_testBit(u1, num_bits - 1)) |
|
||||||
|
((!!uECC_vli_testBit(u2, num_bits - 1)) << 1)];
|
||||||
|
uECC_vli_set(rx, point, num_words);
|
||||||
|
uECC_vli_set(ry, point + num_words, num_words);
|
||||||
|
uECC_vli_clear(z, num_words);
|
||||||
|
z[0] = 1;
|
||||||
|
|
||||||
|
for (i = num_bits - 2; i >= 0; --i) {
|
||||||
|
uECC_word_t index;
|
||||||
|
curve->double_jacobian(rx, ry, z, curve);
|
||||||
|
|
||||||
|
index = (!!uECC_vli_testBit(u1, i)) | ((!!uECC_vli_testBit(u2, i)) << 1);
|
||||||
|
point = points[index];
|
||||||
|
if (point) {
|
||||||
|
uECC_vli_set(tx, point, num_words);
|
||||||
|
uECC_vli_set(ty, point + num_words, num_words);
|
||||||
|
apply_z(tx, ty, z, curve);
|
||||||
|
uECC_vli_modSub(tz, rx, tx, curve->p, num_words); /* Z = x2 - x1 */
|
||||||
|
XYcZ_add(tx, ty, rx, ry, curve);
|
||||||
|
uECC_vli_modMult_fast(z, z, tz, curve);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uECC_vli_modInv(z, z, curve->p, num_words); /* Z = 1/Z */
|
||||||
|
apply_z(rx, ry, z, curve);
|
||||||
|
|
||||||
|
/* v = x1 (mod n) */
|
||||||
|
if (uECC_vli_cmp_unsafe(curve->n, rx, num_n_words) != 1) {
|
||||||
|
uECC_vli_sub(rx, rx, curve->n, num_n_words);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Accept only if v == r. */
|
||||||
|
return (int)(uECC_vli_equal(rx, r, num_words));
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
import ecdsa
|
||||||
|
import hashlib
|
||||||
|
import binascii
|
||||||
|
import re
|
||||||
|
|
||||||
|
def main():
|
||||||
|
sk = ecdsa.SigningKey.generate(curve=ecdsa.curves.SECP256k1, hashfunc=hashlib.sha256)
|
||||||
|
sk_pem = sk.to_pem()
|
||||||
|
vk = sk.get_verifying_key()
|
||||||
|
|
||||||
|
vk_hex = binascii.hexlify(vk.to_string())
|
||||||
|
vk_h = "uint8_t fw_public_key[] = { " + re.sub(r"(..)", "0x\\1, ", vk_hex) + "};"
|
||||||
|
open("secret_key.pem","w").write(sk.to_pem())
|
||||||
|
open("public_key.h","w").write(vk_h)
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
Loading…
Reference in New Issue