Add fast ARM asm; cleaned up code. Added optimization setting. (#50)

This commit is contained in:
Ken MacKay
2015-10-12 21:29:56 -07:00
parent 08ae3fd516
commit 5f01beb717
8 changed files with 3253 additions and 2907 deletions
-2455
View File
File diff suppressed because it is too large Load Diff
+845
View File
@@ -0,0 +1,845 @@
/* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */
#ifndef _UECC_ASM_ARM_FAST_H_
#define _UECC_ASM_ARM_FAST_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_thumb2)
#define RESUME_SYNTAX
#else
#define RESUME_SYNTAX ".syntax divided \n\t"
#endif
static uECC_word_t vli_add(uECC_word_t *result,
const uECC_word_t *left,
const uECC_word_t *right,
wordcount_t num_words) {
#if (uECC_PLATFORM == uECC_arm_thumb) || (uECC_PLATFORM == uECC_arm_thumb2)
uint32_t jump = ((uECC_MAX_WORDS - num_words) * 4 + 5) * 2 + 1;
#else /* ARM */
uint32_t jump = ((uECC_MAX_WORDS - num_words) * 4 + 5) * 4;
#endif
uint32_t carry;
uint32_t left_word;
uint32_t right_word;
__asm__ volatile (
".syntax unified \n\t"
"movs %[carry], #0 \n\t"
"mov %[left], pc \n\t"
"adds %[jump], %[left] \n\t"
"ldmia %[lptr]!, {%[left]} \n\t"
"ldmia %[rptr]!, {%[right]} \n\t"
"adds %[left], %[right] \n\t"
"stmia %[dptr]!, {%[left]} \n\t"
"bx %[jump] \n\t"
"ldmia %[lptr]!, {%[left]} \n\t"
"ldmia %[rptr]!, {%[right]} \n\t"
"adcs %[left], %[right] \n\t"
"stmia %[dptr]!, {%[left]} \n\t"
"ldmia %[lptr]!, {%[left]} \n\t"
"ldmia %[rptr]!, {%[right]} \n\t"
"adcs %[left], %[right] \n\t"
"stmia %[dptr]!, {%[left]} \n\t"
"ldmia %[lptr]!, {%[left]} \n\t"
"ldmia %[rptr]!, {%[right]} \n\t"
"adcs %[left], %[right] \n\t"
"stmia %[dptr]!, {%[left]} \n\t"
"ldmia %[lptr]!, {%[left]} \n\t"
"ldmia %[rptr]!, {%[right]} \n\t"
"adcs %[left], %[right] \n\t"
"stmia %[dptr]!, {%[left]} \n\t"
#if (uECC_MAX_WORDS >= 6)
"ldmia %[lptr]!, {%[left]} \n\t"
"ldmia %[rptr]!, {%[right]} \n\t"
"adcs %[left], %[right] \n\t"
"stmia %[dptr]!, {%[left]} \n\t"
#endif
#if (uECC_MAX_WORDS >= 7)
"ldmia %[lptr]!, {%[left]} \n\t"
"ldmia %[rptr]!, {%[right]} \n\t"
"adcs %[left], %[right] \n\t"
"stmia %[dptr]!, {%[left]} \n\t"
#endif
#if (uECC_MAX_WORDS >= 8)
"ldmia %[lptr]!, {%[left]} \n\t"
"ldmia %[rptr]!, {%[right]} \n\t"
"adcs %[left], %[right] \n\t"
"stmia %[dptr]!, {%[left]} \n\t"
#endif
"adcs %[carry], %[carry] \n\t"
RESUME_SYNTAX
: [dptr] REG_RW (result), [lptr] REG_RW (left), [rptr] REG_RW (right),
[carry] REG_WRITE (carry), [left] REG_WRITE (left_word), [right] REG_WRITE (right_word),
[jump] REG_RW (jump)
:
: "cc", "memory"
);
return carry;
}
#define asm_add 1
static uECC_word_t vli_sub(uECC_word_t *result,
const uECC_word_t *left,
const uECC_word_t *right,
wordcount_t num_words) {
#if (uECC_PLATFORM == uECC_arm_thumb) || (uECC_PLATFORM == uECC_arm_thumb2)
uint32_t jump = ((uECC_MAX_WORDS - num_words) * 4 + 5) * 2 + 1;
#else /* ARM */
uint32_t jump = ((uECC_MAX_WORDS - num_words) * 4 + 5) * 4;
#endif
uint32_t carry;
uint32_t left_word;
uint32_t right_word;
__asm__ volatile (
".syntax unified \n\t"
"movs %[carry], #0 \n\t"
"mov %[left], pc \n\t"
"adds %[jump], %[left] \n\t"
"ldmia %[lptr]!, {%[left]} \n\t"
"ldmia %[rptr]!, {%[right]} \n\t"
"subs %[left], %[right] \n\t"
"stmia %[dptr]!, {%[left]} \n\t"
"bx %[jump] \n\t"
"ldmia %[lptr]!, {%[left]} \n\t"
"ldmia %[rptr]!, {%[right]} \n\t"
"sbcs %[left], %[right] \n\t"
"stmia %[dptr]!, {%[left]} \n\t"
"ldmia %[lptr]!, {%[left]} \n\t"
"ldmia %[rptr]!, {%[right]} \n\t"
"sbcs %[left], %[right] \n\t"
"stmia %[dptr]!, {%[left]} \n\t"
"ldmia %[lptr]!, {%[left]} \n\t"
"ldmia %[rptr]!, {%[right]} \n\t"
"sbcs %[left], %[right] \n\t"
"stmia %[dptr]!, {%[left]} \n\t"
"ldmia %[lptr]!, {%[left]} \n\t"
"ldmia %[rptr]!, {%[right]} \n\t"
"sbcs %[left], %[right] \n\t"
"stmia %[dptr]!, {%[left]} \n\t"
#if (uECC_MAX_WORDS >= 6)
"ldmia %[lptr]!, {%[left]} \n\t"
"ldmia %[rptr]!, {%[right]} \n\t"
"sbcs %[left], %[right] \n\t"
"stmia %[dptr]!, {%[left]} \n\t"
#endif
#if (uECC_MAX_WORDS >= 7)
"ldmia %[lptr]!, {%[left]} \n\t"
"ldmia %[rptr]!, {%[right]} \n\t"
"sbcs %[left], %[right] \n\t"
"stmia %[dptr]!, {%[left]} \n\t"
#endif
#if (uECC_MAX_WORDS >= 8)
"ldmia %[lptr]!, {%[left]} \n\t"
"ldmia %[rptr]!, {%[right]} \n\t"
"sbcs %[left], %[right] \n\t"
"stmia %[dptr]!, {%[left]} \n\t"
#endif
"adcs %[carry], %[carry] \n\t"
RESUME_SYNTAX
: [dptr] REG_RW (result), [lptr] REG_RW (left), [rptr] REG_RW (right),
[carry] REG_WRITE (carry), [left] REG_WRITE (left_word), [right] REG_WRITE (right_word),
[jump] REG_RW (jump)
:
: "cc", "memory"
);
return !carry; /* Note that on ARM, carry flag set means "no borrow" when subtracting
(for some reason...) */
}
#define asm_sub 1
#define FAST_MULT_ASM_5_TO_6 \
"cmp r3, #5 \n\t" \
"beq 1f \n\t" \
\
/* r4 = left high, r5 = right high */ \
"ldr r4, [r1] \n\t" \
"ldr r5, [r2] \n\t" \
\
"sub r0, #20 \n\t" \
"sub r1, #20 \n\t" \
"sub r2, #20 \n\t" \
\
"ldr r6, [r0] \n\t" \
"ldr r7, [r1], #4 \n\t" \
"ldr r8, [r2], #4 \n\t" \
"mov r14, #0 \n\t" \
"umull r9, r10, r4, r8 \n\t" \
"umull r11, r12, r5, r7 \n\t" \
"adds r9, r6 \n\t" \
"adc r10, #0 \n\t" \
"adds r9, r11 \n\t" \
"adcs r10, r12 \n\t" \
"adc r14, #0 \n\t" \
"str r9, [r0], #4 \n\t" \
\
"ldr r6, [r0] \n\t" \
"adds r10, r6 \n\t" \
"adcs r14, #0 \n\t" \
"ldr r7, [r1], #4 \n\t" \
"ldr r8, [r2], #4 \n\t" \
"mov r9, #0 \n\t" \
"umull r11, r12, r4, r8 \n\t" \
"adds r10, r11 \n\t" \
"adcs r14, r12 \n\t" \
"adc r9, #0 \n\t" \
"umull r11, r12, r5, r7 \n\t" \
"adds r10, r11 \n\t" \
"adcs r14, r12 \n\t" \
"adc r9, #0 \n\t" \
"str r10, [r0], #4 \n\t" \
\
"ldr r6, [r0] \n\t" \
"adds r14, r6 \n\t" \
"adcs r9, #0 \n\t" \
"ldr r7, [r1], #4 \n\t" \
"ldr r8, [r2], #4 \n\t" \
"mov r10, #0 \n\t" \
"umull r11, r12, r4, r8 \n\t" \
"adds r14, r11 \n\t" \
"adcs r9, r12 \n\t" \
"adc r10, #0 \n\t" \
"umull r11, r12, r5, r7 \n\t" \
"adds r14, r11 \n\t" \
"adcs r9, r12 \n\t" \
"adc r10, #0 \n\t" \
"str r14, [r0], #4 \n\t" \
\
"ldr r6, [r0] \n\t" \
"adds r9, r6 \n\t" \
"adcs r10, #0 \n\t" \
"ldr r7, [r1], #4 \n\t" \
"ldr r8, [r2], #4 \n\t" \
"mov r14, #0 \n\t" \
"umull r11, r12, r4, r8 \n\t" \
"adds r9, r11 \n\t" \
"adcs r10, r12 \n\t" \
"adc r14, #0 \n\t" \
"umull r11, r12, r5, r7 \n\t" \
"adds r9, r11 \n\t" \
"adcs r10, r12 \n\t" \
"adc r14, #0 \n\t" \
"str r9, [r0], #4 \n\t" \
\
"ldr r6, [r0] \n\t" \
"adds r10, r6 \n\t" \
"adcs r14, #0 \n\t" \
/* skip past already-loaded (r4, r5) */ \
"ldr r7, [r1], #8 \n\t" \
"ldr r8, [r2], #8 \n\t" \
"mov r9, #0 \n\t" \
"umull r11, r12, r4, r8 \n\t" \
"adds r10, r11 \n\t" \
"adcs r14, r12 \n\t" \
"adc r9, #0 \n\t" \
"umull r11, r12, r5, r7 \n\t" \
"adds r10, r11 \n\t" \
"adcs r14, r12 \n\t" \
"adc r9, #0 \n\t" \
"str r10, [r0], #4 \n\t" \
\
"umull r11, r12, r4, r5 \n\t" \
"adds r11, r14 \n\t" \
"adc r12, r9 \n\t" \
"stmia r0!, {r11, r12} \n\t"
#define FAST_MULT_ASM_6_TO_7 \
"cmp r3, #6 \n\t" \
"beq 1f \n\t" \
\
/* r4 = left high, r5 = right high */ \
"ldr r4, [r1] \n\t" \
"ldr r5, [r2] \n\t" \
\
"sub r0, #24 \n\t" \
"sub r1, #24 \n\t" \
"sub r2, #24 \n\t" \
\
"ldr r6, [r0] \n\t" \
"ldr r7, [r1], #4 \n\t" \
"ldr r8, [r2], #4 \n\t" \
"mov r14, #0 \n\t" \
"umull r9, r10, r4, r8 \n\t" \
"umull r11, r12, r5, r7 \n\t" \
"adds r9, r6 \n\t" \
"adc r10, #0 \n\t" \
"adds r9, r11 \n\t" \
"adcs r10, r12 \n\t" \
"adc r14, #0 \n\t" \
"str r9, [r0], #4 \n\t" \
\
"ldr r6, [r0] \n\t" \
"adds r10, r6 \n\t" \
"adcs r14, #0 \n\t" \
"ldr r7, [r1], #4 \n\t" \
"ldr r8, [r2], #4 \n\t" \
"mov r9, #0 \n\t" \
"umull r11, r12, r4, r8 \n\t" \
"adds r10, r11 \n\t" \
"adcs r14, r12 \n\t" \
"adc r9, #0 \n\t" \
"umull r11, r12, r5, r7 \n\t" \
"adds r10, r11 \n\t" \
"adcs r14, r12 \n\t" \
"adc r9, #0 \n\t" \
"str r10, [r0], #4 \n\t" \
\
"ldr r6, [r0] \n\t" \
"adds r14, r6 \n\t" \
"adcs r9, #0 \n\t" \
"ldr r7, [r1], #4 \n\t" \
"ldr r8, [r2], #4 \n\t" \
"mov r10, #0 \n\t" \
"umull r11, r12, r4, r8 \n\t" \
"adds r14, r11 \n\t" \
"adcs r9, r12 \n\t" \
"adc r10, #0 \n\t" \
"umull r11, r12, r5, r7 \n\t" \
"adds r14, r11 \n\t" \
"adcs r9, r12 \n\t" \
"adc r10, #0 \n\t" \
"str r14, [r0], #4 \n\t" \
\
"ldr r6, [r0] \n\t" \
"adds r9, r6 \n\t" \
"adcs r10, #0 \n\t" \
"ldr r7, [r1], #4 \n\t" \
"ldr r8, [r2], #4 \n\t" \
"mov r14, #0 \n\t" \
"umull r11, r12, r4, r8 \n\t" \
"adds r9, r11 \n\t" \
"adcs r10, r12 \n\t" \
"adc r14, #0 \n\t" \
"umull r11, r12, r5, r7 \n\t" \
"adds r9, r11 \n\t" \
"adcs r10, r12 \n\t" \
"adc r14, #0 \n\t" \
"str r9, [r0], #4 \n\t" \
\
"ldr r6, [r0] \n\t" \
"adds r10, r6 \n\t" \
"adcs r14, #0 \n\t" \
"ldr r7, [r1], #4 \n\t" \
"ldr r8, [r2], #4 \n\t" \
"mov r9, #0 \n\t" \
"umull r11, r12, r4, r8 \n\t" \
"adds r10, r11 \n\t" \
"adcs r14, r12 \n\t" \
"adc r9, #0 \n\t" \
"umull r11, r12, r5, r7 \n\t" \
"adds r10, r11 \n\t" \
"adcs r14, r12 \n\t" \
"adc r9, #0 \n\t" \
"str r10, [r0], #4 \n\t" \
\
"ldr r6, [r0] \n\t" \
"adds r14, r6 \n\t" \
"adcs r9, #0 \n\t" \
/* skip past already-loaded (r4, r5) */ \
"ldr r7, [r1], #8 \n\t" \
"ldr r8, [r2], #8 \n\t" \
"mov r10, #0 \n\t" \
"umull r11, r12, r4, r8 \n\t" \
"adds r14, r11 \n\t" \
"adcs r9, r12 \n\t" \
"adc r10, #0 \n\t" \
"umull r11, r12, r5, r7 \n\t" \
"adds r14, r11 \n\t" \
"adcs r9, r12 \n\t" \
"adc r10, #0 \n\t" \
"str r14, [r0], #4 \n\t" \
\
"umull r11, r12, r4, r5 \n\t" \
"adds r11, r9 \n\t" \
"adc r12, r10 \n\t" \
"stmia r0!, {r11, r12} \n\t"
#define FAST_MULT_ASM_7_TO_8 \
"cmp r3, #7 \n\t" \
"beq 1f \n\t" \
\
/* r4 = left high, r5 = right high */ \
"ldr r4, [r1] \n\t" \
"ldr r5, [r2] \n\t" \
\
"sub r0, #28 \n\t" \
"sub r1, #28 \n\t" \
"sub r2, #28 \n\t" \
\
"ldr r6, [r0] \n\t" \
"ldr r7, [r1], #4 \n\t" \
"ldr r8, [r2], #4 \n\t" \
"mov r14, #0 \n\t" \
"umull r9, r10, r4, r8 \n\t" \
"umull r11, r12, r5, r7 \n\t" \
"adds r9, r6 \n\t" \
"adc r10, #0 \n\t" \
"adds r9, r11 \n\t" \
"adcs r10, r12 \n\t" \
"adc r14, #0 \n\t" \
"str r9, [r0], #4 \n\t" \
\
"ldr r6, [r0] \n\t" \
"adds r10, r6 \n\t" \
"adcs r14, #0 \n\t" \
"ldr r7, [r1], #4 \n\t" \
"ldr r8, [r2], #4 \n\t" \
"mov r9, #0 \n\t" \
"umull r11, r12, r4, r8 \n\t" \
"adds r10, r11 \n\t" \
"adcs r14, r12 \n\t" \
"adc r9, #0 \n\t" \
"umull r11, r12, r5, r7 \n\t" \
"adds r10, r11 \n\t" \
"adcs r14, r12 \n\t" \
"adc r9, #0 \n\t" \
"str r10, [r0], #4 \n\t" \
\
"ldr r6, [r0] \n\t" \
"adds r14, r6 \n\t" \
"adcs r9, #0 \n\t" \
"ldr r7, [r1], #4 \n\t" \
"ldr r8, [r2], #4 \n\t" \
"mov r10, #0 \n\t" \
"umull r11, r12, r4, r8 \n\t" \
"adds r14, r11 \n\t" \
"adcs r9, r12 \n\t" \
"adc r10, #0 \n\t" \
"umull r11, r12, r5, r7 \n\t" \
"adds r14, r11 \n\t" \
"adcs r9, r12 \n\t" \
"adc r10, #0 \n\t" \
"str r14, [r0], #4 \n\t" \
\
"ldr r6, [r0] \n\t" \
"adds r9, r6 \n\t" \
"adcs r10, #0 \n\t" \
"ldr r7, [r1], #4 \n\t" \
"ldr r8, [r2], #4 \n\t" \
"mov r14, #0 \n\t" \
"umull r11, r12, r4, r8 \n\t" \
"adds r9, r11 \n\t" \
"adcs r10, r12 \n\t" \
"adc r14, #0 \n\t" \
"umull r11, r12, r5, r7 \n\t" \
"adds r9, r11 \n\t" \
"adcs r10, r12 \n\t" \
"adc r14, #0 \n\t" \
"str r9, [r0], #4 \n\t" \
\
"ldr r6, [r0] \n\t" \
"adds r10, r6 \n\t" \
"adcs r14, #0 \n\t" \
"ldr r7, [r1], #4 \n\t" \
"ldr r8, [r2], #4 \n\t" \
"mov r9, #0 \n\t" \
"umull r11, r12, r4, r8 \n\t" \
"adds r10, r11 \n\t" \
"adcs r14, r12 \n\t" \
"adc r9, #0 \n\t" \
"umull r11, r12, r5, r7 \n\t" \
"adds r10, r11 \n\t" \
"adcs r14, r12 \n\t" \
"adc r9, #0 \n\t" \
"str r10, [r0], #4 \n\t" \
\
"ldr r6, [r0] \n\t" \
"adds r14, r6 \n\t" \
"adcs r9, #0 \n\t" \
"ldr r7, [r1], #4 \n\t" \
"ldr r8, [r2], #4 \n\t" \
"mov r10, #0 \n\t" \
"umull r11, r12, r4, r8 \n\t" \
"adds r14, r11 \n\t" \
"adcs r9, r12 \n\t" \
"adc r10, #0 \n\t" \
"umull r11, r12, r5, r7 \n\t" \
"adds r14, r11 \n\t" \
"adcs r9, r12 \n\t" \
"adc r10, #0 \n\t" \
"str r14, [r0], #4 \n\t" \
\
"ldr r6, [r0] \n\t" \
"adds r9, r6 \n\t" \
"adcs r10, #0 \n\t" \
/* skip past already-loaded (r4, r5) */ \
"ldr r7, [r1], #8 \n\t" \
"ldr r8, [r2], #8 \n\t" \
"mov r14, #0 \n\t" \
"umull r11, r12, r4, r8 \n\t" \
"adds r9, r11 \n\t" \
"adcs r10, r12 \n\t" \
"adc r14, #0 \n\t" \
"umull r11, r12, r5, r7 \n\t" \
"adds r9, r11 \n\t" \
"adcs r10, r12 \n\t" \
"adc r14, #0 \n\t" \
"str r9, [r0], #4 \n\t" \
\
"umull r11, r12, r4, r5 \n\t" \
"adds r11, r10 \n\t" \
"adc r12, r14 \n\t" \
"stmia r0!, {r11, r12} \n\t"
#if (uECC_PLATFORM != uECC_arm_thumb)
static void vli_mult(uint32_t *result,
const uint32_t *left,
const uint32_t *right,
wordcount_t num_words) {
register uint32_t *r0 __asm__("r0") = result;
register const uint32_t *r1 __asm__("r1") = left;
register const uint32_t *r2 __asm__("r2") = right;
register uint32_t r3 __asm__("r3") = num_words;
__asm__ volatile (
".syntax unified \n\t"
"push {r3} \n\t"
#if (uECC_MIN_WORDS == 5)
FAST_MULT_ASM_5
"pop {r3} \n\t"
#if (uECC_MAX_WORDS > 5)
FAST_MULT_ASM_5_TO_6
#endif
#if (uECC_MAX_WORDS > 6)
FAST_MULT_ASM_6_TO_7
#endif
#if (uECC_MAX_WORDS > 7)
FAST_MULT_ASM_7_TO_8
#endif
#elif (uECC_MIN_WORDS == 6)
FAST_MULT_ASM_6
"pop {r3} \n\t"
#if (uECC_MAX_WORDS > 6)
FAST_MULT_ASM_6_TO_7
#endif
#if (uECC_MAX_WORDS > 7)
FAST_MULT_ASM_7_TO_8
#endif
#elif (uECC_MIN_WORDS == 7)
FAST_MULT_ASM_7
"pop {r3} \n\t"
#if (uECC_MAX_WORDS > 7)
FAST_MULT_ASM_7_TO_8
#endif
#elif (uECC_MIN_WORDS == 8)
FAST_MULT_ASM_8
"pop {r3} \n\t"
#endif
"1: \n\t"
RESUME_SYNTAX
: "+r" (r0), "+r" (r1), "+r" (r2)
: "r" (r3)
: "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory"
);
}
#define asm_mult 1
#if uECC_SQUARE_FUNC
#define FAST_SQUARE_ASM_5_TO_6 \
"cmp r2, #5 \n\t" \
"beq 1f \n\t" \
\
/* r3 = high */ \
"ldr r3, [r1] \n\t" \
\
"sub r0, #20 \n\t" \
"sub r1, #20 \n\t" \
\
/* Do off-center multiplication */ \
"ldr r14, [r1], #4 \n\t" \
"umull r4, r5, r3, r14 \n\t" \
"ldr r14, [r1], #4 \n\t" \
"umull r7, r6, r3, r14 \n\t" \
"adds r5, r7 \n\t" \
"ldr r14, [r1], #4 \n\t" \
"umull r8, r7, r3, r14 \n\t" \
"adcs r6, r8 \n\t" \
"ldr r14, [r1], #4 \n\t" \
"umull r9, r8, r3, r14 \n\t" \
"adcs r7, r9 \n\t" \
/* Skip already-loaded r3 */ \
"ldr r14, [r1], #8 \n\t" \
"umull r10, r9, r3, r14 \n\t" \
"adcs r8, r10 \n\t" \
"adcs r9, #0 \n\t" \
\
/* Multiply by 2 */ \
"mov r10, #0 \n\t" \
"adds r4, r4 \n\t" \
"adcs r5, r5 \n\t" \
"adcs r6, r6 \n\t" \
"adcs r7, r7 \n\t" \
"adcs r8, r8 \n\t" \
"adcs r9, r9 \n\t" \
"adcs r10, #0 \n\t" \
\
/* Add into previous */ \
"ldr r14, [r0] \n\t" \
"adds r4, r14 \n\t" \
"str r4, [r0], #4 \n\t" \
"ldr r14, [r0] \n\t" \
"adcs r5, r14 \n\t" \
"str r5, [r0], #4 \n\t" \
"ldr r14, [r0] \n\t" \
"adcs r6, r14 \n\t" \
"str r6, [r0], #4 \n\t" \
"ldr r14, [r0] \n\t" \
"adcs r7, r14 \n\t" \
"str r7, [r0], #4 \n\t" \
"ldr r14, [r0] \n\t" \
"adcs r8, r14 \n\t" \
"str r8, [r0], #4 \n\t" \
"adcs r9, #0 \n\t" \
"adcs r10, #0 \n\t" \
\
/* Perform center multiplication */ \
"umull r4, r5, r3, r3 \n\t" \
"adds r4, r9 \n\t" \
"adc r5, r10 \n\t" \
"stmia r0!, {r4, r5} \n\t"
#define FAST_SQUARE_ASM_6_TO_7 \
"cmp r2, #6 \n\t" \
"beq 1f \n\t" \
\
/* r3 = high */ \
"ldr r3, [r1] \n\t" \
\
"sub r0, #24 \n\t" \
"sub r1, #24 \n\t" \
\
/* Do off-center multiplication */ \
"ldr r14, [r1], #4 \n\t" \
"umull r4, r5, r3, r14 \n\t" \
"ldr r14, [r1], #4 \n\t" \
"umull r7, r6, r3, r14 \n\t" \
"adds r5, r7 \n\t" \
"ldr r14, [r1], #4 \n\t" \
"umull r8, r7, r3, r14 \n\t" \
"adcs r6, r8 \n\t" \
"ldr r14, [r1], #4 \n\t" \
"umull r9, r8, r3, r14 \n\t" \
"adcs r7, r9 \n\t" \
"ldr r14, [r1], #4 \n\t" \
"umull r10, r9, r3, r14 \n\t" \
"adcs r8, r10 \n\t" \
/* Skip already-loaded r3 */ \
"ldr r14, [r1], #8 \n\t" \
"umull r11, r10, r3, r14 \n\t" \
"adcs r9, r11 \n\t" \
"adcs r10, #0 \n\t" \
\
/* Multiply by 2 */ \
"mov r11, #0 \n\t" \
"adds r4, r4 \n\t" \
"adcs r5, r5 \n\t" \
"adcs r6, r6 \n\t" \
"adcs r7, r7 \n\t" \
"adcs r8, r8 \n\t" \
"adcs r9, r9 \n\t" \
"adcs r10, r10 \n\t" \
"adcs r11, #0 \n\t" \
\
/* Add into previous */ \
"ldr r14, [r0] \n\t" \
"adds r4, r14 \n\t" \
"str r4, [r0], #4 \n\t" \
"ldr r14, [r0] \n\t" \
"adcs r5, r14 \n\t" \
"str r5, [r0], #4 \n\t" \
"ldr r14, [r0] \n\t" \
"adcs r6, r14 \n\t" \
"str r6, [r0], #4 \n\t" \
"ldr r14, [r0] \n\t" \
"adcs r7, r14 \n\t" \
"str r7, [r0], #4 \n\t" \
"ldr r14, [r0] \n\t" \
"adcs r8, r14 \n\t" \
"str r8, [r0], #4 \n\t" \
"ldr r14, [r0] \n\t" \
"adcs r9, r14 \n\t" \
"str r9, [r0], #4 \n\t" \
"adcs r10, #0 \n\t" \
"adcs r11, #0 \n\t" \
\
/* Perform center multiplication */ \
"umull r4, r5, r3, r3 \n\t" \
"adds r4, r10 \n\t" \
"adc r5, r11 \n\t" \
"stmia r0!, {r4, r5} \n\t"
#define FAST_SQUARE_ASM_7_TO_8 \
"cmp r2, #7 \n\t" \
"beq 1f \n\t" \
\
/* r3 = high */ \
"ldr r3, [r1] \n\t" \
\
"sub r0, #28 \n\t" \
"sub r1, #28 \n\t" \
\
/* Do off-center multiplication */ \
"ldr r14, [r1], #4 \n\t" \
"umull r4, r5, r3, r14 \n\t" \
"ldr r14, [r1], #4 \n\t" \
"umull r7, r6, r3, r14 \n\t" \
"adds r5, r7 \n\t" \
"ldr r14, [r1], #4 \n\t" \
"umull r8, r7, r3, r14 \n\t" \
"adcs r6, r8 \n\t" \
"ldr r14, [r1], #4 \n\t" \
"umull r9, r8, r3, r14 \n\t" \
"adcs r7, r9 \n\t" \
"ldr r14, [r1], #4 \n\t" \
"umull r10, r9, r3, r14 \n\t" \
"adcs r8, r10 \n\t" \
"ldr r14, [r1], #4 \n\t" \
"umull r11, r10, r3, r14 \n\t" \
"adcs r9, r11 \n\t" \
/* Skip already-loaded r3 */ \
"ldr r14, [r1], #8 \n\t" \
"umull r12, r11, r3, r14 \n\t" \
"adcs r10, r12 \n\t" \
"adcs r11, #0 \n\t" \
\
/* Multiply by 2 */ \
"mov r12, #0 \n\t" \
"adds r4, r4 \n\t" \
"adcs r5, r5 \n\t" \
"adcs r6, r6 \n\t" \
"adcs r7, r7 \n\t" \
"adcs r8, r8 \n\t" \
"adcs r9, r9 \n\t" \
"adcs r10, r10 \n\t" \
"adcs r11, r11 \n\t" \
"adcs r12, #0 \n\t" \
\
/* Add into previous */ \
"ldr r14, [r0] \n\t" \
"adds r4, r14 \n\t" \
"str r4, [r0], #4 \n\t" \
"ldr r14, [r0] \n\t" \
"adcs r5, r14 \n\t" \
"str r5, [r0], #4 \n\t" \
"ldr r14, [r0] \n\t" \
"adcs r6, r14 \n\t" \
"str r6, [r0], #4 \n\t" \
"ldr r14, [r0] \n\t" \
"adcs r7, r14 \n\t" \
"str r7, [r0], #4 \n\t" \
"ldr r14, [r0] \n\t" \
"adcs r8, r14 \n\t" \
"str r8, [r0], #4 \n\t" \
"ldr r14, [r0] \n\t" \
"adcs r9, r14 \n\t" \
"str r9, [r0], #4 \n\t" \
"ldr r14, [r0] \n\t" \
"adcs r10, r14 \n\t" \
"str r10, [r0], #4 \n\t" \
"adcs r11, #0 \n\t" \
"adcs r12, #0 \n\t" \
\
/* Perform center multiplication */ \
"umull r4, r5, r3, r3 \n\t" \
"adds r4, r11 \n\t" \
"adc r5, r12 \n\t" \
"stmia r0!, {r4, r5} \n\t"
static void vli_square(uECC_word_t *result, const uECC_word_t *left, wordcount_t num_words) {
register uint32_t *r0 __asm__("r0") = result;
register const uint32_t *r1 __asm__("r1") = left;
register uint32_t r2 __asm__("r2") = num_words;
__asm__ volatile (
".syntax unified \n\t"
"push {r1, r2} \n\t"
#if (uECC_MIN_WORDS == 5)
FAST_SQUARE_ASM_5
"pop {r1, r2} \n\t"
#if (uECC_MAX_WORDS > 5)
"add r1, #20 \n\t"
FAST_SQUARE_ASM_5_TO_6
#endif
#if (uECC_MAX_WORDS > 6)
FAST_SQUARE_ASM_6_TO_7
#endif
#if (uECC_MAX_WORDS > 7)
FAST_SQUARE_ASM_7_TO_8
#endif
#elif (uECC_MIN_WORDS == 6)
FAST_SQUARE_ASM_6
"pop {r1, r2} \n\t"
#if (uECC_MAX_WORDS > 6)
"add r1, #24 \n\t"
FAST_SQUARE_ASM_6_TO_7
#endif
#if (uECC_MAX_WORDS > 7)
FAST_SQUARE_ASM_7_TO_8
#endif
#elif (uECC_MIN_WORDS == 7)
FAST_SQUARE_ASM_7
"pop {r1, r2} \n\t"
#if (uECC_MAX_WORDS > 7)
"add r1, #28 \n\t"
FAST_SQUARE_ASM_7_TO_8
#endif
#elif (uECC_MIN_WORDS == 8)
FAST_SQUARE_ASM_8
"pop {r1, r2} \n\t"
#endif
"1: \n\t"
RESUME_SYNTAX
: "+r" (r0), "+r" (r1)
: "r" (r2)
: "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory"
);
}
#define asm_square 1
#endif /* uECC_SQUARE_FUNC */
#endif /* uECC_PLATFORM != uECC_arm_thumb */
#endif /* _UECC_ASM_ARM_FAST_H_ */
File diff suppressed because it is too large Load Diff
+19 -4
View File
@@ -1,3 +1,8 @@
/* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */
#ifndef _UECC_ASM_ARM_SMALL_H_
#define _UECC_ASM_ARM_SMALL_H_
#if (uECC_PLATFORM == uECC_arm_thumb)
#define REG_RW "+l"
#define REG_WRITE "=l"
@@ -12,6 +17,7 @@
#define RESUME_SYNTAX ".syntax divided \n\t"
#endif
#if !asm_add
static uECC_word_t vli_add(uECC_word_t *result,
const uECC_word_t *left,
const uECC_word_t *right,
@@ -41,11 +47,13 @@ static uECC_word_t vli_add(uECC_word_t *result,
return carry;
}
#define asm_add 1
#endif
static uint32_t vli_sub(uECC_word_t *result,
const uECC_word_t *left,
const uECC_word_t *right,
wordcount_t num_words) {
#if !asm_sub
static uECC_word_t vli_sub(uECC_word_t *result,
const uECC_word_t *left,
const uECC_word_t *right,
wordcount_t num_words) {
uint32_t carry = 1; /* carry = 1 initially (means don't borrow) */
uint32_t left_word;
uint32_t right_word;
@@ -71,7 +79,9 @@ static uint32_t vli_sub(uECC_word_t *result,
return !carry;
}
#define asm_sub 1
#endif
#if !asm_mult
static void vli_mult(uECC_word_t *result,
const uECC_word_t *left,
const uECC_word_t *right,
@@ -229,8 +239,10 @@ static void vli_mult(uECC_word_t *result,
#endif
}
#define asm_mult 1
#endif
#if uECC_SQUARE_FUNC
#if !asm_square
static void vli_square(uECC_word_t *result, const uECC_word_t *left, wordcount_t num_words) {
#if (uECC_PLATFORM != uECC_arm_thumb)
uint32_t c0 = 0;
@@ -404,4 +416,7 @@ static void vli_square(uECC_word_t *result, const uECC_word_t *left, wordcount_t
#endif
}
#define asm_square 1
#endif
#endif /* uECC_SQUARE_FUNC */
#endif /* _UECC_ASM_ARM_SMALL_H_ */
+450 -388
View File
@@ -1,3 +1,8 @@
/* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */
#ifndef _UECC_CURVE_SPECIFIC_H_
#define _UECC_CURVE_SPECIFIC_H_
#define num_bytes_secp160r1 20
#define num_bytes_secp192r1 24
#define num_bytes_secp224r1 28
@@ -46,26 +51,85 @@
#endif /* uECC_WORD_SIZE */
static void double_jacobian_secp256k1(uECC_word_t * X1,
uECC_word_t * Y1,
uECC_word_t * Z1,
uECC_Curve curve);
static void double_jacobian_default(uECC_word_t * X1,
uECC_word_t * Y1,
uECC_word_t * Z1,
uECC_Curve curve);
uECC_Curve curve) {
/* t1 = X, t2 = Y, t3 = Z */
uECC_word_t t4[uECC_MAX_WORDS];
uECC_word_t t5[uECC_MAX_WORDS];
static void mod_sqrt_default(uECC_word_t *a, uECC_Curve curve);
static void mod_sqrt_secp224r1(uECC_word_t *a, uECC_Curve curve);
if (vli_isZero(Z1, curve->num_words)) {
return;
}
static void x_side_default(uECC_word_t *result, const uECC_word_t *x, uECC_Curve curve);
static void x_side_secp256k1(uECC_word_t *result, const uECC_word_t *x, uECC_Curve curve);
vli_modSquare_fast(t4, Y1, curve); /* t4 = y1^2 */
vli_modMult_fast(t5, X1, t4, curve); /* t5 = x1*y1^2 = A */
vli_modSquare_fast(t4, t4, curve); /* t4 = y1^4 */
vli_modMult_fast(Y1, Y1, Z1, curve); /* t2 = y1*z1 = z3 */
vli_modSquare_fast(Z1, Z1, curve); /* t3 = z1^2 */
vli_modAdd(X1, X1, Z1, curve->p, curve->num_words); /* t1 = x1 + z1^2 */
vli_modAdd(Z1, Z1, Z1, curve->p, curve->num_words); /* t3 = 2*z1^2 */
vli_modSub(Z1, X1, Z1, curve->p, curve->num_words); /* t3 = x1 - z1^2 */
vli_modMult_fast(X1, X1, Z1, curve); /* t1 = x1^2 - z1^4 */
vli_modAdd(Z1, X1, X1, curve->p, curve->num_words); /* t3 = 2*(x1^2 - z1^4) */
vli_modAdd(X1, X1, Z1, curve->p, curve->num_words); /* t1 = 3*(x1^2 - z1^4) */
if (vli_testBit(X1, 0)) {
uECC_word_t l_carry = vli_add(X1, X1, curve->p, curve->num_words);
vli_rshift1(X1, curve->num_words);
X1[curve->num_words - 1] |= l_carry << (uECC_WORD_BITS - 1);
} else {
vli_rshift1(X1, curve->num_words);
}
/* t1 = 3/2*(x1^2 - z1^4) = B */
vli_modSquare_fast(Z1, X1, curve); /* t3 = B^2 */
vli_modSub(Z1, Z1, t5, curve->p, curve->num_words); /* t3 = B^2 - A */
vli_modSub(Z1, Z1, t5, curve->p, curve->num_words); /* t3 = B^2 - 2A = x3 */
vli_modSub(t5, t5, Z1, curve->p, curve->num_words); /* t5 = A - x3 */
vli_modMult_fast(X1, X1, t5, curve); /* t1 = B * (A - x3) */
vli_modSub(t4, X1, t4, curve->p, curve->num_words); /* t4 = B * (A - x3) - y1^4 = y3 */
vli_set(X1, Z1, curve->num_words);
vli_set(Z1, Y1, curve->num_words);
vli_set(Y1, t4, curve->num_words);
}
/* Compute a = sqrt(a) (mod curve_p). */
static void mod_sqrt_default(uECC_word_t *a, uECC_Curve curve) {
bitcount_t i;
uECC_word_t p1[uECC_MAX_WORDS] = {1};
uECC_word_t l_result[uECC_MAX_WORDS] = {1};
/* When curve->p == 3 (mod 4), we can compute
sqrt(a) = a^((curve->p + 1) / 4) (mod curve->p). */
vli_add(p1, curve->p, p1, curve->num_words); /* p1 = curve_p + 1 */
for (i = vli_numBits(p1, curve->num_words) - 1; i > 1; --i) {
vli_modSquare_fast(l_result, l_result, curve);
if (vli_testBit(p1, i)) {
vli_modMult_fast(l_result, l_result, a, curve);
}
}
vli_set(a, l_result, curve->num_words);
}
/* Computes result = x^3 + ax + b. result must not overlap x. */
static void x_side_default(uECC_word_t *result, const uECC_word_t *x, uECC_Curve curve) {
uECC_word_t _3[uECC_MAX_WORDS] = {3}; /* -a = 3 */
vli_modSquare_fast(result, x, curve); /* r = x^2 */
vli_modSub(result, result, _3, curve->p, curve->num_words); /* r = x^2 - 3 */
vli_modMult_fast(result, result, x, curve); /* r = x^3 - 3x */
vli_modAdd(result, result, curve->b, curve->p, curve->num_words); /* r = x^3 - 3x + b */
}
#if uECC_SUPPORTS_secp160r1
#if (uECC_OPTIMIZATION_LEVEL > 0)
static void vli_mmod_fast_secp160r1(uECC_word_t *result, uECC_word_t *product);
static void vli_mmod_fast_secp192r1(uECC_word_t *result, uECC_word_t *product);
static void vli_mmod_fast_secp224r1(uECC_word_t *result, uECC_word_t *product);
static void vli_mmod_fast_secp256r1(uECC_word_t *result, uECC_word_t *product);
static void vli_mmod_fast_secp256k1(uECC_word_t *result, uECC_word_t *product);
#endif
static const struct uECC_Curve_t curve_secp160r1 = {
num_words_secp160r1,
@@ -90,9 +154,126 @@ static const struct uECC_Curve_t curve_secp160r1 = {
&double_jacobian_default,
&mod_sqrt_default,
&x_side_default,
#if (uECC_OPTIMIZATION_LEVEL > 0)
&vli_mmod_fast_secp160r1
#endif
};
uECC_Curve uECC_secp160r1(void) { return &curve_secp160r1; }
#if (uECC_OPTIMIZATION_LEVEL > 0)
/* Computes result = product % curve_p
see http://www.isys.uni-klu.ac.at/PDF/2001-0126-MT.pdf page 354
Note that this only works if log2(omega) < log2(p) / 2 */
static void omega_mult_secp160r1(uECC_word_t *result, const uECC_word_t *right);
#if uECC_WORD_SIZE == 8
static void vli_mmod_fast_secp160r1(uECC_word_t *result, uECC_word_t *product) {
uECC_word_t tmp[2 * num_words_secp160r1];
uECC_word_t copy;
vli_clear(tmp, num_words_secp160r1);
vli_clear(tmp + num_words_secp160r1, num_words_secp160r1);
omega_mult_secp160r1(tmp, product + num_words_secp160r1 - 1); /* (Rq, q) = q * c */
product[num_words_secp160r1 - 1] &= 0xffffffff;
copy = tmp[num_words_secp160r1 - 1];
tmp[num_words_secp160r1 - 1] &= 0xffffffff;
vli_add(result, product, tmp, num_words_secp160r1); /* (C, r) = r + q */
vli_clear(product, num_words_secp160r1);
tmp[num_words_secp160r1 - 1] = copy;
omega_mult_secp160r1(product, tmp + num_words_secp160r1 - 1); /* Rq*c */
vli_add(result, result, product, num_words_secp160r1); /* (C1, r) = r + Rq*c */
while (vli_cmp(result, curve_secp160r1.p, num_words_secp160r1) > 0) {
vli_sub(result, result, curve_secp160r1.p, num_words_secp160r1);
}
}
static void omega_mult_secp160r1(uint64_t *result, const uint64_t *right) {
uint32_t carry;
unsigned i;
/* Multiply by (2^31 + 1). */
carry = 0;
for (i = 0; i < num_words_secp160r1; ++i) {
uint64_t tmp = (right[i] >> 32) | (right[i + 1] << 32);
result[i] = (tmp << 31) + tmp + carry;
carry = (tmp >> 33) + (result[i] < tmp || (carry && result[i] == tmp));
}
result[i] = carry;
}
#else
static void vli_mmod_fast_secp160r1(uECC_word_t *result, uECC_word_t *product) {
uECC_word_t tmp[2 * num_words_secp160r1];
uECC_word_t carry;
vli_clear(tmp, num_words_secp160r1);
vli_clear(tmp + num_words_secp160r1, num_words_secp160r1);
omega_mult_secp160r1(tmp, product + num_words_secp160r1); /* (Rq, q) = q * c */
carry = vli_add(result, product, tmp, num_words_secp160r1); /* (C, r) = r + q */
vli_clear(product, num_words_secp160r1);
omega_mult_secp160r1(product, tmp + num_words_secp160r1); /* Rq*c */
carry += vli_add(result, result, product, num_words_secp160r1); /* (C1, r) = r + Rq*c */
while (carry > 0) {
--carry;
vli_sub(result, result, curve_secp160r1.p, num_words_secp160r1);
}
if (vli_cmp(result, curve_secp160r1.p, num_words_secp160r1) > 0) {
vli_sub(result, result, curve_secp160r1.p, num_words_secp160r1);
}
}
#endif
#if uECC_WORD_SIZE == 1
static void omega_mult_secp160r1(uint8_t *result, const uint8_t *right) {
uint8_t carry;
uint8_t i;
/* Multiply by (2^31 + 1). */
vli_set(result + 4, right, num_words_secp160r1); /* 2^32 */
vli_rshift1(result + 4, num_words_secp160r1); /* 2^31 */
result[3] = right[0] << 7; /* get last bit from shift */
carry = vli_add(result, result, right, num_words_secp160r1); /* 2^31 + 1 */
for (i = num_words_secp160r1; carry; ++i) {
uint16_t sum = (uint16_t)result[i] + carry;
result[i] = (uint8_t)sum;
carry = sum >> 8;
}
}
#elif uECC_WORD_SIZE == 4
static void omega_mult_secp160r1(uint32_t *result, const uint32_t *right) {
uint32_t carry;
unsigned i;
/* Multiply by (2^31 + 1). */
vli_set(result + 1, right, num_words_secp160r1); /* 2^32 */
vli_rshift1(result + 1, num_words_secp160r1); /* 2^31 */
result[0] = right[0] << 31; /* get last bit from shift */
carry = vli_add(result, result, right, num_words_secp160r1); /* 2^31 + 1 */
for (i = num_words_secp160r1; carry; ++i) {
uint64_t sum = (uint64_t)result[i] + carry;
result[i] = (uint32_t)sum;
carry = sum >> 32;
}
}
#endif /* uECC_WORD_SIZE */
#endif /* (uECC_OPTIMIZATION_LEVEL > 0) */
#endif /* uECC_SUPPORTS_secp160r1 */
#if uECC_SUPPORTS_secp192r1
#if (uECC_OPTIMIZATION_LEVEL > 0)
static void vli_mmod_fast_secp192r1(uECC_word_t *result, uECC_word_t *product);
#endif
static const struct uECC_Curve_t curve_secp192r1 = {
num_words_secp192r1,
num_words_secp192r1,
@@ -116,9 +297,109 @@ static const struct uECC_Curve_t curve_secp192r1 = {
&double_jacobian_default,
&mod_sqrt_default,
&x_side_default,
#if (uECC_OPTIMIZATION_LEVEL > 0)
&vli_mmod_fast_secp192r1
#endif
};
uECC_Curve uECC_secp192r1(void) { return &curve_secp192r1; }
#if (uECC_OPTIMIZATION_LEVEL > 0)
/* Computes result = product % curve_p.
See algorithm 5 and 6 from http://www.isys.uni-klu.ac.at/PDF/2001-0126-MT.pdf */
#if uECC_WORD_SIZE == 1
static void vli_mmod_fast_secp192r1(uint8_t *result, uint8_t *product) {
uint8_t tmp[num_words_secp192r1];
uint8_t carry;
vli_set(result, product, num_words_secp192r1);
vli_set(tmp, &product[24], num_words_secp192r1);
carry = vli_add(result, result, tmp, num_words_secp192r1);
tmp[0] = tmp[1] = tmp[2] = tmp[3] = tmp[4] = tmp[5] = tmp[6] = tmp[7] = 0;
tmp[8] = product[24]; tmp[9] = product[25]; tmp[10] = product[26]; tmp[11] = product[27];
tmp[12] = product[28]; tmp[13] = product[29]; tmp[14] = product[30]; tmp[15] = product[31];
tmp[16] = product[32]; tmp[17] = product[33]; tmp[18] = product[34]; tmp[19] = product[35];
tmp[20] = product[36]; tmp[21] = product[37]; tmp[22] = product[38]; tmp[23] = product[39];
carry += vli_add(result, result, tmp, num_words_secp192r1);
tmp[0] = tmp[8] = product[40];
tmp[1] = tmp[9] = product[41];
tmp[2] = tmp[10] = product[42];
tmp[3] = tmp[11] = product[43];
tmp[4] = tmp[12] = product[44];
tmp[5] = tmp[13] = product[45];
tmp[6] = tmp[14] = product[46];
tmp[7] = tmp[15] = product[47];
tmp[16] = tmp[17] = tmp[18] = tmp[19] = tmp[20] = tmp[21] = tmp[22] = tmp[23] = 0;
carry += vli_add(result, result, tmp, num_words_secp192r1);
while (carry || vli_cmp(curve_secp192r1.p, result, num_words_secp192r1) != 1) {
carry -= vli_sub(result, result, curve_secp192r1.p, num_words_secp192r1);
}
}
#elif uECC_WORD_SIZE == 4
static void vli_mmod_fast_secp192r1(uint32_t *result, uint32_t *product) {
uint32_t tmp[num_words_secp192r1];
int carry;
vli_set(result, product, num_words_secp192r1);
vli_set(tmp, &product[6], num_words_secp192r1);
carry = vli_add(result, result, tmp, num_words_secp192r1);
tmp[0] = tmp[1] = 0;
tmp[2] = product[6];
tmp[3] = product[7];
tmp[4] = product[8];
tmp[5] = product[9];
carry += vli_add(result, result, tmp, num_words_secp192r1);
tmp[0] = tmp[2] = product[10];
tmp[1] = tmp[3] = product[11];
tmp[4] = tmp[5] = 0;
carry += vli_add(result, result, tmp, num_words_secp192r1);
while (carry || vli_cmp(curve_secp192r1.p, result, num_words_secp192r1) != 1) {
carry -= vli_sub(result, result, curve_secp192r1.p, num_words_secp192r1);
}
}
#else
static void vli_mmod_fast_secp192r1(uint64_t *result, uint64_t *product) {
uint64_t tmp[num_words_secp192r1];
int carry;
vli_set(result, product, num_words_secp192r1);
vli_set(tmp, &product[3], num_words_secp192r1);
carry = vli_add(result, result, tmp, num_words_secp192r1);
tmp[0] = 0;
tmp[1] = product[3];
tmp[2] = product[4];
carry += vli_add(result, result, tmp, num_words_secp192r1);
tmp[0] = tmp[1] = product[5];
tmp[2] = 0;
carry += vli_add(result, result, tmp, num_words_secp192r1);
while (carry || vli_cmp(curve_secp192r1.p, result, num_words_secp192r1) != 1) {
carry -= vli_sub(result, result, curve_secp192r1.p, num_words_secp192r1);
}
}
#endif /* uECC_WORD_SIZE */
#endif /* (uECC_OPTIMIZATION_LEVEL > 0) */
#endif /* uECC_SUPPORTS_secp192r1 */
#if uECC_SUPPORTS_secp224r1
static void mod_sqrt_secp224r1(uECC_word_t *a, uECC_Curve curve);
#if (uECC_OPTIMIZATION_LEVEL > 0)
static void vli_mmod_fast_secp224r1(uECC_word_t *result, uECC_word_t *product);
#endif
static const struct uECC_Curve_t curve_secp224r1 = {
num_words_secp224r1,
num_words_secp224r1,
@@ -147,179 +428,13 @@ static const struct uECC_Curve_t curve_secp224r1 = {
&double_jacobian_default,
&mod_sqrt_secp224r1,
&x_side_default,
#if (uECC_OPTIMIZATION_LEVEL > 0)
&vli_mmod_fast_secp224r1
#endif
};
static const struct uECC_Curve_t curve_secp256r1 = {
num_words_secp256r1,
num_words_secp256r1,
num_bytes_secp256r1,
{ BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF),
BYTES_TO_WORDS_8(FF, FF, FF, FF, 00, 00, 00, 00),
BYTES_TO_WORDS_8(00, 00, 00, 00, 00, 00, 00, 00),
BYTES_TO_WORDS_8(01, 00, 00, 00, FF, FF, FF, FF) },
{ BYTES_TO_WORDS_8(51, 25, 63, FC, C2, CA, B9, F3),
BYTES_TO_WORDS_8(84, 9E, 17, A7, AD, FA, E6, BC),
BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF),
BYTES_TO_WORDS_8(00, 00, 00, 00, FF, FF, FF, FF) },
{ BYTES_TO_WORDS_8(96, C2, 98, D8, 45, 39, A1, F4),
BYTES_TO_WORDS_8(A0, 33, EB, 2D, 81, 7D, 03, 77),
BYTES_TO_WORDS_8(F2, 40, A4, 63, E5, E6, BC, F8),
BYTES_TO_WORDS_8(47, 42, 2C, E1, F2, D1, 17, 6B),
BYTES_TO_WORDS_8(F5, 51, BF, 37, 68, 40, B6, CB),
BYTES_TO_WORDS_8(CE, 5E, 31, 6B, 57, 33, CE, 2B),
BYTES_TO_WORDS_8(16, 9E, 0F, 7C, 4A, EB, E7, 8E),
BYTES_TO_WORDS_8(9B, 7F, 1A, FE, E2, 42, E3, 4F) },
{ BYTES_TO_WORDS_8(4B, 60, D2, 27, 3E, 3C, CE, 3B),
BYTES_TO_WORDS_8(F6, B0, 53, CC, B0, 06, 1D, 65),
BYTES_TO_WORDS_8(BC, 86, 98, 76, 55, BD, EB, B3),
BYTES_TO_WORDS_8(E7, 93, 3A, AA, D8, 35, C6, 5A) },
&double_jacobian_default,
&mod_sqrt_default,
&x_side_default,
&vli_mmod_fast_secp256r1
};
static const struct uECC_Curve_t curve_secp256k1 = {
num_words_secp256k1,
num_words_secp256k1,
num_bytes_secp256k1,
{ 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,
&mod_sqrt_default,
&x_side_secp256k1,
&vli_mmod_fast_secp256k1
};
uECC_Curve uECC_secp160r1(void) { return &curve_secp160r1; }
uECC_Curve uECC_secp192r1(void) { return &curve_secp192r1; }
uECC_Curve uECC_secp224r1(void) { return &curve_secp224r1; }
uECC_Curve uECC_secp256r1(void) { return &curve_secp256r1; }
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 (vli_isZero(Z1, num_words_secp256k1)) {
return;
}
vli_modSquare_fast(t5, Y1, curve); /* t5 = y1^2 */
vli_modMult_fast(t4, X1, t5, curve); /* t4 = x1*y1^2 = A */
vli_modSquare_fast(X1, X1, curve); /* t1 = x1^2 */
vli_modSquare_fast(t5, t5, curve); /* t5 = y1^4 */
vli_modMult_fast(Z1, Y1, Z1, curve); /* t3 = y1*z1 = z3 */
vli_modAdd(Y1, X1, X1, curve->p, num_words_secp256k1); /* t2 = 2*x1^2 */
vli_modAdd(Y1, Y1, X1, curve->p, num_words_secp256k1); /* t2 = 3*x1^2 */
if (vli_testBit(Y1, 0)) {
uECC_word_t carry = vli_add(Y1, Y1, curve->p, num_words_secp256k1);
vli_rshift1(Y1, num_words_secp256k1);
Y1[num_words_secp256k1 - 1] |= carry << (uECC_WORD_BITS - 1);
} else {
vli_rshift1(Y1, num_words_secp256k1);
}
/* t2 = 3/2*(x1^2) = B */
vli_modSquare_fast(X1, Y1, curve); /* t1 = B^2 */
vli_modSub(X1, X1, t4, curve->p, num_words_secp256k1); /* t1 = B^2 - A */
vli_modSub(X1, X1, t4, curve->p, num_words_secp256k1); /* t1 = B^2 - 2A = x3 */
vli_modSub(t4, t4, X1, curve->p, num_words_secp256k1); /* t4 = A - x3 */
vli_modMult_fast(Y1, Y1, t4, curve); /* t2 = B * (A - x3) */
vli_modSub(Y1, Y1, t5, curve->p, num_words_secp256k1); /* t2 = B * (A - x3) - y1^4 = y3 */
}
static void double_jacobian_default(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[uECC_MAX_WORDS];
uECC_word_t t5[uECC_MAX_WORDS];
if (vli_isZero(Z1, curve->num_words)) {
return;
}
vli_modSquare_fast(t4, Y1, curve); /* t4 = y1^2 */
vli_modMult_fast(t5, X1, t4, curve); /* t5 = x1*y1^2 = A */
vli_modSquare_fast(t4, t4, curve); /* t4 = y1^4 */
vli_modMult_fast(Y1, Y1, Z1, curve); /* t2 = y1*z1 = z3 */
vli_modSquare_fast(Z1, Z1, curve); /* t3 = z1^2 */
vli_modAdd(X1, X1, Z1, curve->p, curve->num_words); /* t1 = x1 + z1^2 */
vli_modAdd(Z1, Z1, Z1, curve->p, curve->num_words); /* t3 = 2*z1^2 */
vli_modSub(Z1, X1, Z1, curve->p, curve->num_words); /* t3 = x1 - z1^2 */
vli_modMult_fast(X1, X1, Z1, curve); /* t1 = x1^2 - z1^4 */
vli_modAdd(Z1, X1, X1, curve->p, curve->num_words); /* t3 = 2*(x1^2 - z1^4) */
vli_modAdd(X1, X1, Z1, curve->p, curve->num_words); /* t1 = 3*(x1^2 - z1^4) */
if (vli_testBit(X1, 0)) {
uECC_word_t l_carry = vli_add(X1, X1, curve->p, curve->num_words);
vli_rshift1(X1, curve->num_words);
X1[curve->num_words - 1] |= l_carry << (uECC_WORD_BITS - 1);
} else {
vli_rshift1(X1, curve->num_words);
}
/* t1 = 3/2*(x1^2 - z1^4) = B */
vli_modSquare_fast(Z1, X1, curve); /* t3 = B^2 */
vli_modSub(Z1, Z1, t5, curve->p, curve->num_words); /* t3 = B^2 - A */
vli_modSub(Z1, Z1, t5, curve->p, curve->num_words); /* t3 = B^2 - 2A = x3 */
vli_modSub(t5, t5, Z1, curve->p, curve->num_words); /* t5 = A - x3 */
vli_modMult_fast(X1, X1, t5, curve); /* t1 = B * (A - x3) */
vli_modSub(t4, X1, t4, curve->p, curve->num_words); /* t4 = B * (A - x3) - y1^4 = y3 */
vli_set(X1, Z1, curve->num_words);
vli_set(Z1, Y1, curve->num_words);
vli_set(Y1, t4, curve->num_words);
}
/* Compute a = sqrt(a) (mod curve_p). */
static void mod_sqrt_default(uECC_word_t *a, uECC_Curve curve) {
bitcount_t i;
uECC_word_t p1[uECC_MAX_WORDS] = {1};
uECC_word_t l_result[uECC_MAX_WORDS] = {1};
/* When curve->p == 3 (mod 4), we can compute
sqrt(a) = a^((curve->p + 1) / 4) (mod curve->p). */
vli_add(p1, curve->p, p1, curve->num_words); /* p1 = curve_p + 1 */
for (i = vli_numBits(p1, curve->num_words) - 1; i > 1; --i) {
vli_modSquare_fast(l_result, l_result, curve);
if (vli_testBit(p1, i)) {
vli_modMult_fast(l_result, l_result, a, curve);
}
}
vli_set(a, l_result, curve->num_words);
}
/* Routine 3.2.4 RS; from http://www.nsa.gov/ia/_files/nist-routines.pdf */
static void mod_sqrt_secp224r1_rs(uECC_word_t *d1,
@@ -437,213 +552,11 @@ static void mod_sqrt_secp224r1(uECC_word_t *a, uECC_Curve curve) {
vli_modMult_fast(a, d0, f1, &curve_secp224r1); /* a <-- d0 / e0 */
}
/* Computes result = x^3 + ax + b. result must not overlap x. */
static void x_side_default(uECC_word_t *result, const uECC_word_t *x, uECC_Curve curve) {
uECC_word_t _3[uECC_MAX_WORDS] = {3}; /* -a = 3 */
vli_modSquare_fast(result, x, curve); /* r = x^2 */
vli_modSub(result, result, _3, curve->p, curve->num_words); /* r = x^2 - 3 */
vli_modMult_fast(result, result, x, curve); /* r = x^3 - 3x */
vli_modAdd(result, result, curve->b, curve->p, curve->num_words); /* r = x^3 - 3x + b */
}
/* 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) {
vli_modSquare_fast(result, x, curve); /* r = x^2 */
vli_modMult_fast(result, result, x, curve); /* r = x^3 */
vli_modAdd(result, result, curve->b, curve->p, num_words_secp256k1); /* r = x^3 + b */
}
/* Computes result = product % curve_p
see http://www.isys.uni-klu.ac.at/PDF/2001-0126-MT.pdf page 354
Note that this only works if log2(omega) < log2(p) / 2 */
static void omega_mult_secp160r1(uECC_word_t *result, const uECC_word_t *right);
#if uECC_WORD_SIZE == 8
static void vli_mmod_fast_secp160r1(uECC_word_t *result, uECC_word_t *product) {
uECC_word_t tmp[2 * num_words_secp160r1];
uECC_word_t copy;
vli_clear(tmp, 2 * num_words_secp160r1);
omega_mult_secp160r1(tmp, product + num_words_secp160r1 - 1); /* (Rq, q) = q * c */
product[num_words_secp160r1 - 1] &= 0xffffffff;
copy = tmp[num_words_secp160r1 - 1];
tmp[num_words_secp160r1 - 1] &= 0xffffffff;
vli_add(result, product, tmp, num_words_secp160r1); /* (C, r) = r + q */
vli_clear(product, num_words_secp160r1);
tmp[num_words_secp160r1 - 1] = copy;
omega_mult_secp160r1(product, tmp + num_words_secp160r1 - 1); /* Rq*c */
vli_add(result, result, product, num_words_secp160r1); /* (C1, r) = r + Rq*c */
while (vli_cmp(result, curve_secp160r1.p, num_words_secp160r1) > 0) {
vli_sub(result, result, curve_secp160r1.p, num_words_secp160r1);
}
}
static void omega_mult_secp160r1(uint64_t *result, const uint64_t *right) {
uint32_t carry;
unsigned i;
/* Multiply by (2^31 + 1). */
carry = 0;
for (i = 0; i < num_words_secp160r1; ++i) {
uint64_t tmp = (right[i] >> 32) | (right[i + 1] << 32);
result[i] = (tmp << 31) + tmp + carry;
carry = (tmp >> 33) + (result[i] < tmp || (carry && result[i] == tmp));
}
result[i] = carry;
}
#else
static void vli_mmod_fast_secp160r1(uECC_word_t *result, uECC_word_t *product) {
uECC_word_t tmp[2 * num_words_secp160r1];
uECC_word_t carry;
vli_clear(tmp, 2 * num_words_secp160r1);
omega_mult_secp160r1(tmp, product + num_words_secp160r1); /* (Rq, q) = q * c */
carry = vli_add(result, product, tmp, num_words_secp160r1); /* (C, r) = r + q */
vli_clear(product, num_words_secp160r1);
omega_mult_secp160r1(product, tmp + num_words_secp160r1); /* Rq*c */
carry += vli_add(result, result, product, num_words_secp160r1); /* (C1, r) = r + Rq*c */
while (carry > 0) {
--carry;
vli_sub(result, result, curve_secp160r1.p, num_words_secp160r1);
}
if (vli_cmp(result, curve_secp160r1.p, num_words_secp160r1) > 0) {
vli_sub(result, result, curve_secp160r1.p, num_words_secp160r1);
}
}
#endif
#if uECC_WORD_SIZE == 1
static void omega_mult_secp160r1(uint8_t *result, const uint8_t *right) {
uint8_t carry;
uint8_t i;
/* Multiply by (2^31 + 1). */
vli_set(result + 4, right, num_words_secp160r1); /* 2^32 */
vli_rshift1(result + 4, num_words_secp160r1); /* 2^31 */
result[3] = right[0] << 7; /* get last bit from shift */
carry = vli_add(result, result, right, num_words_secp160r1); /* 2^31 + 1 */
for (i = num_words_secp160r1; carry; ++i) {
uint16_t sum = (uint16_t)result[i] + carry;
result[i] = (uint8_t)sum;
carry = sum >> 8;
}
}
#elif uECC_WORD_SIZE == 4
static void omega_mult_secp160r1(uint32_t *result, const uint32_t *right) {
uint32_t carry;
unsigned i;
/* Multiply by (2^31 + 1). */
vli_set(result + 1, right, num_words_secp160r1); /* 2^32 */
vli_rshift1(result + 1, num_words_secp160r1); /* 2^31 */
result[0] = right[0] << 31; /* get last bit from shift */
carry = vli_add(result, result, right, num_words_secp160r1); /* 2^31 + 1 */
for (i = num_words_secp160r1; carry; ++i) {
uint64_t sum = (uint64_t)result[i] + carry;
result[i] = (uint32_t)sum;
carry = sum >> 32;
}
}
#endif /* uECC_WORD_SIZE */
/* Computes result = product % curve_p.
See algorithm 5 and 6 from http://www.isys.uni-klu.ac.at/PDF/2001-0126-MT.pdf */
#if uECC_WORD_SIZE == 1
static void vli_mmod_fast_secp192r1(uint8_t *result, uint8_t *product) {
uint8_t tmp[num_words_secp192r1];
uint8_t carry;
vli_set(result, product, num_words_secp192r1);
vli_set(tmp, &product[24], num_words_secp192r1);
carry = vli_add(result, result, tmp, num_words_secp192r1);
tmp[0] = tmp[1] = tmp[2] = tmp[3] = tmp[4] = tmp[5] = tmp[6] = tmp[7] = 0;
tmp[8] = product[24]; tmp[9] = product[25]; tmp[10] = product[26]; tmp[11] = product[27];
tmp[12] = product[28]; tmp[13] = product[29]; tmp[14] = product[30]; tmp[15] = product[31];
tmp[16] = product[32]; tmp[17] = product[33]; tmp[18] = product[34]; tmp[19] = product[35];
tmp[20] = product[36]; tmp[21] = product[37]; tmp[22] = product[38]; tmp[23] = product[39];
carry += vli_add(result, result, tmp, num_words_secp192r1);
tmp[0] = tmp[8] = product[40];
tmp[1] = tmp[9] = product[41];
tmp[2] = tmp[10] = product[42];
tmp[3] = tmp[11] = product[43];
tmp[4] = tmp[12] = product[44];
tmp[5] = tmp[13] = product[45];
tmp[6] = tmp[14] = product[46];
tmp[7] = tmp[15] = product[47];
tmp[16] = tmp[17] = tmp[18] = tmp[19] = tmp[20] = tmp[21] = tmp[22] = tmp[23] = 0;
carry += vli_add(result, result, tmp, num_words_secp192r1);
while (carry || vli_cmp(curve_secp192r1.p, result, num_words_secp192r1) != 1) {
carry -= vli_sub(result, result, curve_secp192r1.p, num_words_secp192r1);
}
}
#elif uECC_WORD_SIZE == 4
static void vli_mmod_fast_secp192r1(uint32_t *result, uint32_t *product) {
uint32_t tmp[num_words_secp192r1];
int carry;
vli_set(result, product, num_words_secp192r1);
vli_set(tmp, &product[6], num_words_secp192r1);
carry = vli_add(result, result, tmp, num_words_secp192r1);
tmp[0] = tmp[1] = 0;
tmp[2] = product[6];
tmp[3] = product[7];
tmp[4] = product[8];
tmp[5] = product[9];
carry += vli_add(result, result, tmp, num_words_secp192r1);
tmp[0] = tmp[2] = product[10];
tmp[1] = tmp[3] = product[11];
tmp[4] = tmp[5] = 0;
carry += vli_add(result, result, tmp, num_words_secp192r1);
while (carry || vli_cmp(curve_secp192r1.p, result, num_words_secp192r1) != 1) {
carry -= vli_sub(result, result, curve_secp192r1.p, num_words_secp192r1);
}
}
#else
static void vli_mmod_fast_secp192r1(uint64_t *result, uint64_t *product) {
uint64_t tmp[num_words_secp192r1];
int carry;
vli_set(result, product, num_words_secp192r1);
vli_set(tmp, &product[3], num_words_secp192r1);
carry = vli_add(result, result, tmp, num_words_secp192r1);
tmp[0] = 0;
tmp[1] = product[3];
tmp[2] = product[4];
carry += vli_add(result, result, tmp, num_words_secp192r1);
tmp[0] = tmp[1] = product[5];
tmp[2] = 0;
carry += vli_add(result, result, tmp, num_words_secp192r1);
while (carry || vli_cmp(curve_secp192r1.p, result, num_words_secp192r1) != 1) {
carry -= vli_sub(result, result, curve_secp192r1.p, num_words_secp192r1);
}
}
#endif /* uECC_WORD_SIZE */
#if (uECC_OPTIMIZATION_LEVEL > 0)
/* Computes result = product % curve_p
from http://www.nsa.gov/ia/_files/nist-routines.pdf */
#if uECC_WORD_SIZE == 1
void vli_mmod_fast_secp224r1(uint8_t *result, uint8_t *product) {
static void vli_mmod_fast_secp224r1(uint8_t *result, uint8_t *product) {
uint8_t tmp[num_words_secp224r1];
int8_t carry;
@@ -698,7 +611,7 @@ void vli_mmod_fast_secp224r1(uint8_t *result, uint8_t *product) {
}
}
#elif uECC_WORD_SIZE == 4
void vli_mmod_fast_secp224r1(uint32_t *result, uint32_t *product)
static void vli_mmod_fast_secp224r1(uint32_t *result, uint32_t *product)
{
uint32_t tmp[num_words_secp224r1];
int carry;
@@ -749,7 +662,7 @@ void vli_mmod_fast_secp224r1(uint32_t *result, uint32_t *product)
}
}
#else
void vli_mmod_fast_secp224r1(uint64_t *result, uint64_t *product)
static void vli_mmod_fast_secp224r1(uint64_t *result, uint64_t *product)
{
uint64_t tmp[num_words_secp224r1];
int carry = 0;
@@ -795,7 +708,53 @@ void vli_mmod_fast_secp224r1(uint64_t *result, uint64_t *product)
}
}
#endif /* uECC_WORD_SIZE */
#endif /* (uECC_OPTIMIZATION_LEVEL > 0) */
#endif /* uECC_SUPPORTS_secp224r1 */
#if uECC_SUPPORTS_secp256r1
#if (uECC_OPTIMIZATION_LEVEL > 0)
static void vli_mmod_fast_secp256r1(uECC_word_t *result, uECC_word_t *product);
#endif
static const struct uECC_Curve_t curve_secp256r1 = {
num_words_secp256r1,
num_words_secp256r1,
num_bytes_secp256r1,
{ BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF),
BYTES_TO_WORDS_8(FF, FF, FF, FF, 00, 00, 00, 00),
BYTES_TO_WORDS_8(00, 00, 00, 00, 00, 00, 00, 00),
BYTES_TO_WORDS_8(01, 00, 00, 00, FF, FF, FF, FF) },
{ BYTES_TO_WORDS_8(51, 25, 63, FC, C2, CA, B9, F3),
BYTES_TO_WORDS_8(84, 9E, 17, A7, AD, FA, E6, BC),
BYTES_TO_WORDS_8(FF, FF, FF, FF, FF, FF, FF, FF),
BYTES_TO_WORDS_8(00, 00, 00, 00, FF, FF, FF, FF) },
{ BYTES_TO_WORDS_8(96, C2, 98, D8, 45, 39, A1, F4),
BYTES_TO_WORDS_8(A0, 33, EB, 2D, 81, 7D, 03, 77),
BYTES_TO_WORDS_8(F2, 40, A4, 63, E5, E6, BC, F8),
BYTES_TO_WORDS_8(47, 42, 2C, E1, F2, D1, 17, 6B),
BYTES_TO_WORDS_8(F5, 51, BF, 37, 68, 40, B6, CB),
BYTES_TO_WORDS_8(CE, 5E, 31, 6B, 57, 33, CE, 2B),
BYTES_TO_WORDS_8(16, 9E, 0F, 7C, 4A, EB, E7, 8E),
BYTES_TO_WORDS_8(9B, 7F, 1A, FE, E2, 42, E3, 4F) },
{ BYTES_TO_WORDS_8(4B, 60, D2, 27, 3E, 3C, CE, 3B),
BYTES_TO_WORDS_8(F6, B0, 53, CC, B0, 06, 1D, 65),
BYTES_TO_WORDS_8(BC, 86, 98, 76, 55, BD, EB, B3),
BYTES_TO_WORDS_8(E7, 93, 3A, AA, D8, 35, C6, 5A) },
&double_jacobian_default,
&mod_sqrt_default,
&x_side_default,
#if (uECC_OPTIMIZATION_LEVEL > 0)
&vli_mmod_fast_secp256r1
#endif
};
uECC_Curve uECC_secp256r1(void) { return &curve_secp256r1; }
#if (uECC_OPTIMIZATION_LEVEL > 0)
/* Computes result = product % curve_p
from http://www.nsa.gov/ia/_files/nist-routines.pdf */
#if uECC_WORD_SIZE == 1
@@ -1077,13 +1036,111 @@ static void vli_mmod_fast_secp256r1(uint64_t *result, uint64_t *product) {
}
}
#endif /* uECC_WORD_SIZE */
#endif /* (uECC_OPTIMIZATION_LEVEL > 0) */
#endif /* uECC_SUPPORTS_secp256r1 */
#if uECC_SUPPORTS_secp256k1
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);
#if (uECC_OPTIMIZATION_LEVEL > 0)
static void vli_mmod_fast_secp256k1(uECC_word_t *result, uECC_word_t *product);
#endif
static const struct uECC_Curve_t curve_secp256k1 = {
num_words_secp256k1,
num_words_secp256k1,
num_bytes_secp256k1,
{ 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,
&mod_sqrt_default,
&x_side_secp256k1,
#if (uECC_OPTIMIZATION_LEVEL > 0)
&vli_mmod_fast_secp256k1
#endif
};
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 (vli_isZero(Z1, num_words_secp256k1)) {
return;
}
vli_modSquare_fast(t5, Y1, curve); /* t5 = y1^2 */
vli_modMult_fast(t4, X1, t5, curve); /* t4 = x1*y1^2 = A */
vli_modSquare_fast(X1, X1, curve); /* t1 = x1^2 */
vli_modSquare_fast(t5, t5, curve); /* t5 = y1^4 */
vli_modMult_fast(Z1, Y1, Z1, curve); /* t3 = y1*z1 = z3 */
vli_modAdd(Y1, X1, X1, curve->p, num_words_secp256k1); /* t2 = 2*x1^2 */
vli_modAdd(Y1, Y1, X1, curve->p, num_words_secp256k1); /* t2 = 3*x1^2 */
if (vli_testBit(Y1, 0)) {
uECC_word_t carry = vli_add(Y1, Y1, curve->p, num_words_secp256k1);
vli_rshift1(Y1, num_words_secp256k1);
Y1[num_words_secp256k1 - 1] |= carry << (uECC_WORD_BITS - 1);
} else {
vli_rshift1(Y1, num_words_secp256k1);
}
/* t2 = 3/2*(x1^2) = B */
vli_modSquare_fast(X1, Y1, curve); /* t1 = B^2 */
vli_modSub(X1, X1, t4, curve->p, num_words_secp256k1); /* t1 = B^2 - A */
vli_modSub(X1, X1, t4, curve->p, num_words_secp256k1); /* t1 = B^2 - 2A = x3 */
vli_modSub(t4, t4, X1, curve->p, num_words_secp256k1); /* t4 = A - x3 */
vli_modMult_fast(Y1, Y1, t4, curve); /* t2 = B * (A - x3) */
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) {
vli_modSquare_fast(result, x, curve); /* r = x^2 */
vli_modMult_fast(result, result, x, curve); /* r = x^3 */
vli_modAdd(result, result, curve->b, curve->p, num_words_secp256k1); /* r = x^3 + b */
}
#if (uECC_OPTIMIZATION_LEVEL > 0)
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;
vli_clear(tmp, 2 * num_words_secp256k1);
vli_clear(tmp, num_words_secp256k1);
vli_clear(tmp + num_words_secp256k1, num_words_secp256k1);
omega_mult_secp256k1(tmp, product + num_words_secp256k1); /* (Rq, q) = q * c */
@@ -1163,3 +1220,8 @@ static void omega_mult_secp256k1(uint64_t * result, const uint64_t * right) {
result[num_words_secp256k1] = r0;
}
#endif /* uECC_WORD_SIZE */
#endif /* (uECC_OPTIMIZATION_LEVEL > 0) */
#endif /* uECC_SUPPORTS_secp256k1 */
#endif /* _UECC_CURVE_SPECIFIC_H_ */
+12 -29
View File
@@ -1,3 +1,8 @@
/* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */
#ifndef _UECC_PLATFORM_SPECIFIC_H_
#define _UECC_PLATFORM_SPECIFIC_H_
#ifndef uECC_PLATFORM
#if __AVR__
#define uECC_PLATFORM uECC_avr
@@ -32,29 +37,16 @@
#error "Unsupported value for uECC_WORD_SIZE"
#endif
/* Optimization options... */
#define uECC_asm_none 0
#define uECC_asm_small 1
#define uECC_asm_fast 2
#ifndef uECC_ASM
#define uECC_ASM uECC_asm_small
#endif
#ifndef uECC_SQUARE_FUNC
#define uECC_SQUARE_FUNC 0
#endif
/* --- end --- */
#if (uECC_ASM && (uECC_PLATFORM == uECC_avr) && (uECC_WORD_SIZE != 1))
#pragma message ("uECC_WORD_SIZE must be 1 when using AVR asm")
#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_ASM && \
(uECC_PLATFORM == uECC_arm || uECC_PLATFORM == uECC_arm_thumb) && \
#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 when using ARM asm")
#pragma message ("uECC_WORD_SIZE must be 4 for ARM")
#undef uECC_WORD_SIZE
#define uECC_WORD_SIZE 4
#endif
@@ -172,15 +164,6 @@ static int default_RNG(uint8_t *dest, unsigned size) {
return 0;
}
#endif
#endif /* platform */
// #ifdef __GNUC__ /* Only support GCC inline asm for now */
// #if (uECC_ASM && (uECC_PLATFORM == uECC_avr))
// #include "asm_avr.inc"
// #endif
//
// #if (uECC_ASM && (uECC_PLATFORM == uECC_arm || uECC_PLATFORM == uECC_arm_thumb || \
// uECC_PLATFORM == uECC_arm_thumb2))
// #include "asm_arm.inc"
// #endif
// #endif
#endif /* _UECC_PLATFORM_SPECIFIC_H_ */
+82 -27
View File
@@ -4,14 +4,30 @@
#define MAX_TRIES 64
#if uECC_SUPPORTS_secp160r1
#define uECC_MAX_BYTES 21 /* Due to the size of curve_n. */
#endif
#if uECC_SUPPORTS_secp192r1
#undef uECC_MAX_BYTES
#define uECC_MAX_BYTES 24
#endif
#if uECC_SUPPORTS_secp224r1
#undef uECC_MAX_BYTES
#define uECC_MAX_BYTES 28
#endif
#if (uECC_SUPPORTS_secp256r1 || uECC_SUPPORTS_secp256k1)
#undef uECC_MAX_BYTES
#define uECC_MAX_BYTES 32
#endif
#include "platform-specific.inc"
#if (uECC_WORD_SIZE == 1)
#define uECC_MAX_WORDS 32
#define uECC_MAX_WORDS uECC_MAX_BYTES
#elif (uECC_WORD_SIZE == 4)
#define uECC_MAX_WORDS 8
#define uECC_MAX_WORDS ((uECC_MAX_BYTES + 3) / 4)
#elif (uECC_WORD_SIZE == 8)
#define uECC_MAX_WORDS 4
#define uECC_MAX_WORDS ((uECC_MAX_BYTES + 7) / 8)
#endif /* uECC_WORD_SIZE */
struct uECC_Curve_t {
@@ -28,14 +44,24 @@ struct uECC_Curve_t {
uECC_Curve curve);
void (*mod_sqrt)(uECC_word_t *a, uECC_Curve curve);
void (*x_side)(uECC_word_t *result, const uECC_word_t *x, uECC_Curve curve);
#if (uECC_OPTIMIZATION_LEVEL > 0)
void (*mmod_fast)(uECC_word_t *result, uECC_word_t *product);
#endif
};
#if (uECC_ASM == uECC_asm_small)
#if (uECC_PLATFORM == uECC_arm || uECC_PLATFORM == uECC_arm_thumb || \
uECC_PLATFORM == uECC_arm_thumb2)
#include "asm_arm_small.inc"
#if (uECC_OPTIMIZATION_LEVEL > 0) && (uECC_OPTIMIZATION_LEVEL % 2 == 0)
#define uECC_SQUARE_FUNC 1
#else
#define uECC_SQUARE_FUNC 0
#endif
#if (uECC_PLATFORM == uECC_arm || uECC_PLATFORM == uECC_arm_thumb || \
uECC_PLATFORM == uECC_arm_thumb2)
#if (uECC_OPTIMIZATION_LEVEL > 2)
#include "asm_arm_mult_square.inc"
#include "asm_arm_fast.inc"
#endif
#include "asm_arm_small.inc"
#endif
static uECC_RNG_Function g_rng_function = &default_RNG;
@@ -190,7 +216,7 @@ static void muladd(uECC_word_t a,
i2 += (i0 >> 32);
i2 += i1;
if (i2 < i1) { // overflow
if (i2 < i1) { /* overflow */
i3 += 0x100000000ull;
}
@@ -266,7 +292,7 @@ static void mul2add(uECC_word_t a,
i2 += (i0 >> 32);
i2 += i1;
if (i2 < i1)
{ // overflow
{ /* overflow */
i3 += 0x100000000ull;
}
@@ -365,7 +391,7 @@ static void vli_mmod(uECC_word_t *result,
uECC_word_t *v[2] = {tmp, product};
uECC_word_t index;
// Shift mod so its highest set bit is at the maximum position.
/* Shift mod so its highest set bit is at the maximum position. */
bitcount_t shift = (num_words * 2 * uECC_WORD_BITS) - vli_numBits(mod, num_words);
wordcount_t word_shift = shift / uECC_WORD_BITS;
wordcount_t bit_shift = shift % uECC_WORD_BITS;
@@ -381,9 +407,19 @@ static void vli_mmod(uECC_word_t *result,
}
for (index = 1; shift >= 0; --shift) {
uECC_word_t borrow = vli_sub(v[1 - index], v[index], mod_multiple, num_words * 2);
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 */
vli_rshift1(mod_multiple, num_words * 2);
vli_rshift1(mod_multiple, num_words);
mod_multiple[num_words - 1] |= mod_multiple[num_words] << (uECC_WORD_BITS - 1);
vli_rshift1(mod_multiple + num_words, num_words);
}
vli_set(result, v[index], num_words);
}
@@ -399,6 +435,8 @@ static void vli_modMult(uECC_word_t *result,
vli_mmod(result, product, mod, num_words);
}
#if (uECC_OPTIMIZATION_LEVEL > 0)
static void vli_modMult_fast(uECC_word_t *result,
const uECC_word_t *left,
const uECC_word_t *right,
@@ -408,6 +446,13 @@ static void vli_modMult_fast(uECC_word_t *result,
curve->mmod_fast(result, product);
}
#else /* (uECC_OPTIMIZATION_LEVEL > 0) */
#define vli_modMult_fast(result, left, right, curve) \
vli_modMult((result), (left), (right), (curve)->p, (curve)->num_words)
#endif /* (uECC_OPTIMIZATION_LEVEL > 0) */
#if uECC_SQUARE_FUNC
/* Computes result = left^2 % mod. */
@@ -420,6 +465,8 @@ static void vli_modSquare(uECC_word_t *result,
vli_mmod(result, product, mod, num_words);
}
#if (uECC_OPTIMIZATION_LEVEL > 0)
static void vli_modSquare_fast(uECC_word_t *result,
const uECC_word_t *left,
uECC_Curve curve) {
@@ -428,6 +475,13 @@ static void vli_modSquare_fast(uECC_word_t *result,
curve->mmod_fast(result, product);
}
#else /* (uECC_OPTIMIZATION_LEVEL > 0) */
#define vli_modSquare_fast(result, left, curve) \
vli_modSquare((result), (left), (curve)->p, (curve)->num_words)
#endif /* (uECC_OPTIMIZATION_LEVEL > 0) */
#else /* uECC_SQUARE_FUNC */
#define vli_modSquare(result, left, mod, num_words) \
@@ -508,7 +562,8 @@ static void vli_modInv(uECC_word_t *result,
/* Returns 1 if 'point' is the point at infinity, 0 otherwise. */
static cmpresult_t EccPoint_isZero(const uECC_word_t *point, uECC_Curve curve) {
return vli_isZero(point, curve->num_words * 2);
return vli_isZero(point, curve->num_words) &&
vli_isZero(point + curve->num_words, curve->num_words);
}
/* Point multiplication algorithm using Montgomery's ladder with co-Z coordinates.
@@ -695,8 +750,8 @@ static uECC_word_t EccPoint_compute_public_key(uECC_word_t *result,
return 0;
}
// Regularize the bitcount for the private key so that attackers cannot use a side channel
// attack to learn the number of leading zeros.
/* Regularize the bitcount for the private key so that attackers cannot use a side channel
attack to learn the number of leading zeros. */
carry = regularize_k(private, tmp1, tmp2, curve);
EccPoint_mult(result, curve->G, p2[!carry], 0,
@@ -822,12 +877,12 @@ int uECC_shared_secret(const uint8_t *public_key,
vli_bytesToNative(public, public_key, curve);
vli_bytesToNative(public + curve->num_words, public_key + curve->num_bytes, curve);
// Regularize the bitcount for the private key so that attackers cannot use a side channel
// attack to learn the number of leading zeros.
/* Regularize the bitcount for the private key so that attackers cannot use a side channel
attack to learn the number of leading zeros. */
carry = regularize_k(private, private, tmp, curve);
// If an RNG function was specified, try to get a random initial Z value to improve
// protection against side-channel attacks.
/* If an RNG function was specified, try to get a random initial Z value to improve
protection against side-channel attacks. */
if (g_rng_function != &default_RNG) {
for (tries = 0; tries < MAX_TRIES; ++tries) {
if (!generate_random_int(p2[carry], curve->num_words, curve->num_bytes * 8)) {
@@ -880,12 +935,12 @@ int uECC_valid_public_key(const uint8_t *public_key, uECC_Curve curve) {
vli_bytesToNative(public, public_key, curve);
vli_bytesToNative(public + curve->num_words, public_key + curve->num_bytes, curve);
// The point at infinity is invalid.
/* The point at infinity is invalid. */
if (EccPoint_isZero(public, curve)) {
return 0;
}
// x and y must be smaller than p.
/* x and y must be smaller than p. */
if (vli_cmp(curve->p, public, curve->num_words) != 1 ||
vli_cmp(curve->p, public + curve->num_words, curve->num_words) != 1) {
return 0;
@@ -1065,8 +1120,8 @@ int uECC_sign_deterministic(const uint8_t *private_key,
V[i] = 0x01;
K[i] = 0;
}
// K = HMAC_K(V || 0x00 || int2octets(x) || h(m))
/* K = HMAC_K(V || 0x00 || int2octets(x) || h(m)) */
HMAC_init(hash_context, K);
V[hash_context->result_size] = 0x00;
HMAC_update(hash_context, V, hash_context->result_size + 1);
@@ -1075,8 +1130,8 @@ int uECC_sign_deterministic(const uint8_t *private_key,
HMAC_finish(hash_context, K, K);
update_V(hash_context, K, V);
// K = HMAC_K(V || 0x01 || int2octets(x) || h(m))
/* K = HMAC_K(V || 0x01 || int2octets(x) || h(m)) */
HMAC_init(hash_context, K);
V[hash_context->result_size] = 0x01;
HMAC_update(hash_context, V, hash_context->result_size + 1);
@@ -1106,7 +1161,7 @@ int uECC_sign_deterministic(const uint8_t *private_key,
return 1;
}
// K = HMAC_K(V || 0x00)
/* K = HMAC_K(V || 0x00) */
HMAC_init(hash_context, K);
V[hash_context->result_size] = 0x00;
HMAC_update(hash_context, V, hash_context->result_size + 1);
+37 -4
View File
@@ -1,7 +1,7 @@
/* Copyright 2014, Kenneth MacKay. Licensed under the BSD 2-clause license. */
#ifndef _MICRO_ECC_H_
#define _MICRO_ECC_H_
#ifndef _UECC_H_
#define _UECC_H_
#include <stdint.h>
@@ -17,11 +17,34 @@ Possible values for uECC_PLATFORM are defined below: */
#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. */
#ifndef uECC_OPTIMIZATION_LEVEL
#define uECC_OPTIMIZATION_LEVEL 1
#endif
/* Curve support selection. Set to 0 to remove that curve. */
#ifndef uECC_SUPPORTS_secp160r1
#define uECC_SUPPORTS_secp160r1 1
#endif
#ifndef uECC_SUPPORTS_secp192r1
#define uECC_SUPPORTS_secp192r1 1
#endif
#ifndef uECC_SUPPORTS_secp224r1
#define uECC_SUPPORTS_secp224r1 1
#endif
#ifndef uECC_SUPPORTS_secp256r1
#define uECC_SUPPORTS_secp256r1 1
#endif
#ifndef uECC_SUPPORTS_secp256k1
#define uECC_SUPPORTS_secp256k1 1
#endif
struct uECC_Curve_t;
typedef const struct uECC_Curve_t * uECC_Curve;
@@ -30,11 +53,21 @@ extern "C"
{
#endif
#if uECC_SUPPORTS_secp160r1
uECC_Curve uECC_secp160r1(void);
#endif
#if uECC_SUPPORTS_secp192r1
uECC_Curve uECC_secp192r1(void);
#endif
#if uECC_SUPPORTS_secp224r1
uECC_Curve uECC_secp224r1(void);
#endif
#if uECC_SUPPORTS_secp256r1
uECC_Curve uECC_secp256r1(void);
#endif
#if uECC_SUPPORTS_secp256k1
uECC_Curve uECC_secp256k1(void);
#endif
/* uECC_RNG_Function type
The RNG function should fill 'size' random bytes into 'dest'. It should return 1 if
@@ -261,4 +294,4 @@ int uECC_verify(const uint8_t *private_key,
} /* end of extern "C" */
#endif
#endif /* _MICRO_ECC_H_ */
#endif /* _UECC_H_ */