diff --git a/ctaocrypt/src/ecc.c b/ctaocrypt/src/ecc.c index bd5cb7108..9f03ed2f2 100644 --- a/ctaocrypt/src/ecc.c +++ b/ctaocrypt/src/ecc.c @@ -1,1516 +1 @@ -/* ecc.c - * - * Copyright (C) 2006-2011 Sawtooth Consulting Ltd. - * - * This file is part of CyaSSL. - * - * CyaSSL is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * CyaSSL is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - - -#ifdef HAVE_ECC - -#include "ctc_ecc.h" -#include "asn.h" -#include "error.h" - - -/* map - - ptmul -> mulmod - -*/ - -#define ECC112 -#define ECC128 -#define ECC160 -#define ECC192 -#define ECC224 -#define ECC256 -#define ECC384 -#define ECC521 - - - -/* This holds the key settings. ***MUST*** be organized by size from - smallest to largest. */ - -const ecc_set_type ecc_sets[] = { -#ifdef ECC112 -{ - 14, - "SECP112R1", - "DB7C2ABF62E35E668076BEAD208B", - "659EF8BA043916EEDE8911702B22", - "DB7C2ABF62E35E7628DFAC6561C5", - "09487239995A5EE76B55F9C2F098", - "A89CE5AF8724C0A23E0E0FF77500" -}, -#endif -#ifdef ECC128 -{ - 16, - "SECP128R1", - "FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF", - "E87579C11079F43DD824993C2CEE5ED3", - "FFFFFFFE0000000075A30D1B9038A115", - "161FF7528B899B2D0C28607CA52C5B86", - "CF5AC8395BAFEB13C02DA292DDED7A83", -}, -#endif -#ifdef ECC160 -{ - 20, - "SECP160R1", - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF", - "1C97BEFC54BD7A8B65ACF89F81D4D4ADC565FA45", - "0100000000000000000001F4C8F927AED3CA752257", - "4A96B5688EF573284664698968C38BB913CBFC82", - "23A628553168947D59DCC912042351377AC5FB32", -}, -#endif -#ifdef ECC192 -{ - 24, - "ECC-192", - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF", - "64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1", - "FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831", - "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012", - "7192B95FFC8DA78631011ED6B24CDD573F977A11E794811", -}, -#endif -#ifdef ECC224 -{ - 28, - "ECC-224", - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001", - "B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4", - "FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D", - "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21", - "BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34", -}, -#endif -#ifdef ECC256 -{ - 32, - "ECC-256", - "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF", - "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B", - "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551", - "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296", - "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5", -}, -#endif -#ifdef ECC384 -{ - 48, - "ECC-384", - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF", - "B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF", - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973", - "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7", - "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F", -}, -#endif -#ifdef ECC521 -{ - 66, - "ECC-521", - "1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", - "51953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00", - "1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409", - "C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66", - "11839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650", -}, -#endif -{ - 0, - NULL, NULL, NULL, NULL, NULL, NULL -} -}; - - -ecc_point* ecc_new_point(void); -void ecc_del_point(ecc_point* p); -int ecc_map(ecc_point*, mp_int*, mp_digit*); -int ecc_projective_add_point(ecc_point* P, ecc_point* Q, ecc_point* R, - mp_int* modulus, mp_digit* mp); -int ecc_projective_dbl_point(ecc_point* P, ecc_point* R, mp_int* modulus, - mp_digit* mp); - - -/* helper for either lib */ -static int get_digit_count(mp_int* a) -{ - if (a == NULL) - return 0; - - return a->used; -} - -/* helper for either lib */ -static unsigned long get_digit(mp_int* a, int n) -{ - if (a == NULL) - return 0; - - return (n >= a->used || n < 0) ? 0 : a->dp[n]; -} - - -/** - Add two ECC points - P The point to add - Q The point to add - R [out] The destination of the double - modulus The modulus of the field the ECC curve is in - mp The "b" value from montgomery_setup() - return MP_OKAY on success -*/ -int ecc_projective_add_point(ecc_point* P, ecc_point* Q, ecc_point* R, - mp_int* modulus, mp_digit* mp) -{ - mp_int t1; - mp_int t2; - mp_int x; - mp_int y; - mp_int z; - int err; - - if (P == NULL || Q == NULL || R == NULL || modulus == NULL || mp == NULL) - return ECC_BAD_ARG_E; - - if ((err = mp_init_multi(&t1, &t2, &x, &y, &z, NULL)) != MP_OKAY) { - return err; - } - - /* should we dbl instead? */ - err = mp_sub(modulus, &Q->y, &t1); - - if (err == MP_OKAY) { - if ( (mp_cmp(&P->x, &Q->x) == MP_EQ) && - (get_digit_count(&Q->z) && mp_cmp(&P->z, &Q->z) == MP_EQ) && - (mp_cmp(&P->y, &Q->y) == MP_EQ || mp_cmp(&P->y, &t1) == MP_EQ)) { - mp_clear(&t1); - mp_clear(&t2); - mp_clear(&x); - mp_clear(&y); - mp_clear(&z); - - return ecc_projective_dbl_point(P, R, modulus, mp); - } - } - - if (err == MP_OKAY) - err = mp_copy(&P->x, &x); - if (err == MP_OKAY) - err = mp_copy(&P->y, &y); - if (err == MP_OKAY) - err = mp_copy(&P->z, &z); - - /* if Z is one then these are no-operations */ - if (err == MP_OKAY) { - if (get_digit_count(&Q->z)) { - /* T1 = Z' * Z' */ - err = mp_sqr(&Q->z, &t1); - if (err == MP_OKAY) - err = mp_montgomery_reduce(&t1, modulus, *mp); - - /* X = X * T1 */ - if (err == MP_OKAY) - err = mp_mul(&t1, &x, &x); - if (err == MP_OKAY) - err = mp_montgomery_reduce(&x, modulus, *mp); - - /* T1 = Z' * T1 */ - if (err == MP_OKAY) - err = mp_mul(&Q->z, &t1, &t1); - if (err == MP_OKAY) - err = mp_montgomery_reduce(&t1, modulus, *mp); - - /* Y = Y * T1 */ - if (err == MP_OKAY) - err = mp_mul(&t1, &y, &y); - if (err == MP_OKAY) - err = mp_montgomery_reduce(&y, modulus, *mp); - } - } - - /* T1 = Z*Z */ - if (err == MP_OKAY) - err = mp_sqr(&z, &t1); - if (err == MP_OKAY) - err = mp_montgomery_reduce(&t1, modulus, *mp); - - /* T2 = X' * T1 */ - if (err == MP_OKAY) - err = mp_mul(&Q->x, &t1, &t2); - if (err == MP_OKAY) - err = mp_montgomery_reduce(&t2, modulus, *mp); - - /* T1 = Z * T1 */ - if (err == MP_OKAY) - err = mp_mul(&z, &t1, &t1); - if (err == MP_OKAY) - err = mp_montgomery_reduce(&t1, modulus, *mp); - - /* T1 = Y' * T1 */ - if (err == MP_OKAY) - err = mp_mul(&Q->y, &t1, &t1); - if (err == MP_OKAY) - err = mp_montgomery_reduce(&t1, modulus, *mp); - - /* Y = Y - T1 */ - if (err == MP_OKAY) - err = mp_sub(&y, &t1, &y); - if (err == MP_OKAY) { - if (mp_cmp_d(&y, 0) == MP_LT) - err = mp_add(&y, modulus, &y); - } - /* T1 = 2T1 */ - if (err == MP_OKAY) - err = mp_add(&t1, &t1, &t1); - if (err == MP_OKAY) { - if (mp_cmp(&t1, modulus) != MP_LT) - err = mp_sub(&t1, modulus, &t1); - } - /* T1 = Y + T1 */ - if (err == MP_OKAY) - err = mp_add(&t1, &y, &t1); - if (err == MP_OKAY) { - if (mp_cmp(&t1, modulus) != MP_LT) - err = mp_sub(&t1, modulus, &t1); - } - /* X = X - T2 */ - if (err == MP_OKAY) - err = mp_sub(&x, &t2, &x); - if (err == MP_OKAY) { - if (mp_cmp_d(&x, 0) == MP_LT) - err = mp_add(&x, modulus, &x); - } - /* T2 = 2T2 */ - if (err == MP_OKAY) - err = mp_add(&t2, &t2, &t2); - if (err == MP_OKAY) { - if (mp_cmp(&t2, modulus) != MP_LT) - err = mp_sub(&t2, modulus, &t2); - } - /* T2 = X + T2 */ - if (err == MP_OKAY) - err = mp_add(&t2, &x, &t2); - if (err == MP_OKAY) { - if (mp_cmp(&t2, modulus) != MP_LT) - err = mp_sub(&t2, modulus, &t2); - } - - if (err == MP_OKAY) { - if (get_digit_count(&Q->z)) { - /* Z = Z * Z' */ - err = mp_mul(&z, &Q->z, &z); - if (err == MP_OKAY) - err = mp_montgomery_reduce(&z, modulus, *mp); - } - } - - /* Z = Z * X */ - if (err == MP_OKAY) - err = mp_mul(&z, &x, &z); - if (err == MP_OKAY) - err = mp_montgomery_reduce(&z, modulus, *mp); - - /* T1 = T1 * X */ - if (err == MP_OKAY) - err = mp_mul(&t1, &x, &t1); - if (err == MP_OKAY) - err = mp_montgomery_reduce(&t1, modulus, *mp); - - /* X = X * X */ - if (err == MP_OKAY) - err = mp_sqr(&x, &x); - if (err == MP_OKAY) - err = mp_montgomery_reduce(&x, modulus, *mp); - - /* T2 = T2 * x */ - if (err == MP_OKAY) - err = mp_mul(&t2, &x, &t2); - if (err == MP_OKAY) - err = mp_montgomery_reduce(&t2, modulus, *mp); - - /* T1 = T1 * X */ - if (err == MP_OKAY) - err = mp_mul(&t1, &x, &t1); - if (err == MP_OKAY) - err = mp_montgomery_reduce(&t1, modulus, *mp); - - /* X = Y*Y */ - if (err == MP_OKAY) - err = mp_sqr(&y, &x); - if (err == MP_OKAY) - err = mp_montgomery_reduce(&x, modulus, *mp); - - /* X = X - T2 */ - if (err == MP_OKAY) - err = mp_sub(&x, &t2, &x); - if (err == MP_OKAY) { - if (mp_cmp_d(&x, 0) == MP_LT) - err = mp_add(&x, modulus, &x); - } - /* T2 = T2 - X */ - if (err == MP_OKAY) - err = mp_sub(&t2, &x, &t2); - if (err == MP_OKAY) { - if (mp_cmp_d(&t2, 0) == MP_LT) - err = mp_add(&t2, modulus, &t2); - } - /* T2 = T2 - X */ - if (err == MP_OKAY) - err = mp_sub(&t2, &x, &t2); - if (err == MP_OKAY) { - if (mp_cmp_d(&t2, 0) == MP_LT) - err = mp_add(&t2, modulus, &t2); - } - /* T2 = T2 * Y */ - if (err == MP_OKAY) - err = mp_mul(&t2, &y, &t2); - if (err == MP_OKAY) - err = mp_montgomery_reduce(&t2, modulus, *mp); - - /* Y = T2 - T1 */ - if (err == MP_OKAY) - err = mp_sub(&t2, &t1, &y); - if (err == MP_OKAY) { - if (mp_cmp_d(&y, 0) == MP_LT) - err = mp_add(&y, modulus, &y); - } - /* Y = Y/2 */ - if (err == MP_OKAY) { - if (mp_isodd(&y)) - err = mp_add(&y, modulus, &y); - } - if (err == MP_OKAY) - err = mp_div_2(&y, &y); - - if (err == MP_OKAY) - err = mp_copy(&x, &R->x); - if (err == MP_OKAY) - err = mp_copy(&y, &R->y); - if (err == MP_OKAY) - err = mp_copy(&z, &R->z); - - /* clean up */ - mp_clear(&t1); - mp_clear(&t2); - mp_clear(&x); - mp_clear(&y); - mp_clear(&z); - - return err; -} - - -/** - Double an ECC point - P The point to double - R [out] The destination of the double - modulus The modulus of the field the ECC curve is in - mp The "b" value from montgomery_setup() - return MP_OKAY on success -*/ -int ecc_projective_dbl_point(ecc_point *P, ecc_point *R, mp_int* modulus, - mp_digit* mp) -{ - mp_int t1; - mp_int t2; - int err; - - if (P == NULL || R == NULL || modulus == NULL || mp == NULL) - return ECC_BAD_ARG_E; - - if ((err = mp_init_multi(&t1, &t2, NULL, NULL, NULL, NULL)) != MP_OKAY) { - return err; - } - - if (P != R) { - err = mp_copy(&P->x, &R->x); - if (err == MP_OKAY) - err = mp_copy(&P->y, &R->y); - if (err == MP_OKAY) - err = mp_copy(&P->z, &R->z); - } - - /* t1 = Z * Z */ - if (err == MP_OKAY) - err = mp_sqr(&R->z, &t1); - if (err == MP_OKAY) - err = mp_montgomery_reduce(&t1, modulus, *mp); - - /* Z = Y * Z */ - if (err == MP_OKAY) - err = mp_mul(&R->z, &R->y, &R->z); - if (err == MP_OKAY) - err = mp_montgomery_reduce(&R->z, modulus, *mp); - - /* Z = 2Z */ - if (err == MP_OKAY) - err = mp_add(&R->z, &R->z, &R->z); - if (err == MP_OKAY) { - if (mp_cmp(&R->z, modulus) != MP_LT) - err = mp_sub(&R->z, modulus, &R->z); - } - - /* T2 = X - T1 */ - if (err == MP_OKAY) - err = mp_sub(&R->x, &t1, &t2); - if (err == MP_OKAY) { - if (mp_cmp_d(&t2, 0) == MP_LT) - err = mp_add(&t2, modulus, &t2); - } - /* T1 = X + T1 */ - if (err == MP_OKAY) - err = mp_add(&t1, &R->x, &t1); - if (err == MP_OKAY) { - if (mp_cmp(&t1, modulus) != MP_LT) - err = mp_sub(&t1, modulus, &t1); - } - /* T2 = T1 * T2 */ - if (err == MP_OKAY) - err = mp_mul(&t1, &t2, &t2); - if (err == MP_OKAY) - err = mp_montgomery_reduce(&t2, modulus, *mp); - - /* T1 = 2T2 */ - if (err == MP_OKAY) - err = mp_add(&t2, &t2, &t1); - if (err == MP_OKAY) { - if (mp_cmp(&t1, modulus) != MP_LT) - err = mp_sub(&t1, modulus, &t1); - } - /* T1 = T1 + T2 */ - if (err == MP_OKAY) - err = mp_add(&t1, &t2, &t1); - if (err == MP_OKAY) { - if (mp_cmp(&t1, modulus) != MP_LT) - err = mp_sub(&t1, modulus, &t1); - } - /* Y = 2Y */ - if (err == MP_OKAY) - err = mp_add(&R->y, &R->y, &R->y); - if (err == MP_OKAY) { - if (mp_cmp(&R->y, modulus) != MP_LT) - err = mp_sub(&R->y, modulus, &R->y); - } - /* Y = Y * Y */ - if (err == MP_OKAY) - err = mp_sqr(&R->y, &R->y); - if (err == MP_OKAY) - err = mp_montgomery_reduce(&R->y, modulus, *mp); - - /* T2 = Y * Y */ - if (err == MP_OKAY) - err = mp_sqr(&R->y, &t2); - if (err == MP_OKAY) - err = mp_montgomery_reduce(&t2, modulus, *mp); - - /* T2 = T2/2 */ - if (err == MP_OKAY) { - if (mp_isodd(&t2)) - err = mp_add(&t2, modulus, &t2); - } - if (err == MP_OKAY) - err = mp_div_2(&t2, &t2); - - /* Y = Y * X */ - if (err == MP_OKAY) - err = mp_mul(&R->y, &R->x, &R->y); - if (err == MP_OKAY) - err = mp_montgomery_reduce(&R->y, modulus, *mp); - - /* X = T1 * T1 */ - if (err == MP_OKAY) - err = mp_sqr(&t1, &R->x); - if (err == MP_OKAY) - err = mp_montgomery_reduce(&R->x, modulus, *mp); - - /* X = X - Y */ - if (err == MP_OKAY) - err = mp_sub(&R->x, &R->y, &R->x); - if (err == MP_OKAY) { - if (mp_cmp_d(&R->x, 0) == MP_LT) - err = mp_add(&R->x, modulus, &R->x); - } - /* X = X - Y */ - if (err == MP_OKAY) - err = mp_sub(&R->x, &R->y, &R->x); - if (err == MP_OKAY) { - if (mp_cmp_d(&R->x, 0) == MP_LT) - err = mp_add(&R->x, modulus, &R->x); - } - /* Y = Y - X */ - if (err == MP_OKAY) - err = mp_sub(&R->y, &R->x, &R->y); - if (err == MP_OKAY) { - if (mp_cmp_d(&R->y, 0) == MP_LT) - err = mp_add(&R->y, modulus, &R->y); - } - /* Y = Y * T1 */ - if (err == MP_OKAY) - err = mp_mul(&R->y, &t1, &R->y); - if (err == MP_OKAY) - err = mp_montgomery_reduce(&R->y, modulus, *mp); - - /* Y = Y - T2 */ - if (err == MP_OKAY) - err = mp_sub(&R->y, &t2, &R->y); - if (err == MP_OKAY) { - if (mp_cmp_d(&R->y, 0) == MP_LT) - err = mp_add(&R->y, modulus, &R->y); - } - - /* clean up */ - mp_clear(&t1); - mp_clear(&t2); - - return err; -} - - -/** - Map a projective jacbobian point back to affine space - P [in/out] The point to map - modulus The modulus of the field the ECC curve is in - mp The "b" value from montgomery_setup() - return MP_OKAY on success -*/ -int ecc_map(ecc_point* P, mp_int* modulus, mp_digit* mp) -{ - mp_int t1; - mp_int t2; - int err; - - if (P == NULL || mp == NULL || modulus == NULL) - return ECC_BAD_ARG_E; - - if ((err = mp_init_multi(&t1, &t2, NULL, NULL, NULL, NULL)) != MP_OKAY) { - return MEMORY_E; - } - - /* first map z back to normal */ - err = mp_montgomery_reduce(&P->z, modulus, *mp); - - /* get 1/z */ - if (err == MP_OKAY) - err = mp_invmod(&P->z, modulus, &t1); - - /* get 1/z^2 and 1/z^3 */ - if (err == MP_OKAY) - err = mp_sqr(&t1, &t2); - if (err == MP_OKAY) - err = mp_mod(&t2, modulus, &t2); - if (err == MP_OKAY) - err = mp_mul(&t1, &t2, &t1); - if (err == MP_OKAY) - err = mp_mod(&t1, modulus, &t1); - - /* multiply against x/y */ - if (err == MP_OKAY) - err = mp_mul(&P->x, &t2, &P->x); - if (err == MP_OKAY) - err = mp_montgomery_reduce(&P->x, modulus, *mp); - if (err == MP_OKAY) - err = mp_mul(&P->y, &t1, &P->y); - if (err == MP_OKAY) - err = mp_montgomery_reduce(&P->y, modulus, *mp); - - if (err == MP_OKAY) - mp_set(&P->z, 1); - - /* clean up */ - mp_clear(&t1); - mp_clear(&t2); - - return err; -} - - -#ifndef ECC_TIMING_RESISTANT - -/* size of sliding window, don't change this! */ -#define WINSIZE 4 - -/** - Perform a point multiplication - k The scalar to multiply by - G The base point - R [out] Destination for kG - modulus The modulus of the field the ECC curve is in - map Boolean whether to map back to affine or not - (1==map, 0 == leave in projective) - return MP_OKAY on success -*/ -static int ecc_mulmod(mp_int* k, ecc_point *G, ecc_point *R, mp_int* modulus, - int map) -{ - ecc_point *tG, *M[8]; - int i, j, err; - mp_int mu; - mp_digit mp; - unsigned long buf; - int first, bitbuf, bitcpy, bitcnt, mode, digidx; - - if (k == NULL || G == NULL || R == NULL || modulus == NULL) - return ECC_BAD_ARG_E; - - /* init montgomery reduction */ - if ((err = mp_montgomery_setup(modulus, &mp)) != MP_OKAY) { - return err; - } - if ((err = mp_init(&mu)) != MP_OKAY) { - return err; - } - if ((err = mp_montgomery_calc_normalization(&mu, modulus)) != MP_OKAY) { - mp_clear(&mu); - return err; - } - - /* alloc ram for window temps */ - for (i = 0; i < 8; i++) { - M[i] = ecc_new_point(); - if (M[i] == NULL) { - for (j = 0; j < i; j++) { - ecc_del_point(M[j]); - } - mp_clear(&mu); - return MEMORY_E; - } - } - - /* make a copy of G incase R==G */ - tG = ecc_new_point(); - if (tG == NULL) - err = MEMORY_E; - - /* tG = G and convert to montgomery */ - if (err == MP_OKAY) { - if (mp_cmp_d(&mu, 1) == MP_EQ) { - err = mp_copy(&G->x, &tG->x); - if (err == MP_OKAY) - err = mp_copy(&G->y, &tG->y); - if (err == MP_OKAY) - err = mp_copy(&G->z, &tG->z); - } else { - err = mp_mulmod(&G->x, &mu, modulus, &tG->x); - if (err == MP_OKAY) - err = mp_mulmod(&G->y, &mu, modulus, &tG->y); - if (err == MP_OKAY) - err = mp_mulmod(&G->z, &mu, modulus, &tG->z); - } - } - mp_clear(&mu); - - /* calc the M tab, which holds kG for k==8..15 */ - /* M[0] == 8G */ - if (err == MP_OKAY) - err = ecc_projective_dbl_point(tG, M[0], modulus, &mp); - if (err == MP_OKAY) - err = ecc_projective_dbl_point(M[0], M[0], modulus, &mp); - if (err == MP_OKAY) - err = ecc_projective_dbl_point(M[0], M[0], modulus, &mp); - - /* now find (8+k)G for k=1..7 */ - if (err == MP_OKAY) - for (j = 9; j < 16; j++) { - err = ecc_projective_add_point(M[j-9], tG, M[j-8], modulus, &mp); - if (err != MP_OKAY) break; - } - - /* setup sliding window */ - if (err == MP_OKAY) { - mode = 0; - bitcnt = 1; - buf = 0; - digidx = get_digit_count(k) - 1; - bitcpy = bitbuf = 0; - first = 1; - - /* perform ops */ - for (;;) { - /* grab next digit as required */ - if (--bitcnt == 0) { - if (digidx == -1) { - break; - } - buf = get_digit(k, digidx); - bitcnt = (int) DIGIT_BIT; - --digidx; - } - - /* grab the next msb from the ltiplicand */ - i = (buf >> (DIGIT_BIT - 1)) & 1; - buf <<= 1; - - /* skip leading zero bits */ - if (mode == 0 && i == 0) - continue; - - /* if the bit is zero and mode == 1 then we double */ - if (mode == 1 && i == 0) { - err = ecc_projective_dbl_point(R, R, modulus, &mp); - if (err != MP_OKAY) break; - continue; - } - - /* else we add it to the window */ - bitbuf |= (i << (WINSIZE - ++bitcpy)); - mode = 2; - - if (bitcpy == WINSIZE) { - /* if this is the first window we do a simple copy */ - if (first == 1) { - /* R = kG [k = first window] */ - err = mp_copy(&M[bitbuf-8]->x, &R->x); - if (err != MP_OKAY) break; - - err = mp_copy(&M[bitbuf-8]->y, &R->y); - if (err != MP_OKAY) break; - - err = mp_copy(&M[bitbuf-8]->z, &R->z); - first = 0; - } else { - /* normal window */ - /* ok window is filled so double as required and add */ - /* double first */ - for (j = 0; j < WINSIZE; j++) { - err = ecc_projective_dbl_point(R, R, modulus, &mp); - if (err != MP_OKAY) break; - } - if (err != MP_OKAY) break; /* out of first for(;;) */ - - /* then add, bitbuf will be 8..15 [8..2^WINSIZE] guaranted */ - err = ecc_projective_add_point(R,M[bitbuf-8],R,modulus,&mp); - } - if (err != MP_OKAY) break; - /* empty window and reset */ - bitcpy = bitbuf = 0; - mode = 1; - } - } - } - - /* if bits remain then double/add */ - if (err == MP_OKAY) { - if (mode == 2 && bitcpy > 0) { - /* double then add */ - for (j = 0; j < bitcpy; j++) { - /* only double if we have had at least one add first */ - if (first == 0) { - err = ecc_projective_dbl_point(R, R, modulus, &mp); - if (err != MP_OKAY) break; - } - - bitbuf <<= 1; - if ((bitbuf & (1 << WINSIZE)) != 0) { - if (first == 1) { - /* first add, so copy */ - err = mp_copy(&tG->x, &R->x); - if (err != MP_OKAY) break; - - err = mp_copy(&tG->y, &R->y); - if (err != MP_OKAY) break; - - err = mp_copy(&tG->z, &R->z); - if (err != MP_OKAY) break; - first = 0; - } else { - /* then add */ - err = ecc_projective_add_point(R, tG, R, modulus, &mp); - if (err != MP_OKAY) break; - } - } - } - } - } - - /* map R back from projective space */ - if (err == MP_OKAY && map) - err = ecc_map(R, modulus, &mp); - - mp_clear(&mu); - ecc_del_point(tG); - for (i = 0; i < 8; i++) { - ecc_del_point(M[i]); - } - return err; -} - -#undef WINSIZE -#endif /* ECC_TIMING_RESISTANT */ - - -/** - Allocate a new ECC point - return A newly allocated point or NULL on error -*/ -ecc_point* ecc_new_point(void) -{ - ecc_point* p; - p = XMALLOC(sizeof(ecc_point), 0, DYNAMIC_TYPE_BIGINT); - if (p == NULL) { - return NULL; - } - XMEMSET(p, 0, sizeof(ecc_point)); - if (mp_init_multi(&p->x, &p->y, &p->z, NULL, NULL, NULL) != MP_OKAY) { - XFREE(p, 0, DYNAMIC_TYPE_BIGINT); - return NULL; - } - return p; -} - -/** Free an ECC point from memory - p The point to free -*/ -void ecc_del_point(ecc_point* p) -{ - /* prevents free'ing null arguments */ - if (p != NULL) { - mp_clear(&p->x); - mp_clear(&p->y); - mp_clear(&p->z); - XFREE(p, 0, DYNAMIC_TYPE_BIGINT); - } -} - - -/** Returns whether an ECC idx is valid or not - n The idx number to check - return 1 if valid, 0 if not -*/ -static int ecc_is_valid_idx(int n) -{ - int x; - - for (x = 0; ecc_sets[x].size != 0; x++) - ; - /* -1 is a valid index --- indicating that the domain params - were supplied by the user */ - if ((n >= -1) && (n < x)) { - return 1; - } - return 0; -} - - -/** - Create an ECC shared secret between two keys - private_key The private ECC key - public_key The public key - out [out] Destination of the shared secret - Conforms to EC-DH from ANSI X9.63 - outlen [in/out] The max size and resulting size of the shared secret - return MP_OKAY if successful -*/ -int ecc_shared_secret(ecc_key* private_key, ecc_key* public_key, byte* out, - word32* outlen) -{ - word32 x; - ecc_point* result; - mp_int prime; - int err; - - if (private_key == NULL || public_key == NULL || out == NULL || - outlen == NULL) - return BAD_FUNC_ARG; - - /* type valid? */ - if (private_key->type != ECC_PRIVATEKEY) { - return ECC_BAD_ARG_E; - } - - if (ecc_is_valid_idx(private_key->idx) == 0 || - ecc_is_valid_idx(public_key->idx) == 0) - return ECC_BAD_ARG_E; - - if (XSTRNCMP(private_key->dp->name, public_key->dp->name, ECC_MAXNAME) != 0) - return ECC_BAD_ARG_E; - - /* make new point */ - result = ecc_new_point(); - if (result == NULL) { - return MEMORY_E; - } - - if ((err = mp_init(&prime)) != MP_OKAY) { - ecc_del_point(result); - return err; - } - - err = mp_read_radix(&prime, (char *)private_key->dp->prime, 16); - - if (err == MP_OKAY) - err = ecc_mulmod(&private_key->k, &public_key->pubkey, result, &prime,1); - - if (err == MP_OKAY) { - x = (unsigned long)mp_unsigned_bin_size(&prime); - if (*outlen < x) - err = BUFFER_E; - } - - if (err == MP_OKAY) { - XMEMSET(out, 0, x); - err = mp_to_unsigned_bin(&result->x,out + (x - - mp_unsigned_bin_size(&result->x))); - *outlen = x; - } - - mp_clear(&prime); - ecc_del_point(result); - - return err; -} - - -int ecc_make_key_ex(RNG* rng, ecc_key* key, const ecc_set_type* dp); - -/** - Make a new ECC key - prng An active PRNG state - wprng The index of the PRNG you wish to use - keysize The keysize for the new key (in octets from 20 to 65 bytes) - key [out] Destination of the newly created key - return MP_OKAY if successful, - upon error all allocated memory will be freed -*/ -int ecc_make_key(RNG* rng, int keysize, ecc_key* key) -{ - int x, err; - - /* find key size */ - for (x = 0; (keysize > ecc_sets[x].size) && (ecc_sets[x].size != 0); x++) - ; - keysize = ecc_sets[x].size; - - if (keysize > ECC_MAXSIZE || ecc_sets[x].size == 0) { - return BAD_FUNC_ARG; - } - err = ecc_make_key_ex(rng, key, &ecc_sets[x]); - key->idx = x; - - return err; -} - -int ecc_make_key_ex(RNG* rng, ecc_key* key, const ecc_set_type* dp) -{ - int err; - ecc_point* base; - mp_int prime; - mp_int order; - byte buf[ECC_MAXSIZE]; - int keysize; - - if (key == NULL || rng == NULL || dp == NULL) - return ECC_BAD_ARG_E; - - key->idx = -1; - key->dp = dp; - keysize = dp->size; - - /* allocate ram */ - base = NULL; - - /* make up random string */ - RNG_GenerateBlock(rng, buf, keysize); - buf[0] |= 0x0c; - - /* setup the key variables */ - if ((err = mp_init_multi(&key->pubkey.x, &key->pubkey.y, &key->pubkey.z, - &key->k, &prime, &order)) != MP_OKAY) - return MEMORY_E; - - base = ecc_new_point(); - if (base == NULL) - err = MEMORY_E; - - /* read in the specs for this key */ - if (err == MP_OKAY) - err = mp_read_radix(&prime, (char *)key->dp->prime, 16); - if (err == MP_OKAY) - err = mp_read_radix(&order, (char *)key->dp->order, 16); - if (err == MP_OKAY) - err = mp_read_radix(&base->x, (char *)key->dp->Gx, 16); - if (err == MP_OKAY) - err = mp_read_radix(&base->y, (char *)key->dp->Gy, 16); - - if (err == MP_OKAY) - mp_set(&base->z, 1); - if (err == MP_OKAY) - err = mp_read_unsigned_bin(&key->k, (byte*)buf, keysize); - - /* the key should be smaller than the order of base point */ - if (err == MP_OKAY) { - if (mp_cmp(&key->k, &order) != MP_LT) - err = mp_mod(&key->k, &order, &key->k); - } - /* make the public key */ - if (err == MP_OKAY) - err = ecc_mulmod(&key->k, base, &key->pubkey, &prime, 1); - if (err == MP_OKAY) - key->type = ECC_PRIVATEKEY; - - if (err != MP_OKAY) { - /* clean up */ - mp_clear(&key->pubkey.x); - mp_clear(&key->pubkey.y); - mp_clear(&key->pubkey.z); - mp_clear(&key->k); - } - ecc_del_point(base); - mp_clear(&prime); - mp_clear(&order); -#ifdef ECC_CLEAN_STACK - XMEMSET(buff, 0, ECC_MAXSIZE); -#endif - return err; -} - - -/* Setup dynamic pointers is using normal math for proper freeing */ -void ecc_init(ecc_key* key) -{ -#ifndef USE_FAST_MATH - key->pubkey.x.dp = NULL; - key->pubkey.y.dp = NULL; - key->pubkey.z.dp = NULL; - - key->k.dp = NULL; -#endif -} - - -/** - Sign a message digest - in The message digest to sign - inlen The length of the digest - out [out] The destination for the signature - outlen [in/out] The max size and resulting size of the signature - key A private ECC key - return MP_OKAY if successful -*/ -int ecc_sign_hash(const byte* in, word32 inlen, byte* out, word32 *outlen, - RNG* rng, ecc_key* key) -{ - mp_int r; - mp_int s; - mp_int e; - mp_int p; - int err; - - if (in == NULL || out == NULL || outlen == NULL || key == NULL || rng ==NULL) - return ECC_BAD_ARG_E; - - /* is this a private key? */ - if (key->type != ECC_PRIVATEKEY) { - return ECC_BAD_ARG_E; - } - - /* is the IDX valid ? */ - if (ecc_is_valid_idx(key->idx) != 1) { - return ECC_BAD_ARG_E; - } - - /* get the hash and load it as a bignum into 'e' */ - /* init the bignums */ - if ((err = mp_init_multi(&r, &s, &p, &e, NULL, NULL)) != MP_OKAY) { - return err; - } - err = mp_read_radix(&p, (char *)key->dp->order, 16); - - if (err == MP_OKAY) - err = mp_read_unsigned_bin(&e, (byte*)in, (int)inlen); - - /* make up a key and export the public copy */ - if (err == MP_OKAY) { - ecc_key pubkey; - ecc_init(&pubkey); - for (;;) { - err = ecc_make_key_ex(rng, &pubkey, key->dp); - if (err != MP_OKAY) break; - - /* find r = x1 mod n */ - err = mp_mod(&pubkey.pubkey.x, &p, &r); - if (err != MP_OKAY) break; - - if (mp_iszero(&r) == MP_YES) - ecc_free(&pubkey); - else { - /* find s = (e + xr)/k */ - err = mp_invmod(&pubkey.k, &p, &pubkey.k); - if (err != MP_OKAY) break; - - err = mp_mulmod(&key->k, &r, &p, &s); /* s = xr */ - if (err != MP_OKAY) break; - - err = mp_add(&e, &s, &s); /* s = e + xr */ - if (err != MP_OKAY) break; - - err = mp_mod(&s, &p, &s); /* s = e + xr */ - if (err != MP_OKAY) break; - - err = mp_mulmod(&s, &pubkey.k, &p, &s); /* s = (e + xr)/k */ - if (err != MP_OKAY) break; - - ecc_free(&pubkey); - if (mp_iszero(&s) == MP_NO) - break; - } - } - ecc_free(&pubkey); - } - - /* store as SEQUENCE { r, s -- integer } */ - if (err == MP_OKAY) - err = StoreECC_DSA_Sig(out, outlen, &r, &s); - - mp_clear(&r); - mp_clear(&s); - mp_clear(&p); - mp_clear(&e); - - return err; -} - - -/** - Free an ECC key from memory - key The key you wish to free -*/ -void ecc_free(ecc_key* key) -{ - if (key == NULL) - return; - - mp_clear(&key->pubkey.x); - mp_clear(&key->pubkey.y); - mp_clear(&key->pubkey.z); - mp_clear(&key->k); -} - - -/* verify - * - * w = s^-1 mod n - * u1 = xw - * u2 = rw - * X = u1*G + u2*Q - * v = X_x1 mod n - * accept if v == r - */ - -/** - Verify an ECC signature - sig The signature to verify - siglen The length of the signature (octets) - hash The hash (message digest) that was signed - hashlen The length of the hash (octets) - stat Result of signature, 1==valid, 0==invalid - key The corresponding public ECC key - return MP_OKAY if successful (even if the signature is not valid) -*/ -int ecc_verify_hash(const byte* sig, word32 siglen, byte* hash, word32 hashlen, - int* stat, ecc_key* key) -{ - ecc_point *mG, *mQ; - mp_int r; - mp_int s; - mp_int v; - mp_int w; - mp_int u1; - mp_int u2; - mp_int e; - mp_int p; - mp_int m; - mp_digit mp; - int err; - - if (sig == NULL || hash == NULL || stat == NULL || key == NULL) - return ECC_BAD_ARG_E; - - /* default to invalid signature */ - *stat = 0; - - /* is the IDX valid ? */ - if (ecc_is_valid_idx(key->idx) != 1) { - return ECC_BAD_ARG_E; - } - - /* allocate ints */ - if ((err = mp_init_multi(&r, &s, &v, &w, &u1, &u2)) != MP_OKAY) { - return MEMORY_E; - } - - if ((err = mp_init_multi(&p, &e, &m, NULL, NULL, NULL)) != MP_OKAY) { - mp_clear(&r); - mp_clear(&s); - mp_clear(&v); - mp_clear(&w); - mp_clear(&u1); - mp_clear(&u2); - return MEMORY_E; - } - - /* allocate points */ - mG = ecc_new_point(); - mQ = ecc_new_point(); - if (mQ == NULL || mG == NULL) - err = MEMORY_E; - - if (err == MP_OKAY) - err = DecodeECC_DSA_Sig(sig, siglen, &r, &s); - - /* get the order */ - if (err == MP_OKAY) - err = mp_read_radix(&p, (char *)key->dp->order, 16); - - /* get the modulus */ - if (err == MP_OKAY) - err = mp_read_radix(&m, (char *)key->dp->prime, 16); - - /* check for zero */ - if (err == MP_OKAY) { - if (mp_iszero(&r) || mp_iszero(&s) || mp_cmp(&r, &p) != MP_LT || - mp_cmp(&s, &p) != MP_LT) - err = MP_ZERO_E; - } - /* read hash */ - if (err == MP_OKAY) - err = mp_read_unsigned_bin(&e, (byte*)hash, (int)hashlen); - - /* w = s^-1 mod n */ - if (err == MP_OKAY) - err = mp_invmod(&s, &p, &w); - - /* u1 = ew */ - if (err == MP_OKAY) - err = mp_mulmod(&e, &w, &p, &u1); - - /* u2 = rw */ - if (err == MP_OKAY) - err = mp_mulmod(&r, &w, &p, &u2); - - /* find mG and mQ */ - if (err == MP_OKAY) - err = mp_read_radix(&mG->x, (char *)key->dp->Gx, 16); - - if (err == MP_OKAY) - err = mp_read_radix(&mG->y, (char *)key->dp->Gy, 16); - if (err == MP_OKAY) - mp_set(&mG->z, 1); - - if (err == MP_OKAY) - err = mp_copy(&key->pubkey.x, &mQ->x); - if (err == MP_OKAY) - err = mp_copy(&key->pubkey.y, &mQ->y); - if (err == MP_OKAY) - err = mp_copy(&key->pubkey.z, &mQ->z); - -#ifndef ECC_SHAMIR - /* compute u1*mG + u2*mQ = mG */ - if (err == MP_OKAY) - err = ecc_mulmod(&u1, mG, mG, &m, 0); - if (err == MP_OKAY) - err = ecc_mulmod(&u2, mQ, mQ, &m, 0); - - /* find the montgomery mp */ - if (err == MP_OKAY) - err = mp_montgomery_setup(&m, &mp); - - /* add them */ - if (err == MP_OKAY) - err = ecc_projective_add_point(mQ, mG, mG, &m, &mp); - - /* reduce */ - if (err == MP_OKAY) - err = ecc_map(mG, &m, &mp); -#else - /* use Shamir's trick to compute u1*mG + u2*mQ using half the doubles */ - if (err == MP_OKAY) - err = ecc_mul2add(mG, &u1, mQ, &u2, mG, &m); -#endif /* ECC_SHAMIR */ - - /* v = X_x1 mod n */ - if (err == MP_OKAY) - err = mp_mod(&mG->x, &p, &v); - - /* does v == r */ - if (err == MP_OKAY) { - if (mp_cmp(&v, &r) == MP_EQ) - *stat = 1; - } - - ecc_del_point(mG); - ecc_del_point(mQ); - - mp_clear(&r); - mp_clear(&s); - mp_clear(&v); - mp_clear(&w); - mp_clear(&u1); - mp_clear(&u2); - mp_clear(&p); - mp_clear(&e); - mp_clear(&m); - - return err; -} - - -/* export public ECC key in ANSI X9.63 format */ -int ecc_export_x963(ecc_key* key, byte* out, word32* outLen) -{ - byte buf[ECC_BUFSIZE]; - word32 numlen; - - if (key == NULL || out == NULL || outLen == NULL) - return ECC_BAD_ARG_E; - - if (ecc_is_valid_idx(key->idx) == 0) { - return ECC_BAD_ARG_E; - } - numlen = key->dp->size; - - if (*outLen < (1 + 2*numlen)) { - *outLen = 1 + 2*numlen; - return BUFFER_E; - } - - /* store byte 0x04 */ - out[0] = 0x04; - - /* pad and store x */ - XMEMSET(buf, 0, sizeof(buf)); - mp_to_unsigned_bin(&key->pubkey.x, - buf + (numlen - mp_unsigned_bin_size(&key->pubkey.x))); - XMEMCPY(out+1, buf, numlen); - - /* pad and store y */ - XMEMSET(buf, 0, sizeof(buf)); - mp_to_unsigned_bin(&key->pubkey.y, - buf + (numlen - mp_unsigned_bin_size(&key->pubkey.y))); - XMEMCPY(out+1+numlen, buf, numlen); - - *outLen = 1 + 2*numlen; - - return 0; -} - - -/* import public ECC key in ANSI X9.63 format */ -int ecc_import_x963(const byte* in, word32 inLen, ecc_key* key) -{ - int x, err; - - - if (in == NULL || key == NULL) - return ECC_BAD_ARG_E; - - /* must be odd */ - if ((inLen & 1) == 0) { - return ECC_BAD_ARG_E; - } - - /* init key */ - if (mp_init_multi(&key->pubkey.x, &key->pubkey.y, &key->pubkey.z, &key->k, - NULL, NULL) != MP_OKAY) { - return MEMORY_E; - } - err = MP_OKAY; - - /* check for 4, 6 or 7 */ - if (in[0] != 4 && in[0] != 6 && in[0] != 7) { - err = ASN_PARSE_E; - } - - /* read data */ - if (err == MP_OKAY) - err = mp_read_unsigned_bin(&key->pubkey.x, (byte*)in+1, (inLen-1)>>1); - - if (err == MP_OKAY) - err = mp_read_unsigned_bin(&key->pubkey.y, (byte*)in+1+((inLen-1)>>1), - (inLen-1)>>1); - - if (err == MP_OKAY) - mp_set(&key->pubkey.z, 1); - - if (err == MP_OKAY) { - /* determine the idx */ - for (x = 0; ecc_sets[x].size != 0; x++) { - if ((unsigned)ecc_sets[x].size >= ((inLen-1)>>1)) { - break; - } - } - if (ecc_sets[x].size == 0) { - err = ASN_PARSE_E; - } else { - /* set the idx */ - key->idx = x; - key->dp = &ecc_sets[x]; - key->type = ECC_PUBLICKEY; - } - } - - if (err != MP_OKAY) { - mp_clear(&key->pubkey.x); - mp_clear(&key->pubkey.y); - mp_clear(&key->pubkey.z); - mp_clear(&key->k); - } - - return err; -} - - -/* ecc private key import, public key in ANSI X9.63 format, private raw */ -int ecc_import_private_key(const byte* priv, word32 privSz, const byte* pub, - word32 pubSz, ecc_key* key) -{ - int ret = ecc_import_x963(pub, pubSz, key); - if (ret != 0) - return ret; - - key->type = ECC_PRIVATEKEY; - - return mp_read_unsigned_bin(&key->k, priv, privSz); -} - - -/* key size in octets */ -int ecc_size(ecc_key* key) -{ - if (key == NULL) return 0; - - return key->dp->size; -} - - -/* signature size in octets */ -int ecc_sig_size(ecc_key* key) -{ - int sz = ecc_size(key); - if (sz < 0) - return sz; - - return sz * 2 + SIG_HEADER_SZ; -} - -#endif /* HAVE_ECC */ +/* dummy ecc.c for dist */