| /* ecc.c - TinyCrypt implementation of ECC auxiliary functions */ |
| |
| /* |
| * |
| * Copyright (c) 2013, Kenneth MacKay |
| * All rights reserved. |
| * https://github.com/kmackay/micro-ecc |
| * |
| * Redistribution and use in source and binary forms, with or without modification, |
| * are permitted provided that the following conditions are met: |
| * * Redistributions of source code must retain the above copyright notice, this |
| * list of conditions and the following disclaimer. |
| * * Redistributions in binary form must reproduce the above copyright notice, |
| * this list of conditions and the following disclaimer in the documentation |
| * and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
| * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR |
| * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON |
| * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| * |
| * Copyright (C) 2015 by Intel Corporation, All Rights Reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are met: |
| * |
| * - Redistributions of source code must retain the above copyright notice, |
| * this list of conditions and the following disclaimer. |
| * |
| * - Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * - Neither the name of Intel Corporation nor the names of its contributors |
| * may be used to endorse or promote products derived from this software |
| * without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
| * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| * POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include <tinycrypt/ecc.h> |
| |
| /* ------ Curve NIST P-256 constants: ------ */ |
| |
| #define Curve_P {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, \ |
| 0x00000000, 0x00000000, 0x00000001, 0xFFFFFFFF} |
| |
| #define Curve_B {0x27D2604B, 0x3BCE3C3E, 0xCC53B0F6, 0x651D06B0, \ |
| 0x769886BC, 0xB3EBBD55, 0xAA3A93E7, 0x5AC635D8} |
| |
| #define Curve_N {0xFC632551, 0xF3B9CAC2, 0xA7179E84, 0xBCE6FAAD, \ |
| 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF} |
| |
| #define Curve_G {{0xD898C296, 0xF4A13945, 0x2DEB33A0, 0x77037D81, \ |
| 0x63A440F2, 0xF8BCE6E5, 0xE12C4247, 0x6B17D1F2}, \ |
| {0x37BF51F5, 0xCBB64068, 0x6B315ECE, 0x2BCE3357, \ |
| 0x7C0F9E16, 0x8EE7EB4A, 0xFE1A7F9B, 0x4FE342E2} } |
| |
| #define Curve_P_Barrett {0x00000003, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFE, \ |
| 0xFFFFFFFE, 0xFFFFFFFE, 0xFFFFFFFF, 0x00000000, 0x00000001} |
| |
| #define Curve_N_Barrett {0xEEDF9BFE, 0x012FFD85, 0xDF1A6C21, 0x43190552, \ |
| 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0x00000000, 0x00000001} |
| |
| uint32_t curve_p[NUM_ECC_DIGITS] = Curve_P; |
| uint32_t curve_b[NUM_ECC_DIGITS] = Curve_B; |
| EccPoint curve_G = Curve_G; |
| uint32_t curve_n[NUM_ECC_DIGITS] = Curve_N; |
| uint32_t curve_pb[NUM_ECC_DIGITS + 1] = Curve_P_Barrett; |
| uint32_t curve_nb[NUM_ECC_DIGITS + 1] = Curve_N_Barrett; |
| |
| /* ------ Static functions: ------ */ |
| |
| /* Zeroing out p_vli. */ |
| static void vli_clear(uint32_t *p_vli) |
| { |
| uint32_t i; |
| |
| for (i = 0; i < NUM_ECC_DIGITS; ++i) { |
| p_vli[i] = 0; |
| } |
| } |
| |
| /* Returns nonzero if bit p_bit of p_vli is set. */ |
| static uint32_t vli_testBit(uint32_t *p_vli, uint32_t p_bit) |
| { |
| return (p_vli[p_bit / 32] & (1 << (p_bit % 32))); |
| } |
| |
| uint32_t vli_isZero(uint32_t *p_vli) |
| { |
| uint32_t acc = 0; |
| |
| for (uint32_t i = 0; i < NUM_ECC_DIGITS; ++i) { |
| acc |= p_vli[i]; |
| } |
| |
| return (!acc); |
| } |
| |
| /* |
| * Find the right-most nonzero 32-bit "digits" in p_vli. |
| * |
| * Side-channel countermeasure: algorithm strengthened against timing attack. |
| */ |
| static uint32_t vli_numDigits(uint32_t *p_vli) |
| { |
| int32_t i; |
| uint32_t digits = 0; |
| |
| for (i = NUM_ECC_DIGITS - 1; i >= 0 ; --i) { |
| digits += p_vli[i] || digits; |
| } |
| |
| return digits; |
| } |
| |
| /* |
| * Find the left-most non-zero bit in p_vli. |
| * |
| * Side-channel countermeasure: algorithm strengthened against timing attack. |
| */ |
| static uint32_t vli_numBits(uint32_t *p_vli) |
| { |
| uint32_t l_digit; |
| uint32_t i, acc = 32; |
| uint32_t l_numDigits = vli_numDigits(p_vli); |
| |
| l_digit = p_vli[l_numDigits - 1]; |
| |
| for (i = 0; i < 32; ++i) { |
| acc -= !l_digit; |
| l_digit >>= 1; |
| } |
| |
| return ((l_numDigits - 1) * 32 + acc); |
| } |
| |
| /* |
| * Computes p_result = p_left + p_right, returns carry. |
| * |
| * Side-channel countermeasure: algorithm strengthened against timing attack. |
| */ |
| static uint32_t vli_add(uint32_t *p_result, uint32_t *p_left, |
| uint32_t *p_right) |
| { |
| |
| uint32_t l_carry = 0; |
| |
| for (uint32_t i = 0; i < NUM_ECC_DIGITS; ++i) { |
| uint32_t l_sum = p_left[i] + p_right[i] + l_carry; |
| |
| l_carry = (l_sum < p_left[i]) | ((l_sum == p_left[i]) && l_carry); |
| p_result[i] = l_sum; |
| } |
| |
| return l_carry; |
| } |
| |
| |
| /* Computes p_result = p_left * p_right. */ |
| static void vli_mult(uint32_t *p_result, uint32_t *p_left, |
| uint32_t *p_right, uint32_t word_size) |
| { |
| |
| uint64_t r01 = 0; |
| uint32_t r2 = 0; |
| |
| /* Compute each digit of p_result in sequence, maintaining the carries. */ |
| for (uint32_t k = 0; k < word_size*2 - 1; ++k) { |
| |
| uint32_t l_min = (k < word_size ? 0 : (k + 1) - word_size); |
| |
| for (uint32_t i = l_min; i <= k && i < word_size; ++i) { |
| |
| uint64_t l_product = (uint64_t)p_left[i] * p_right[k - i]; |
| |
| r01 += l_product; |
| r2 += (r01 < l_product); |
| } |
| p_result[k] = (uint32_t)r01; |
| r01 = (r01 >> 32) | (((uint64_t)r2) << 32); |
| r2 = 0; |
| } |
| |
| p_result[word_size * 2 - 1] = (uint32_t)r01; |
| } |
| |
| /* Computes p_result = p_left^2. */ |
| static void vli_square(uint32_t *p_result, uint32_t *p_left) |
| { |
| |
| uint64_t r01 = 0; |
| uint32_t r2 = 0; |
| uint32_t i, k; |
| |
| for (k = 0; k < NUM_ECC_DIGITS * 2 - 1; ++k) { |
| |
| uint32_t l_min = (k < NUM_ECC_DIGITS ? 0 : (k + 1) - NUM_ECC_DIGITS); |
| |
| for (i = l_min; i <= k && i <= k - i; ++i) { |
| |
| uint64_t l_product = (uint64_t)p_left[i] * p_left[k - i]; |
| |
| if (i < k - i) { |
| |
| r2 += l_product >> 63; |
| l_product *= 2; |
| } |
| r01 += l_product; |
| r2 += (r01 < l_product); |
| } |
| p_result[k] = (uint32_t)r01; |
| r01 = (r01 >> 32) | (((uint64_t)r2) << 32); |
| r2 = 0; |
| } |
| |
| p_result[NUM_ECC_DIGITS * 2 - 1] = (uint32_t)r01; |
| } |
| |
| /* Computes p_result = p_product % curve_p using Barrett reduction. */ |
| static void vli_mmod_barrett(uint32_t *p_result, uint32_t *p_product, |
| uint32_t *p_mod, uint32_t *p_barrett) |
| { |
| uint32_t i; |
| uint32_t q1[NUM_ECC_DIGITS + 1]; |
| |
| for (i = NUM_ECC_DIGITS - 1; i < 2 * NUM_ECC_DIGITS; i++) { |
| q1[i - (NUM_ECC_DIGITS - 1)] = p_product[i]; |
| } |
| |
| uint32_t q2[2*NUM_ECC_DIGITS + 2]; |
| |
| vli_mult(q2, q1, p_barrett, NUM_ECC_DIGITS + 1); |
| for (i = NUM_ECC_DIGITS + 1; i < 2 * NUM_ECC_DIGITS + 2; i++) { |
| q1[i - (NUM_ECC_DIGITS + 1)] = q2[i]; |
| } |
| |
| uint32_t prime2[2*NUM_ECC_DIGITS]; |
| |
| for (i = 0; i < NUM_ECC_DIGITS; i++) { |
| prime2[i] = p_mod[i]; |
| prime2[NUM_ECC_DIGITS + i] = 0; |
| } |
| |
| vli_mult(q2, q1, prime2, NUM_ECC_DIGITS + 1); |
| vli_sub(p_product, p_product, q2, 2 * NUM_ECC_DIGITS); |
| |
| uint32_t borrow; |
| |
| borrow = vli_sub(q1, p_product, prime2, NUM_ECC_DIGITS + 1); |
| vli_cond_set(p_product, p_product, q1, borrow); |
| p_product[NUM_ECC_DIGITS] = q1[NUM_ECC_DIGITS] * (!borrow); |
| borrow = vli_sub(q1, p_product, prime2, NUM_ECC_DIGITS + 1); |
| vli_cond_set(p_product, p_product, q1, borrow); |
| p_product[NUM_ECC_DIGITS] = q1[NUM_ECC_DIGITS] * (!borrow); |
| borrow = vli_sub(q1, p_product, prime2, NUM_ECC_DIGITS + 1); |
| vli_cond_set(p_product, p_product, q1, borrow); |
| p_product[NUM_ECC_DIGITS] = q1[NUM_ECC_DIGITS] * (!borrow); |
| |
| for (i = 0; i < NUM_ECC_DIGITS; i++) { |
| p_result[i] = p_product[i]; |
| } |
| } |
| |
| /* |
| * Computes modular exponentiation. |
| * |
| * Side-channel countermeasure: algorithm strengthened against timing attack. |
| */ |
| static void vli_modExp(uint32_t *p_result, uint32_t *p_base, |
| uint32_t *p_exp, uint32_t *p_mod, uint32_t *p_barrett) |
| { |
| |
| uint32_t acc[NUM_ECC_DIGITS], tmp[NUM_ECC_DIGITS], product[2 * NUM_ECC_DIGITS]; |
| uint32_t j; |
| int32_t i; |
| |
| vli_clear(acc); |
| acc[0] = 1; |
| |
| for (i = NUM_ECC_DIGITS - 1; i >= 0; i--) { |
| for (j = 1 << 31; j > 0; j = j >> 1) { |
| vli_square(product, acc); |
| vli_mmod_barrett(acc, product, p_mod, p_barrett); |
| vli_mult(product, acc, p_base, NUM_ECC_DIGITS); |
| vli_mmod_barrett(tmp, product, p_mod, p_barrett); |
| vli_cond_set(acc, tmp, acc, j & p_exp[i]); |
| } |
| } |
| |
| vli_set(p_result, acc); |
| } |
| |
| /* Conversion from Affine coordinates to Jacobi coordinates. */ |
| static void EccPoint_fromAffine(EccPointJacobi *p_point_jacobi, |
| EccPoint *p_point) { |
| |
| vli_set(p_point_jacobi->X, p_point->x); |
| vli_set(p_point_jacobi->Y, p_point->y); |
| vli_clear(p_point_jacobi->Z); |
| p_point_jacobi->Z[0] = 1; |
| } |
| |
| /* |
| * Elliptic curve point doubling in Jacobi coordinates: P = P + P. |
| * |
| * Requires 4 squares and 4 multiplications. |
| */ |
| static void EccPoint_double(EccPointJacobi *P) |
| { |
| |
| uint32_t m[NUM_ECC_DIGITS], s[NUM_ECC_DIGITS], t[NUM_ECC_DIGITS]; |
| |
| vli_modSquare_fast(t, P->Z); |
| vli_modSub(m, P->X, t, curve_p); |
| vli_modAdd(s, P->X, t, curve_p); |
| vli_modMult_fast(m, m, s); |
| vli_modAdd(s, m, m, curve_p); |
| vli_modAdd(m, s, m, curve_p); /* m = 3X^2 - 3Z^4 */ |
| vli_modSquare_fast(t, P->Y); |
| vli_modMult_fast(s, P->X, t); |
| vli_modAdd(s, s, s, curve_p); |
| vli_modAdd(s, s, s, curve_p); /* s = 4XY^2 */ |
| vli_modMult_fast(P->Z, P->Y, P->Z); |
| vli_modAdd(P->Z, P->Z, P->Z, curve_p); /* Z' = 2YZ */ |
| vli_modSquare_fast(P->X, m); |
| vli_modSub(P->X, P->X, s, curve_p); |
| vli_modSub(P->X, P->X, s, curve_p); /* X' = m^2 - 2s */ |
| vli_modSquare_fast(P->Y, t); |
| vli_modAdd(P->Y, P->Y, P->Y, curve_p); |
| vli_modAdd(P->Y, P->Y, P->Y, curve_p); |
| vli_modAdd(P->Y, P->Y, P->Y, curve_p); |
| vli_modSub(t, s, P->X, curve_p); |
| vli_modMult_fast(t, t, m); |
| vli_modSub(P->Y, t, P->Y, curve_p); /* Y' = m(s - X') - 8Y^4 */ |
| |
| } |
| |
| /* Copy input to target. */ |
| static void EccPointJacobi_set(EccPointJacobi *target, EccPointJacobi *input) |
| { |
| vli_set(target->X, input->X); |
| vli_set(target->Y, input->Y); |
| vli_set(target->Z, input->Z); |
| } |
| |
| /* ------ Externally visible functions (see header file for comments): ------ */ |
| |
| void vli_set(uint32_t *p_dest, uint32_t *p_src) |
| { |
| |
| uint32_t i; |
| |
| for (i = 0; i < NUM_ECC_DIGITS; ++i) { |
| p_dest[i] = p_src[i]; |
| } |
| } |
| |
| int32_t vli_cmp(uint32_t *p_left, uint32_t *p_right, int32_t word_size) |
| { |
| |
| int32_t i, cmp = 0; |
| |
| for (i = word_size-1; i >= 0; --i) { |
| cmp |= ((p_left[i] > p_right[i]) - (p_left[i] < p_right[i])) * (!cmp); |
| } |
| |
| return cmp; |
| } |
| |
| uint32_t vli_sub(uint32_t *p_result, uint32_t *p_left, uint32_t *p_right, |
| uint32_t word_size) |
| { |
| |
| uint32_t l_borrow = 0; |
| |
| for (uint32_t i = 0; i < word_size; ++i) { |
| uint32_t l_diff = p_left[i] - p_right[i] - l_borrow; |
| |
| l_borrow = (l_diff > p_left[i]) | ((l_diff == p_left[i]) && l_borrow); |
| p_result[i] = l_diff; |
| } |
| |
| return l_borrow; |
| } |
| |
| void vli_cond_set(uint32_t *output, uint32_t *p_true, uint32_t *p_false, |
| uint32_t cond) |
| { |
| uint32_t i; |
| |
| cond = (!cond); |
| |
| for (i = 0; i < NUM_ECC_DIGITS; i++) { |
| output[i] = (p_true[i]*(!cond)) | (p_false[i]*cond); |
| } |
| } |
| |
| void vli_modAdd(uint32_t *p_result, uint32_t *p_left, uint32_t *p_right, |
| uint32_t *p_mod) |
| { |
| uint32_t l_carry = vli_add(p_result, p_left, p_right); |
| uint32_t p_temp[NUM_ECC_DIGITS]; |
| |
| l_carry = l_carry == vli_sub(p_temp, p_result, p_mod, NUM_ECC_DIGITS); |
| vli_cond_set(p_result, p_temp, p_result, l_carry); |
| } |
| |
| void vli_modSub(uint32_t *p_result, uint32_t *p_left, uint32_t *p_right, |
| uint32_t *p_mod) |
| { |
| uint32_t l_borrow = vli_sub(p_result, p_left, p_right, NUM_ECC_DIGITS); |
| uint32_t p_temp[NUM_ECC_DIGITS]; |
| |
| vli_add(p_temp, p_result, p_mod); |
| vli_cond_set(p_result, p_temp, p_result, l_borrow); |
| } |
| |
| void vli_modMult_fast(uint32_t *p_result, uint32_t *p_left, |
| uint32_t *p_right) |
| { |
| uint32_t l_product[2 * NUM_ECC_DIGITS]; |
| |
| vli_mult(l_product, p_left, p_right, NUM_ECC_DIGITS); |
| vli_mmod_barrett(p_result, l_product, curve_p, curve_pb); |
| } |
| |
| void vli_modSquare_fast(uint32_t *p_result, uint32_t *p_left) |
| { |
| uint32_t l_product[2 * NUM_ECC_DIGITS]; |
| |
| vli_square(l_product, p_left); |
| vli_mmod_barrett(p_result, l_product, curve_p, curve_pb); |
| } |
| |
| void vli_modMult(uint32_t *p_result, uint32_t *p_left, uint32_t *p_right, |
| uint32_t *p_mod, uint32_t *p_barrett) |
| { |
| |
| uint32_t l_product[2 * NUM_ECC_DIGITS]; |
| |
| vli_mult(l_product, p_left, p_right, NUM_ECC_DIGITS); |
| vli_mmod_barrett(p_result, l_product, p_mod, p_barrett); |
| } |
| |
| void vli_modInv(uint32_t *p_result, uint32_t *p_input, uint32_t *p_mod, |
| uint32_t *p_barrett) |
| { |
| uint32_t p_power[NUM_ECC_DIGITS]; |
| |
| vli_set(p_power, p_mod); |
| p_power[0] -= 2; |
| vli_modExp(p_result, p_input, p_power, p_mod, p_barrett); |
| } |
| |
| uint32_t EccPoint_isZero(EccPoint *p_point) |
| { |
| return (vli_isZero(p_point->x) && vli_isZero(p_point->y)); |
| } |
| |
| uint32_t EccPointJacobi_isZero(EccPointJacobi *p_point_jacobi) |
| { |
| return vli_isZero(p_point_jacobi->Z); |
| } |
| |
| void EccPoint_toAffine(EccPoint *p_point, EccPointJacobi *p_point_jacobi) |
| { |
| |
| if (vli_isZero(p_point_jacobi->Z)) { |
| vli_clear(p_point->x); |
| vli_clear(p_point->y); |
| return; |
| } |
| |
| uint32_t z[NUM_ECC_DIGITS]; |
| |
| vli_set(z, p_point_jacobi->Z); |
| vli_modInv(z, z, curve_p, curve_pb); |
| vli_modSquare_fast(p_point->x, z); |
| vli_modMult_fast(p_point->y, p_point->x, z); |
| vli_modMult_fast(p_point->x, p_point->x, p_point_jacobi->X); |
| vli_modMult_fast(p_point->y, p_point->y, p_point_jacobi->Y); |
| } |
| |
| void EccPoint_add(EccPointJacobi *P1, EccPointJacobi *P2) |
| { |
| |
| uint32_t s1[NUM_ECC_DIGITS], u1[NUM_ECC_DIGITS], t[NUM_ECC_DIGITS]; |
| uint32_t h[NUM_ECC_DIGITS], r[NUM_ECC_DIGITS]; |
| |
| vli_modSquare_fast(r, P1->Z); |
| vli_modSquare_fast(s1, P2->Z); |
| vli_modMult_fast(u1, P1->X, s1); /* u1 = X1 Z2^2 */ |
| vli_modMult_fast(h, P2->X, r); |
| vli_modMult_fast(s1, P1->Y, s1); |
| vli_modMult_fast(s1, s1, P2->Z); /* s1 = Y1 Z2^3 */ |
| vli_modMult_fast(r, P2->Y, r); |
| vli_modMult_fast(r, r, P1->Z); |
| vli_modSub(h, h, u1, curve_p); /* h = X2 Z1^2 - u1 */ |
| vli_modSub(r, r, s1, curve_p); /* r = Y2 Z1^3 - s1 */ |
| |
| if (vli_isZero(h)) { |
| if (vli_isZero(r)) { |
| /* P1 = P2 */ |
| EccPoint_double(P1); |
| return; |
| } |
| /* point at infinity */ |
| vli_clear(P1->Z); |
| return; |
| } |
| |
| vli_modMult_fast(P1->Z, P1->Z, P2->Z); |
| vli_modMult_fast(P1->Z, P1->Z, h); /* Z3 = h Z1 Z2 */ |
| vli_modSquare_fast(t, h); |
| vli_modMult_fast(h, t, h); |
| vli_modMult_fast(u1, u1, t); |
| vli_modSquare_fast(P1->X, r); |
| vli_modSub(P1->X, P1->X, h, curve_p); |
| vli_modSub(P1->X, P1->X, u1, curve_p); |
| vli_modSub(P1->X, P1->X, u1, curve_p); /* X3 = r^2 - h^3 - 2 u1 h^2 */ |
| vli_modMult_fast(t, s1, h); |
| vli_modSub(P1->Y, u1, P1->X, curve_p); |
| vli_modMult_fast(P1->Y, P1->Y, r); |
| vli_modSub(P1->Y, P1->Y, t, curve_p); /* Y3 = r(u1 h^2 - X3) - s1 h^3 */ |
| } |
| |
| /* |
| * Elliptic curve scalar multiplication with result in Jacobi coordinates: |
| * |
| * p_result = p_scalar * p_point. |
| */ |
| void EccPoint_mult(EccPointJacobi *p_result, EccPoint *p_point, uint32_t *p_scalar) |
| { |
| |
| int32_t i; |
| uint32_t bit; |
| EccPointJacobi p_point_jacobi, p_tmp; |
| |
| EccPoint_fromAffine(p_result, p_point); |
| EccPoint_fromAffine(&p_point_jacobi, p_point); |
| |
| for (i = vli_numBits(p_scalar) - 2; i >= 0; i--) { |
| EccPoint_double(p_result); |
| EccPointJacobi_set(&p_tmp, p_result); |
| EccPoint_add(&p_tmp, &p_point_jacobi); |
| bit = vli_testBit(p_scalar, i); |
| vli_cond_set(p_result->X, p_tmp.X, p_result->X, bit); |
| vli_cond_set(p_result->Y, p_tmp.Y, p_result->Y, bit); |
| vli_cond_set(p_result->Z, p_tmp.Z, p_result->Z, bit); |
| } |
| } |
| |
| /* -------- Conversions between big endian and little endian: -------- */ |
| |
| void ecc_bytes2native(uint32_t p_native[NUM_ECC_DIGITS], |
| uint8_t p_bytes[NUM_ECC_DIGITS * 4]) |
| { |
| |
| uint32_t i; |
| |
| for (i = 0; i < NUM_ECC_DIGITS; ++i) { |
| uint8_t *p_digit = p_bytes + 4 * (NUM_ECC_DIGITS - 1 - i); |
| |
| 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]; |
| } |
| } |
| |
| void ecc_native2bytes(uint8_t p_bytes[NUM_ECC_DIGITS * 4], |
| uint32_t p_native[NUM_ECC_DIGITS]) |
| { |
| |
| uint32_t i; |
| |
| for (i = 0; i < NUM_ECC_DIGITS; ++i) { |
| uint8_t *p_digit = p_bytes + 4 * (NUM_ECC_DIGITS - 1 - i); |
| |
| p_digit[0] = p_native[i] >> 24; |
| p_digit[1] = p_native[i] >> 16; |
| p_digit[2] = p_native[i] >> 8; |
| p_digit[3] = p_native[i]; |
| } |
| } |
| |