sara matheu
/
CurvasElipticas
Operaciones de generacion de claves, D-H, firma y validacion.
ecc.cpp@1:4875e39abd1e, 2015-02-05 (annotated)
- Committer:
- saranieves92
- Date:
- Thu Feb 05 23:04:03 2015 +0000
- Revision:
- 1:4875e39abd1e
Prueba de generacion de claves, D-H, firma y validacion pasada correctamente
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
saranieves92 | 1:4875e39abd1e | 1 | #include "ecc.h" |
saranieves92 | 1:4875e39abd1e | 2 | |
saranieves92 | 1:4875e39abd1e | 3 | #include <string.h> |
saranieves92 | 1:4875e39abd1e | 4 | |
saranieves92 | 1:4875e39abd1e | 5 | typedef unsigned int uint; |
saranieves92 | 1:4875e39abd1e | 6 | |
saranieves92 | 1:4875e39abd1e | 7 | #define Curve_P_1 {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFD} |
saranieves92 | 1:4875e39abd1e | 8 | #define Curve_P_2 {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF} |
saranieves92 | 1:4875e39abd1e | 9 | #define Curve_P_3 {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0xFFFFFFFF} |
saranieves92 | 1:4875e39abd1e | 10 | #define Curve_P_4 {0xFFFFFFFF, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, \ |
saranieves92 | 1:4875e39abd1e | 11 | 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF} |
saranieves92 | 1:4875e39abd1e | 12 | #define Curve_P_5 {0xFFFFFC2F, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF} |
saranieves92 | 1:4875e39abd1e | 13 | |
saranieves92 | 1:4875e39abd1e | 14 | #define Curve_B_1 {0x2CEE5ED3, 0xD824993C, 0x1079F43D, 0xE87579C1} |
saranieves92 | 1:4875e39abd1e | 15 | #define Curve_B_2 {0xC146B9B1, 0xFEB8DEEC, 0x72243049, 0x0FA7E9AB, 0xE59C80E7, 0x64210519} |
saranieves92 | 1:4875e39abd1e | 16 | #define Curve_B_3 {0x27D2604B, 0x3BCE3C3E, 0xCC53B0F6, 0x651D06B0, 0x769886BC, 0xB3EBBD55, 0xAA3A93E7, 0x5AC635D8} |
saranieves92 | 1:4875e39abd1e | 17 | #define Curve_B_4 {0xD3EC2AEF, 0x2A85C8ED, 0x8A2ED19D, 0xC656398D, 0x5013875A, 0x0314088F, 0xFE814112, 0x181D9C6E, \ |
saranieves92 | 1:4875e39abd1e | 18 | 0xE3F82D19, 0x988E056B, 0xE23EE7E4, 0xB3312FA7} |
saranieves92 | 1:4875e39abd1e | 19 | #define Curve_B_5 {0x00000007, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000} |
saranieves92 | 1:4875e39abd1e | 20 | |
saranieves92 | 1:4875e39abd1e | 21 | #define Curve_G_1 { \ |
saranieves92 | 1:4875e39abd1e | 22 | {0xA52C5B86, 0x0C28607C, 0x8B899B2D, 0x161FF752}, \ |
saranieves92 | 1:4875e39abd1e | 23 | {0xDDED7A83, 0xC02DA292, 0x5BAFEB13, 0xCF5AC839}} |
saranieves92 | 1:4875e39abd1e | 24 | |
saranieves92 | 1:4875e39abd1e | 25 | #define Curve_G_2 { \ |
saranieves92 | 1:4875e39abd1e | 26 | {0x82FF1012, 0xF4FF0AFD, 0x43A18800, 0x7CBF20EB, 0xB03090F6, 0x188DA80E}, \ |
saranieves92 | 1:4875e39abd1e | 27 | {0x1E794811, 0x73F977A1, 0x6B24CDD5, 0x631011ED, 0xFFC8DA78, 0x07192B95}} |
saranieves92 | 1:4875e39abd1e | 28 | |
saranieves92 | 1:4875e39abd1e | 29 | #define Curve_G_3 { \ |
saranieves92 | 1:4875e39abd1e | 30 | {0xD898C296, 0xF4A13945, 0x2DEB33A0, 0x77037D81, 0x63A440F2, 0xF8BCE6E5, 0xE12C4247, 0x6B17D1F2}, \ |
saranieves92 | 1:4875e39abd1e | 31 | {0x37BF51F5, 0xCBB64068, 0x6B315ECE, 0x2BCE3357, 0x7C0F9E16, 0x8EE7EB4A, 0xFE1A7F9B, 0x4FE342E2}} |
saranieves92 | 1:4875e39abd1e | 32 | |
saranieves92 | 1:4875e39abd1e | 33 | #define Curve_G_4 { \ |
saranieves92 | 1:4875e39abd1e | 34 | {0x72760AB7, 0x3A545E38, 0xBF55296C, 0x5502F25D, 0x82542A38, 0x59F741E0, 0x8BA79B98, 0x6E1D3B62, \ |
saranieves92 | 1:4875e39abd1e | 35 | 0xF320AD74, 0x8EB1C71E, 0xBE8B0537, 0xAA87CA22}, \ |
saranieves92 | 1:4875e39abd1e | 36 | {0x90EA0E5F, 0x7A431D7C, 0x1D7E819D, 0x0A60B1CE, 0xB5F0B8C0, 0xE9DA3113, 0x289A147C, 0xF8F41DBD, \ |
saranieves92 | 1:4875e39abd1e | 37 | 0x9292DC29, 0x5D9E98BF, 0x96262C6F, 0x3617DE4A}} |
saranieves92 | 1:4875e39abd1e | 38 | |
saranieves92 | 1:4875e39abd1e | 39 | #define Curve_G_5 { \ |
saranieves92 | 1:4875e39abd1e | 40 | {0x16F81798, 0x59F2815B, 0x2DCE28D9, 0x029BFCDB, 0xCE870B07, 0x55A06295, 0xF9DCBBAC, 0x79BE667E}, \ |
saranieves92 | 1:4875e39abd1e | 41 | {0xFB10D4B8, 0x9C47D08F, 0xA6855419, 0xFD17B448, 0x0E1108A8, 0x5DA4FBFC, 0x26A3C465, 0x483ADA77}} |
saranieves92 | 1:4875e39abd1e | 42 | |
saranieves92 | 1:4875e39abd1e | 43 | #define Curve_N_1 {0x9038A115, 0x75A30D1B, 0x00000000, 0xFFFFFFFE} |
saranieves92 | 1:4875e39abd1e | 44 | #define Curve_N_2 {0xB4D22831, 0x146BC9B1, 0x99DEF836, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF} |
saranieves92 | 1:4875e39abd1e | 45 | #define Curve_N_3 {0xFC632551, 0xF3B9CAC2, 0xA7179E84, 0xBCE6FAAD, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF} |
saranieves92 | 1:4875e39abd1e | 46 | #define Curve_N_4 {0xCCC52973, 0xECEC196A, 0x48B0A77A, 0x581A0DB2, 0xF4372DDF, 0xC7634D81, 0xFFFFFFFF, 0xFFFFFFFF, \ |
saranieves92 | 1:4875e39abd1e | 47 | 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF} |
saranieves92 | 1:4875e39abd1e | 48 | #define Curve_N_5 {0xD0364141, 0xBFD25E8C, 0xAF48A03B, 0xBAAEDCE6, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF} |
saranieves92 | 1:4875e39abd1e | 49 | |
saranieves92 | 1:4875e39abd1e | 50 | static uint32_t curve_p[NUM_ECC_DIGITS] = ECC_CONCAT(Curve_P_, ECC_CURVE); |
saranieves92 | 1:4875e39abd1e | 51 | static uint32_t curve_b[NUM_ECC_DIGITS] = ECC_CONCAT(Curve_B_, ECC_CURVE); |
saranieves92 | 1:4875e39abd1e | 52 | static EccPoint curve_G = ECC_CONCAT(Curve_G_, ECC_CURVE); |
saranieves92 | 1:4875e39abd1e | 53 | static uint32_t curve_n[NUM_ECC_DIGITS] = ECC_CONCAT(Curve_N_, ECC_CURVE); |
saranieves92 | 1:4875e39abd1e | 54 | |
saranieves92 | 1:4875e39abd1e | 55 | static void vli_clear(uint32_t *p_vli) |
saranieves92 | 1:4875e39abd1e | 56 | { |
saranieves92 | 1:4875e39abd1e | 57 | uint i; |
saranieves92 | 1:4875e39abd1e | 58 | for(i=0; i<NUM_ECC_DIGITS; ++i) |
saranieves92 | 1:4875e39abd1e | 59 | { |
saranieves92 | 1:4875e39abd1e | 60 | p_vli[i] = 0; |
saranieves92 | 1:4875e39abd1e | 61 | } |
saranieves92 | 1:4875e39abd1e | 62 | } |
saranieves92 | 1:4875e39abd1e | 63 | |
saranieves92 | 1:4875e39abd1e | 64 | /* Returns 1 if p_vli == 0, 0 otherwise. */ |
saranieves92 | 1:4875e39abd1e | 65 | static int vli_isZero(const uint32_t *p_vli) |
saranieves92 | 1:4875e39abd1e | 66 | { |
saranieves92 | 1:4875e39abd1e | 67 | uint i; |
saranieves92 | 1:4875e39abd1e | 68 | for(i = 0; i < NUM_ECC_DIGITS; ++i) |
saranieves92 | 1:4875e39abd1e | 69 | { |
saranieves92 | 1:4875e39abd1e | 70 | if(p_vli[i]) |
saranieves92 | 1:4875e39abd1e | 71 | { |
saranieves92 | 1:4875e39abd1e | 72 | return 0; |
saranieves92 | 1:4875e39abd1e | 73 | } |
saranieves92 | 1:4875e39abd1e | 74 | } |
saranieves92 | 1:4875e39abd1e | 75 | return 1; |
saranieves92 | 1:4875e39abd1e | 76 | } |
saranieves92 | 1:4875e39abd1e | 77 | |
saranieves92 | 1:4875e39abd1e | 78 | /* Returns nonzero if bit p_bit of p_vli is set. */ |
saranieves92 | 1:4875e39abd1e | 79 | static uint32_t vli_testBit(const uint32_t *p_vli, const unsigned int p_bit) |
saranieves92 | 1:4875e39abd1e | 80 | { |
saranieves92 | 1:4875e39abd1e | 81 | return (p_vli[p_bit/32] & (1 << (p_bit % 32))); |
saranieves92 | 1:4875e39abd1e | 82 | } |
saranieves92 | 1:4875e39abd1e | 83 | |
saranieves92 | 1:4875e39abd1e | 84 | /* Counts the number of 32-bit "digits" in p_vli. */ |
saranieves92 | 1:4875e39abd1e | 85 | static uint vli_numDigits(const uint32_t *p_vli) |
saranieves92 | 1:4875e39abd1e | 86 | { |
saranieves92 | 1:4875e39abd1e | 87 | int i; |
saranieves92 | 1:4875e39abd1e | 88 | /* Search from the end until we find a non-zero digit. |
saranieves92 | 1:4875e39abd1e | 89 | We do it in reverse because we expect that most digits will be nonzero. */ |
saranieves92 | 1:4875e39abd1e | 90 | for(i = NUM_ECC_DIGITS - 1; i >= 0 && p_vli[i] == 0; --i) |
saranieves92 | 1:4875e39abd1e | 91 | { |
saranieves92 | 1:4875e39abd1e | 92 | } |
saranieves92 | 1:4875e39abd1e | 93 | |
saranieves92 | 1:4875e39abd1e | 94 | return (i + 1); |
saranieves92 | 1:4875e39abd1e | 95 | } |
saranieves92 | 1:4875e39abd1e | 96 | |
saranieves92 | 1:4875e39abd1e | 97 | /* Counts the number of bits required for p_vli. */ |
saranieves92 | 1:4875e39abd1e | 98 | static uint vli_numBits(const uint32_t *p_vli) |
saranieves92 | 1:4875e39abd1e | 99 | { |
saranieves92 | 1:4875e39abd1e | 100 | uint i; |
saranieves92 | 1:4875e39abd1e | 101 | uint32_t l_digit; |
saranieves92 | 1:4875e39abd1e | 102 | |
saranieves92 | 1:4875e39abd1e | 103 | uint l_numDigits = vli_numDigits(p_vli); |
saranieves92 | 1:4875e39abd1e | 104 | if(l_numDigits == 0) |
saranieves92 | 1:4875e39abd1e | 105 | { |
saranieves92 | 1:4875e39abd1e | 106 | return 0; |
saranieves92 | 1:4875e39abd1e | 107 | } |
saranieves92 | 1:4875e39abd1e | 108 | |
saranieves92 | 1:4875e39abd1e | 109 | l_digit = p_vli[l_numDigits - 1]; |
saranieves92 | 1:4875e39abd1e | 110 | for(i=0; l_digit; ++i) |
saranieves92 | 1:4875e39abd1e | 111 | { |
saranieves92 | 1:4875e39abd1e | 112 | l_digit >>= 1; |
saranieves92 | 1:4875e39abd1e | 113 | } |
saranieves92 | 1:4875e39abd1e | 114 | |
saranieves92 | 1:4875e39abd1e | 115 | return ((l_numDigits - 1) * 32 + i); |
saranieves92 | 1:4875e39abd1e | 116 | } |
saranieves92 | 1:4875e39abd1e | 117 | |
saranieves92 | 1:4875e39abd1e | 118 | /* Sets p_dest = p_src. */ |
saranieves92 | 1:4875e39abd1e | 119 | static void vli_set(uint32_t *p_dest, const uint32_t *p_src) |
saranieves92 | 1:4875e39abd1e | 120 | { |
saranieves92 | 1:4875e39abd1e | 121 | uint i; |
saranieves92 | 1:4875e39abd1e | 122 | for(i=0; i<NUM_ECC_DIGITS; ++i) |
saranieves92 | 1:4875e39abd1e | 123 | { |
saranieves92 | 1:4875e39abd1e | 124 | p_dest[i] = p_src[i]; |
saranieves92 | 1:4875e39abd1e | 125 | } |
saranieves92 | 1:4875e39abd1e | 126 | } |
saranieves92 | 1:4875e39abd1e | 127 | |
saranieves92 | 1:4875e39abd1e | 128 | /* Returns sign of p_left - p_right. */ |
saranieves92 | 1:4875e39abd1e | 129 | static int vli_cmp(const uint32_t *p_left, const uint32_t *p_right) |
saranieves92 | 1:4875e39abd1e | 130 | { |
saranieves92 | 1:4875e39abd1e | 131 | int i; |
saranieves92 | 1:4875e39abd1e | 132 | for(i = NUM_ECC_DIGITS-1; i >= 0; --i) |
saranieves92 | 1:4875e39abd1e | 133 | { |
saranieves92 | 1:4875e39abd1e | 134 | if(p_left[i] > p_right[i]) |
saranieves92 | 1:4875e39abd1e | 135 | { |
saranieves92 | 1:4875e39abd1e | 136 | return 1; |
saranieves92 | 1:4875e39abd1e | 137 | } |
saranieves92 | 1:4875e39abd1e | 138 | else if(p_left[i] < p_right[i]) |
saranieves92 | 1:4875e39abd1e | 139 | { |
saranieves92 | 1:4875e39abd1e | 140 | return -1; |
saranieves92 | 1:4875e39abd1e | 141 | } |
saranieves92 | 1:4875e39abd1e | 142 | } |
saranieves92 | 1:4875e39abd1e | 143 | return 0; |
saranieves92 | 1:4875e39abd1e | 144 | } |
saranieves92 | 1:4875e39abd1e | 145 | |
saranieves92 | 1:4875e39abd1e | 146 | /* Computes p_result = p_in << c, returning carry. Can modify in place (if p_result == p_in). 0 < p_shift < 32. */ |
saranieves92 | 1:4875e39abd1e | 147 | static uint32_t vli_lshift(uint32_t *p_result, const uint32_t *p_in, const unsigned int p_shift) |
saranieves92 | 1:4875e39abd1e | 148 | { |
saranieves92 | 1:4875e39abd1e | 149 | uint32_t l_carry = 0; |
saranieves92 | 1:4875e39abd1e | 150 | uint i; |
saranieves92 | 1:4875e39abd1e | 151 | for(i = 0; i < NUM_ECC_DIGITS; ++i) |
saranieves92 | 1:4875e39abd1e | 152 | { |
saranieves92 | 1:4875e39abd1e | 153 | uint32_t l_temp = p_in[i]; |
saranieves92 | 1:4875e39abd1e | 154 | p_result[i] = (l_temp << p_shift) | l_carry; |
saranieves92 | 1:4875e39abd1e | 155 | l_carry = l_temp >> (32 - p_shift); |
saranieves92 | 1:4875e39abd1e | 156 | } |
saranieves92 | 1:4875e39abd1e | 157 | |
saranieves92 | 1:4875e39abd1e | 158 | return l_carry; |
saranieves92 | 1:4875e39abd1e | 159 | } |
saranieves92 | 1:4875e39abd1e | 160 | |
saranieves92 | 1:4875e39abd1e | 161 | /* Computes p_vli = p_vli >> 1. */ |
saranieves92 | 1:4875e39abd1e | 162 | static void vli_rshift1(uint32_t *p_vli) |
saranieves92 | 1:4875e39abd1e | 163 | { |
saranieves92 | 1:4875e39abd1e | 164 | uint32_t *l_end = p_vli; |
saranieves92 | 1:4875e39abd1e | 165 | uint32_t l_carry = 0; |
saranieves92 | 1:4875e39abd1e | 166 | |
saranieves92 | 1:4875e39abd1e | 167 | p_vli += NUM_ECC_DIGITS; |
saranieves92 | 1:4875e39abd1e | 168 | while(p_vli-- > l_end) |
saranieves92 | 1:4875e39abd1e | 169 | { |
saranieves92 | 1:4875e39abd1e | 170 | uint32_t l_temp = *p_vli; |
saranieves92 | 1:4875e39abd1e | 171 | *p_vli = (l_temp >> 1) | l_carry; |
saranieves92 | 1:4875e39abd1e | 172 | l_carry = l_temp << 31; |
saranieves92 | 1:4875e39abd1e | 173 | } |
saranieves92 | 1:4875e39abd1e | 174 | } |
saranieves92 | 1:4875e39abd1e | 175 | |
saranieves92 | 1:4875e39abd1e | 176 | /* Computes p_result = p_left + p_right, returning carry. Can modify in place. */ |
saranieves92 | 1:4875e39abd1e | 177 | static uint32_t vli_add(uint32_t *p_result, const uint32_t *p_left, const uint32_t *p_right) |
saranieves92 | 1:4875e39abd1e | 178 | { |
saranieves92 | 1:4875e39abd1e | 179 | #if (ECC_ASM == ecc_asm_thumb || ECC_ASM == ecc_asm_thumb2 || ECC_ASM == ecc_asm_arm) |
saranieves92 | 1:4875e39abd1e | 180 | uint32_t l_counter = NUM_ECC_DIGITS; |
saranieves92 | 1:4875e39abd1e | 181 | uint32_t l_carry = 0; /* carry = 0 initially */ |
saranieves92 | 1:4875e39abd1e | 182 | uint32_t l_left; |
saranieves92 | 1:4875e39abd1e | 183 | uint32_t l_right; |
saranieves92 | 1:4875e39abd1e | 184 | |
saranieves92 | 1:4875e39abd1e | 185 | asm volatile ( |
saranieves92 | 1:4875e39abd1e | 186 | ".syntax unified \n\t" |
saranieves92 | 1:4875e39abd1e | 187 | "1: \n\t" |
saranieves92 | 1:4875e39abd1e | 188 | "ldmia %[lptr]!, {%[left]} \n\t" /* Load left word. */ |
saranieves92 | 1:4875e39abd1e | 189 | "ldmia %[rptr]!, {%[right]} \n\t" /* Load right word. */ |
saranieves92 | 1:4875e39abd1e | 190 | "lsrs %[carry], #1 \n\t" /* Set up carry flag (l_carry = 0 after this). */ |
saranieves92 | 1:4875e39abd1e | 191 | "adcs %[left], %[right] \n\t" /* Add with carry. */ |
saranieves92 | 1:4875e39abd1e | 192 | "adcs %[carry], %[carry] \n\t" /* Store carry bit in l_carry. */ |
saranieves92 | 1:4875e39abd1e | 193 | "stmia %[dptr]!, {%[left]} \n\t" /* Store result word. */ |
saranieves92 | 1:4875e39abd1e | 194 | "subs %[ctr], #1 \n\t" /* Decrement index. */ |
saranieves92 | 1:4875e39abd1e | 195 | "bne 1b \n\t" /* Loop until index == 0. */ |
saranieves92 | 1:4875e39abd1e | 196 | #if (ECC_ASM != ecc_asm_thumb2) |
saranieves92 | 1:4875e39abd1e | 197 | ".syntax divided \n\t" |
saranieves92 | 1:4875e39abd1e | 198 | #endif |
saranieves92 | 1:4875e39abd1e | 199 | #if (ECC_ASM == ecc_asm_thumb) |
saranieves92 | 1:4875e39abd1e | 200 | : [dptr] "+l" (p_result), [lptr] "+l" (p_left), [rptr] "+l" (p_right), [ctr] "+l" (l_counter), [carry] "+l" (l_carry), [left] "=l" (l_left), [right] "=l" (l_right) |
saranieves92 | 1:4875e39abd1e | 201 | #else |
saranieves92 | 1:4875e39abd1e | 202 | : [dptr] "+r" (p_result), [lptr] "+r" (p_left), [rptr] "+r" (p_right), [ctr] "+r" (l_counter), [carry] "+r" (l_carry), [left] "=r" (l_left), [right] "=r" (l_right) |
saranieves92 | 1:4875e39abd1e | 203 | #endif |
saranieves92 | 1:4875e39abd1e | 204 | : |
saranieves92 | 1:4875e39abd1e | 205 | : "cc", "memory" |
saranieves92 | 1:4875e39abd1e | 206 | ); |
saranieves92 | 1:4875e39abd1e | 207 | return l_carry; |
saranieves92 | 1:4875e39abd1e | 208 | |
saranieves92 | 1:4875e39abd1e | 209 | #else |
saranieves92 | 1:4875e39abd1e | 210 | |
saranieves92 | 1:4875e39abd1e | 211 | uint32_t l_carry = 0; |
saranieves92 | 1:4875e39abd1e | 212 | uint i; |
saranieves92 | 1:4875e39abd1e | 213 | for(i=0; i<NUM_ECC_DIGITS; ++i) |
saranieves92 | 1:4875e39abd1e | 214 | { |
saranieves92 | 1:4875e39abd1e | 215 | uint32_t l_sum = p_left[i] + p_right[i] + l_carry; |
saranieves92 | 1:4875e39abd1e | 216 | if(l_sum != p_left[i]) |
saranieves92 | 1:4875e39abd1e | 217 | { |
saranieves92 | 1:4875e39abd1e | 218 | l_carry = (l_sum < p_left[i]); |
saranieves92 | 1:4875e39abd1e | 219 | } |
saranieves92 | 1:4875e39abd1e | 220 | p_result[i] = l_sum; |
saranieves92 | 1:4875e39abd1e | 221 | } |
saranieves92 | 1:4875e39abd1e | 222 | return l_carry; |
saranieves92 | 1:4875e39abd1e | 223 | #endif |
saranieves92 | 1:4875e39abd1e | 224 | } |
saranieves92 | 1:4875e39abd1e | 225 | |
saranieves92 | 1:4875e39abd1e | 226 | /* Computes p_result = p_left - p_right, returning borrow. Can modify in place. */ |
saranieves92 | 1:4875e39abd1e | 227 | static uint32_t vli_sub(uint32_t *p_result, const uint32_t *p_left, const uint32_t *p_right) |
saranieves92 | 1:4875e39abd1e | 228 | { |
saranieves92 | 1:4875e39abd1e | 229 | #if (ECC_ASM == ecc_asm_thumb || ECC_ASM == ecc_asm_thumb2 || ECC_ASM == ecc_asm_arm) |
saranieves92 | 1:4875e39abd1e | 230 | uint32_t l_counter = NUM_ECC_DIGITS; |
saranieves92 | 1:4875e39abd1e | 231 | uint32_t l_carry = 1; /* carry = 1 initially (means don't borrow) */ |
saranieves92 | 1:4875e39abd1e | 232 | uint32_t l_left; |
saranieves92 | 1:4875e39abd1e | 233 | uint32_t l_right; |
saranieves92 | 1:4875e39abd1e | 234 | |
saranieves92 | 1:4875e39abd1e | 235 | asm volatile ( |
saranieves92 | 1:4875e39abd1e | 236 | ".syntax unified \n\t" |
saranieves92 | 1:4875e39abd1e | 237 | "1: \n\t" |
saranieves92 | 1:4875e39abd1e | 238 | "ldmia %[lptr]!, {%[left]} \n\t" /* Load left word. */ |
saranieves92 | 1:4875e39abd1e | 239 | "ldmia %[rptr]!, {%[right]} \n\t" /* Load right word. */ |
saranieves92 | 1:4875e39abd1e | 240 | "lsrs %[carry], #1 \n\t" /* Set up carry flag (l_carry = 0 after this). */ |
saranieves92 | 1:4875e39abd1e | 241 | "sbcs %[left], %[right] \n\t" /* Subtract with borrow. */ |
saranieves92 | 1:4875e39abd1e | 242 | "adcs %[carry], %[carry] \n\t" /* Store carry bit in l_carry. */ |
saranieves92 | 1:4875e39abd1e | 243 | "stmia %[dptr]!, {%[left]} \n\t" /* Store result word. */ |
saranieves92 | 1:4875e39abd1e | 244 | "subs %[ctr], #1 \n\t" /* Decrement index. */ |
saranieves92 | 1:4875e39abd1e | 245 | "bne 1b \n\t" /* Loop until index == 0. */ |
saranieves92 | 1:4875e39abd1e | 246 | #if (ECC_ASM != ecc_asm_thumb2) |
saranieves92 | 1:4875e39abd1e | 247 | ".syntax divided \n\t" |
saranieves92 | 1:4875e39abd1e | 248 | #endif |
saranieves92 | 1:4875e39abd1e | 249 | #if (ECC_ASM == ecc_asm_thumb) |
saranieves92 | 1:4875e39abd1e | 250 | : [dptr] "+l" (p_result), [lptr] "+l" (p_left), [rptr] "+l" (p_right), [ctr] "+l" (l_counter), [carry] "+l" (l_carry), [left] "=l" (l_left), [right] "=l" (l_right) |
saranieves92 | 1:4875e39abd1e | 251 | #else |
saranieves92 | 1:4875e39abd1e | 252 | : [dptr] "+r" (p_result), [lptr] "+r" (p_left), [rptr] "+r" (p_right), [ctr] "+r" (l_counter), [carry] "+r" (l_carry), [left] "=r" (l_left), [right] "=r" (l_right) |
saranieves92 | 1:4875e39abd1e | 253 | #endif |
saranieves92 | 1:4875e39abd1e | 254 | : |
saranieves92 | 1:4875e39abd1e | 255 | : "cc", "memory" |
saranieves92 | 1:4875e39abd1e | 256 | ); |
saranieves92 | 1:4875e39abd1e | 257 | return !l_carry; |
saranieves92 | 1:4875e39abd1e | 258 | |
saranieves92 | 1:4875e39abd1e | 259 | #else |
saranieves92 | 1:4875e39abd1e | 260 | |
saranieves92 | 1:4875e39abd1e | 261 | uint32_t l_borrow = 0; |
saranieves92 | 1:4875e39abd1e | 262 | uint i; |
saranieves92 | 1:4875e39abd1e | 263 | for(i=0; i<NUM_ECC_DIGITS; ++i) |
saranieves92 | 1:4875e39abd1e | 264 | { |
saranieves92 | 1:4875e39abd1e | 265 | uint32_t l_diff = p_left[i] - p_right[i] - l_borrow; |
saranieves92 | 1:4875e39abd1e | 266 | if(l_diff != p_left[i]) |
saranieves92 | 1:4875e39abd1e | 267 | { |
saranieves92 | 1:4875e39abd1e | 268 | l_borrow = (l_diff > p_left[i]); |
saranieves92 | 1:4875e39abd1e | 269 | } |
saranieves92 | 1:4875e39abd1e | 270 | p_result[i] = l_diff; |
saranieves92 | 1:4875e39abd1e | 271 | } |
saranieves92 | 1:4875e39abd1e | 272 | return l_borrow; |
saranieves92 | 1:4875e39abd1e | 273 | #endif |
saranieves92 | 1:4875e39abd1e | 274 | } |
saranieves92 | 1:4875e39abd1e | 275 | |
saranieves92 | 1:4875e39abd1e | 276 | /* Computes p_result = p_left * p_right. */ |
saranieves92 | 1:4875e39abd1e | 277 | static void vli_mult(uint32_t *p_result, const uint32_t *p_left, const uint32_t *p_right) |
saranieves92 | 1:4875e39abd1e | 278 | { |
saranieves92 | 1:4875e39abd1e | 279 | #if (ECC_ASM == ecc_asm_thumb2 || ECC_ASM == ecc_asm_arm) |
saranieves92 | 1:4875e39abd1e | 280 | uint32_t c0 = 0; |
saranieves92 | 1:4875e39abd1e | 281 | uint32_t c1 = 0; |
saranieves92 | 1:4875e39abd1e | 282 | uint32_t c2 = 0; |
saranieves92 | 1:4875e39abd1e | 283 | uint32_t k = 0; |
saranieves92 | 1:4875e39abd1e | 284 | uint32_t i; |
saranieves92 | 1:4875e39abd1e | 285 | uint32_t t0, t1; |
saranieves92 | 1:4875e39abd1e | 286 | |
saranieves92 | 1:4875e39abd1e | 287 | asm volatile ( |
saranieves92 | 1:4875e39abd1e | 288 | ".syntax unified \n\t" |
saranieves92 | 1:4875e39abd1e | 289 | |
saranieves92 | 1:4875e39abd1e | 290 | "1: \n\t" /* outer loop (k < NUM_ECC_DIGITS) */ |
saranieves92 | 1:4875e39abd1e | 291 | "movs %[i], #0 \n\t" /* i = 0 */ |
saranieves92 | 1:4875e39abd1e | 292 | "b 3f \n\t" |
saranieves92 | 1:4875e39abd1e | 293 | |
saranieves92 | 1:4875e39abd1e | 294 | "2: \n\t" /* outer loop (k >= NUM_ECC_DIGITS) */ |
saranieves92 | 1:4875e39abd1e | 295 | "movs %[i], %[k] \n\t" /* i = k */ |
saranieves92 | 1:4875e39abd1e | 296 | "subs %[i], %[eccdm1] \n\t" /* i = k - (NUM_ECC_DIGITS - 1) (times 4) */ |
saranieves92 | 1:4875e39abd1e | 297 | |
saranieves92 | 1:4875e39abd1e | 298 | "3: \n\t" /* inner loop */ |
saranieves92 | 1:4875e39abd1e | 299 | "subs %[t0], %[k], %[i] \n\t" /* t0 = k-i */ |
saranieves92 | 1:4875e39abd1e | 300 | |
saranieves92 | 1:4875e39abd1e | 301 | "ldr %[t1], [%[right], %[t0]] \n\t" /* t1 = p_right[k-i] */ |
saranieves92 | 1:4875e39abd1e | 302 | "ldr %[t0], [%[left], %[i]] \n\t" /* t0 = p_left[i] */ |
saranieves92 | 1:4875e39abd1e | 303 | |
saranieves92 | 1:4875e39abd1e | 304 | "umull %[t0], %[t1], %[t0], %[t1] \n\t" /* (t0, t1) = p_left[i] * p_right[k-i] */ |
saranieves92 | 1:4875e39abd1e | 305 | |
saranieves92 | 1:4875e39abd1e | 306 | "adds %[c0], %[t0] \n\t" /* add low word to c0 */ |
saranieves92 | 1:4875e39abd1e | 307 | "adcs %[c1], %[t1] \n\t" /* add high word to c1, including carry */ |
saranieves92 | 1:4875e39abd1e | 308 | "adcs %[c2], #0 \n\t" /* add carry to c2 */ |
saranieves92 | 1:4875e39abd1e | 309 | |
saranieves92 | 1:4875e39abd1e | 310 | "adds %[i], #4 \n\t" /* i += 4 */ |
saranieves92 | 1:4875e39abd1e | 311 | "cmp %[i], %[eccd] \n\t" /* i < NUM_ECC_DIGITS (times 4)? */ |
saranieves92 | 1:4875e39abd1e | 312 | "bge 4f \n\t" /* if not, exit the loop */ |
saranieves92 | 1:4875e39abd1e | 313 | "cmp %[i], %[k] \n\t" /* i <= k? */ |
saranieves92 | 1:4875e39abd1e | 314 | "ble 3b \n\t" /* if so, continue looping */ |
saranieves92 | 1:4875e39abd1e | 315 | |
saranieves92 | 1:4875e39abd1e | 316 | "4: \n\t" /* end inner loop */ |
saranieves92 | 1:4875e39abd1e | 317 | |
saranieves92 | 1:4875e39abd1e | 318 | "str %[c0], [%[result], %[k]] \n\t" /* p_result[k] = c0 */ |
saranieves92 | 1:4875e39abd1e | 319 | "mov %[c0], %[c1] \n\t" /* c0 = c1 */ |
saranieves92 | 1:4875e39abd1e | 320 | "mov %[c1], %[c2] \n\t" /* c1 = c2 */ |
saranieves92 | 1:4875e39abd1e | 321 | "movs %[c2], #0 \n\t" /* c2 = 0 */ |
saranieves92 | 1:4875e39abd1e | 322 | "adds %[k], #4 \n\t" /* k += 4 */ |
saranieves92 | 1:4875e39abd1e | 323 | "cmp %[k], %[eccd] \n\t" /* k < NUM_ECC_DIGITS (times 4) ? */ |
saranieves92 | 1:4875e39abd1e | 324 | "blt 1b \n\t" /* if not, loop back, start with i = 0 */ |
saranieves92 | 1:4875e39abd1e | 325 | "cmp %[k], %[eccd2m1] \n\t" /* k < NUM_ECC_DIGITS * 2 - 1 (times 4) ? */ |
saranieves92 | 1:4875e39abd1e | 326 | "blt 2b \n\t" /* if not, loop back, start with i = (k+1) - NUM_ECC_DIGITS */ |
saranieves92 | 1:4875e39abd1e | 327 | /* end outer loop */ |
saranieves92 | 1:4875e39abd1e | 328 | |
saranieves92 | 1:4875e39abd1e | 329 | "str %[c0], [%[result], %[k]] \n\t" /* p_result[NUM_ECC_DIGITS * 2 - 1] = c0 */ |
saranieves92 | 1:4875e39abd1e | 330 | #if (ECC_ASM != ecc_asm_thumb2) |
saranieves92 | 1:4875e39abd1e | 331 | ".syntax divided \n\t" |
saranieves92 | 1:4875e39abd1e | 332 | #endif |
saranieves92 | 1:4875e39abd1e | 333 | : [c0] "+r" (c0), [c1] "+r" (c1), [c2] "+r" (c2), [k] "+r" (k), [i] "=&r" (i), [t0] "=&r" (t0), [t1] "=&r" (t1) |
saranieves92 | 1:4875e39abd1e | 334 | : [result] "r" (p_result), [left] "r" (p_left), [right] "r" (p_right), |
saranieves92 | 1:4875e39abd1e | 335 | [eccd] "I" (NUM_ECC_DIGITS * 4), [eccdm1] "I" ((NUM_ECC_DIGITS-1) * 4), [eccd2m1] "I" ((NUM_ECC_DIGITS * 2 - 1) * 4) |
saranieves92 | 1:4875e39abd1e | 336 | : "cc", "memory" |
saranieves92 | 1:4875e39abd1e | 337 | ); |
saranieves92 | 1:4875e39abd1e | 338 | |
saranieves92 | 1:4875e39abd1e | 339 | #elif (ECC_ASM == ecc_asm_thumb) |
saranieves92 | 1:4875e39abd1e | 340 | |
saranieves92 | 1:4875e39abd1e | 341 | register uint32_t *r0 asm("r0") = p_result; |
saranieves92 | 1:4875e39abd1e | 342 | register uint32_t *r1 asm("r1") = p_left; |
saranieves92 | 1:4875e39abd1e | 343 | register uint32_t *r2 asm("r2") = p_right; |
saranieves92 | 1:4875e39abd1e | 344 | |
saranieves92 | 1:4875e39abd1e | 345 | asm volatile ( |
saranieves92 | 1:4875e39abd1e | 346 | ".syntax unified \n\t" |
saranieves92 | 1:4875e39abd1e | 347 | "movs r3, #0 \n\t" /* c0 = 0 */ |
saranieves92 | 1:4875e39abd1e | 348 | "movs r4, #0 \n\t" /* c1 = 0 */ |
saranieves92 | 1:4875e39abd1e | 349 | "movs r5, #0 \n\t" /* c2 = 0 */ |
saranieves92 | 1:4875e39abd1e | 350 | "movs r6, #0 \n\t" /* k = 0 */ |
saranieves92 | 1:4875e39abd1e | 351 | |
saranieves92 | 1:4875e39abd1e | 352 | "push {r0} \n\t" /* keep p_result on the stack */ |
saranieves92 | 1:4875e39abd1e | 353 | |
saranieves92 | 1:4875e39abd1e | 354 | "1: \n\t" /* outer loop (k < NUM_ECC_DIGITS) */ |
saranieves92 | 1:4875e39abd1e | 355 | "movs r7, #0 \n\t" /* r7 = i = 0 */ |
saranieves92 | 1:4875e39abd1e | 356 | "b 3f \n\t" |
saranieves92 | 1:4875e39abd1e | 357 | |
saranieves92 | 1:4875e39abd1e | 358 | "2: \n\t" /* outer loop (k >= NUM_ECC_DIGITS) */ |
saranieves92 | 1:4875e39abd1e | 359 | "movs r7, r6 \n\t" /* r7 = k */ |
saranieves92 | 1:4875e39abd1e | 360 | "subs r7, %[eccdm1] \n\t" /* r7 = i = k - (NUM_ECC_DIGITS - 1) (times 4) */ |
saranieves92 | 1:4875e39abd1e | 361 | |
saranieves92 | 1:4875e39abd1e | 362 | "3: \n\t" /* inner loop */ |
saranieves92 | 1:4875e39abd1e | 363 | "push {r3, r4, r5, r6} \n\t" /* push things, r3 (c0) is at the top of stack. */ |
saranieves92 | 1:4875e39abd1e | 364 | "subs r0, r6, r7 \n\t" /* r0 = k-i */ |
saranieves92 | 1:4875e39abd1e | 365 | |
saranieves92 | 1:4875e39abd1e | 366 | "ldr r4, [r2, r0] \n\t" /* r4 = p_right[k-i] */ |
saranieves92 | 1:4875e39abd1e | 367 | "ldr r0, [r1, r7] \n\t" /* r0 = p_left[i] */ |
saranieves92 | 1:4875e39abd1e | 368 | |
saranieves92 | 1:4875e39abd1e | 369 | "lsrs r3, r0, #16 \n\t" /* r3 = a1 */ |
saranieves92 | 1:4875e39abd1e | 370 | "uxth r0, r0 \n\t" /* r0 = a0 */ |
saranieves92 | 1:4875e39abd1e | 371 | |
saranieves92 | 1:4875e39abd1e | 372 | "lsrs r5, r4, #16 \n\t" /* r5 = b1 */ |
saranieves92 | 1:4875e39abd1e | 373 | "uxth r4, r4 \n\t" /* r4 = b0 */ |
saranieves92 | 1:4875e39abd1e | 374 | |
saranieves92 | 1:4875e39abd1e | 375 | "movs r6, r3 \n\t" /* r6 = a1 */ |
saranieves92 | 1:4875e39abd1e | 376 | "muls r6, r5, r6 \n\t" /* r6 = a1*b1 */ |
saranieves92 | 1:4875e39abd1e | 377 | "muls r3, r4, r3 \n\t" /* r3 = b0*a1 */ |
saranieves92 | 1:4875e39abd1e | 378 | "muls r5, r0, r5 \n\t" /* r5 = a0*b1 */ |
saranieves92 | 1:4875e39abd1e | 379 | "muls r0, r4, r0 \n\t" /* r0 = a0*b0 */ |
saranieves92 | 1:4875e39abd1e | 380 | |
saranieves92 | 1:4875e39abd1e | 381 | "movs r4, #0 \n\t" /* r4 = 0 */ |
saranieves92 | 1:4875e39abd1e | 382 | "adds r3, r5 \n\t" /* r3 = b0*a1 + a0*b1 */ |
saranieves92 | 1:4875e39abd1e | 383 | "adcs r4, r4 \n\t" /* r4 = carry */ |
saranieves92 | 1:4875e39abd1e | 384 | "lsls r4, #16 \n\t" /* r4 = carry << 16 */ |
saranieves92 | 1:4875e39abd1e | 385 | "adds r6, r4 \n\t" /* r6 = a1*b1 + carry */ |
saranieves92 | 1:4875e39abd1e | 386 | |
saranieves92 | 1:4875e39abd1e | 387 | "lsls r4, r3, #16 \n\t" /* r4 = (b0*a1 + a0*b1) << 16 */ |
saranieves92 | 1:4875e39abd1e | 388 | "lsrs r3, #16 \n\t" /* r3 = (b0*a1 + a0*b1) >> 16 */ |
saranieves92 | 1:4875e39abd1e | 389 | "adds r0, r4 \n\t" /* r0 = low word = a0*b0 + ((b0*a1 + a0*b1) << 16) */ |
saranieves92 | 1:4875e39abd1e | 390 | "adcs r6, r3 \n\t" /* r6 = high word = a1*b1 + carry + ((b0*a1 + a0*b1) >> 16) */ |
saranieves92 | 1:4875e39abd1e | 391 | |
saranieves92 | 1:4875e39abd1e | 392 | "pop {r3, r4, r5} \n\t" /* r3 = c0, r4 = c1, r5 = c2 */ |
saranieves92 | 1:4875e39abd1e | 393 | "adds r3, r0 \n\t" /* add low word to c0 */ |
saranieves92 | 1:4875e39abd1e | 394 | "adcs r4, r6 \n\t" /* add high word to c1, including carry */ |
saranieves92 | 1:4875e39abd1e | 395 | "movs r0, #0 \n\t" /* r0 = 0 (does not affect carry bit) */ |
saranieves92 | 1:4875e39abd1e | 396 | "adcs r5, r0 \n\t" /* add carry to c2 */ |
saranieves92 | 1:4875e39abd1e | 397 | |
saranieves92 | 1:4875e39abd1e | 398 | "pop {r6} \n\t" /* r6 = k */ |
saranieves92 | 1:4875e39abd1e | 399 | |
saranieves92 | 1:4875e39abd1e | 400 | "adds r7, #4 \n\t" /* i += 4 */ |
saranieves92 | 1:4875e39abd1e | 401 | "cmp r7, %[eccd] \n\t" /* i < NUM_ECC_DIGITS (times 4)? */ |
saranieves92 | 1:4875e39abd1e | 402 | "bge 4f \n\t" /* if not, exit the loop */ |
saranieves92 | 1:4875e39abd1e | 403 | "cmp r7, r6 \n\t" /* i <= k? */ |
saranieves92 | 1:4875e39abd1e | 404 | "ble 3b \n\t" /* if so, continue looping */ |
saranieves92 | 1:4875e39abd1e | 405 | |
saranieves92 | 1:4875e39abd1e | 406 | "4: \n\t" /* end inner loop */ |
saranieves92 | 1:4875e39abd1e | 407 | |
saranieves92 | 1:4875e39abd1e | 408 | "ldr r0, [sp, #0] \n\t" /* r0 = p_result */ |
saranieves92 | 1:4875e39abd1e | 409 | |
saranieves92 | 1:4875e39abd1e | 410 | "str r3, [r0, r6] \n\t" /* p_result[k] = c0 */ |
saranieves92 | 1:4875e39abd1e | 411 | "mov r3, r4 \n\t" /* c0 = c1 */ |
saranieves92 | 1:4875e39abd1e | 412 | "mov r4, r5 \n\t" /* c1 = c2 */ |
saranieves92 | 1:4875e39abd1e | 413 | "movs r5, #0 \n\t" /* c2 = 0 */ |
saranieves92 | 1:4875e39abd1e | 414 | "adds r6, #4 \n\t" /* k += 4 */ |
saranieves92 | 1:4875e39abd1e | 415 | "cmp r6, %[eccd] \n\t" /* k < NUM_ECC_DIGITS (times 4) ? */ |
saranieves92 | 1:4875e39abd1e | 416 | "blt 1b \n\t" /* if not, loop back, start with i = 0 */ |
saranieves92 | 1:4875e39abd1e | 417 | "cmp r6, %[eccd2m1] \n\t" /* k < NUM_ECC_DIGITS * 2 - 1 (times 4) ? */ |
saranieves92 | 1:4875e39abd1e | 418 | "blt 2b \n\t" /* if not, loop back, start with i = (k+1) - NUM_ECC_DIGITS */ |
saranieves92 | 1:4875e39abd1e | 419 | /* end outer loop */ |
saranieves92 | 1:4875e39abd1e | 420 | |
saranieves92 | 1:4875e39abd1e | 421 | "str r3, [r0, r6] \n\t" /* p_result[NUM_ECC_DIGITS * 2 - 1] = c0 */ |
saranieves92 | 1:4875e39abd1e | 422 | "pop {r0} \n\t" /* pop p_result off the stack */ |
saranieves92 | 1:4875e39abd1e | 423 | |
saranieves92 | 1:4875e39abd1e | 424 | ".syntax divided \n\t" |
saranieves92 | 1:4875e39abd1e | 425 | : |
saranieves92 | 1:4875e39abd1e | 426 | : [r0] "l" (r0), [r1] "l" (r1), [r2] "l" (r2), [eccd] "I" (NUM_ECC_DIGITS * 4), [eccdm1] "I" ((NUM_ECC_DIGITS-1) * 4), [eccd2m1] "I" ((NUM_ECC_DIGITS * 2 - 1) * 4) |
saranieves92 | 1:4875e39abd1e | 427 | : "r3", "r4", "r5", "r6", "r7", "cc", "memory" |
saranieves92 | 1:4875e39abd1e | 428 | ); |
saranieves92 | 1:4875e39abd1e | 429 | |
saranieves92 | 1:4875e39abd1e | 430 | #else |
saranieves92 | 1:4875e39abd1e | 431 | |
saranieves92 | 1:4875e39abd1e | 432 | uint64_t r01 = 0; |
saranieves92 | 1:4875e39abd1e | 433 | uint32_t r2 = 0; |
saranieves92 | 1:4875e39abd1e | 434 | |
saranieves92 | 1:4875e39abd1e | 435 | uint i, k; |
saranieves92 | 1:4875e39abd1e | 436 | |
saranieves92 | 1:4875e39abd1e | 437 | /* Compute each digit of p_result in sequence, maintaining the carries. */ |
saranieves92 | 1:4875e39abd1e | 438 | for(k=0; k < NUM_ECC_DIGITS*2 - 1; ++k) |
saranieves92 | 1:4875e39abd1e | 439 | { |
saranieves92 | 1:4875e39abd1e | 440 | uint l_min = (k < NUM_ECC_DIGITS ? 0 : (k + 1) - NUM_ECC_DIGITS); |
saranieves92 | 1:4875e39abd1e | 441 | for(i=l_min; i<=k && i<NUM_ECC_DIGITS; ++i) |
saranieves92 | 1:4875e39abd1e | 442 | { |
saranieves92 | 1:4875e39abd1e | 443 | uint64_t l_product = (uint64_t)p_left[i] * p_right[k-i]; |
saranieves92 | 1:4875e39abd1e | 444 | r01 += l_product; |
saranieves92 | 1:4875e39abd1e | 445 | r2 += (r01 < l_product); |
saranieves92 | 1:4875e39abd1e | 446 | } |
saranieves92 | 1:4875e39abd1e | 447 | p_result[k] = (uint32_t)r01; |
saranieves92 | 1:4875e39abd1e | 448 | r01 = (r01 >> 32) | (((uint64_t)r2) << 32); |
saranieves92 | 1:4875e39abd1e | 449 | r2 = 0; |
saranieves92 | 1:4875e39abd1e | 450 | } |
saranieves92 | 1:4875e39abd1e | 451 | |
saranieves92 | 1:4875e39abd1e | 452 | p_result[NUM_ECC_DIGITS*2 - 1] = (uint32_t)r01; |
saranieves92 | 1:4875e39abd1e | 453 | #endif |
saranieves92 | 1:4875e39abd1e | 454 | } |
saranieves92 | 1:4875e39abd1e | 455 | |
saranieves92 | 1:4875e39abd1e | 456 | /* Computes p_result = (p_left + p_right) % p_mod. |
saranieves92 | 1:4875e39abd1e | 457 | Assumes that p_left < p_mod and p_right < p_mod, p_result != p_mod. */ |
saranieves92 | 1:4875e39abd1e | 458 | static void vli_modAdd(uint32_t *p_result, const uint32_t *p_left, |
saranieves92 | 1:4875e39abd1e | 459 | const uint32_t *p_right, const uint32_t *p_mod) |
saranieves92 | 1:4875e39abd1e | 460 | { |
saranieves92 | 1:4875e39abd1e | 461 | uint32_t l_carry = vli_add(p_result, p_left, p_right); |
saranieves92 | 1:4875e39abd1e | 462 | if(l_carry || vli_cmp(p_result, p_mod) >= 0) |
saranieves92 | 1:4875e39abd1e | 463 | { /* p_result > p_mod (p_result = p_mod + remainder), so subtract p_mod to get remainder. */ |
saranieves92 | 1:4875e39abd1e | 464 | vli_sub(p_result, p_result, p_mod); |
saranieves92 | 1:4875e39abd1e | 465 | } |
saranieves92 | 1:4875e39abd1e | 466 | } |
saranieves92 | 1:4875e39abd1e | 467 | |
saranieves92 | 1:4875e39abd1e | 468 | /* Computes p_result = (p_left - p_right) % p_mod. |
saranieves92 | 1:4875e39abd1e | 469 | Assumes that p_left < p_mod and p_right < p_mod, p_result != p_mod. */ |
saranieves92 | 1:4875e39abd1e | 470 | static void vli_modSub(uint32_t *p_result, const uint32_t *p_left, |
saranieves92 | 1:4875e39abd1e | 471 | const uint32_t *p_right, const uint32_t *p_mod) |
saranieves92 | 1:4875e39abd1e | 472 | { |
saranieves92 | 1:4875e39abd1e | 473 | uint32_t l_borrow = vli_sub(p_result, p_left, p_right); |
saranieves92 | 1:4875e39abd1e | 474 | if(l_borrow) |
saranieves92 | 1:4875e39abd1e | 475 | { /* In this case, p_result == -diff == (max int) - diff. |
saranieves92 | 1:4875e39abd1e | 476 | Since -x % d == d - x, we can get the correct result from p_result + p_mod (with overflow). */ |
saranieves92 | 1:4875e39abd1e | 477 | vli_add(p_result, p_result, p_mod); |
saranieves92 | 1:4875e39abd1e | 478 | } |
saranieves92 | 1:4875e39abd1e | 479 | } |
saranieves92 | 1:4875e39abd1e | 480 | |
saranieves92 | 1:4875e39abd1e | 481 | #if (ECC_CURVE == secp128r1) |
saranieves92 | 1:4875e39abd1e | 482 | |
saranieves92 | 1:4875e39abd1e | 483 | /* Computes p_result = p_product % curve_p. |
saranieves92 | 1:4875e39abd1e | 484 | See algorithm 5 and 6 from http://www.isys.uni-klu.ac.at/PDF/2001-0126-MT.pdf */ |
saranieves92 | 1:4875e39abd1e | 485 | static void vli_mmod_fast(uint32_t *p_result, const uint32_t *p_product) |
saranieves92 | 1:4875e39abd1e | 486 | { |
saranieves92 | 1:4875e39abd1e | 487 | uint32_t l_tmp[NUM_ECC_DIGITS]; |
saranieves92 | 1:4875e39abd1e | 488 | int l_carry; |
saranieves92 | 1:4875e39abd1e | 489 | |
saranieves92 | 1:4875e39abd1e | 490 | vli_set(p_result, p_product); |
saranieves92 | 1:4875e39abd1e | 491 | |
saranieves92 | 1:4875e39abd1e | 492 | l_tmp[0] = p_product[4]; |
saranieves92 | 1:4875e39abd1e | 493 | l_tmp[1] = p_product[5]; |
saranieves92 | 1:4875e39abd1e | 494 | l_tmp[2] = p_product[6]; |
saranieves92 | 1:4875e39abd1e | 495 | l_tmp[3] = (p_product[7] & 0x00000001) | (p_product[4] << 1); |
saranieves92 | 1:4875e39abd1e | 496 | l_carry = vli_add(p_result, p_result, l_tmp); |
saranieves92 | 1:4875e39abd1e | 497 | |
saranieves92 | 1:4875e39abd1e | 498 | l_tmp[0] = (p_product[4] >> 31) | (p_product[5] << 1); |
saranieves92 | 1:4875e39abd1e | 499 | l_tmp[1] = (p_product[5] >> 31) | (p_product[6] << 1); |
saranieves92 | 1:4875e39abd1e | 500 | l_tmp[2] = (p_product[6] >> 31) | (p_product[7] << 1); |
saranieves92 | 1:4875e39abd1e | 501 | l_tmp[3] = (p_product[7] >> 31) | ((p_product[4] & 0x80000000) >> 30) | (p_product[5] << 2); |
saranieves92 | 1:4875e39abd1e | 502 | l_carry += vli_add(p_result, p_result, l_tmp); |
saranieves92 | 1:4875e39abd1e | 503 | |
saranieves92 | 1:4875e39abd1e | 504 | l_tmp[0] = (p_product[5] >> 30) | (p_product[6] << 2); |
saranieves92 | 1:4875e39abd1e | 505 | l_tmp[1] = (p_product[6] >> 30) | (p_product[7] << 2); |
saranieves92 | 1:4875e39abd1e | 506 | l_tmp[2] = (p_product[7] >> 30); |
saranieves92 | 1:4875e39abd1e | 507 | l_tmp[3] = ((p_product[5] & 0xC0000000) >> 29) | (p_product[6] << 3); |
saranieves92 | 1:4875e39abd1e | 508 | l_carry += vli_add(p_result, p_result, l_tmp); |
saranieves92 | 1:4875e39abd1e | 509 | |
saranieves92 | 1:4875e39abd1e | 510 | l_tmp[0] = (p_product[6] >> 29) | (p_product[7] << 3); |
saranieves92 | 1:4875e39abd1e | 511 | l_tmp[1] = (p_product[7] >> 29); |
saranieves92 | 1:4875e39abd1e | 512 | l_tmp[2] = 0; |
saranieves92 | 1:4875e39abd1e | 513 | l_tmp[3] = ((p_product[6] & 0xE0000000) >> 28) | (p_product[7] << 4); |
saranieves92 | 1:4875e39abd1e | 514 | l_carry += vli_add(p_result, p_result, l_tmp); |
saranieves92 | 1:4875e39abd1e | 515 | |
saranieves92 | 1:4875e39abd1e | 516 | l_tmp[0] = (p_product[7] >> 28); |
saranieves92 | 1:4875e39abd1e | 517 | l_tmp[1] = 0; |
saranieves92 | 1:4875e39abd1e | 518 | l_tmp[2] = 0; |
saranieves92 | 1:4875e39abd1e | 519 | l_tmp[3] = (p_product[7] & 0xFFFFFFFE); |
saranieves92 | 1:4875e39abd1e | 520 | l_carry += vli_add(p_result, p_result, l_tmp); |
saranieves92 | 1:4875e39abd1e | 521 | |
saranieves92 | 1:4875e39abd1e | 522 | l_tmp[0] = 0; |
saranieves92 | 1:4875e39abd1e | 523 | l_tmp[1] = 0; |
saranieves92 | 1:4875e39abd1e | 524 | l_tmp[2] = 0; |
saranieves92 | 1:4875e39abd1e | 525 | l_tmp[3] = ((p_product[7] & 0xF0000000) >> 27); |
saranieves92 | 1:4875e39abd1e | 526 | l_carry += vli_add(p_result, p_result, l_tmp); |
saranieves92 | 1:4875e39abd1e | 527 | |
saranieves92 | 1:4875e39abd1e | 528 | while(l_carry || vli_cmp(curve_p, p_result) != 1) |
saranieves92 | 1:4875e39abd1e | 529 | { |
saranieves92 | 1:4875e39abd1e | 530 | l_carry -= vli_sub(p_result, p_result, curve_p); |
saranieves92 | 1:4875e39abd1e | 531 | } |
saranieves92 | 1:4875e39abd1e | 532 | } |
saranieves92 | 1:4875e39abd1e | 533 | |
saranieves92 | 1:4875e39abd1e | 534 | #elif (ECC_CURVE == secp192r1) |
saranieves92 | 1:4875e39abd1e | 535 | |
saranieves92 | 1:4875e39abd1e | 536 | /* Computes p_result = p_product % curve_p. |
saranieves92 | 1:4875e39abd1e | 537 | See algorithm 5 and 6 from http://www.isys.uni-klu.ac.at/PDF/2001-0126-MT.pdf */ |
saranieves92 | 1:4875e39abd1e | 538 | static void vli_mmod_fast(uint32_t *p_result, const uint32_t *p_product) |
saranieves92 | 1:4875e39abd1e | 539 | { |
saranieves92 | 1:4875e39abd1e | 540 | uint32_t l_tmp[NUM_ECC_DIGITS]; |
saranieves92 | 1:4875e39abd1e | 541 | int l_carry; |
saranieves92 | 1:4875e39abd1e | 542 | |
saranieves92 | 1:4875e39abd1e | 543 | vli_set(p_result, p_product); |
saranieves92 | 1:4875e39abd1e | 544 | |
saranieves92 | 1:4875e39abd1e | 545 | vli_set(l_tmp, &p_product[6]); |
saranieves92 | 1:4875e39abd1e | 546 | l_carry = vli_add(p_result, p_result, l_tmp); |
saranieves92 | 1:4875e39abd1e | 547 | |
saranieves92 | 1:4875e39abd1e | 548 | l_tmp[0] = l_tmp[1] = 0; |
saranieves92 | 1:4875e39abd1e | 549 | l_tmp[2] = p_product[6]; |
saranieves92 | 1:4875e39abd1e | 550 | l_tmp[3] = p_product[7]; |
saranieves92 | 1:4875e39abd1e | 551 | l_tmp[4] = p_product[8]; |
saranieves92 | 1:4875e39abd1e | 552 | l_tmp[5] = p_product[9]; |
saranieves92 | 1:4875e39abd1e | 553 | l_carry += vli_add(p_result, p_result, l_tmp); |
saranieves92 | 1:4875e39abd1e | 554 | |
saranieves92 | 1:4875e39abd1e | 555 | l_tmp[0] = l_tmp[2] = p_product[10]; |
saranieves92 | 1:4875e39abd1e | 556 | l_tmp[1] = l_tmp[3] = p_product[11]; |
saranieves92 | 1:4875e39abd1e | 557 | l_tmp[4] = l_tmp[5] = 0; |
saranieves92 | 1:4875e39abd1e | 558 | l_carry += vli_add(p_result, p_result, l_tmp); |
saranieves92 | 1:4875e39abd1e | 559 | |
saranieves92 | 1:4875e39abd1e | 560 | while(l_carry || vli_cmp(curve_p, p_result) != 1) |
saranieves92 | 1:4875e39abd1e | 561 | { |
saranieves92 | 1:4875e39abd1e | 562 | l_carry -= vli_sub(p_result, p_result, curve_p); |
saranieves92 | 1:4875e39abd1e | 563 | } |
saranieves92 | 1:4875e39abd1e | 564 | } |
saranieves92 | 1:4875e39abd1e | 565 | |
saranieves92 | 1:4875e39abd1e | 566 | #elif (ECC_CURVE == secp256r1) |
saranieves92 | 1:4875e39abd1e | 567 | |
saranieves92 | 1:4875e39abd1e | 568 | /* Computes p_result = p_product % curve_p |
saranieves92 | 1:4875e39abd1e | 569 | from http://www.nsa.gov/ia/_files/nist-routines.pdf */ |
saranieves92 | 1:4875e39abd1e | 570 | static void vli_mmod_fast(uint32_t *p_result, const uint32_t *p_product) |
saranieves92 | 1:4875e39abd1e | 571 | { |
saranieves92 | 1:4875e39abd1e | 572 | uint32_t l_tmp[NUM_ECC_DIGITS]; |
saranieves92 | 1:4875e39abd1e | 573 | int l_carry; |
saranieves92 | 1:4875e39abd1e | 574 | |
saranieves92 | 1:4875e39abd1e | 575 | /* t */ |
saranieves92 | 1:4875e39abd1e | 576 | vli_set(p_result, p_product); |
saranieves92 | 1:4875e39abd1e | 577 | |
saranieves92 | 1:4875e39abd1e | 578 | /* s1 */ |
saranieves92 | 1:4875e39abd1e | 579 | l_tmp[0] = l_tmp[1] = l_tmp[2] = 0; |
saranieves92 | 1:4875e39abd1e | 580 | l_tmp[3] = p_product[11]; |
saranieves92 | 1:4875e39abd1e | 581 | l_tmp[4] = p_product[12]; |
saranieves92 | 1:4875e39abd1e | 582 | l_tmp[5] = p_product[13]; |
saranieves92 | 1:4875e39abd1e | 583 | l_tmp[6] = p_product[14]; |
saranieves92 | 1:4875e39abd1e | 584 | l_tmp[7] = p_product[15]; |
saranieves92 | 1:4875e39abd1e | 585 | l_carry = vli_lshift(l_tmp, l_tmp, 1); |
saranieves92 | 1:4875e39abd1e | 586 | l_carry += vli_add(p_result, p_result, l_tmp); |
saranieves92 | 1:4875e39abd1e | 587 | |
saranieves92 | 1:4875e39abd1e | 588 | /* s2 */ |
saranieves92 | 1:4875e39abd1e | 589 | l_tmp[3] = p_product[12]; |
saranieves92 | 1:4875e39abd1e | 590 | l_tmp[4] = p_product[13]; |
saranieves92 | 1:4875e39abd1e | 591 | l_tmp[5] = p_product[14]; |
saranieves92 | 1:4875e39abd1e | 592 | l_tmp[6] = p_product[15]; |
saranieves92 | 1:4875e39abd1e | 593 | l_tmp[7] = 0; |
saranieves92 | 1:4875e39abd1e | 594 | l_carry += vli_lshift(l_tmp, l_tmp, 1); |
saranieves92 | 1:4875e39abd1e | 595 | l_carry += vli_add(p_result, p_result, l_tmp); |
saranieves92 | 1:4875e39abd1e | 596 | |
saranieves92 | 1:4875e39abd1e | 597 | /* s3 */ |
saranieves92 | 1:4875e39abd1e | 598 | l_tmp[0] = p_product[8]; |
saranieves92 | 1:4875e39abd1e | 599 | l_tmp[1] = p_product[9]; |
saranieves92 | 1:4875e39abd1e | 600 | l_tmp[2] = p_product[10]; |
saranieves92 | 1:4875e39abd1e | 601 | l_tmp[3] = l_tmp[4] = l_tmp[5] = 0; |
saranieves92 | 1:4875e39abd1e | 602 | l_tmp[6] = p_product[14]; |
saranieves92 | 1:4875e39abd1e | 603 | l_tmp[7] = p_product[15]; |
saranieves92 | 1:4875e39abd1e | 604 | l_carry += vli_add(p_result, p_result, l_tmp); |
saranieves92 | 1:4875e39abd1e | 605 | |
saranieves92 | 1:4875e39abd1e | 606 | /* s4 */ |
saranieves92 | 1:4875e39abd1e | 607 | l_tmp[0] = p_product[9]; |
saranieves92 | 1:4875e39abd1e | 608 | l_tmp[1] = p_product[10]; |
saranieves92 | 1:4875e39abd1e | 609 | l_tmp[2] = p_product[11]; |
saranieves92 | 1:4875e39abd1e | 610 | l_tmp[3] = p_product[13]; |
saranieves92 | 1:4875e39abd1e | 611 | l_tmp[4] = p_product[14]; |
saranieves92 | 1:4875e39abd1e | 612 | l_tmp[5] = p_product[15]; |
saranieves92 | 1:4875e39abd1e | 613 | l_tmp[6] = p_product[13]; |
saranieves92 | 1:4875e39abd1e | 614 | l_tmp[7] = p_product[8]; |
saranieves92 | 1:4875e39abd1e | 615 | l_carry += vli_add(p_result, p_result, l_tmp); |
saranieves92 | 1:4875e39abd1e | 616 | |
saranieves92 | 1:4875e39abd1e | 617 | /* d1 */ |
saranieves92 | 1:4875e39abd1e | 618 | l_tmp[0] = p_product[11]; |
saranieves92 | 1:4875e39abd1e | 619 | l_tmp[1] = p_product[12]; |
saranieves92 | 1:4875e39abd1e | 620 | l_tmp[2] = p_product[13]; |
saranieves92 | 1:4875e39abd1e | 621 | l_tmp[3] = l_tmp[4] = l_tmp[5] = 0; |
saranieves92 | 1:4875e39abd1e | 622 | l_tmp[6] = p_product[8]; |
saranieves92 | 1:4875e39abd1e | 623 | l_tmp[7] = p_product[10]; |
saranieves92 | 1:4875e39abd1e | 624 | l_carry -= vli_sub(p_result, p_result, l_tmp); |
saranieves92 | 1:4875e39abd1e | 625 | |
saranieves92 | 1:4875e39abd1e | 626 | /* d2 */ |
saranieves92 | 1:4875e39abd1e | 627 | l_tmp[0] = p_product[12]; |
saranieves92 | 1:4875e39abd1e | 628 | l_tmp[1] = p_product[13]; |
saranieves92 | 1:4875e39abd1e | 629 | l_tmp[2] = p_product[14]; |
saranieves92 | 1:4875e39abd1e | 630 | l_tmp[3] = p_product[15]; |
saranieves92 | 1:4875e39abd1e | 631 | l_tmp[4] = l_tmp[5] = 0; |
saranieves92 | 1:4875e39abd1e | 632 | l_tmp[6] = p_product[9]; |
saranieves92 | 1:4875e39abd1e | 633 | l_tmp[7] = p_product[11]; |
saranieves92 | 1:4875e39abd1e | 634 | l_carry -= vli_sub(p_result, p_result, l_tmp); |
saranieves92 | 1:4875e39abd1e | 635 | |
saranieves92 | 1:4875e39abd1e | 636 | /* d3 */ |
saranieves92 | 1:4875e39abd1e | 637 | l_tmp[0] = p_product[13]; |
saranieves92 | 1:4875e39abd1e | 638 | l_tmp[1] = p_product[14]; |
saranieves92 | 1:4875e39abd1e | 639 | l_tmp[2] = p_product[15]; |
saranieves92 | 1:4875e39abd1e | 640 | l_tmp[3] = p_product[8]; |
saranieves92 | 1:4875e39abd1e | 641 | l_tmp[4] = p_product[9]; |
saranieves92 | 1:4875e39abd1e | 642 | l_tmp[5] = p_product[10]; |
saranieves92 | 1:4875e39abd1e | 643 | l_tmp[6] = 0; |
saranieves92 | 1:4875e39abd1e | 644 | l_tmp[7] = p_product[12]; |
saranieves92 | 1:4875e39abd1e | 645 | l_carry -= vli_sub(p_result, p_result, l_tmp); |
saranieves92 | 1:4875e39abd1e | 646 | |
saranieves92 | 1:4875e39abd1e | 647 | /* d4 */ |
saranieves92 | 1:4875e39abd1e | 648 | l_tmp[0] = p_product[14]; |
saranieves92 | 1:4875e39abd1e | 649 | l_tmp[1] = p_product[15]; |
saranieves92 | 1:4875e39abd1e | 650 | l_tmp[2] = 0; |
saranieves92 | 1:4875e39abd1e | 651 | l_tmp[3] = p_product[9]; |
saranieves92 | 1:4875e39abd1e | 652 | l_tmp[4] = p_product[10]; |
saranieves92 | 1:4875e39abd1e | 653 | l_tmp[5] = p_product[11]; |
saranieves92 | 1:4875e39abd1e | 654 | l_tmp[6] = 0; |
saranieves92 | 1:4875e39abd1e | 655 | l_tmp[7] = p_product[13]; |
saranieves92 | 1:4875e39abd1e | 656 | l_carry -= vli_sub(p_result, p_result, l_tmp); |
saranieves92 | 1:4875e39abd1e | 657 | |
saranieves92 | 1:4875e39abd1e | 658 | if(l_carry < 0) |
saranieves92 | 1:4875e39abd1e | 659 | { |
saranieves92 | 1:4875e39abd1e | 660 | do |
saranieves92 | 1:4875e39abd1e | 661 | { |
saranieves92 | 1:4875e39abd1e | 662 | l_carry += vli_add(p_result, p_result, curve_p); |
saranieves92 | 1:4875e39abd1e | 663 | } while(l_carry < 0); |
saranieves92 | 1:4875e39abd1e | 664 | } |
saranieves92 | 1:4875e39abd1e | 665 | else |
saranieves92 | 1:4875e39abd1e | 666 | { |
saranieves92 | 1:4875e39abd1e | 667 | while(l_carry || vli_cmp(curve_p, p_result) != 1) |
saranieves92 | 1:4875e39abd1e | 668 | { |
saranieves92 | 1:4875e39abd1e | 669 | l_carry -= vli_sub(p_result, p_result, curve_p); |
saranieves92 | 1:4875e39abd1e | 670 | } |
saranieves92 | 1:4875e39abd1e | 671 | } |
saranieves92 | 1:4875e39abd1e | 672 | } |
saranieves92 | 1:4875e39abd1e | 673 | |
saranieves92 | 1:4875e39abd1e | 674 | #elif (ECC_CURVE == secp384r1) |
saranieves92 | 1:4875e39abd1e | 675 | |
saranieves92 | 1:4875e39abd1e | 676 | static void omega_mult(uint32_t *p_result, const uint32_t *p_right) |
saranieves92 | 1:4875e39abd1e | 677 | { |
saranieves92 | 1:4875e39abd1e | 678 | /* Multiply by (2^128 + 2^96 - 2^32 + 1). */ |
saranieves92 | 1:4875e39abd1e | 679 | vli_set(p_result, p_right); /* 1 */ |
saranieves92 | 1:4875e39abd1e | 680 | p_result[3 + NUM_ECC_DIGITS] = vli_add(p_result + 3, p_result + 3, p_right); /* 2^96 + 1 */ |
saranieves92 | 1:4875e39abd1e | 681 | p_result[4 + NUM_ECC_DIGITS] = vli_add(p_result + 4, p_result + 4, p_right); /* 2^128 + 2^96 + 1 */ |
saranieves92 | 1:4875e39abd1e | 682 | if(vli_sub(p_result + 1, p_result + 1, p_right)) /* 2^128 + 2^96 - 2^32 + 1 */ |
saranieves92 | 1:4875e39abd1e | 683 | { /* Propagate borrow if necessary. */ |
saranieves92 | 1:4875e39abd1e | 684 | uint i; |
saranieves92 | 1:4875e39abd1e | 685 | for(i = 1 + NUM_ECC_DIGITS; ; ++i) |
saranieves92 | 1:4875e39abd1e | 686 | { |
saranieves92 | 1:4875e39abd1e | 687 | --p_result[i]; |
saranieves92 | 1:4875e39abd1e | 688 | if(p_result[i] != 0xffffffff) |
saranieves92 | 1:4875e39abd1e | 689 | { |
saranieves92 | 1:4875e39abd1e | 690 | break; |
saranieves92 | 1:4875e39abd1e | 691 | } |
saranieves92 | 1:4875e39abd1e | 692 | } |
saranieves92 | 1:4875e39abd1e | 693 | } |
saranieves92 | 1:4875e39abd1e | 694 | } |
saranieves92 | 1:4875e39abd1e | 695 | |
saranieves92 | 1:4875e39abd1e | 696 | /* Computes p_result = p_product % curve_p |
saranieves92 | 1:4875e39abd1e | 697 | see PDF "Comparing Elliptic Curve Cryptography and RSA on 8-bit CPUs" |
saranieves92 | 1:4875e39abd1e | 698 | section "Curve-Specific Optimizations" */ |
saranieves92 | 1:4875e39abd1e | 699 | static void vli_mmod_fast(uint32_t *p_result, const uint32_t *p_product) |
saranieves92 | 1:4875e39abd1e | 700 | { |
saranieves92 | 1:4875e39abd1e | 701 | uint32_t l_tmp[2*NUM_ECC_DIGITS]; |
saranieves92 | 1:4875e39abd1e | 702 | |
saranieves92 | 1:4875e39abd1e | 703 | while(!vli_isZero(p_product + NUM_ECC_DIGITS)) /* While c1 != 0 */ |
saranieves92 | 1:4875e39abd1e | 704 | { |
saranieves92 | 1:4875e39abd1e | 705 | uint32_t l_carry = 0; |
saranieves92 | 1:4875e39abd1e | 706 | uint i; |
saranieves92 | 1:4875e39abd1e | 707 | |
saranieves92 | 1:4875e39abd1e | 708 | vli_clear(l_tmp); |
saranieves92 | 1:4875e39abd1e | 709 | vli_clear(l_tmp + NUM_ECC_DIGITS); |
saranieves92 | 1:4875e39abd1e | 710 | omega_mult(l_tmp, p_product + NUM_ECC_DIGITS); /* tmp = w * c1 */ |
saranieves92 | 1:4875e39abd1e | 711 | vli_clear(p_product + NUM_ECC_DIGITS); /* p = c0 */ |
saranieves92 | 1:4875e39abd1e | 712 | |
saranieves92 | 1:4875e39abd1e | 713 | /* (c1, c0) = c0 + w * c1 */ |
saranieves92 | 1:4875e39abd1e | 714 | for(i=0; i<NUM_ECC_DIGITS+5; ++i) |
saranieves92 | 1:4875e39abd1e | 715 | { |
saranieves92 | 1:4875e39abd1e | 716 | uint32_t l_sum = p_product[i] + l_tmp[i] + l_carry; |
saranieves92 | 1:4875e39abd1e | 717 | if(l_sum != p_product[i]) |
saranieves92 | 1:4875e39abd1e | 718 | { |
saranieves92 | 1:4875e39abd1e | 719 | l_carry = (l_sum < p_product[i]); |
saranieves92 | 1:4875e39abd1e | 720 | } |
saranieves92 | 1:4875e39abd1e | 721 | p_product[i] = l_sum; |
saranieves92 | 1:4875e39abd1e | 722 | } |
saranieves92 | 1:4875e39abd1e | 723 | } |
saranieves92 | 1:4875e39abd1e | 724 | |
saranieves92 | 1:4875e39abd1e | 725 | while(vli_cmp(p_product, curve_p) > 0) |
saranieves92 | 1:4875e39abd1e | 726 | { |
saranieves92 | 1:4875e39abd1e | 727 | vli_sub(p_product, p_product, curve_p); |
saranieves92 | 1:4875e39abd1e | 728 | } |
saranieves92 | 1:4875e39abd1e | 729 | vli_set(p_result, p_product); |
saranieves92 | 1:4875e39abd1e | 730 | } |
saranieves92 | 1:4875e39abd1e | 731 | |
saranieves92 | 1:4875e39abd1e | 732 | #elif (ECC_CURVE == secp256k1) |
saranieves92 | 1:4875e39abd1e | 733 | |
saranieves92 | 1:4875e39abd1e | 734 | static void omega_mult(uint32_t *p_result, const uint32_t *p_right) |
saranieves92 | 1:4875e39abd1e | 735 | { |
saranieves92 | 1:4875e39abd1e | 736 | /* Multiply by (2^32 + 2^9 + 2^8 + 2^7 + 2^6 + 2^4 + 1). */ |
saranieves92 | 1:4875e39abd1e | 737 | uint64_t l_mult = 0x3D1; /* everything except 2^32 */ |
saranieves92 | 1:4875e39abd1e | 738 | uint32_t l_carry = 0; |
saranieves92 | 1:4875e39abd1e | 739 | uint i; |
saranieves92 | 1:4875e39abd1e | 740 | for(i=0; i<NUM_ECC_DIGITS; ++i) |
saranieves92 | 1:4875e39abd1e | 741 | { |
saranieves92 | 1:4875e39abd1e | 742 | uint64_t p = l_mult * p_right[i] + l_carry; |
saranieves92 | 1:4875e39abd1e | 743 | p_result[i] = (p & 0xffffffff); |
saranieves92 | 1:4875e39abd1e | 744 | l_carry = p >> 32; |
saranieves92 | 1:4875e39abd1e | 745 | } |
saranieves92 | 1:4875e39abd1e | 746 | p_result[NUM_ECC_DIGITS] = l_carry; |
saranieves92 | 1:4875e39abd1e | 747 | |
saranieves92 | 1:4875e39abd1e | 748 | p_result[1 + NUM_ECC_DIGITS] = vli_add(p_result + 1, p_result + 1, p_right); /* add the 2^32 multiple */ |
saranieves92 | 1:4875e39abd1e | 749 | } |
saranieves92 | 1:4875e39abd1e | 750 | |
saranieves92 | 1:4875e39abd1e | 751 | /* Computes p_result = p_product % curve_p */ |
saranieves92 | 1:4875e39abd1e | 752 | static void vli_mmod_fast(uint32_t *p_result, const uint32_t *p_product) |
saranieves92 | 1:4875e39abd1e | 753 | { |
saranieves92 | 1:4875e39abd1e | 754 | uint32_t l_tmp[2*NUM_ECC_DIGITS]; |
saranieves92 | 1:4875e39abd1e | 755 | |
saranieves92 | 1:4875e39abd1e | 756 | while(!vli_isZero(p_product + NUM_ECC_DIGITS)) /* While c1 != 0 */ |
saranieves92 | 1:4875e39abd1e | 757 | { |
saranieves92 | 1:4875e39abd1e | 758 | uint32_t l_carry = 0; |
saranieves92 | 1:4875e39abd1e | 759 | uint i; |
saranieves92 | 1:4875e39abd1e | 760 | |
saranieves92 | 1:4875e39abd1e | 761 | vli_clear(l_tmp); |
saranieves92 | 1:4875e39abd1e | 762 | vli_clear(l_tmp + NUM_ECC_DIGITS); |
saranieves92 | 1:4875e39abd1e | 763 | omega_mult(l_tmp, p_product + NUM_ECC_DIGITS); /* tmp = w * c1 */ |
saranieves92 | 1:4875e39abd1e | 764 | vli_clear(p_product + NUM_ECC_DIGITS); /* p = c0 */ |
saranieves92 | 1:4875e39abd1e | 765 | |
saranieves92 | 1:4875e39abd1e | 766 | /* (c1, c0) = c0 + w * c1 */ |
saranieves92 | 1:4875e39abd1e | 767 | for(i=0; i<NUM_ECC_DIGITS+2; ++i) |
saranieves92 | 1:4875e39abd1e | 768 | { |
saranieves92 | 1:4875e39abd1e | 769 | uint32_t l_sum = p_product[i] + l_tmp[i] + l_carry; |
saranieves92 | 1:4875e39abd1e | 770 | if(l_sum != p_product[i]) |
saranieves92 | 1:4875e39abd1e | 771 | { |
saranieves92 | 1:4875e39abd1e | 772 | l_carry = (l_sum < p_product[i]); |
saranieves92 | 1:4875e39abd1e | 773 | } |
saranieves92 | 1:4875e39abd1e | 774 | p_product[i] = l_sum; |
saranieves92 | 1:4875e39abd1e | 775 | } |
saranieves92 | 1:4875e39abd1e | 776 | } |
saranieves92 | 1:4875e39abd1e | 777 | |
saranieves92 | 1:4875e39abd1e | 778 | while(vli_cmp(p_product, curve_p) > 0) |
saranieves92 | 1:4875e39abd1e | 779 | { |
saranieves92 | 1:4875e39abd1e | 780 | vli_sub(p_product, p_product, curve_p); |
saranieves92 | 1:4875e39abd1e | 781 | } |
saranieves92 | 1:4875e39abd1e | 782 | vli_set(p_result, p_product); |
saranieves92 | 1:4875e39abd1e | 783 | } |
saranieves92 | 1:4875e39abd1e | 784 | |
saranieves92 | 1:4875e39abd1e | 785 | #endif |
saranieves92 | 1:4875e39abd1e | 786 | |
saranieves92 | 1:4875e39abd1e | 787 | /* Computes p_result = (p_left * p_right) % curve_p. */ |
saranieves92 | 1:4875e39abd1e | 788 | static void vli_modMult_fast(uint32_t *p_result, const uint32_t *p_left, const uint32_t *p_right) |
saranieves92 | 1:4875e39abd1e | 789 | { |
saranieves92 | 1:4875e39abd1e | 790 | uint32_t l_product[2 * NUM_ECC_DIGITS]; |
saranieves92 | 1:4875e39abd1e | 791 | vli_mult(l_product, p_left, p_right); |
saranieves92 | 1:4875e39abd1e | 792 | vli_mmod_fast(p_result, l_product); |
saranieves92 | 1:4875e39abd1e | 793 | } |
saranieves92 | 1:4875e39abd1e | 794 | |
saranieves92 | 1:4875e39abd1e | 795 | #if ECC_SQUARE_FUNC |
saranieves92 | 1:4875e39abd1e | 796 | |
saranieves92 | 1:4875e39abd1e | 797 | /* Computes p_result = p_left^2. */ |
saranieves92 | 1:4875e39abd1e | 798 | static void vli_square(uint32_t *p_result, const uint32_t *p_left) |
saranieves92 | 1:4875e39abd1e | 799 | { |
saranieves92 | 1:4875e39abd1e | 800 | #if (ECC_ASM == ecc_asm_thumb2 || ECC_ASM == ecc_asm_arm) |
saranieves92 | 1:4875e39abd1e | 801 | uint32_t c0 = 0; |
saranieves92 | 1:4875e39abd1e | 802 | uint32_t c1 = 0; |
saranieves92 | 1:4875e39abd1e | 803 | uint32_t c2 = 0; |
saranieves92 | 1:4875e39abd1e | 804 | uint32_t k = 0; |
saranieves92 | 1:4875e39abd1e | 805 | uint32_t i, tt; |
saranieves92 | 1:4875e39abd1e | 806 | uint32_t t0, t1; |
saranieves92 | 1:4875e39abd1e | 807 | |
saranieves92 | 1:4875e39abd1e | 808 | asm volatile ( |
saranieves92 | 1:4875e39abd1e | 809 | ".syntax unified \n\t" |
saranieves92 | 1:4875e39abd1e | 810 | |
saranieves92 | 1:4875e39abd1e | 811 | "1: \n\t" /* outer loop (k < NUM_ECC_DIGITS) */ |
saranieves92 | 1:4875e39abd1e | 812 | "movs %[i], #0 \n\t" /* i = 0 */ |
saranieves92 | 1:4875e39abd1e | 813 | "b 3f \n\t" |
saranieves92 | 1:4875e39abd1e | 814 | |
saranieves92 | 1:4875e39abd1e | 815 | "2: \n\t" /* outer loop (k >= NUM_ECC_DIGITS) */ |
saranieves92 | 1:4875e39abd1e | 816 | "movs %[i], %[k] \n\t" /* i = k */ |
saranieves92 | 1:4875e39abd1e | 817 | "subs %[i], %[eccdm1] \n\t" /* i = k - (NUM_ECC_DIGITS - 1) (times 4) */ |
saranieves92 | 1:4875e39abd1e | 818 | |
saranieves92 | 1:4875e39abd1e | 819 | "3: \n\t" /* inner loop */ |
saranieves92 | 1:4875e39abd1e | 820 | "subs %[tt], %[k], %[i] \n\t" /* tt = k-i */ |
saranieves92 | 1:4875e39abd1e | 821 | |
saranieves92 | 1:4875e39abd1e | 822 | "ldr %[t1], [%[left], %[tt]] \n\t" /* t1 = p_left[k-i] */ |
saranieves92 | 1:4875e39abd1e | 823 | "ldr %[t0], [%[left], %[i]] \n\t" /* t0 = p_left[i] */ |
saranieves92 | 1:4875e39abd1e | 824 | |
saranieves92 | 1:4875e39abd1e | 825 | "umull %[t0], %[t1], %[t0], %[t1] \n\t" /* (t0, t1) = p_left[i] * p_right[k-i] */ |
saranieves92 | 1:4875e39abd1e | 826 | |
saranieves92 | 1:4875e39abd1e | 827 | "cmp %[i], %[tt] \n\t" /* (i < k-i) ? */ |
saranieves92 | 1:4875e39abd1e | 828 | "bge 4f \n\t" /* if i >= k-i, skip */ |
saranieves92 | 1:4875e39abd1e | 829 | "lsls %[t1], #1 \n\t" /* high word << 1 */ |
saranieves92 | 1:4875e39abd1e | 830 | "adc %[c2], #0 \n\t" /* add carry bit to c2 */ |
saranieves92 | 1:4875e39abd1e | 831 | "lsls %[t0], #1 \n\t" /* low word << 1 */ |
saranieves92 | 1:4875e39abd1e | 832 | "adc %[t1], #0 \n\t" /* add carry bit to high word */ |
saranieves92 | 1:4875e39abd1e | 833 | |
saranieves92 | 1:4875e39abd1e | 834 | "4: \n\t" |
saranieves92 | 1:4875e39abd1e | 835 | |
saranieves92 | 1:4875e39abd1e | 836 | "adds %[c0], %[t0] \n\t" /* add low word to c0 */ |
saranieves92 | 1:4875e39abd1e | 837 | "adcs %[c1], %[t1] \n\t" /* add high word to c1, including carry */ |
saranieves92 | 1:4875e39abd1e | 838 | "adc %[c2], #0 \n\t" /* add carry to c2 */ |
saranieves92 | 1:4875e39abd1e | 839 | |
saranieves92 | 1:4875e39abd1e | 840 | "adds %[i], #4 \n\t" /* i += 4 */ |
saranieves92 | 1:4875e39abd1e | 841 | "cmp %[i], %[k] \n\t" /* i <= k? */ |
saranieves92 | 1:4875e39abd1e | 842 | "bge 5f \n\t" /* if not, exit the loop */ |
saranieves92 | 1:4875e39abd1e | 843 | "subs %[tt], %[k], %[i] \n\t" /* tt = k-i */ |
saranieves92 | 1:4875e39abd1e | 844 | "cmp %[i], %[tt] \n\t" /* i <= k-i? */ |
saranieves92 | 1:4875e39abd1e | 845 | "ble 3b \n\t" /* if so, continue looping */ |
saranieves92 | 1:4875e39abd1e | 846 | |
saranieves92 | 1:4875e39abd1e | 847 | "5: \n\t" /* end inner loop */ |
saranieves92 | 1:4875e39abd1e | 848 | |
saranieves92 | 1:4875e39abd1e | 849 | "str %[c0], [%[result], %[k]] \n\t" /* p_result[k] = c0 */ |
saranieves92 | 1:4875e39abd1e | 850 | "mov %[c0], %[c1] \n\t" /* c0 = c1 */ |
saranieves92 | 1:4875e39abd1e | 851 | "mov %[c1], %[c2] \n\t" /* c1 = c2 */ |
saranieves92 | 1:4875e39abd1e | 852 | "movs %[c2], #0 \n\t" /* c2 = 0 */ |
saranieves92 | 1:4875e39abd1e | 853 | "adds %[k], #4 \n\t" /* k += 4 */ |
saranieves92 | 1:4875e39abd1e | 854 | "cmp %[k], %[eccd] \n\t" /* k < NUM_ECC_DIGITS (times 4) ? */ |
saranieves92 | 1:4875e39abd1e | 855 | "blt 1b \n\t" /* if not, loop back, start with i = 0 */ |
saranieves92 | 1:4875e39abd1e | 856 | "cmp %[k], %[eccd2m1] \n\t" /* k < NUM_ECC_DIGITS * 2 - 1 (times 4) ? */ |
saranieves92 | 1:4875e39abd1e | 857 | "blt 2b \n\t" /* if not, loop back, start with i = (k+1) - NUM_ECC_DIGITS */ |
saranieves92 | 1:4875e39abd1e | 858 | /* end outer loop */ |
saranieves92 | 1:4875e39abd1e | 859 | |
saranieves92 | 1:4875e39abd1e | 860 | "str %[c0], [%[result], %[k]] \n\t" /* p_result[NUM_ECC_DIGITS * 2 - 1] = c0 */ |
saranieves92 | 1:4875e39abd1e | 861 | #if (ECC_ASM != ecc_asm_thumb2) |
saranieves92 | 1:4875e39abd1e | 862 | ".syntax divided \n\t" |
saranieves92 | 1:4875e39abd1e | 863 | #endif |
saranieves92 | 1:4875e39abd1e | 864 | : [c0] "+r" (c0), [c1] "+r" (c1), [c2] "+r" (c2), [k] "+r" (k), [i] "=&r" (i), [tt] "=&r" (tt), [t0] "=&r" (t0), [t1] "=&r" (t1) |
saranieves92 | 1:4875e39abd1e | 865 | : [result] "r" (p_result), [left] "r" (p_left), |
saranieves92 | 1:4875e39abd1e | 866 | [eccd] "I" (NUM_ECC_DIGITS * 4), [eccdm1] "I" ((NUM_ECC_DIGITS-1) * 4), [eccd2m1] "I" ((NUM_ECC_DIGITS * 2 - 1) * 4) |
saranieves92 | 1:4875e39abd1e | 867 | : "cc", "memory" |
saranieves92 | 1:4875e39abd1e | 868 | ); |
saranieves92 | 1:4875e39abd1e | 869 | |
saranieves92 | 1:4875e39abd1e | 870 | #elif (ECC_ASM == ecc_asm_thumb) |
saranieves92 | 1:4875e39abd1e | 871 | |
saranieves92 | 1:4875e39abd1e | 872 | register uint32_t *r0 asm("r0") = p_result; |
saranieves92 | 1:4875e39abd1e | 873 | register uint32_t *r1 asm("r1") = p_left; |
saranieves92 | 1:4875e39abd1e | 874 | |
saranieves92 | 1:4875e39abd1e | 875 | asm volatile ( |
saranieves92 | 1:4875e39abd1e | 876 | ".syntax unified \n\t" |
saranieves92 | 1:4875e39abd1e | 877 | "movs r2, #0 \n\t" /* c0 = 0 */ |
saranieves92 | 1:4875e39abd1e | 878 | "movs r3, #0 \n\t" /* c1 = 0 */ |
saranieves92 | 1:4875e39abd1e | 879 | "movs r4, #0 \n\t" /* c2 = 0 */ |
saranieves92 | 1:4875e39abd1e | 880 | "movs r5, #0 \n\t" /* k = 0 */ |
saranieves92 | 1:4875e39abd1e | 881 | |
saranieves92 | 1:4875e39abd1e | 882 | "push {r0} \n\t" /* keep p_result on the stack */ |
saranieves92 | 1:4875e39abd1e | 883 | |
saranieves92 | 1:4875e39abd1e | 884 | "1: \n\t" /* outer loop (k < NUM_ECC_DIGITS) */ |
saranieves92 | 1:4875e39abd1e | 885 | "movs r6, #0 \n\t" /* r6 = i = 0 */ |
saranieves92 | 1:4875e39abd1e | 886 | "b 3f \n\t" |
saranieves92 | 1:4875e39abd1e | 887 | |
saranieves92 | 1:4875e39abd1e | 888 | "2: \n\t" /* outer loop (k >= NUM_ECC_DIGITS) */ |
saranieves92 | 1:4875e39abd1e | 889 | "movs r6, r5 \n\t" /* r6 = k */ |
saranieves92 | 1:4875e39abd1e | 890 | "subs r6, %[eccdm1] \n\t" /* r6 = i = k - (NUM_ECC_DIGITS - 1) (times 4) */ |
saranieves92 | 1:4875e39abd1e | 891 | |
saranieves92 | 1:4875e39abd1e | 892 | "3: \n\t" /* inner loop */ |
saranieves92 | 1:4875e39abd1e | 893 | "push {r2, r3, r4, r5} \n\t" /* push things, r2 (c0) is at the top of stack. */ |
saranieves92 | 1:4875e39abd1e | 894 | "subs r7, r5, r6 \n\t" /* r7 = k-i */ |
saranieves92 | 1:4875e39abd1e | 895 | |
saranieves92 | 1:4875e39abd1e | 896 | "ldr r3, [r1, r7] \n\t" /* r3 = p_left[k-i] */ |
saranieves92 | 1:4875e39abd1e | 897 | "ldr r0, [r1, r6] \n\t" /* r0 = p_left[i] */ |
saranieves92 | 1:4875e39abd1e | 898 | |
saranieves92 | 1:4875e39abd1e | 899 | "lsrs r2, r0, #16 \n\t" /* r2 = a1 */ |
saranieves92 | 1:4875e39abd1e | 900 | "uxth r0, r0 \n\t" /* r0 = a0 */ |
saranieves92 | 1:4875e39abd1e | 901 | |
saranieves92 | 1:4875e39abd1e | 902 | "lsrs r4, r3, #16 \n\t" /* r4 = b1 */ |
saranieves92 | 1:4875e39abd1e | 903 | "uxth r3, r3 \n\t" /* r3 = b0 */ |
saranieves92 | 1:4875e39abd1e | 904 | |
saranieves92 | 1:4875e39abd1e | 905 | "movs r5, r2 \n\t" /* r5 = a1 */ |
saranieves92 | 1:4875e39abd1e | 906 | "muls r5, r4, r5 \n\t" /* r5 = a1*b1 */ |
saranieves92 | 1:4875e39abd1e | 907 | "muls r2, r3, r2 \n\t" /* r2 = b0*a1 */ |
saranieves92 | 1:4875e39abd1e | 908 | "muls r4, r0, r4 \n\t" /* r4 = a0*b1 */ |
saranieves92 | 1:4875e39abd1e | 909 | "muls r0, r3, r0 \n\t" /* r0 = a0*b0 */ |
saranieves92 | 1:4875e39abd1e | 910 | |
saranieves92 | 1:4875e39abd1e | 911 | "movs r3, #0 \n\t" /* r3 = 0 */ |
saranieves92 | 1:4875e39abd1e | 912 | "adds r2, r4 \n\t" /* r2 = b0*a1 + a0*b1 */ |
saranieves92 | 1:4875e39abd1e | 913 | "adcs r3, r3 \n\t" /* r3 = carry */ |
saranieves92 | 1:4875e39abd1e | 914 | "lsls r3, #16 \n\t" /* r3 = carry << 16 */ |
saranieves92 | 1:4875e39abd1e | 915 | "adds r5, r3 \n\t" /* r5 = a1*b1 + carry */ |
saranieves92 | 1:4875e39abd1e | 916 | |
saranieves92 | 1:4875e39abd1e | 917 | "lsls r3, r2, #16 \n\t" /* r3 = (b0*a1 + a0*b1) << 16 */ |
saranieves92 | 1:4875e39abd1e | 918 | "lsrs r2, #16 \n\t" /* r2 = (b0*a1 + a0*b1) >> 16 */ |
saranieves92 | 1:4875e39abd1e | 919 | "adds r0, r3 \n\t" /* r0 = low word = a0*b0 + ((b0*a1 + a0*b1) << 16) */ |
saranieves92 | 1:4875e39abd1e | 920 | "adcs r5, r2 \n\t" /* r5 = high word = a1*b1 + carry + ((b0*a1 + a0*b1) >> 16) */ |
saranieves92 | 1:4875e39abd1e | 921 | |
saranieves92 | 1:4875e39abd1e | 922 | "movs r3, #0 \n\t" /* r3 = 0 */ |
saranieves92 | 1:4875e39abd1e | 923 | "cmp r6, r7 \n\t" /* (i < k-i) ? */ |
saranieves92 | 1:4875e39abd1e | 924 | "mov r7, r3 \n\t" /* r7 = 0 (does not affect condition)*/ |
saranieves92 | 1:4875e39abd1e | 925 | "bge 4f \n\t" /* if i >= k-i, skip */ |
saranieves92 | 1:4875e39abd1e | 926 | "lsls r5, #1 \n\t" /* high word << 1 */ |
saranieves92 | 1:4875e39abd1e | 927 | "adcs r7, r3 \n\t" /* r7 = carry bit for c2 */ |
saranieves92 | 1:4875e39abd1e | 928 | "lsls r0, #1 \n\t" /* low word << 1 */ |
saranieves92 | 1:4875e39abd1e | 929 | "adcs r5, r3 \n\t" /* add carry from shift to high word */ |
saranieves92 | 1:4875e39abd1e | 930 | |
saranieves92 | 1:4875e39abd1e | 931 | "4: \n\t" |
saranieves92 | 1:4875e39abd1e | 932 | "pop {r2, r3, r4} \n\t" /* r2 = c0, r3 = c1, r4 = c2 */ |
saranieves92 | 1:4875e39abd1e | 933 | "adds r2, r0 \n\t" /* add low word to c0 */ |
saranieves92 | 1:4875e39abd1e | 934 | "adcs r3, r5 \n\t" /* add high word to c1, including carry */ |
saranieves92 | 1:4875e39abd1e | 935 | "movs r0, #0 \n\t" /* r0 = 0 (does not affect carry bit) */ |
saranieves92 | 1:4875e39abd1e | 936 | "adcs r4, r0 \n\t" /* add carry to c2 */ |
saranieves92 | 1:4875e39abd1e | 937 | "adds r4, r7 \n\t" /* add carry from doubling (if any) */ |
saranieves92 | 1:4875e39abd1e | 938 | |
saranieves92 | 1:4875e39abd1e | 939 | "pop {r5} \n\t" /* r5 = k */ |
saranieves92 | 1:4875e39abd1e | 940 | |
saranieves92 | 1:4875e39abd1e | 941 | "adds r6, #4 \n\t" /* i += 4 */ |
saranieves92 | 1:4875e39abd1e | 942 | "cmp r6, r5 \n\t" /* i <= k? */ |
saranieves92 | 1:4875e39abd1e | 943 | "bge 5f \n\t" /* if not, exit the loop */ |
saranieves92 | 1:4875e39abd1e | 944 | "subs r7, r5, r6 \n\t" /* r7 = k-i */ |
saranieves92 | 1:4875e39abd1e | 945 | "cmp r6, r7 \n\t" /* i <= k-i? */ |
saranieves92 | 1:4875e39abd1e | 946 | "ble 3b \n\t" /* if so, continue looping */ |
saranieves92 | 1:4875e39abd1e | 947 | |
saranieves92 | 1:4875e39abd1e | 948 | "5: \n\t" /* end inner loop */ |
saranieves92 | 1:4875e39abd1e | 949 | |
saranieves92 | 1:4875e39abd1e | 950 | "ldr r0, [sp, #0] \n\t" /* r0 = p_result */ |
saranieves92 | 1:4875e39abd1e | 951 | |
saranieves92 | 1:4875e39abd1e | 952 | "str r2, [r0, r5] \n\t" /* p_result[k] = c0 */ |
saranieves92 | 1:4875e39abd1e | 953 | "mov r2, r3 \n\t" /* c0 = c1 */ |
saranieves92 | 1:4875e39abd1e | 954 | "mov r3, r4 \n\t" /* c1 = c2 */ |
saranieves92 | 1:4875e39abd1e | 955 | "movs r4, #0 \n\t" /* c2 = 0 */ |
saranieves92 | 1:4875e39abd1e | 956 | "adds r5, #4 \n\t" /* k += 4 */ |
saranieves92 | 1:4875e39abd1e | 957 | "cmp r5, %[eccd] \n\t" /* k < NUM_ECC_DIGITS (times 4) ? */ |
saranieves92 | 1:4875e39abd1e | 958 | "blt 1b \n\t" /* if not, loop back, start with i = 0 */ |
saranieves92 | 1:4875e39abd1e | 959 | "cmp r5, %[eccd2m1] \n\t" /* k < NUM_ECC_DIGITS * 2 - 1 (times 4) ? */ |
saranieves92 | 1:4875e39abd1e | 960 | "blt 2b \n\t" /* if not, loop back, start with i = (k+1) - NUM_ECC_DIGITS */ |
saranieves92 | 1:4875e39abd1e | 961 | /* end outer loop */ |
saranieves92 | 1:4875e39abd1e | 962 | |
saranieves92 | 1:4875e39abd1e | 963 | "str r2, [r0, r5] \n\t" /* p_result[NUM_ECC_DIGITS * 2 - 1] = c0 */ |
saranieves92 | 1:4875e39abd1e | 964 | "pop {r0} \n\t" /* pop p_result off the stack */ |
saranieves92 | 1:4875e39abd1e | 965 | |
saranieves92 | 1:4875e39abd1e | 966 | ".syntax divided \n\t" |
saranieves92 | 1:4875e39abd1e | 967 | : [r0] "+l" (r0), [r1] "+l" (r1) |
saranieves92 | 1:4875e39abd1e | 968 | : [eccd] "I" (NUM_ECC_DIGITS * 4), [eccdm1] "I" ((NUM_ECC_DIGITS-1) * 4), [eccd2m1] "I" ((NUM_ECC_DIGITS * 2 - 1) * 4) |
saranieves92 | 1:4875e39abd1e | 969 | : "r2", "r3", "r4", "r5", "r6", "r7", "cc", "memory" |
saranieves92 | 1:4875e39abd1e | 970 | ); |
saranieves92 | 1:4875e39abd1e | 971 | |
saranieves92 | 1:4875e39abd1e | 972 | #else |
saranieves92 | 1:4875e39abd1e | 973 | |
saranieves92 | 1:4875e39abd1e | 974 | uint64_t r01 = 0; |
saranieves92 | 1:4875e39abd1e | 975 | uint32_t r2 = 0; |
saranieves92 | 1:4875e39abd1e | 976 | |
saranieves92 | 1:4875e39abd1e | 977 | uint i, k; |
saranieves92 | 1:4875e39abd1e | 978 | for(k=0; k < NUM_ECC_DIGITS*2 - 1; ++k) |
saranieves92 | 1:4875e39abd1e | 979 | { |
saranieves92 | 1:4875e39abd1e | 980 | uint l_min = (k < NUM_ECC_DIGITS ? 0 : (k + 1) - NUM_ECC_DIGITS); |
saranieves92 | 1:4875e39abd1e | 981 | for(i=l_min; i<=k && i<=k-i; ++i) |
saranieves92 | 1:4875e39abd1e | 982 | { |
saranieves92 | 1:4875e39abd1e | 983 | uint64_t l_product = (uint64_t)p_left[i] * p_left[k-i]; |
saranieves92 | 1:4875e39abd1e | 984 | if(i < k-i) |
saranieves92 | 1:4875e39abd1e | 985 | { |
saranieves92 | 1:4875e39abd1e | 986 | r2 += l_product >> 63; |
saranieves92 | 1:4875e39abd1e | 987 | l_product *= 2; |
saranieves92 | 1:4875e39abd1e | 988 | } |
saranieves92 | 1:4875e39abd1e | 989 | r01 += l_product; |
saranieves92 | 1:4875e39abd1e | 990 | r2 += (r01 < l_product); |
saranieves92 | 1:4875e39abd1e | 991 | } |
saranieves92 | 1:4875e39abd1e | 992 | p_result[k] = (uint32_t)r01; |
saranieves92 | 1:4875e39abd1e | 993 | r01 = (r01 >> 32) | (((uint64_t)r2) << 32); |
saranieves92 | 1:4875e39abd1e | 994 | r2 = 0; |
saranieves92 | 1:4875e39abd1e | 995 | } |
saranieves92 | 1:4875e39abd1e | 996 | |
saranieves92 | 1:4875e39abd1e | 997 | p_result[NUM_ECC_DIGITS*2 - 1] = (uint32_t)r01; |
saranieves92 | 1:4875e39abd1e | 998 | #endif |
saranieves92 | 1:4875e39abd1e | 999 | } |
saranieves92 | 1:4875e39abd1e | 1000 | |
saranieves92 | 1:4875e39abd1e | 1001 | /* Computes p_result = p_left^2 % curve_p. */ |
saranieves92 | 1:4875e39abd1e | 1002 | static void vli_modSquare_fast(uint32_t *p_result, const uint32_t *p_left) |
saranieves92 | 1:4875e39abd1e | 1003 | { |
saranieves92 | 1:4875e39abd1e | 1004 | uint32_t l_product[2 * NUM_ECC_DIGITS]; |
saranieves92 | 1:4875e39abd1e | 1005 | vli_square(l_product, p_left); |
saranieves92 | 1:4875e39abd1e | 1006 | vli_mmod_fast(p_result, l_product); |
saranieves92 | 1:4875e39abd1e | 1007 | } |
saranieves92 | 1:4875e39abd1e | 1008 | |
saranieves92 | 1:4875e39abd1e | 1009 | #else /* ECC_SQUARE_FUNC */ |
saranieves92 | 1:4875e39abd1e | 1010 | |
saranieves92 | 1:4875e39abd1e | 1011 | #define vli_square(result, left, size) vli_mult((result), (left), (left), (size)) |
saranieves92 | 1:4875e39abd1e | 1012 | #define vli_modSquare_fast(result, left) vli_modMult_fast((result), (left), (left)) |
saranieves92 | 1:4875e39abd1e | 1013 | |
saranieves92 | 1:4875e39abd1e | 1014 | #endif /* ECC_SQUARE_FUNC */ |
saranieves92 | 1:4875e39abd1e | 1015 | |
saranieves92 | 1:4875e39abd1e | 1016 | #define EVEN(vli) (!(vli[0] & 1)) |
saranieves92 | 1:4875e39abd1e | 1017 | /* Computes p_result = (1 / p_input) % p_mod. All VLIs are the same size. |
saranieves92 | 1:4875e39abd1e | 1018 | See "From Euclid's GCD to Montgomery Multiplication to the Great Divide" |
saranieves92 | 1:4875e39abd1e | 1019 | https://labs.oracle.com/techrep/2001/smli_tr-2001-95.pdf */ |
saranieves92 | 1:4875e39abd1e | 1020 | static void vli_modInv(uint32_t *p_result, const uint32_t *p_input, const uint32_t *p_mod) |
saranieves92 | 1:4875e39abd1e | 1021 | { |
saranieves92 | 1:4875e39abd1e | 1022 | uint32_t a[NUM_ECC_DIGITS], b[NUM_ECC_DIGITS], u[NUM_ECC_DIGITS], v[NUM_ECC_DIGITS]; |
saranieves92 | 1:4875e39abd1e | 1023 | uint32_t l_carry; |
saranieves92 | 1:4875e39abd1e | 1024 | |
saranieves92 | 1:4875e39abd1e | 1025 | vli_set(a, p_input); |
saranieves92 | 1:4875e39abd1e | 1026 | vli_set(b, p_mod); |
saranieves92 | 1:4875e39abd1e | 1027 | vli_clear(u); |
saranieves92 | 1:4875e39abd1e | 1028 | u[0] = 1; |
saranieves92 | 1:4875e39abd1e | 1029 | vli_clear(v); |
saranieves92 | 1:4875e39abd1e | 1030 | |
saranieves92 | 1:4875e39abd1e | 1031 | int l_cmpResult; |
saranieves92 | 1:4875e39abd1e | 1032 | while((l_cmpResult = vli_cmp(a, b)) != 0) |
saranieves92 | 1:4875e39abd1e | 1033 | { |
saranieves92 | 1:4875e39abd1e | 1034 | l_carry = 0; |
saranieves92 | 1:4875e39abd1e | 1035 | if(EVEN(a)) |
saranieves92 | 1:4875e39abd1e | 1036 | { |
saranieves92 | 1:4875e39abd1e | 1037 | vli_rshift1(a); |
saranieves92 | 1:4875e39abd1e | 1038 | if(!EVEN(u)) |
saranieves92 | 1:4875e39abd1e | 1039 | { |
saranieves92 | 1:4875e39abd1e | 1040 | l_carry = vli_add(u, u, p_mod); |
saranieves92 | 1:4875e39abd1e | 1041 | } |
saranieves92 | 1:4875e39abd1e | 1042 | vli_rshift1(u); |
saranieves92 | 1:4875e39abd1e | 1043 | if(l_carry) |
saranieves92 | 1:4875e39abd1e | 1044 | { |
saranieves92 | 1:4875e39abd1e | 1045 | u[NUM_ECC_DIGITS-1] |= 0x80000000; |
saranieves92 | 1:4875e39abd1e | 1046 | } |
saranieves92 | 1:4875e39abd1e | 1047 | } |
saranieves92 | 1:4875e39abd1e | 1048 | else if(EVEN(b)) |
saranieves92 | 1:4875e39abd1e | 1049 | { |
saranieves92 | 1:4875e39abd1e | 1050 | vli_rshift1(b); |
saranieves92 | 1:4875e39abd1e | 1051 | if(!EVEN(v)) |
saranieves92 | 1:4875e39abd1e | 1052 | { |
saranieves92 | 1:4875e39abd1e | 1053 | l_carry = vli_add(v, v, p_mod); |
saranieves92 | 1:4875e39abd1e | 1054 | } |
saranieves92 | 1:4875e39abd1e | 1055 | vli_rshift1(v); |
saranieves92 | 1:4875e39abd1e | 1056 | if(l_carry) |
saranieves92 | 1:4875e39abd1e | 1057 | { |
saranieves92 | 1:4875e39abd1e | 1058 | v[NUM_ECC_DIGITS-1] |= 0x80000000; |
saranieves92 | 1:4875e39abd1e | 1059 | } |
saranieves92 | 1:4875e39abd1e | 1060 | } |
saranieves92 | 1:4875e39abd1e | 1061 | else if(l_cmpResult > 0) |
saranieves92 | 1:4875e39abd1e | 1062 | { |
saranieves92 | 1:4875e39abd1e | 1063 | vli_sub(a, a, b); |
saranieves92 | 1:4875e39abd1e | 1064 | vli_rshift1(a); |
saranieves92 | 1:4875e39abd1e | 1065 | if(vli_cmp(u, v) < 0) |
saranieves92 | 1:4875e39abd1e | 1066 | { |
saranieves92 | 1:4875e39abd1e | 1067 | vli_add(u, u, p_mod); |
saranieves92 | 1:4875e39abd1e | 1068 | } |
saranieves92 | 1:4875e39abd1e | 1069 | vli_sub(u, u, v); |
saranieves92 | 1:4875e39abd1e | 1070 | if(!EVEN(u)) |
saranieves92 | 1:4875e39abd1e | 1071 | { |
saranieves92 | 1:4875e39abd1e | 1072 | l_carry = vli_add(u, u, p_mod); |
saranieves92 | 1:4875e39abd1e | 1073 | } |
saranieves92 | 1:4875e39abd1e | 1074 | vli_rshift1(u); |
saranieves92 | 1:4875e39abd1e | 1075 | if(l_carry) |
saranieves92 | 1:4875e39abd1e | 1076 | { |
saranieves92 | 1:4875e39abd1e | 1077 | u[NUM_ECC_DIGITS-1] |= 0x80000000; |
saranieves92 | 1:4875e39abd1e | 1078 | } |
saranieves92 | 1:4875e39abd1e | 1079 | } |
saranieves92 | 1:4875e39abd1e | 1080 | else |
saranieves92 | 1:4875e39abd1e | 1081 | { |
saranieves92 | 1:4875e39abd1e | 1082 | vli_sub(b, b, a); |
saranieves92 | 1:4875e39abd1e | 1083 | vli_rshift1(b); |
saranieves92 | 1:4875e39abd1e | 1084 | if(vli_cmp(v, u) < 0) |
saranieves92 | 1:4875e39abd1e | 1085 | { |
saranieves92 | 1:4875e39abd1e | 1086 | vli_add(v, v, p_mod); |
saranieves92 | 1:4875e39abd1e | 1087 | } |
saranieves92 | 1:4875e39abd1e | 1088 | vli_sub(v, v, u); |
saranieves92 | 1:4875e39abd1e | 1089 | if(!EVEN(v)) |
saranieves92 | 1:4875e39abd1e | 1090 | { |
saranieves92 | 1:4875e39abd1e | 1091 | l_carry = vli_add(v, v, p_mod); |
saranieves92 | 1:4875e39abd1e | 1092 | } |
saranieves92 | 1:4875e39abd1e | 1093 | vli_rshift1(v); |
saranieves92 | 1:4875e39abd1e | 1094 | if(l_carry) |
saranieves92 | 1:4875e39abd1e | 1095 | { |
saranieves92 | 1:4875e39abd1e | 1096 | v[NUM_ECC_DIGITS-1] |= 0x80000000; |
saranieves92 | 1:4875e39abd1e | 1097 | } |
saranieves92 | 1:4875e39abd1e | 1098 | } |
saranieves92 | 1:4875e39abd1e | 1099 | } |
saranieves92 | 1:4875e39abd1e | 1100 | |
saranieves92 | 1:4875e39abd1e | 1101 | vli_set(p_result, u); |
saranieves92 | 1:4875e39abd1e | 1102 | } |
saranieves92 | 1:4875e39abd1e | 1103 | |
saranieves92 | 1:4875e39abd1e | 1104 | /* ------ Point operations ------ */ |
saranieves92 | 1:4875e39abd1e | 1105 | |
saranieves92 | 1:4875e39abd1e | 1106 | /* Returns 1 if p_point is the point at infinity, 0 otherwise. */ |
saranieves92 | 1:4875e39abd1e | 1107 | static int EccPoint_isZero(const EccPoint *p_point) |
saranieves92 | 1:4875e39abd1e | 1108 | { |
saranieves92 | 1:4875e39abd1e | 1109 | return (vli_isZero(p_point->x) && vli_isZero(p_point->y)); |
saranieves92 | 1:4875e39abd1e | 1110 | } |
saranieves92 | 1:4875e39abd1e | 1111 | |
saranieves92 | 1:4875e39abd1e | 1112 | /* Point multiplication algorithm using Montgomery's ladder with co-Z coordinates. |
saranieves92 | 1:4875e39abd1e | 1113 | From http://eprint.iacr.org/2011/338.pdf |
saranieves92 | 1:4875e39abd1e | 1114 | */ |
saranieves92 | 1:4875e39abd1e | 1115 | |
saranieves92 | 1:4875e39abd1e | 1116 | /* Double in place */ |
saranieves92 | 1:4875e39abd1e | 1117 | #if (ECC_CURVE == secp256k1) |
saranieves92 | 1:4875e39abd1e | 1118 | static void EccPoint_double_jacobian(uint32_t *X1, uint32_t *Y1, uint32_t *Z1) |
saranieves92 | 1:4875e39abd1e | 1119 | { |
saranieves92 | 1:4875e39abd1e | 1120 | /* t1 = X, t2 = Y, t3 = Z */ |
saranieves92 | 1:4875e39abd1e | 1121 | uint32_t t4[NUM_ECC_DIGITS]; |
saranieves92 | 1:4875e39abd1e | 1122 | uint32_t t5[NUM_ECC_DIGITS]; |
saranieves92 | 1:4875e39abd1e | 1123 | |
saranieves92 | 1:4875e39abd1e | 1124 | if(vli_isZero(Z1)) |
saranieves92 | 1:4875e39abd1e | 1125 | { |
saranieves92 | 1:4875e39abd1e | 1126 | return; |
saranieves92 | 1:4875e39abd1e | 1127 | } |
saranieves92 | 1:4875e39abd1e | 1128 | |
saranieves92 | 1:4875e39abd1e | 1129 | vli_modSquare_fast(t5, Y1); /* t5 = y1^2 */ |
saranieves92 | 1:4875e39abd1e | 1130 | vli_modMult_fast(t4, X1, t5); /* t4 = x1*y1^2 = A */ |
saranieves92 | 1:4875e39abd1e | 1131 | vli_modSquare_fast(X1, X1); /* t1 = x1^2 */ |
saranieves92 | 1:4875e39abd1e | 1132 | vli_modSquare_fast(t5, t5); /* t5 = y1^4 */ |
saranieves92 | 1:4875e39abd1e | 1133 | vli_modMult_fast(Z1, Y1, Z1); /* t3 = y1*z1 = z3 */ |
saranieves92 | 1:4875e39abd1e | 1134 | |
saranieves92 | 1:4875e39abd1e | 1135 | vli_modAdd(Y1, X1, X1, curve_p); /* t2 = 2*x1^2 */ |
saranieves92 | 1:4875e39abd1e | 1136 | vli_modAdd(Y1, Y1, X1, curve_p); /* t2 = 3*x1^2 */ |
saranieves92 | 1:4875e39abd1e | 1137 | if(vli_testBit(Y1, 0)) |
saranieves92 | 1:4875e39abd1e | 1138 | { |
saranieves92 | 1:4875e39abd1e | 1139 | uint32_t l_carry = vli_add(Y1, Y1, curve_p); |
saranieves92 | 1:4875e39abd1e | 1140 | vli_rshift1(Y1); |
saranieves92 | 1:4875e39abd1e | 1141 | Y1[NUM_ECC_DIGITS-1] |= l_carry << 31; |
saranieves92 | 1:4875e39abd1e | 1142 | } |
saranieves92 | 1:4875e39abd1e | 1143 | else |
saranieves92 | 1:4875e39abd1e | 1144 | { |
saranieves92 | 1:4875e39abd1e | 1145 | vli_rshift1(Y1); |
saranieves92 | 1:4875e39abd1e | 1146 | } |
saranieves92 | 1:4875e39abd1e | 1147 | /* t2 = 3/2*(x1^2) = B */ |
saranieves92 | 1:4875e39abd1e | 1148 | |
saranieves92 | 1:4875e39abd1e | 1149 | vli_modSquare_fast(X1, Y1); /* t1 = B^2 */ |
saranieves92 | 1:4875e39abd1e | 1150 | vli_modSub(X1, X1, t4, curve_p); /* t1 = B^2 - A */ |
saranieves92 | 1:4875e39abd1e | 1151 | vli_modSub(X1, X1, t4, curve_p); /* t1 = B^2 - 2A = x3 */ |
saranieves92 | 1:4875e39abd1e | 1152 | |
saranieves92 | 1:4875e39abd1e | 1153 | vli_modSub(t4, t4, X1, curve_p); /* t4 = A - x3 */ |
saranieves92 | 1:4875e39abd1e | 1154 | vli_modMult_fast(Y1, Y1, t4); /* t2 = B * (A - x3) */ |
saranieves92 | 1:4875e39abd1e | 1155 | vli_modSub(Y1, Y1, t5, curve_p); /* t2 = B * (A - x3) - y1^4 = y3 */ |
saranieves92 | 1:4875e39abd1e | 1156 | } |
saranieves92 | 1:4875e39abd1e | 1157 | #else |
saranieves92 | 1:4875e39abd1e | 1158 | static void EccPoint_double_jacobian(uint32_t *X1, uint32_t *Y1, uint32_t *Z1) |
saranieves92 | 1:4875e39abd1e | 1159 | { |
saranieves92 | 1:4875e39abd1e | 1160 | /* t1 = X, t2 = Y, t3 = Z */ |
saranieves92 | 1:4875e39abd1e | 1161 | uint32_t t4[NUM_ECC_DIGITS]; |
saranieves92 | 1:4875e39abd1e | 1162 | uint32_t t5[NUM_ECC_DIGITS]; |
saranieves92 | 1:4875e39abd1e | 1163 | |
saranieves92 | 1:4875e39abd1e | 1164 | if(vli_isZero(Z1)) |
saranieves92 | 1:4875e39abd1e | 1165 | { |
saranieves92 | 1:4875e39abd1e | 1166 | return; |
saranieves92 | 1:4875e39abd1e | 1167 | } |
saranieves92 | 1:4875e39abd1e | 1168 | |
saranieves92 | 1:4875e39abd1e | 1169 | vli_modSquare_fast(t4, Y1); /* t4 = y1^2 */ |
saranieves92 | 1:4875e39abd1e | 1170 | vli_modMult_fast(t5, X1, t4); /* t5 = x1*y1^2 = A */ |
saranieves92 | 1:4875e39abd1e | 1171 | vli_modSquare_fast(t4, t4); /* t4 = y1^4 */ |
saranieves92 | 1:4875e39abd1e | 1172 | vli_modMult_fast(Y1, Y1, Z1); /* t2 = y1*z1 = z3 */ |
saranieves92 | 1:4875e39abd1e | 1173 | vli_modSquare_fast(Z1, Z1); /* t3 = z1^2 */ |
saranieves92 | 1:4875e39abd1e | 1174 | |
saranieves92 | 1:4875e39abd1e | 1175 | vli_modAdd(X1, X1, Z1, curve_p); /* t1 = x1 + z1^2 */ |
saranieves92 | 1:4875e39abd1e | 1176 | vli_modAdd(Z1, Z1, Z1, curve_p); /* t3 = 2*z1^2 */ |
saranieves92 | 1:4875e39abd1e | 1177 | vli_modSub(Z1, X1, Z1, curve_p); /* t3 = x1 - z1^2 */ |
saranieves92 | 1:4875e39abd1e | 1178 | vli_modMult_fast(X1, X1, Z1); /* t1 = x1^2 - z1^4 */ |
saranieves92 | 1:4875e39abd1e | 1179 | |
saranieves92 | 1:4875e39abd1e | 1180 | vli_modAdd(Z1, X1, X1, curve_p); /* t3 = 2*(x1^2 - z1^4) */ |
saranieves92 | 1:4875e39abd1e | 1181 | vli_modAdd(X1, X1, Z1, curve_p); /* t1 = 3*(x1^2 - z1^4) */ |
saranieves92 | 1:4875e39abd1e | 1182 | if(vli_testBit(X1, 0)) |
saranieves92 | 1:4875e39abd1e | 1183 | { |
saranieves92 | 1:4875e39abd1e | 1184 | uint32_t l_carry = vli_add(X1, X1, curve_p); |
saranieves92 | 1:4875e39abd1e | 1185 | vli_rshift1(X1); |
saranieves92 | 1:4875e39abd1e | 1186 | X1[NUM_ECC_DIGITS-1] |= l_carry << 31; |
saranieves92 | 1:4875e39abd1e | 1187 | } |
saranieves92 | 1:4875e39abd1e | 1188 | else |
saranieves92 | 1:4875e39abd1e | 1189 | { |
saranieves92 | 1:4875e39abd1e | 1190 | vli_rshift1(X1); |
saranieves92 | 1:4875e39abd1e | 1191 | } |
saranieves92 | 1:4875e39abd1e | 1192 | /* t1 = 3/2*(x1^2 - z1^4) = B */ |
saranieves92 | 1:4875e39abd1e | 1193 | |
saranieves92 | 1:4875e39abd1e | 1194 | vli_modSquare_fast(Z1, X1); /* t3 = B^2 */ |
saranieves92 | 1:4875e39abd1e | 1195 | vli_modSub(Z1, Z1, t5, curve_p); /* t3 = B^2 - A */ |
saranieves92 | 1:4875e39abd1e | 1196 | vli_modSub(Z1, Z1, t5, curve_p); /* t3 = B^2 - 2A = x3 */ |
saranieves92 | 1:4875e39abd1e | 1197 | vli_modSub(t5, t5, Z1, curve_p); /* t5 = A - x3 */ |
saranieves92 | 1:4875e39abd1e | 1198 | vli_modMult_fast(X1, X1, t5); /* t1 = B * (A - x3) */ |
saranieves92 | 1:4875e39abd1e | 1199 | vli_modSub(t4, X1, t4, curve_p); /* t4 = B * (A - x3) - y1^4 = y3 */ |
saranieves92 | 1:4875e39abd1e | 1200 | |
saranieves92 | 1:4875e39abd1e | 1201 | vli_set(X1, Z1); |
saranieves92 | 1:4875e39abd1e | 1202 | vli_set(Z1, Y1); |
saranieves92 | 1:4875e39abd1e | 1203 | vli_set(Y1, t4); |
saranieves92 | 1:4875e39abd1e | 1204 | } |
saranieves92 | 1:4875e39abd1e | 1205 | #endif |
saranieves92 | 1:4875e39abd1e | 1206 | |
saranieves92 | 1:4875e39abd1e | 1207 | /* Modify (x1, y1) => (x1 * z^2, y1 * z^3) */ |
saranieves92 | 1:4875e39abd1e | 1208 | static void apply_z(uint32_t *X1, uint32_t *Y1, uint32_t *Z) |
saranieves92 | 1:4875e39abd1e | 1209 | { |
saranieves92 | 1:4875e39abd1e | 1210 | uint32_t t1[NUM_ECC_DIGITS]; |
saranieves92 | 1:4875e39abd1e | 1211 | |
saranieves92 | 1:4875e39abd1e | 1212 | vli_modSquare_fast(t1, Z); /* z^2 */ |
saranieves92 | 1:4875e39abd1e | 1213 | vli_modMult_fast(X1, X1, t1); /* x1 * z^2 */ |
saranieves92 | 1:4875e39abd1e | 1214 | vli_modMult_fast(t1, t1, Z); /* z^3 */ |
saranieves92 | 1:4875e39abd1e | 1215 | vli_modMult_fast(Y1, Y1, t1); /* y1 * z^3 */ |
saranieves92 | 1:4875e39abd1e | 1216 | } |
saranieves92 | 1:4875e39abd1e | 1217 | |
saranieves92 | 1:4875e39abd1e | 1218 | /* P = (x1, y1) => 2P, (x2, y2) => P' */ |
saranieves92 | 1:4875e39abd1e | 1219 | static void XYcZ_initial_double(uint32_t *X1, uint32_t *Y1, uint32_t *X2, uint32_t *Y2, const uint32_t *p_initialZ) |
saranieves92 | 1:4875e39abd1e | 1220 | { |
saranieves92 | 1:4875e39abd1e | 1221 | uint32_t z[NUM_ECC_DIGITS]; |
saranieves92 | 1:4875e39abd1e | 1222 | |
saranieves92 | 1:4875e39abd1e | 1223 | vli_set(X2, X1); |
saranieves92 | 1:4875e39abd1e | 1224 | vli_set(Y2, Y1); |
saranieves92 | 1:4875e39abd1e | 1225 | |
saranieves92 | 1:4875e39abd1e | 1226 | vli_clear(z); |
saranieves92 | 1:4875e39abd1e | 1227 | z[0] = 1; |
saranieves92 | 1:4875e39abd1e | 1228 | if(p_initialZ) |
saranieves92 | 1:4875e39abd1e | 1229 | { |
saranieves92 | 1:4875e39abd1e | 1230 | vli_set(z, p_initialZ); |
saranieves92 | 1:4875e39abd1e | 1231 | } |
saranieves92 | 1:4875e39abd1e | 1232 | apply_z(X1, Y1, z); |
saranieves92 | 1:4875e39abd1e | 1233 | |
saranieves92 | 1:4875e39abd1e | 1234 | EccPoint_double_jacobian(X1, Y1, z); |
saranieves92 | 1:4875e39abd1e | 1235 | |
saranieves92 | 1:4875e39abd1e | 1236 | apply_z(X2, Y2, z); |
saranieves92 | 1:4875e39abd1e | 1237 | } |
saranieves92 | 1:4875e39abd1e | 1238 | |
saranieves92 | 1:4875e39abd1e | 1239 | /* Input P = (x1, y1, Z), Q = (x2, y2, Z) |
saranieves92 | 1:4875e39abd1e | 1240 | Output P' = (x1', y1', Z3), P + Q = (x3, y3, Z3) |
saranieves92 | 1:4875e39abd1e | 1241 | or P => P', Q => P + Q |
saranieves92 | 1:4875e39abd1e | 1242 | */ |
saranieves92 | 1:4875e39abd1e | 1243 | static void XYcZ_add(uint32_t *X1, uint32_t *Y1, uint32_t *X2, uint32_t *Y2) |
saranieves92 | 1:4875e39abd1e | 1244 | { |
saranieves92 | 1:4875e39abd1e | 1245 | /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */ |
saranieves92 | 1:4875e39abd1e | 1246 | uint32_t t5[NUM_ECC_DIGITS]; |
saranieves92 | 1:4875e39abd1e | 1247 | |
saranieves92 | 1:4875e39abd1e | 1248 | vli_modSub(t5, X2, X1, curve_p); /* t5 = x2 - x1 */ |
saranieves92 | 1:4875e39abd1e | 1249 | vli_modSquare_fast(t5, t5); /* t5 = (x2 - x1)^2 = A */ |
saranieves92 | 1:4875e39abd1e | 1250 | vli_modMult_fast(X1, X1, t5); /* t1 = x1*A = B */ |
saranieves92 | 1:4875e39abd1e | 1251 | vli_modMult_fast(X2, X2, t5); /* t3 = x2*A = C */ |
saranieves92 | 1:4875e39abd1e | 1252 | vli_modSub(Y2, Y2, Y1, curve_p); /* t4 = y2 - y1 */ |
saranieves92 | 1:4875e39abd1e | 1253 | vli_modSquare_fast(t5, Y2); /* t5 = (y2 - y1)^2 = D */ |
saranieves92 | 1:4875e39abd1e | 1254 | |
saranieves92 | 1:4875e39abd1e | 1255 | vli_modSub(t5, t5, X1, curve_p); /* t5 = D - B */ |
saranieves92 | 1:4875e39abd1e | 1256 | vli_modSub(t5, t5, X2, curve_p); /* t5 = D - B - C = x3 */ |
saranieves92 | 1:4875e39abd1e | 1257 | vli_modSub(X2, X2, X1, curve_p); /* t3 = C - B */ |
saranieves92 | 1:4875e39abd1e | 1258 | vli_modMult_fast(Y1, Y1, X2); /* t2 = y1*(C - B) */ |
saranieves92 | 1:4875e39abd1e | 1259 | vli_modSub(X2, X1, t5, curve_p); /* t3 = B - x3 */ |
saranieves92 | 1:4875e39abd1e | 1260 | vli_modMult_fast(Y2, Y2, X2); /* t4 = (y2 - y1)*(B - x3) */ |
saranieves92 | 1:4875e39abd1e | 1261 | vli_modSub(Y2, Y2, Y1, curve_p); /* t4 = y3 */ |
saranieves92 | 1:4875e39abd1e | 1262 | |
saranieves92 | 1:4875e39abd1e | 1263 | vli_set(X2, t5); |
saranieves92 | 1:4875e39abd1e | 1264 | } |
saranieves92 | 1:4875e39abd1e | 1265 | |
saranieves92 | 1:4875e39abd1e | 1266 | /* Input P = (x1, y1, Z), Q = (x2, y2, Z) |
saranieves92 | 1:4875e39abd1e | 1267 | Output P + Q = (x3, y3, Z3), P - Q = (x3', y3', Z3) |
saranieves92 | 1:4875e39abd1e | 1268 | or P => P - Q, Q => P + Q |
saranieves92 | 1:4875e39abd1e | 1269 | */ |
saranieves92 | 1:4875e39abd1e | 1270 | static void XYcZ_addC(uint32_t *X1, uint32_t *Y1, uint32_t *X2, uint32_t *Y2) |
saranieves92 | 1:4875e39abd1e | 1271 | { |
saranieves92 | 1:4875e39abd1e | 1272 | /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */ |
saranieves92 | 1:4875e39abd1e | 1273 | uint32_t t5[NUM_ECC_DIGITS]; |
saranieves92 | 1:4875e39abd1e | 1274 | uint32_t t6[NUM_ECC_DIGITS]; |
saranieves92 | 1:4875e39abd1e | 1275 | uint32_t t7[NUM_ECC_DIGITS]; |
saranieves92 | 1:4875e39abd1e | 1276 | |
saranieves92 | 1:4875e39abd1e | 1277 | vli_modSub(t5, X2, X1, curve_p); /* t5 = x2 - x1 */ |
saranieves92 | 1:4875e39abd1e | 1278 | vli_modSquare_fast(t5, t5); /* t5 = (x2 - x1)^2 = A */ |
saranieves92 | 1:4875e39abd1e | 1279 | vli_modMult_fast(X1, X1, t5); /* t1 = x1*A = B */ |
saranieves92 | 1:4875e39abd1e | 1280 | vli_modMult_fast(X2, X2, t5); /* t3 = x2*A = C */ |
saranieves92 | 1:4875e39abd1e | 1281 | vli_modAdd(t5, Y2, Y1, curve_p); /* t4 = y2 + y1 */ |
saranieves92 | 1:4875e39abd1e | 1282 | vli_modSub(Y2, Y2, Y1, curve_p); /* t4 = y2 - y1 */ |
saranieves92 | 1:4875e39abd1e | 1283 | |
saranieves92 | 1:4875e39abd1e | 1284 | vli_modSub(t6, X2, X1, curve_p); /* t6 = C - B */ |
saranieves92 | 1:4875e39abd1e | 1285 | vli_modMult_fast(Y1, Y1, t6); /* t2 = y1 * (C - B) */ |
saranieves92 | 1:4875e39abd1e | 1286 | vli_modAdd(t6, X1, X2, curve_p); /* t6 = B + C */ |
saranieves92 | 1:4875e39abd1e | 1287 | vli_modSquare_fast(X2, Y2); /* t3 = (y2 - y1)^2 */ |
saranieves92 | 1:4875e39abd1e | 1288 | vli_modSub(X2, X2, t6, curve_p); /* t3 = x3 */ |
saranieves92 | 1:4875e39abd1e | 1289 | |
saranieves92 | 1:4875e39abd1e | 1290 | vli_modSub(t7, X1, X2, curve_p); /* t7 = B - x3 */ |
saranieves92 | 1:4875e39abd1e | 1291 | vli_modMult_fast(Y2, Y2, t7); /* t4 = (y2 - y1)*(B - x3) */ |
saranieves92 | 1:4875e39abd1e | 1292 | vli_modSub(Y2, Y2, Y1, curve_p); /* t4 = y3 */ |
saranieves92 | 1:4875e39abd1e | 1293 | |
saranieves92 | 1:4875e39abd1e | 1294 | vli_modSquare_fast(t7, t5); /* t7 = (y2 + y1)^2 = F */ |
saranieves92 | 1:4875e39abd1e | 1295 | vli_modSub(t7, t7, t6, curve_p); /* t7 = x3' */ |
saranieves92 | 1:4875e39abd1e | 1296 | vli_modSub(t6, t7, X1, curve_p); /* t6 = x3' - B */ |
saranieves92 | 1:4875e39abd1e | 1297 | vli_modMult_fast(t6, t6, t5); /* t6 = (y2 + y1)*(x3' - B) */ |
saranieves92 | 1:4875e39abd1e | 1298 | vli_modSub(Y1, t6, Y1, curve_p); /* t2 = y3' */ |
saranieves92 | 1:4875e39abd1e | 1299 | |
saranieves92 | 1:4875e39abd1e | 1300 | vli_set(X1, t7); |
saranieves92 | 1:4875e39abd1e | 1301 | } |
saranieves92 | 1:4875e39abd1e | 1302 | |
saranieves92 | 1:4875e39abd1e | 1303 | static void EccPoint_mult(EccPoint *p_result, const EccPoint *p_point, |
saranieves92 | 1:4875e39abd1e | 1304 | const uint32_t *p_scalar, const uint32_t *p_initialZ) |
saranieves92 | 1:4875e39abd1e | 1305 | { |
saranieves92 | 1:4875e39abd1e | 1306 | /* R0 and R1 */ |
saranieves92 | 1:4875e39abd1e | 1307 | uint32_t Rx[2][NUM_ECC_DIGITS]; |
saranieves92 | 1:4875e39abd1e | 1308 | uint32_t Ry[2][NUM_ECC_DIGITS]; |
saranieves92 | 1:4875e39abd1e | 1309 | uint32_t z[NUM_ECC_DIGITS]; |
saranieves92 | 1:4875e39abd1e | 1310 | |
saranieves92 | 1:4875e39abd1e | 1311 | int i, nb; |
saranieves92 | 1:4875e39abd1e | 1312 | |
saranieves92 | 1:4875e39abd1e | 1313 | vli_set(Rx[1], p_point->x); |
saranieves92 | 1:4875e39abd1e | 1314 | vli_set(Ry[1], p_point->y); |
saranieves92 | 1:4875e39abd1e | 1315 | |
saranieves92 | 1:4875e39abd1e | 1316 | XYcZ_initial_double(Rx[1], Ry[1], Rx[0], Ry[0], p_initialZ); |
saranieves92 | 1:4875e39abd1e | 1317 | |
saranieves92 | 1:4875e39abd1e | 1318 | for(i = vli_numBits(p_scalar) - 2; i > 0; --i) |
saranieves92 | 1:4875e39abd1e | 1319 | { |
saranieves92 | 1:4875e39abd1e | 1320 | nb = !vli_testBit(p_scalar, i); |
saranieves92 | 1:4875e39abd1e | 1321 | XYcZ_addC(Rx[1-nb], Ry[1-nb], Rx[nb], Ry[nb]); |
saranieves92 | 1:4875e39abd1e | 1322 | XYcZ_add(Rx[nb], Ry[nb], Rx[1-nb], Ry[1-nb]); |
saranieves92 | 1:4875e39abd1e | 1323 | } |
saranieves92 | 1:4875e39abd1e | 1324 | |
saranieves92 | 1:4875e39abd1e | 1325 | nb = !vli_testBit(p_scalar, 0); |
saranieves92 | 1:4875e39abd1e | 1326 | XYcZ_addC(Rx[1-nb], Ry[1-nb], Rx[nb], Ry[nb]); |
saranieves92 | 1:4875e39abd1e | 1327 | |
saranieves92 | 1:4875e39abd1e | 1328 | /* Find final 1/Z value. */ |
saranieves92 | 1:4875e39abd1e | 1329 | vli_modSub(z, Rx[1], Rx[0], curve_p); /* X1 - X0 */ |
saranieves92 | 1:4875e39abd1e | 1330 | vli_modMult_fast(z, z, Ry[1-nb]); /* Yb * (X1 - X0) */ |
saranieves92 | 1:4875e39abd1e | 1331 | vli_modMult_fast(z, z, p_point->x); /* xP * Yb * (X1 - X0) */ |
saranieves92 | 1:4875e39abd1e | 1332 | vli_modInv(z, z, curve_p); /* 1 / (xP * Yb * (X1 - X0)) */ |
saranieves92 | 1:4875e39abd1e | 1333 | vli_modMult_fast(z, z, p_point->y); /* yP / (xP * Yb * (X1 - X0)) */ |
saranieves92 | 1:4875e39abd1e | 1334 | vli_modMult_fast(z, z, Rx[1-nb]); /* Xb * yP / (xP * Yb * (X1 - X0)) */ |
saranieves92 | 1:4875e39abd1e | 1335 | /* End 1/Z calculation */ |
saranieves92 | 1:4875e39abd1e | 1336 | |
saranieves92 | 1:4875e39abd1e | 1337 | XYcZ_add(Rx[nb], Ry[nb], Rx[1-nb], Ry[1-nb]); |
saranieves92 | 1:4875e39abd1e | 1338 | |
saranieves92 | 1:4875e39abd1e | 1339 | apply_z(Rx[0], Ry[0], z); |
saranieves92 | 1:4875e39abd1e | 1340 | |
saranieves92 | 1:4875e39abd1e | 1341 | vli_set(p_result->x, Rx[0]); |
saranieves92 | 1:4875e39abd1e | 1342 | vli_set(p_result->y, Ry[0]); |
saranieves92 | 1:4875e39abd1e | 1343 | } |
saranieves92 | 1:4875e39abd1e | 1344 | |
saranieves92 | 1:4875e39abd1e | 1345 | int ecc_make_key(EccPoint *p_publicKey, uint32_t p_privateKey[NUM_ECC_DIGITS], |
saranieves92 | 1:4875e39abd1e | 1346 | const uint32_t p_random[NUM_ECC_DIGITS]) |
saranieves92 | 1:4875e39abd1e | 1347 | { |
saranieves92 | 1:4875e39abd1e | 1348 | /* Make sure the private key is in the range [1, n-1]. |
saranieves92 | 1:4875e39abd1e | 1349 | For the supported curves, n is always large enough that we only need to subtract once at most. */ |
saranieves92 | 1:4875e39abd1e | 1350 | vli_set(p_privateKey, p_random); |
saranieves92 | 1:4875e39abd1e | 1351 | if(vli_cmp(curve_n, p_privateKey) != 1) |
saranieves92 | 1:4875e39abd1e | 1352 | { |
saranieves92 | 1:4875e39abd1e | 1353 | vli_sub(p_privateKey, p_privateKey, curve_n); |
saranieves92 | 1:4875e39abd1e | 1354 | } |
saranieves92 | 1:4875e39abd1e | 1355 | |
saranieves92 | 1:4875e39abd1e | 1356 | if(vli_isZero(p_privateKey)) |
saranieves92 | 1:4875e39abd1e | 1357 | { |
saranieves92 | 1:4875e39abd1e | 1358 | return 0; /* The private key cannot be 0 (mod p). */ |
saranieves92 | 1:4875e39abd1e | 1359 | } |
saranieves92 | 1:4875e39abd1e | 1360 | |
saranieves92 | 1:4875e39abd1e | 1361 | EccPoint_mult(p_publicKey, &curve_G, p_privateKey, NULL); |
saranieves92 | 1:4875e39abd1e | 1362 | return 1; |
saranieves92 | 1:4875e39abd1e | 1363 | } |
saranieves92 | 1:4875e39abd1e | 1364 | |
saranieves92 | 1:4875e39abd1e | 1365 | #if (ECC_CURVE == secp256k1) |
saranieves92 | 1:4875e39abd1e | 1366 | /* Compute p_result = x^3 + b */ |
saranieves92 | 1:4875e39abd1e | 1367 | static void curve_x_side(uint32_t p_result[NUM_ECC_DIGITS], const uint32_t x[NUM_ECC_DIGITS]) |
saranieves92 | 1:4875e39abd1e | 1368 | { |
saranieves92 | 1:4875e39abd1e | 1369 | vli_modSquare_fast(p_result, x); /* r = x^2 */ |
saranieves92 | 1:4875e39abd1e | 1370 | vli_modMult_fast(p_result, p_result, x); /* r = x^3 */ |
saranieves92 | 1:4875e39abd1e | 1371 | vli_modAdd(p_result, p_result, curve_b, curve_p); /* r = x^3 + b */ |
saranieves92 | 1:4875e39abd1e | 1372 | } |
saranieves92 | 1:4875e39abd1e | 1373 | #else |
saranieves92 | 1:4875e39abd1e | 1374 | /* Compute p_result = x^3 - 3x + b */ |
saranieves92 | 1:4875e39abd1e | 1375 | static void curve_x_side(uint32_t p_result[NUM_ECC_DIGITS], const uint32_t x[NUM_ECC_DIGITS]) |
saranieves92 | 1:4875e39abd1e | 1376 | { |
saranieves92 | 1:4875e39abd1e | 1377 | uint32_t _3[NUM_ECC_DIGITS] = {3}; /* -a = 3 */ |
saranieves92 | 1:4875e39abd1e | 1378 | |
saranieves92 | 1:4875e39abd1e | 1379 | vli_modSquare_fast(p_result, x); /* r = x^2 */ |
saranieves92 | 1:4875e39abd1e | 1380 | vli_modSub(p_result, p_result, _3, curve_p); /* r = x^2 - 3 */ |
saranieves92 | 1:4875e39abd1e | 1381 | vli_modMult_fast(p_result, p_result, x); /* r = x^3 - 3x */ |
saranieves92 | 1:4875e39abd1e | 1382 | vli_modAdd(p_result, p_result, curve_b, curve_p); /* r = x^3 - 3x + b */ |
saranieves92 | 1:4875e39abd1e | 1383 | } |
saranieves92 | 1:4875e39abd1e | 1384 | #endif |
saranieves92 | 1:4875e39abd1e | 1385 | |
saranieves92 | 1:4875e39abd1e | 1386 | int ecc_valid_public_key(const EccPoint *p_publicKey) |
saranieves92 | 1:4875e39abd1e | 1387 | { |
saranieves92 | 1:4875e39abd1e | 1388 | uint32_t l_tmp1[NUM_ECC_DIGITS]; |
saranieves92 | 1:4875e39abd1e | 1389 | uint32_t l_tmp2[NUM_ECC_DIGITS]; |
saranieves92 | 1:4875e39abd1e | 1390 | |
saranieves92 | 1:4875e39abd1e | 1391 | if(EccPoint_isZero(p_publicKey)) |
saranieves92 | 1:4875e39abd1e | 1392 | { |
saranieves92 | 1:4875e39abd1e | 1393 | return 0; |
saranieves92 | 1:4875e39abd1e | 1394 | } |
saranieves92 | 1:4875e39abd1e | 1395 | |
saranieves92 | 1:4875e39abd1e | 1396 | if(vli_cmp(curve_p, p_publicKey->x) != 1 || vli_cmp(curve_p, p_publicKey->y) != 1) |
saranieves92 | 1:4875e39abd1e | 1397 | { |
saranieves92 | 1:4875e39abd1e | 1398 | return 0; |
saranieves92 | 1:4875e39abd1e | 1399 | } |
saranieves92 | 1:4875e39abd1e | 1400 | |
saranieves92 | 1:4875e39abd1e | 1401 | vli_modSquare_fast(l_tmp1, p_publicKey->y); /* tmp1 = y^2 */ |
saranieves92 | 1:4875e39abd1e | 1402 | |
saranieves92 | 1:4875e39abd1e | 1403 | curve_x_side(l_tmp2, p_publicKey->x); /* tmp2 = x^3 - 3x + b */ |
saranieves92 | 1:4875e39abd1e | 1404 | |
saranieves92 | 1:4875e39abd1e | 1405 | /* Make sure that y^2 == x^3 + ax + b */ |
saranieves92 | 1:4875e39abd1e | 1406 | if(vli_cmp(l_tmp1, l_tmp2) != 0) |
saranieves92 | 1:4875e39abd1e | 1407 | { |
saranieves92 | 1:4875e39abd1e | 1408 | return 0; |
saranieves92 | 1:4875e39abd1e | 1409 | } |
saranieves92 | 1:4875e39abd1e | 1410 | |
saranieves92 | 1:4875e39abd1e | 1411 | return 1; |
saranieves92 | 1:4875e39abd1e | 1412 | } |
saranieves92 | 1:4875e39abd1e | 1413 | |
saranieves92 | 1:4875e39abd1e | 1414 | int ecdh_shared_secret(uint32_t p_secret[NUM_ECC_DIGITS], const EccPoint *p_publicKey, |
saranieves92 | 1:4875e39abd1e | 1415 | const uint32_t p_privateKey[NUM_ECC_DIGITS], const uint32_t p_random[NUM_ECC_DIGITS]) |
saranieves92 | 1:4875e39abd1e | 1416 | { |
saranieves92 | 1:4875e39abd1e | 1417 | EccPoint l_product; |
saranieves92 | 1:4875e39abd1e | 1418 | |
saranieves92 | 1:4875e39abd1e | 1419 | EccPoint_mult(&l_product, p_publicKey, p_privateKey, p_random); |
saranieves92 | 1:4875e39abd1e | 1420 | if(EccPoint_isZero(&l_product)) |
saranieves92 | 1:4875e39abd1e | 1421 | { |
saranieves92 | 1:4875e39abd1e | 1422 | return 0; |
saranieves92 | 1:4875e39abd1e | 1423 | } |
saranieves92 | 1:4875e39abd1e | 1424 | |
saranieves92 | 1:4875e39abd1e | 1425 | vli_set(p_secret, l_product.x); |
saranieves92 | 1:4875e39abd1e | 1426 | |
saranieves92 | 1:4875e39abd1e | 1427 | return 1; |
saranieves92 | 1:4875e39abd1e | 1428 | } |
saranieves92 | 1:4875e39abd1e | 1429 | |
saranieves92 | 1:4875e39abd1e | 1430 | /* -------- ECDSA code -------- */ |
saranieves92 | 1:4875e39abd1e | 1431 | |
saranieves92 | 1:4875e39abd1e | 1432 | /* Computes p_result = (p_left * p_right) % p_mod. */ |
saranieves92 | 1:4875e39abd1e | 1433 | static void vli_modMult(uint32_t *p_result, const uint32_t *p_left, |
saranieves92 | 1:4875e39abd1e | 1434 | const uint32_t *p_right, const uint32_t *p_mod) |
saranieves92 | 1:4875e39abd1e | 1435 | { |
saranieves92 | 1:4875e39abd1e | 1436 | uint32_t l_product[2 * NUM_ECC_DIGITS]; |
saranieves92 | 1:4875e39abd1e | 1437 | uint32_t l_modMultiple[2 * NUM_ECC_DIGITS]; |
saranieves92 | 1:4875e39abd1e | 1438 | uint l_digitShift, l_bitShift; |
saranieves92 | 1:4875e39abd1e | 1439 | uint l_productBits; |
saranieves92 | 1:4875e39abd1e | 1440 | uint l_modBits = vli_numBits(p_mod); |
saranieves92 | 1:4875e39abd1e | 1441 | |
saranieves92 | 1:4875e39abd1e | 1442 | vli_mult(l_product, p_left, p_right); |
saranieves92 | 1:4875e39abd1e | 1443 | l_productBits = vli_numBits(l_product + NUM_ECC_DIGITS); |
saranieves92 | 1:4875e39abd1e | 1444 | if(l_productBits) |
saranieves92 | 1:4875e39abd1e | 1445 | { |
saranieves92 | 1:4875e39abd1e | 1446 | l_productBits += NUM_ECC_DIGITS * 32; |
saranieves92 | 1:4875e39abd1e | 1447 | } |
saranieves92 | 1:4875e39abd1e | 1448 | else |
saranieves92 | 1:4875e39abd1e | 1449 | { |
saranieves92 | 1:4875e39abd1e | 1450 | l_productBits = vli_numBits(l_product); |
saranieves92 | 1:4875e39abd1e | 1451 | } |
saranieves92 | 1:4875e39abd1e | 1452 | |
saranieves92 | 1:4875e39abd1e | 1453 | if(l_productBits < l_modBits) |
saranieves92 | 1:4875e39abd1e | 1454 | { /* l_product < p_mod. */ |
saranieves92 | 1:4875e39abd1e | 1455 | vli_set(p_result, l_product); |
saranieves92 | 1:4875e39abd1e | 1456 | return; |
saranieves92 | 1:4875e39abd1e | 1457 | } |
saranieves92 | 1:4875e39abd1e | 1458 | |
saranieves92 | 1:4875e39abd1e | 1459 | /* Shift p_mod by (l_leftBits - l_modBits). This multiplies p_mod by the largest |
saranieves92 | 1:4875e39abd1e | 1460 | power of two possible while still resulting in a number less than p_left. */ |
saranieves92 | 1:4875e39abd1e | 1461 | vli_clear(l_modMultiple); |
saranieves92 | 1:4875e39abd1e | 1462 | vli_clear(l_modMultiple + NUM_ECC_DIGITS); |
saranieves92 | 1:4875e39abd1e | 1463 | l_digitShift = (l_productBits - l_modBits) / 32; |
saranieves92 | 1:4875e39abd1e | 1464 | l_bitShift = (l_productBits - l_modBits) % 32; |
saranieves92 | 1:4875e39abd1e | 1465 | if(l_bitShift) |
saranieves92 | 1:4875e39abd1e | 1466 | { |
saranieves92 | 1:4875e39abd1e | 1467 | l_modMultiple[l_digitShift + NUM_ECC_DIGITS] = vli_lshift(l_modMultiple + l_digitShift, p_mod, l_bitShift); |
saranieves92 | 1:4875e39abd1e | 1468 | } |
saranieves92 | 1:4875e39abd1e | 1469 | else |
saranieves92 | 1:4875e39abd1e | 1470 | { |
saranieves92 | 1:4875e39abd1e | 1471 | vli_set(l_modMultiple + l_digitShift, p_mod); |
saranieves92 | 1:4875e39abd1e | 1472 | } |
saranieves92 | 1:4875e39abd1e | 1473 | |
saranieves92 | 1:4875e39abd1e | 1474 | /* Subtract all multiples of p_mod to get the remainder. */ |
saranieves92 | 1:4875e39abd1e | 1475 | vli_clear(p_result); |
saranieves92 | 1:4875e39abd1e | 1476 | p_result[0] = 1; /* Use p_result as a temp var to store 1 (for subtraction) */ |
saranieves92 | 1:4875e39abd1e | 1477 | while(l_productBits > NUM_ECC_DIGITS * 32 || vli_cmp(l_modMultiple, p_mod) >= 0) |
saranieves92 | 1:4875e39abd1e | 1478 | { |
saranieves92 | 1:4875e39abd1e | 1479 | int l_cmp = vli_cmp(l_modMultiple + NUM_ECC_DIGITS, l_product + NUM_ECC_DIGITS); |
saranieves92 | 1:4875e39abd1e | 1480 | if(l_cmp < 0 || (l_cmp == 0 && vli_cmp(l_modMultiple, l_product) <= 0)) |
saranieves92 | 1:4875e39abd1e | 1481 | { |
saranieves92 | 1:4875e39abd1e | 1482 | if(vli_sub(l_product, l_product, l_modMultiple)) |
saranieves92 | 1:4875e39abd1e | 1483 | { /* borrow */ |
saranieves92 | 1:4875e39abd1e | 1484 | vli_sub(l_product + NUM_ECC_DIGITS, l_product + NUM_ECC_DIGITS, p_result); |
saranieves92 | 1:4875e39abd1e | 1485 | } |
saranieves92 | 1:4875e39abd1e | 1486 | vli_sub(l_product + NUM_ECC_DIGITS, l_product + NUM_ECC_DIGITS, l_modMultiple + NUM_ECC_DIGITS); |
saranieves92 | 1:4875e39abd1e | 1487 | } |
saranieves92 | 1:4875e39abd1e | 1488 | uint32_t l_carry = (l_modMultiple[NUM_ECC_DIGITS] & 0x01) << 31; |
saranieves92 | 1:4875e39abd1e | 1489 | vli_rshift1(l_modMultiple + NUM_ECC_DIGITS); |
saranieves92 | 1:4875e39abd1e | 1490 | vli_rshift1(l_modMultiple); |
saranieves92 | 1:4875e39abd1e | 1491 | l_modMultiple[NUM_ECC_DIGITS-1] |= l_carry; |
saranieves92 | 1:4875e39abd1e | 1492 | |
saranieves92 | 1:4875e39abd1e | 1493 | --l_productBits; |
saranieves92 | 1:4875e39abd1e | 1494 | } |
saranieves92 | 1:4875e39abd1e | 1495 | vli_set(p_result, l_product); |
saranieves92 | 1:4875e39abd1e | 1496 | } |
saranieves92 | 1:4875e39abd1e | 1497 | |
saranieves92 | 1:4875e39abd1e | 1498 | static inline unsigned int max(const unsigned int a, const unsigned int b) |
saranieves92 | 1:4875e39abd1e | 1499 | { |
saranieves92 | 1:4875e39abd1e | 1500 | return (a > b ? a : b); |
saranieves92 | 1:4875e39abd1e | 1501 | } |
saranieves92 | 1:4875e39abd1e | 1502 | |
saranieves92 | 1:4875e39abd1e | 1503 | int ecdsa_sign(uint32_t r[NUM_ECC_DIGITS], uint32_t s[NUM_ECC_DIGITS], |
saranieves92 | 1:4875e39abd1e | 1504 | const uint32_t p_privateKey[NUM_ECC_DIGITS], const uint32_t p_random[NUM_ECC_DIGITS], |
saranieves92 | 1:4875e39abd1e | 1505 | const uint32_t p_hash[NUM_ECC_DIGITS]) |
saranieves92 | 1:4875e39abd1e | 1506 | { |
saranieves92 | 1:4875e39abd1e | 1507 | uint32_t k[NUM_ECC_DIGITS]; |
saranieves92 | 1:4875e39abd1e | 1508 | EccPoint p; |
saranieves92 | 1:4875e39abd1e | 1509 | |
saranieves92 | 1:4875e39abd1e | 1510 | if(vli_isZero(p_random)) |
saranieves92 | 1:4875e39abd1e | 1511 | { /* The random number must not be 0. */ |
saranieves92 | 1:4875e39abd1e | 1512 | return 0; |
saranieves92 | 1:4875e39abd1e | 1513 | } |
saranieves92 | 1:4875e39abd1e | 1514 | |
saranieves92 | 1:4875e39abd1e | 1515 | vli_set(k, p_random); |
saranieves92 | 1:4875e39abd1e | 1516 | if(vli_cmp(curve_n, k) != 1) |
saranieves92 | 1:4875e39abd1e | 1517 | { |
saranieves92 | 1:4875e39abd1e | 1518 | vli_sub(k, k, curve_n); |
saranieves92 | 1:4875e39abd1e | 1519 | } |
saranieves92 | 1:4875e39abd1e | 1520 | |
saranieves92 | 1:4875e39abd1e | 1521 | /* tmp = k * G */ |
saranieves92 | 1:4875e39abd1e | 1522 | EccPoint_mult(&p, &curve_G, k, NULL); |
saranieves92 | 1:4875e39abd1e | 1523 | |
saranieves92 | 1:4875e39abd1e | 1524 | /* r = x1 (mod n) */ |
saranieves92 | 1:4875e39abd1e | 1525 | vli_set(r, p.x); |
saranieves92 | 1:4875e39abd1e | 1526 | if(vli_cmp(curve_n, r) != 1) |
saranieves92 | 1:4875e39abd1e | 1527 | { |
saranieves92 | 1:4875e39abd1e | 1528 | vli_sub(r, r, curve_n); |
saranieves92 | 1:4875e39abd1e | 1529 | } |
saranieves92 | 1:4875e39abd1e | 1530 | if(vli_isZero(r)) |
saranieves92 | 1:4875e39abd1e | 1531 | { /* If r == 0, fail (need a different random number). */ |
saranieves92 | 1:4875e39abd1e | 1532 | return 0; |
saranieves92 | 1:4875e39abd1e | 1533 | } |
saranieves92 | 1:4875e39abd1e | 1534 | |
saranieves92 | 1:4875e39abd1e | 1535 | vli_modMult(s, r, p_privateKey, curve_n); /* s = r*d */ |
saranieves92 | 1:4875e39abd1e | 1536 | vli_modAdd(s, p_hash, s, curve_n); /* s = e + r*d */ |
saranieves92 | 1:4875e39abd1e | 1537 | vli_modInv(k, k, curve_n); /* k = 1 / k */ |
saranieves92 | 1:4875e39abd1e | 1538 | vli_modMult(s, s, k, curve_n); /* s = (e + r*d) / k */ |
saranieves92 | 1:4875e39abd1e | 1539 | |
saranieves92 | 1:4875e39abd1e | 1540 | return 1; |
saranieves92 | 1:4875e39abd1e | 1541 | } |
saranieves92 | 1:4875e39abd1e | 1542 | |
saranieves92 | 1:4875e39abd1e | 1543 | int ecdsa_verify(const EccPoint *p_publicKey, const uint32_t p_hash[NUM_ECC_DIGITS], |
saranieves92 | 1:4875e39abd1e | 1544 | const uint32_t r[NUM_ECC_DIGITS], const uint32_t s[NUM_ECC_DIGITS]) |
saranieves92 | 1:4875e39abd1e | 1545 | { |
saranieves92 | 1:4875e39abd1e | 1546 | uint32_t u1[NUM_ECC_DIGITS], u2[NUM_ECC_DIGITS]; |
saranieves92 | 1:4875e39abd1e | 1547 | uint32_t z[NUM_ECC_DIGITS]; |
saranieves92 | 1:4875e39abd1e | 1548 | EccPoint l_sum; |
saranieves92 | 1:4875e39abd1e | 1549 | uint32_t rx[NUM_ECC_DIGITS]; |
saranieves92 | 1:4875e39abd1e | 1550 | uint32_t ry[NUM_ECC_DIGITS]; |
saranieves92 | 1:4875e39abd1e | 1551 | uint32_t tx[NUM_ECC_DIGITS]; |
saranieves92 | 1:4875e39abd1e | 1552 | uint32_t ty[NUM_ECC_DIGITS]; |
saranieves92 | 1:4875e39abd1e | 1553 | uint32_t tz[NUM_ECC_DIGITS]; |
saranieves92 | 1:4875e39abd1e | 1554 | |
saranieves92 | 1:4875e39abd1e | 1555 | if(vli_isZero(r) || vli_isZero(s)) |
saranieves92 | 1:4875e39abd1e | 1556 | { /* r, s must not be 0. */ |
saranieves92 | 1:4875e39abd1e | 1557 | return 0; |
saranieves92 | 1:4875e39abd1e | 1558 | } |
saranieves92 | 1:4875e39abd1e | 1559 | |
saranieves92 | 1:4875e39abd1e | 1560 | if(vli_cmp(curve_n, r) != 1 || vli_cmp(curve_n, s) != 1) |
saranieves92 | 1:4875e39abd1e | 1561 | { /* r, s must be < n. */ |
saranieves92 | 1:4875e39abd1e | 1562 | return 0; |
saranieves92 | 1:4875e39abd1e | 1563 | } |
saranieves92 | 1:4875e39abd1e | 1564 | |
saranieves92 | 1:4875e39abd1e | 1565 | /* Calculate u1 and u2. */ |
saranieves92 | 1:4875e39abd1e | 1566 | vli_modInv(z, s, curve_n); /* Z = s^-1 */ |
saranieves92 | 1:4875e39abd1e | 1567 | vli_modMult(u1, p_hash, z, curve_n); /* u1 = e/s */ |
saranieves92 | 1:4875e39abd1e | 1568 | vli_modMult(u2, r, z, curve_n); /* u2 = r/s */ |
saranieves92 | 1:4875e39abd1e | 1569 | |
saranieves92 | 1:4875e39abd1e | 1570 | /* Calculate l_sum = G + Q. */ |
saranieves92 | 1:4875e39abd1e | 1571 | vli_set(l_sum.x, p_publicKey->x); |
saranieves92 | 1:4875e39abd1e | 1572 | vli_set(l_sum.y, p_publicKey->y); |
saranieves92 | 1:4875e39abd1e | 1573 | vli_set(tx, curve_G.x); |
saranieves92 | 1:4875e39abd1e | 1574 | vli_set(ty, curve_G.y); |
saranieves92 | 1:4875e39abd1e | 1575 | vli_modSub(z, l_sum.x, tx, curve_p); /* Z = x2 - x1 */ |
saranieves92 | 1:4875e39abd1e | 1576 | XYcZ_add(tx, ty, l_sum.x, l_sum.y); |
saranieves92 | 1:4875e39abd1e | 1577 | vli_modInv(z, z, curve_p); /* Z = 1/Z */ |
saranieves92 | 1:4875e39abd1e | 1578 | apply_z(l_sum.x, l_sum.y, z); |
saranieves92 | 1:4875e39abd1e | 1579 | |
saranieves92 | 1:4875e39abd1e | 1580 | /* Use Shamir's trick to calculate u1*G + u2*Q */ |
saranieves92 | 1:4875e39abd1e | 1581 | const EccPoint *l_points[4] = {NULL, &curve_G, p_publicKey, &l_sum}; |
saranieves92 | 1:4875e39abd1e | 1582 | uint l_numBits = max(vli_numBits(u1), vli_numBits(u2)); |
saranieves92 | 1:4875e39abd1e | 1583 | |
saranieves92 | 1:4875e39abd1e | 1584 | const EccPoint *l_point = l_points[(!!vli_testBit(u1, l_numBits-1)) | ((!!vli_testBit(u2, l_numBits-1)) << 1)]; |
saranieves92 | 1:4875e39abd1e | 1585 | vli_set(rx, l_point->x); |
saranieves92 | 1:4875e39abd1e | 1586 | vli_set(ry, l_point->y); |
saranieves92 | 1:4875e39abd1e | 1587 | vli_clear(z); |
saranieves92 | 1:4875e39abd1e | 1588 | z[0] = 1; |
saranieves92 | 1:4875e39abd1e | 1589 | |
saranieves92 | 1:4875e39abd1e | 1590 | int i; |
saranieves92 | 1:4875e39abd1e | 1591 | for(i = l_numBits - 2; i >= 0; --i) |
saranieves92 | 1:4875e39abd1e | 1592 | { |
saranieves92 | 1:4875e39abd1e | 1593 | EccPoint_double_jacobian(rx, ry, z); |
saranieves92 | 1:4875e39abd1e | 1594 | |
saranieves92 | 1:4875e39abd1e | 1595 | int l_index = (!!vli_testBit(u1, i)) | ((!!vli_testBit(u2, i)) << 1); |
saranieves92 | 1:4875e39abd1e | 1596 | l_point = l_points[l_index]; |
saranieves92 | 1:4875e39abd1e | 1597 | if(l_point) |
saranieves92 | 1:4875e39abd1e | 1598 | { |
saranieves92 | 1:4875e39abd1e | 1599 | vli_set(tx, l_point->x); |
saranieves92 | 1:4875e39abd1e | 1600 | vli_set(ty, l_point->y); |
saranieves92 | 1:4875e39abd1e | 1601 | apply_z(tx, ty, z); |
saranieves92 | 1:4875e39abd1e | 1602 | vli_modSub(tz, rx, tx, curve_p); /* Z = x2 - x1 */ |
saranieves92 | 1:4875e39abd1e | 1603 | XYcZ_add(tx, ty, rx, ry); |
saranieves92 | 1:4875e39abd1e | 1604 | vli_modMult_fast(z, z, tz); |
saranieves92 | 1:4875e39abd1e | 1605 | } |
saranieves92 | 1:4875e39abd1e | 1606 | } |
saranieves92 | 1:4875e39abd1e | 1607 | |
saranieves92 | 1:4875e39abd1e | 1608 | vli_modInv(z, z, curve_p); /* Z = 1/Z */ |
saranieves92 | 1:4875e39abd1e | 1609 | apply_z(rx, ry, z); |
saranieves92 | 1:4875e39abd1e | 1610 | |
saranieves92 | 1:4875e39abd1e | 1611 | /* v = x1 (mod n) */ |
saranieves92 | 1:4875e39abd1e | 1612 | if(vli_cmp(curve_n, rx) != 1) |
saranieves92 | 1:4875e39abd1e | 1613 | { |
saranieves92 | 1:4875e39abd1e | 1614 | vli_sub(rx, rx, curve_n); |
saranieves92 | 1:4875e39abd1e | 1615 | } |
saranieves92 | 1:4875e39abd1e | 1616 | |
saranieves92 | 1:4875e39abd1e | 1617 | /* Accept only if v == r. */ |
saranieves92 | 1:4875e39abd1e | 1618 | return (vli_cmp(rx, r) == 0); |
saranieves92 | 1:4875e39abd1e | 1619 | } |
saranieves92 | 1:4875e39abd1e | 1620 | |
saranieves92 | 1:4875e39abd1e | 1621 | void ecc_bytes2native(uint32_t p_native[NUM_ECC_DIGITS], const uint8_t p_bytes[NUM_ECC_DIGITS*4]) |
saranieves92 | 1:4875e39abd1e | 1622 | { |
saranieves92 | 1:4875e39abd1e | 1623 | unsigned i; |
saranieves92 | 1:4875e39abd1e | 1624 | for(i=0; i<NUM_ECC_DIGITS; ++i) |
saranieves92 | 1:4875e39abd1e | 1625 | { |
saranieves92 | 1:4875e39abd1e | 1626 | uint8_t *p_digit = (uint8_t *)(p_bytes + 4 * (NUM_ECC_DIGITS - 1 - i)); |
saranieves92 | 1:4875e39abd1e | 1627 | p_native[i] = ((uint32_t)p_digit[0] << 24) | ((uint32_t)p_digit[1] << 16) | ((uint32_t)p_digit[2] << 8) | (uint32_t)p_digit[3]; |
saranieves92 | 1:4875e39abd1e | 1628 | } |
saranieves92 | 1:4875e39abd1e | 1629 | } |
saranieves92 | 1:4875e39abd1e | 1630 | |
saranieves92 | 1:4875e39abd1e | 1631 | void ecc_native2bytes(uint8_t p_bytes[NUM_ECC_DIGITS*4], const uint32_t p_native[NUM_ECC_DIGITS]) |
saranieves92 | 1:4875e39abd1e | 1632 | { |
saranieves92 | 1:4875e39abd1e | 1633 | unsigned i; |
saranieves92 | 1:4875e39abd1e | 1634 | for(i=0; i<NUM_ECC_DIGITS; ++i) |
saranieves92 | 1:4875e39abd1e | 1635 | { |
saranieves92 | 1:4875e39abd1e | 1636 | uint8_t *p_digit = p_bytes + 4 * (NUM_ECC_DIGITS - 1 - i); |
saranieves92 | 1:4875e39abd1e | 1637 | p_digit[0] = p_native[i] >> 24; |
saranieves92 | 1:4875e39abd1e | 1638 | p_digit[1] = p_native[i] >> 16; |
saranieves92 | 1:4875e39abd1e | 1639 | p_digit[2] = p_native[i] >> 8; |
saranieves92 | 1:4875e39abd1e | 1640 | p_digit[3] = p_native[i]; |
saranieves92 | 1:4875e39abd1e | 1641 | } |
saranieves92 | 1:4875e39abd1e | 1642 | } |
saranieves92 | 1:4875e39abd1e | 1643 | |
saranieves92 | 1:4875e39abd1e | 1644 | /* Compute a = sqrt(a) (mod curve_p). */ |
saranieves92 | 1:4875e39abd1e | 1645 | static void mod_sqrt(uint32_t a[NUM_ECC_DIGITS]) |
saranieves92 | 1:4875e39abd1e | 1646 | { |
saranieves92 | 1:4875e39abd1e | 1647 | unsigned i; |
saranieves92 | 1:4875e39abd1e | 1648 | uint32_t p1[NUM_ECC_DIGITS] = {1}; |
saranieves92 | 1:4875e39abd1e | 1649 | uint32_t l_result[NUM_ECC_DIGITS] = {1}; |
saranieves92 | 1:4875e39abd1e | 1650 | |
saranieves92 | 1:4875e39abd1e | 1651 | /* Since curve_p == 3 (mod 4) for all supported curves, we can |
saranieves92 | 1:4875e39abd1e | 1652 | compute sqrt(a) = a^((curve_p + 1) / 4) (mod curve_p). */ |
saranieves92 | 1:4875e39abd1e | 1653 | vli_add(p1, curve_p, p1); /* p1 = curve_p + 1 */ |
saranieves92 | 1:4875e39abd1e | 1654 | for(i = vli_numBits(p1) - 1; i > 1; --i) |
saranieves92 | 1:4875e39abd1e | 1655 | { |
saranieves92 | 1:4875e39abd1e | 1656 | vli_modSquare_fast(l_result, l_result); |
saranieves92 | 1:4875e39abd1e | 1657 | if(vli_testBit(p1, i)) |
saranieves92 | 1:4875e39abd1e | 1658 | { |
saranieves92 | 1:4875e39abd1e | 1659 | vli_modMult_fast(l_result, l_result, a); |
saranieves92 | 1:4875e39abd1e | 1660 | } |
saranieves92 | 1:4875e39abd1e | 1661 | } |
saranieves92 | 1:4875e39abd1e | 1662 | vli_set(a, l_result); |
saranieves92 | 1:4875e39abd1e | 1663 | } |
saranieves92 | 1:4875e39abd1e | 1664 | |
saranieves92 | 1:4875e39abd1e | 1665 | void ecc_point_compress(uint8_t p_compressed[NUM_ECC_DIGITS*4 + 1], const EccPoint *p_point) |
saranieves92 | 1:4875e39abd1e | 1666 | { |
saranieves92 | 1:4875e39abd1e | 1667 | p_compressed[0] = 2 + (p_point->y[0] & 0x01); |
saranieves92 | 1:4875e39abd1e | 1668 | ecc_native2bytes(p_compressed + 1, p_point->x); |
saranieves92 | 1:4875e39abd1e | 1669 | } |
saranieves92 | 1:4875e39abd1e | 1670 | |
saranieves92 | 1:4875e39abd1e | 1671 | void ecc_point_decompress(EccPoint *p_point, const uint8_t p_compressed[NUM_ECC_DIGITS*4 + 1]) |
saranieves92 | 1:4875e39abd1e | 1672 | { |
saranieves92 | 1:4875e39abd1e | 1673 | ecc_bytes2native(p_point->x, p_compressed + 1); |
saranieves92 | 1:4875e39abd1e | 1674 | curve_x_side(p_point->y, p_point->x); |
saranieves92 | 1:4875e39abd1e | 1675 | mod_sqrt(p_point->y); |
saranieves92 | 1:4875e39abd1e | 1676 | if((p_point->y[0] & 0x01) != (p_compressed[0] & 0x01)) |
saranieves92 | 1:4875e39abd1e | 1677 | { |
saranieves92 | 1:4875e39abd1e | 1678 | vli_sub(p_point->y, curve_p, p_point->y); |
saranieves92 | 1:4875e39abd1e | 1679 | } |
saranieves92 | 1:4875e39abd1e | 1680 | } |
saranieves92 | 1:4875e39abd1e | 1681 |