cyassl re-port with cellular comms, PSK test

Dependencies:   VodafoneUSBModem_bleedingedge2 mbed-rtos mbed-src

Committer:
ashleymills
Date:
Fri Apr 26 16:54:58 2013 +0000
Revision:
0:e979170e02e7
Basic operation of SSL with PSK working for cellular.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
ashleymills 0:e979170e02e7 1 /* ecc.c
ashleymills 0:e979170e02e7 2 *
ashleymills 0:e979170e02e7 3 * Copyright (C) 2006-2012 Sawtooth Consulting Ltd.
ashleymills 0:e979170e02e7 4 *
ashleymills 0:e979170e02e7 5 * This file is part of CyaSSL.
ashleymills 0:e979170e02e7 6 *
ashleymills 0:e979170e02e7 7 * CyaSSL is free software; you can redistribute it and/or modify
ashleymills 0:e979170e02e7 8 * it under the terms of the GNU General Public License as published by
ashleymills 0:e979170e02e7 9 * the Free Software Foundation; either version 2 of the License, or
ashleymills 0:e979170e02e7 10 * (at your option) any later version.
ashleymills 0:e979170e02e7 11 *
ashleymills 0:e979170e02e7 12 * CyaSSL is distributed in the hope that it will be useful,
ashleymills 0:e979170e02e7 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
ashleymills 0:e979170e02e7 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
ashleymills 0:e979170e02e7 15 * GNU General Public License for more details.
ashleymills 0:e979170e02e7 16 *
ashleymills 0:e979170e02e7 17 * You should have received a copy of the GNU General Public License
ashleymills 0:e979170e02e7 18 * along with this program; if not, write to the Free Software
ashleymills 0:e979170e02e7 19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
ashleymills 0:e979170e02e7 20 */
ashleymills 0:e979170e02e7 21
ashleymills 0:e979170e02e7 22
ashleymills 0:e979170e02e7 23 #ifdef HAVE_CONFIG_H
ashleymills 0:e979170e02e7 24 #include <config.h>
ashleymills 0:e979170e02e7 25 #endif
ashleymills 0:e979170e02e7 26
ashleymills 0:e979170e02e7 27 /* in case user set HAVE_ECC there */
ashleymills 0:e979170e02e7 28 #include <cyassl/ctaocrypt/settings.h>
ashleymills 0:e979170e02e7 29
ashleymills 0:e979170e02e7 30 #ifdef HAVE_ECC
ashleymills 0:e979170e02e7 31
ashleymills 0:e979170e02e7 32 #include <cyassl/ctaocrypt/ecc.h>
ashleymills 0:e979170e02e7 33 #include <cyassl/ctaocrypt/asn.h>
ashleymills 0:e979170e02e7 34 #include <cyassl/ctaocrypt/error.h>
ashleymills 0:e979170e02e7 35
ashleymills 0:e979170e02e7 36
ashleymills 0:e979170e02e7 37 /* map
ashleymills 0:e979170e02e7 38
ashleymills 0:e979170e02e7 39 ptmul -> mulmod
ashleymills 0:e979170e02e7 40
ashleymills 0:e979170e02e7 41 */
ashleymills 0:e979170e02e7 42
ashleymills 0:e979170e02e7 43 #define ECC112
ashleymills 0:e979170e02e7 44 #define ECC128
ashleymills 0:e979170e02e7 45 #define ECC160
ashleymills 0:e979170e02e7 46 #define ECC192
ashleymills 0:e979170e02e7 47 #define ECC224
ashleymills 0:e979170e02e7 48 #define ECC256
ashleymills 0:e979170e02e7 49 #define ECC384
ashleymills 0:e979170e02e7 50 #define ECC521
ashleymills 0:e979170e02e7 51
ashleymills 0:e979170e02e7 52
ashleymills 0:e979170e02e7 53
ashleymills 0:e979170e02e7 54 /* This holds the key settings. ***MUST*** be organized by size from
ashleymills 0:e979170e02e7 55 smallest to largest. */
ashleymills 0:e979170e02e7 56
ashleymills 0:e979170e02e7 57 const ecc_set_type ecc_sets[] = {
ashleymills 0:e979170e02e7 58 #ifdef ECC112
ashleymills 0:e979170e02e7 59 {
ashleymills 0:e979170e02e7 60 14,
ashleymills 0:e979170e02e7 61 "SECP112R1",
ashleymills 0:e979170e02e7 62 "DB7C2ABF62E35E668076BEAD208B",
ashleymills 0:e979170e02e7 63 "659EF8BA043916EEDE8911702B22",
ashleymills 0:e979170e02e7 64 "DB7C2ABF62E35E7628DFAC6561C5",
ashleymills 0:e979170e02e7 65 "09487239995A5EE76B55F9C2F098",
ashleymills 0:e979170e02e7 66 "A89CE5AF8724C0A23E0E0FF77500"
ashleymills 0:e979170e02e7 67 },
ashleymills 0:e979170e02e7 68 #endif
ashleymills 0:e979170e02e7 69 #ifdef ECC128
ashleymills 0:e979170e02e7 70 {
ashleymills 0:e979170e02e7 71 16,
ashleymills 0:e979170e02e7 72 "SECP128R1",
ashleymills 0:e979170e02e7 73 "FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF",
ashleymills 0:e979170e02e7 74 "E87579C11079F43DD824993C2CEE5ED3",
ashleymills 0:e979170e02e7 75 "FFFFFFFE0000000075A30D1B9038A115",
ashleymills 0:e979170e02e7 76 "161FF7528B899B2D0C28607CA52C5B86",
ashleymills 0:e979170e02e7 77 "CF5AC8395BAFEB13C02DA292DDED7A83",
ashleymills 0:e979170e02e7 78 },
ashleymills 0:e979170e02e7 79 #endif
ashleymills 0:e979170e02e7 80 #ifdef ECC160
ashleymills 0:e979170e02e7 81 {
ashleymills 0:e979170e02e7 82 20,
ashleymills 0:e979170e02e7 83 "SECP160R1",
ashleymills 0:e979170e02e7 84 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF",
ashleymills 0:e979170e02e7 85 "1C97BEFC54BD7A8B65ACF89F81D4D4ADC565FA45",
ashleymills 0:e979170e02e7 86 "0100000000000000000001F4C8F927AED3CA752257",
ashleymills 0:e979170e02e7 87 "4A96B5688EF573284664698968C38BB913CBFC82",
ashleymills 0:e979170e02e7 88 "23A628553168947D59DCC912042351377AC5FB32",
ashleymills 0:e979170e02e7 89 },
ashleymills 0:e979170e02e7 90 #endif
ashleymills 0:e979170e02e7 91 #ifdef ECC192
ashleymills 0:e979170e02e7 92 {
ashleymills 0:e979170e02e7 93 24,
ashleymills 0:e979170e02e7 94 "ECC-192",
ashleymills 0:e979170e02e7 95 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF",
ashleymills 0:e979170e02e7 96 "64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1",
ashleymills 0:e979170e02e7 97 "FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831",
ashleymills 0:e979170e02e7 98 "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012",
ashleymills 0:e979170e02e7 99 "7192B95FFC8DA78631011ED6B24CDD573F977A11E794811",
ashleymills 0:e979170e02e7 100 },
ashleymills 0:e979170e02e7 101 #endif
ashleymills 0:e979170e02e7 102 #ifdef ECC224
ashleymills 0:e979170e02e7 103 {
ashleymills 0:e979170e02e7 104 28,
ashleymills 0:e979170e02e7 105 "ECC-224",
ashleymills 0:e979170e02e7 106 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001",
ashleymills 0:e979170e02e7 107 "B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4",
ashleymills 0:e979170e02e7 108 "FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D",
ashleymills 0:e979170e02e7 109 "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21",
ashleymills 0:e979170e02e7 110 "BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34",
ashleymills 0:e979170e02e7 111 },
ashleymills 0:e979170e02e7 112 #endif
ashleymills 0:e979170e02e7 113 #ifdef ECC256
ashleymills 0:e979170e02e7 114 {
ashleymills 0:e979170e02e7 115 32,
ashleymills 0:e979170e02e7 116 "ECC-256",
ashleymills 0:e979170e02e7 117 "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF",
ashleymills 0:e979170e02e7 118 "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B",
ashleymills 0:e979170e02e7 119 "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551",
ashleymills 0:e979170e02e7 120 "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296",
ashleymills 0:e979170e02e7 121 "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5",
ashleymills 0:e979170e02e7 122 },
ashleymills 0:e979170e02e7 123 #endif
ashleymills 0:e979170e02e7 124 #ifdef ECC384
ashleymills 0:e979170e02e7 125 {
ashleymills 0:e979170e02e7 126 48,
ashleymills 0:e979170e02e7 127 "ECC-384",
ashleymills 0:e979170e02e7 128 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF",
ashleymills 0:e979170e02e7 129 "B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF",
ashleymills 0:e979170e02e7 130 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973",
ashleymills 0:e979170e02e7 131 "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7",
ashleymills 0:e979170e02e7 132 "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F",
ashleymills 0:e979170e02e7 133 },
ashleymills 0:e979170e02e7 134 #endif
ashleymills 0:e979170e02e7 135 #ifdef ECC521
ashleymills 0:e979170e02e7 136 {
ashleymills 0:e979170e02e7 137 66,
ashleymills 0:e979170e02e7 138 "ECC-521",
ashleymills 0:e979170e02e7 139 "1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
ashleymills 0:e979170e02e7 140 "51953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00",
ashleymills 0:e979170e02e7 141 "1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409",
ashleymills 0:e979170e02e7 142 "C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66",
ashleymills 0:e979170e02e7 143 "11839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650",
ashleymills 0:e979170e02e7 144 },
ashleymills 0:e979170e02e7 145 #endif
ashleymills 0:e979170e02e7 146 {
ashleymills 0:e979170e02e7 147 0,
ashleymills 0:e979170e02e7 148 NULL, NULL, NULL, NULL, NULL, NULL
ashleymills 0:e979170e02e7 149 }
ashleymills 0:e979170e02e7 150 };
ashleymills 0:e979170e02e7 151
ashleymills 0:e979170e02e7 152
ashleymills 0:e979170e02e7 153 ecc_point* ecc_new_point(void);
ashleymills 0:e979170e02e7 154 void ecc_del_point(ecc_point* p);
ashleymills 0:e979170e02e7 155 int ecc_map(ecc_point*, mp_int*, mp_digit*);
ashleymills 0:e979170e02e7 156 int ecc_projective_add_point(ecc_point* P, ecc_point* Q, ecc_point* R,
ashleymills 0:e979170e02e7 157 mp_int* modulus, mp_digit* mp);
ashleymills 0:e979170e02e7 158 int ecc_projective_dbl_point(ecc_point* P, ecc_point* R, mp_int* modulus,
ashleymills 0:e979170e02e7 159 mp_digit* mp);
ashleymills 0:e979170e02e7 160
ashleymills 0:e979170e02e7 161
ashleymills 0:e979170e02e7 162 /* helper for either lib */
ashleymills 0:e979170e02e7 163 static int get_digit_count(mp_int* a)
ashleymills 0:e979170e02e7 164 {
ashleymills 0:e979170e02e7 165 if (a == NULL)
ashleymills 0:e979170e02e7 166 return 0;
ashleymills 0:e979170e02e7 167
ashleymills 0:e979170e02e7 168 return a->used;
ashleymills 0:e979170e02e7 169 }
ashleymills 0:e979170e02e7 170
ashleymills 0:e979170e02e7 171 /* helper for either lib */
ashleymills 0:e979170e02e7 172 static unsigned long get_digit(mp_int* a, int n)
ashleymills 0:e979170e02e7 173 {
ashleymills 0:e979170e02e7 174 if (a == NULL)
ashleymills 0:e979170e02e7 175 return 0;
ashleymills 0:e979170e02e7 176
ashleymills 0:e979170e02e7 177 return (n >= a->used || n < 0) ? 0 : a->dp[n];
ashleymills 0:e979170e02e7 178 }
ashleymills 0:e979170e02e7 179
ashleymills 0:e979170e02e7 180
ashleymills 0:e979170e02e7 181 /**
ashleymills 0:e979170e02e7 182 Add two ECC points
ashleymills 0:e979170e02e7 183 P The point to add
ashleymills 0:e979170e02e7 184 Q The point to add
ashleymills 0:e979170e02e7 185 R [out] The destination of the double
ashleymills 0:e979170e02e7 186 modulus The modulus of the field the ECC curve is in
ashleymills 0:e979170e02e7 187 mp The "b" value from montgomery_setup()
ashleymills 0:e979170e02e7 188 return MP_OKAY on success
ashleymills 0:e979170e02e7 189 */
ashleymills 0:e979170e02e7 190 int ecc_projective_add_point(ecc_point* P, ecc_point* Q, ecc_point* R,
ashleymills 0:e979170e02e7 191 mp_int* modulus, mp_digit* mp)
ashleymills 0:e979170e02e7 192 {
ashleymills 0:e979170e02e7 193 mp_int t1;
ashleymills 0:e979170e02e7 194 mp_int t2;
ashleymills 0:e979170e02e7 195 mp_int x;
ashleymills 0:e979170e02e7 196 mp_int y;
ashleymills 0:e979170e02e7 197 mp_int z;
ashleymills 0:e979170e02e7 198 int err;
ashleymills 0:e979170e02e7 199
ashleymills 0:e979170e02e7 200 if (P == NULL || Q == NULL || R == NULL || modulus == NULL || mp == NULL)
ashleymills 0:e979170e02e7 201 return ECC_BAD_ARG_E;
ashleymills 0:e979170e02e7 202
ashleymills 0:e979170e02e7 203 if ((err = mp_init_multi(&t1, &t2, &x, &y, &z, NULL)) != MP_OKAY) {
ashleymills 0:e979170e02e7 204 return err;
ashleymills 0:e979170e02e7 205 }
ashleymills 0:e979170e02e7 206
ashleymills 0:e979170e02e7 207 /* should we dbl instead? */
ashleymills 0:e979170e02e7 208 err = mp_sub(modulus, &Q->y, &t1);
ashleymills 0:e979170e02e7 209
ashleymills 0:e979170e02e7 210 if (err == MP_OKAY) {
ashleymills 0:e979170e02e7 211 if ( (mp_cmp(&P->x, &Q->x) == MP_EQ) &&
ashleymills 0:e979170e02e7 212 (get_digit_count(&Q->z) && mp_cmp(&P->z, &Q->z) == MP_EQ) &&
ashleymills 0:e979170e02e7 213 (mp_cmp(&P->y, &Q->y) == MP_EQ || mp_cmp(&P->y, &t1) == MP_EQ)) {
ashleymills 0:e979170e02e7 214 mp_clear(&t1);
ashleymills 0:e979170e02e7 215 mp_clear(&t2);
ashleymills 0:e979170e02e7 216 mp_clear(&x);
ashleymills 0:e979170e02e7 217 mp_clear(&y);
ashleymills 0:e979170e02e7 218 mp_clear(&z);
ashleymills 0:e979170e02e7 219
ashleymills 0:e979170e02e7 220 return ecc_projective_dbl_point(P, R, modulus, mp);
ashleymills 0:e979170e02e7 221 }
ashleymills 0:e979170e02e7 222 }
ashleymills 0:e979170e02e7 223
ashleymills 0:e979170e02e7 224 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 225 err = mp_copy(&P->x, &x);
ashleymills 0:e979170e02e7 226 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 227 err = mp_copy(&P->y, &y);
ashleymills 0:e979170e02e7 228 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 229 err = mp_copy(&P->z, &z);
ashleymills 0:e979170e02e7 230
ashleymills 0:e979170e02e7 231 /* if Z is one then these are no-operations */
ashleymills 0:e979170e02e7 232 if (err == MP_OKAY) {
ashleymills 0:e979170e02e7 233 if (get_digit_count(&Q->z)) {
ashleymills 0:e979170e02e7 234 /* T1 = Z' * Z' */
ashleymills 0:e979170e02e7 235 err = mp_sqr(&Q->z, &t1);
ashleymills 0:e979170e02e7 236 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 237 err = mp_montgomery_reduce(&t1, modulus, *mp);
ashleymills 0:e979170e02e7 238
ashleymills 0:e979170e02e7 239 /* X = X * T1 */
ashleymills 0:e979170e02e7 240 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 241 err = mp_mul(&t1, &x, &x);
ashleymills 0:e979170e02e7 242 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 243 err = mp_montgomery_reduce(&x, modulus, *mp);
ashleymills 0:e979170e02e7 244
ashleymills 0:e979170e02e7 245 /* T1 = Z' * T1 */
ashleymills 0:e979170e02e7 246 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 247 err = mp_mul(&Q->z, &t1, &t1);
ashleymills 0:e979170e02e7 248 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 249 err = mp_montgomery_reduce(&t1, modulus, *mp);
ashleymills 0:e979170e02e7 250
ashleymills 0:e979170e02e7 251 /* Y = Y * T1 */
ashleymills 0:e979170e02e7 252 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 253 err = mp_mul(&t1, &y, &y);
ashleymills 0:e979170e02e7 254 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 255 err = mp_montgomery_reduce(&y, modulus, *mp);
ashleymills 0:e979170e02e7 256 }
ashleymills 0:e979170e02e7 257 }
ashleymills 0:e979170e02e7 258
ashleymills 0:e979170e02e7 259 /* T1 = Z*Z */
ashleymills 0:e979170e02e7 260 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 261 err = mp_sqr(&z, &t1);
ashleymills 0:e979170e02e7 262 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 263 err = mp_montgomery_reduce(&t1, modulus, *mp);
ashleymills 0:e979170e02e7 264
ashleymills 0:e979170e02e7 265 /* T2 = X' * T1 */
ashleymills 0:e979170e02e7 266 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 267 err = mp_mul(&Q->x, &t1, &t2);
ashleymills 0:e979170e02e7 268 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 269 err = mp_montgomery_reduce(&t2, modulus, *mp);
ashleymills 0:e979170e02e7 270
ashleymills 0:e979170e02e7 271 /* T1 = Z * T1 */
ashleymills 0:e979170e02e7 272 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 273 err = mp_mul(&z, &t1, &t1);
ashleymills 0:e979170e02e7 274 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 275 err = mp_montgomery_reduce(&t1, modulus, *mp);
ashleymills 0:e979170e02e7 276
ashleymills 0:e979170e02e7 277 /* T1 = Y' * T1 */
ashleymills 0:e979170e02e7 278 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 279 err = mp_mul(&Q->y, &t1, &t1);
ashleymills 0:e979170e02e7 280 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 281 err = mp_montgomery_reduce(&t1, modulus, *mp);
ashleymills 0:e979170e02e7 282
ashleymills 0:e979170e02e7 283 /* Y = Y - T1 */
ashleymills 0:e979170e02e7 284 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 285 err = mp_sub(&y, &t1, &y);
ashleymills 0:e979170e02e7 286 if (err == MP_OKAY) {
ashleymills 0:e979170e02e7 287 if (mp_cmp_d(&y, 0) == MP_LT)
ashleymills 0:e979170e02e7 288 err = mp_add(&y, modulus, &y);
ashleymills 0:e979170e02e7 289 }
ashleymills 0:e979170e02e7 290 /* T1 = 2T1 */
ashleymills 0:e979170e02e7 291 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 292 err = mp_add(&t1, &t1, &t1);
ashleymills 0:e979170e02e7 293 if (err == MP_OKAY) {
ashleymills 0:e979170e02e7 294 if (mp_cmp(&t1, modulus) != MP_LT)
ashleymills 0:e979170e02e7 295 err = mp_sub(&t1, modulus, &t1);
ashleymills 0:e979170e02e7 296 }
ashleymills 0:e979170e02e7 297 /* T1 = Y + T1 */
ashleymills 0:e979170e02e7 298 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 299 err = mp_add(&t1, &y, &t1);
ashleymills 0:e979170e02e7 300 if (err == MP_OKAY) {
ashleymills 0:e979170e02e7 301 if (mp_cmp(&t1, modulus) != MP_LT)
ashleymills 0:e979170e02e7 302 err = mp_sub(&t1, modulus, &t1);
ashleymills 0:e979170e02e7 303 }
ashleymills 0:e979170e02e7 304 /* X = X - T2 */
ashleymills 0:e979170e02e7 305 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 306 err = mp_sub(&x, &t2, &x);
ashleymills 0:e979170e02e7 307 if (err == MP_OKAY) {
ashleymills 0:e979170e02e7 308 if (mp_cmp_d(&x, 0) == MP_LT)
ashleymills 0:e979170e02e7 309 err = mp_add(&x, modulus, &x);
ashleymills 0:e979170e02e7 310 }
ashleymills 0:e979170e02e7 311 /* T2 = 2T2 */
ashleymills 0:e979170e02e7 312 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 313 err = mp_add(&t2, &t2, &t2);
ashleymills 0:e979170e02e7 314 if (err == MP_OKAY) {
ashleymills 0:e979170e02e7 315 if (mp_cmp(&t2, modulus) != MP_LT)
ashleymills 0:e979170e02e7 316 err = mp_sub(&t2, modulus, &t2);
ashleymills 0:e979170e02e7 317 }
ashleymills 0:e979170e02e7 318 /* T2 = X + T2 */
ashleymills 0:e979170e02e7 319 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 320 err = mp_add(&t2, &x, &t2);
ashleymills 0:e979170e02e7 321 if (err == MP_OKAY) {
ashleymills 0:e979170e02e7 322 if (mp_cmp(&t2, modulus) != MP_LT)
ashleymills 0:e979170e02e7 323 err = mp_sub(&t2, modulus, &t2);
ashleymills 0:e979170e02e7 324 }
ashleymills 0:e979170e02e7 325
ashleymills 0:e979170e02e7 326 if (err == MP_OKAY) {
ashleymills 0:e979170e02e7 327 if (get_digit_count(&Q->z)) {
ashleymills 0:e979170e02e7 328 /* Z = Z * Z' */
ashleymills 0:e979170e02e7 329 err = mp_mul(&z, &Q->z, &z);
ashleymills 0:e979170e02e7 330 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 331 err = mp_montgomery_reduce(&z, modulus, *mp);
ashleymills 0:e979170e02e7 332 }
ashleymills 0:e979170e02e7 333 }
ashleymills 0:e979170e02e7 334
ashleymills 0:e979170e02e7 335 /* Z = Z * X */
ashleymills 0:e979170e02e7 336 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 337 err = mp_mul(&z, &x, &z);
ashleymills 0:e979170e02e7 338 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 339 err = mp_montgomery_reduce(&z, modulus, *mp);
ashleymills 0:e979170e02e7 340
ashleymills 0:e979170e02e7 341 /* T1 = T1 * X */
ashleymills 0:e979170e02e7 342 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 343 err = mp_mul(&t1, &x, &t1);
ashleymills 0:e979170e02e7 344 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 345 err = mp_montgomery_reduce(&t1, modulus, *mp);
ashleymills 0:e979170e02e7 346
ashleymills 0:e979170e02e7 347 /* X = X * X */
ashleymills 0:e979170e02e7 348 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 349 err = mp_sqr(&x, &x);
ashleymills 0:e979170e02e7 350 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 351 err = mp_montgomery_reduce(&x, modulus, *mp);
ashleymills 0:e979170e02e7 352
ashleymills 0:e979170e02e7 353 /* T2 = T2 * x */
ashleymills 0:e979170e02e7 354 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 355 err = mp_mul(&t2, &x, &t2);
ashleymills 0:e979170e02e7 356 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 357 err = mp_montgomery_reduce(&t2, modulus, *mp);
ashleymills 0:e979170e02e7 358
ashleymills 0:e979170e02e7 359 /* T1 = T1 * X */
ashleymills 0:e979170e02e7 360 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 361 err = mp_mul(&t1, &x, &t1);
ashleymills 0:e979170e02e7 362 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 363 err = mp_montgomery_reduce(&t1, modulus, *mp);
ashleymills 0:e979170e02e7 364
ashleymills 0:e979170e02e7 365 /* X = Y*Y */
ashleymills 0:e979170e02e7 366 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 367 err = mp_sqr(&y, &x);
ashleymills 0:e979170e02e7 368 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 369 err = mp_montgomery_reduce(&x, modulus, *mp);
ashleymills 0:e979170e02e7 370
ashleymills 0:e979170e02e7 371 /* X = X - T2 */
ashleymills 0:e979170e02e7 372 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 373 err = mp_sub(&x, &t2, &x);
ashleymills 0:e979170e02e7 374 if (err == MP_OKAY) {
ashleymills 0:e979170e02e7 375 if (mp_cmp_d(&x, 0) == MP_LT)
ashleymills 0:e979170e02e7 376 err = mp_add(&x, modulus, &x);
ashleymills 0:e979170e02e7 377 }
ashleymills 0:e979170e02e7 378 /* T2 = T2 - X */
ashleymills 0:e979170e02e7 379 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 380 err = mp_sub(&t2, &x, &t2);
ashleymills 0:e979170e02e7 381 if (err == MP_OKAY) {
ashleymills 0:e979170e02e7 382 if (mp_cmp_d(&t2, 0) == MP_LT)
ashleymills 0:e979170e02e7 383 err = mp_add(&t2, modulus, &t2);
ashleymills 0:e979170e02e7 384 }
ashleymills 0:e979170e02e7 385 /* T2 = T2 - X */
ashleymills 0:e979170e02e7 386 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 387 err = mp_sub(&t2, &x, &t2);
ashleymills 0:e979170e02e7 388 if (err == MP_OKAY) {
ashleymills 0:e979170e02e7 389 if (mp_cmp_d(&t2, 0) == MP_LT)
ashleymills 0:e979170e02e7 390 err = mp_add(&t2, modulus, &t2);
ashleymills 0:e979170e02e7 391 }
ashleymills 0:e979170e02e7 392 /* T2 = T2 * Y */
ashleymills 0:e979170e02e7 393 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 394 err = mp_mul(&t2, &y, &t2);
ashleymills 0:e979170e02e7 395 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 396 err = mp_montgomery_reduce(&t2, modulus, *mp);
ashleymills 0:e979170e02e7 397
ashleymills 0:e979170e02e7 398 /* Y = T2 - T1 */
ashleymills 0:e979170e02e7 399 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 400 err = mp_sub(&t2, &t1, &y);
ashleymills 0:e979170e02e7 401 if (err == MP_OKAY) {
ashleymills 0:e979170e02e7 402 if (mp_cmp_d(&y, 0) == MP_LT)
ashleymills 0:e979170e02e7 403 err = mp_add(&y, modulus, &y);
ashleymills 0:e979170e02e7 404 }
ashleymills 0:e979170e02e7 405 /* Y = Y/2 */
ashleymills 0:e979170e02e7 406 if (err == MP_OKAY) {
ashleymills 0:e979170e02e7 407 if (mp_isodd(&y))
ashleymills 0:e979170e02e7 408 err = mp_add(&y, modulus, &y);
ashleymills 0:e979170e02e7 409 }
ashleymills 0:e979170e02e7 410 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 411 err = mp_div_2(&y, &y);
ashleymills 0:e979170e02e7 412
ashleymills 0:e979170e02e7 413 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 414 err = mp_copy(&x, &R->x);
ashleymills 0:e979170e02e7 415 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 416 err = mp_copy(&y, &R->y);
ashleymills 0:e979170e02e7 417 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 418 err = mp_copy(&z, &R->z);
ashleymills 0:e979170e02e7 419
ashleymills 0:e979170e02e7 420 /* clean up */
ashleymills 0:e979170e02e7 421 mp_clear(&t1);
ashleymills 0:e979170e02e7 422 mp_clear(&t2);
ashleymills 0:e979170e02e7 423 mp_clear(&x);
ashleymills 0:e979170e02e7 424 mp_clear(&y);
ashleymills 0:e979170e02e7 425 mp_clear(&z);
ashleymills 0:e979170e02e7 426
ashleymills 0:e979170e02e7 427 return err;
ashleymills 0:e979170e02e7 428 }
ashleymills 0:e979170e02e7 429
ashleymills 0:e979170e02e7 430
ashleymills 0:e979170e02e7 431 /**
ashleymills 0:e979170e02e7 432 Double an ECC point
ashleymills 0:e979170e02e7 433 P The point to double
ashleymills 0:e979170e02e7 434 R [out] The destination of the double
ashleymills 0:e979170e02e7 435 modulus The modulus of the field the ECC curve is in
ashleymills 0:e979170e02e7 436 mp The "b" value from montgomery_setup()
ashleymills 0:e979170e02e7 437 return MP_OKAY on success
ashleymills 0:e979170e02e7 438 */
ashleymills 0:e979170e02e7 439 int ecc_projective_dbl_point(ecc_point *P, ecc_point *R, mp_int* modulus,
ashleymills 0:e979170e02e7 440 mp_digit* mp)
ashleymills 0:e979170e02e7 441 {
ashleymills 0:e979170e02e7 442 mp_int t1;
ashleymills 0:e979170e02e7 443 mp_int t2;
ashleymills 0:e979170e02e7 444 int err;
ashleymills 0:e979170e02e7 445
ashleymills 0:e979170e02e7 446 if (P == NULL || R == NULL || modulus == NULL || mp == NULL)
ashleymills 0:e979170e02e7 447 return ECC_BAD_ARG_E;
ashleymills 0:e979170e02e7 448
ashleymills 0:e979170e02e7 449 if ((err = mp_init_multi(&t1, &t2, NULL, NULL, NULL, NULL)) != MP_OKAY) {
ashleymills 0:e979170e02e7 450 return err;
ashleymills 0:e979170e02e7 451 }
ashleymills 0:e979170e02e7 452
ashleymills 0:e979170e02e7 453 if (P != R) {
ashleymills 0:e979170e02e7 454 err = mp_copy(&P->x, &R->x);
ashleymills 0:e979170e02e7 455 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 456 err = mp_copy(&P->y, &R->y);
ashleymills 0:e979170e02e7 457 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 458 err = mp_copy(&P->z, &R->z);
ashleymills 0:e979170e02e7 459 }
ashleymills 0:e979170e02e7 460
ashleymills 0:e979170e02e7 461 /* t1 = Z * Z */
ashleymills 0:e979170e02e7 462 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 463 err = mp_sqr(&R->z, &t1);
ashleymills 0:e979170e02e7 464 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 465 err = mp_montgomery_reduce(&t1, modulus, *mp);
ashleymills 0:e979170e02e7 466
ashleymills 0:e979170e02e7 467 /* Z = Y * Z */
ashleymills 0:e979170e02e7 468 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 469 err = mp_mul(&R->z, &R->y, &R->z);
ashleymills 0:e979170e02e7 470 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 471 err = mp_montgomery_reduce(&R->z, modulus, *mp);
ashleymills 0:e979170e02e7 472
ashleymills 0:e979170e02e7 473 /* Z = 2Z */
ashleymills 0:e979170e02e7 474 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 475 err = mp_add(&R->z, &R->z, &R->z);
ashleymills 0:e979170e02e7 476 if (err == MP_OKAY) {
ashleymills 0:e979170e02e7 477 if (mp_cmp(&R->z, modulus) != MP_LT)
ashleymills 0:e979170e02e7 478 err = mp_sub(&R->z, modulus, &R->z);
ashleymills 0:e979170e02e7 479 }
ashleymills 0:e979170e02e7 480
ashleymills 0:e979170e02e7 481 /* T2 = X - T1 */
ashleymills 0:e979170e02e7 482 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 483 err = mp_sub(&R->x, &t1, &t2);
ashleymills 0:e979170e02e7 484 if (err == MP_OKAY) {
ashleymills 0:e979170e02e7 485 if (mp_cmp_d(&t2, 0) == MP_LT)
ashleymills 0:e979170e02e7 486 err = mp_add(&t2, modulus, &t2);
ashleymills 0:e979170e02e7 487 }
ashleymills 0:e979170e02e7 488 /* T1 = X + T1 */
ashleymills 0:e979170e02e7 489 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 490 err = mp_add(&t1, &R->x, &t1);
ashleymills 0:e979170e02e7 491 if (err == MP_OKAY) {
ashleymills 0:e979170e02e7 492 if (mp_cmp(&t1, modulus) != MP_LT)
ashleymills 0:e979170e02e7 493 err = mp_sub(&t1, modulus, &t1);
ashleymills 0:e979170e02e7 494 }
ashleymills 0:e979170e02e7 495 /* T2 = T1 * T2 */
ashleymills 0:e979170e02e7 496 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 497 err = mp_mul(&t1, &t2, &t2);
ashleymills 0:e979170e02e7 498 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 499 err = mp_montgomery_reduce(&t2, modulus, *mp);
ashleymills 0:e979170e02e7 500
ashleymills 0:e979170e02e7 501 /* T1 = 2T2 */
ashleymills 0:e979170e02e7 502 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 503 err = mp_add(&t2, &t2, &t1);
ashleymills 0:e979170e02e7 504 if (err == MP_OKAY) {
ashleymills 0:e979170e02e7 505 if (mp_cmp(&t1, modulus) != MP_LT)
ashleymills 0:e979170e02e7 506 err = mp_sub(&t1, modulus, &t1);
ashleymills 0:e979170e02e7 507 }
ashleymills 0:e979170e02e7 508 /* T1 = T1 + T2 */
ashleymills 0:e979170e02e7 509 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 510 err = mp_add(&t1, &t2, &t1);
ashleymills 0:e979170e02e7 511 if (err == MP_OKAY) {
ashleymills 0:e979170e02e7 512 if (mp_cmp(&t1, modulus) != MP_LT)
ashleymills 0:e979170e02e7 513 err = mp_sub(&t1, modulus, &t1);
ashleymills 0:e979170e02e7 514 }
ashleymills 0:e979170e02e7 515 /* Y = 2Y */
ashleymills 0:e979170e02e7 516 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 517 err = mp_add(&R->y, &R->y, &R->y);
ashleymills 0:e979170e02e7 518 if (err == MP_OKAY) {
ashleymills 0:e979170e02e7 519 if (mp_cmp(&R->y, modulus) != MP_LT)
ashleymills 0:e979170e02e7 520 err = mp_sub(&R->y, modulus, &R->y);
ashleymills 0:e979170e02e7 521 }
ashleymills 0:e979170e02e7 522 /* Y = Y * Y */
ashleymills 0:e979170e02e7 523 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 524 err = mp_sqr(&R->y, &R->y);
ashleymills 0:e979170e02e7 525 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 526 err = mp_montgomery_reduce(&R->y, modulus, *mp);
ashleymills 0:e979170e02e7 527
ashleymills 0:e979170e02e7 528 /* T2 = Y * Y */
ashleymills 0:e979170e02e7 529 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 530 err = mp_sqr(&R->y, &t2);
ashleymills 0:e979170e02e7 531 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 532 err = mp_montgomery_reduce(&t2, modulus, *mp);
ashleymills 0:e979170e02e7 533
ashleymills 0:e979170e02e7 534 /* T2 = T2/2 */
ashleymills 0:e979170e02e7 535 if (err == MP_OKAY) {
ashleymills 0:e979170e02e7 536 if (mp_isodd(&t2))
ashleymills 0:e979170e02e7 537 err = mp_add(&t2, modulus, &t2);
ashleymills 0:e979170e02e7 538 }
ashleymills 0:e979170e02e7 539 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 540 err = mp_div_2(&t2, &t2);
ashleymills 0:e979170e02e7 541
ashleymills 0:e979170e02e7 542 /* Y = Y * X */
ashleymills 0:e979170e02e7 543 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 544 err = mp_mul(&R->y, &R->x, &R->y);
ashleymills 0:e979170e02e7 545 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 546 err = mp_montgomery_reduce(&R->y, modulus, *mp);
ashleymills 0:e979170e02e7 547
ashleymills 0:e979170e02e7 548 /* X = T1 * T1 */
ashleymills 0:e979170e02e7 549 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 550 err = mp_sqr(&t1, &R->x);
ashleymills 0:e979170e02e7 551 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 552 err = mp_montgomery_reduce(&R->x, modulus, *mp);
ashleymills 0:e979170e02e7 553
ashleymills 0:e979170e02e7 554 /* X = X - Y */
ashleymills 0:e979170e02e7 555 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 556 err = mp_sub(&R->x, &R->y, &R->x);
ashleymills 0:e979170e02e7 557 if (err == MP_OKAY) {
ashleymills 0:e979170e02e7 558 if (mp_cmp_d(&R->x, 0) == MP_LT)
ashleymills 0:e979170e02e7 559 err = mp_add(&R->x, modulus, &R->x);
ashleymills 0:e979170e02e7 560 }
ashleymills 0:e979170e02e7 561 /* X = X - Y */
ashleymills 0:e979170e02e7 562 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 563 err = mp_sub(&R->x, &R->y, &R->x);
ashleymills 0:e979170e02e7 564 if (err == MP_OKAY) {
ashleymills 0:e979170e02e7 565 if (mp_cmp_d(&R->x, 0) == MP_LT)
ashleymills 0:e979170e02e7 566 err = mp_add(&R->x, modulus, &R->x);
ashleymills 0:e979170e02e7 567 }
ashleymills 0:e979170e02e7 568 /* Y = Y - X */
ashleymills 0:e979170e02e7 569 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 570 err = mp_sub(&R->y, &R->x, &R->y);
ashleymills 0:e979170e02e7 571 if (err == MP_OKAY) {
ashleymills 0:e979170e02e7 572 if (mp_cmp_d(&R->y, 0) == MP_LT)
ashleymills 0:e979170e02e7 573 err = mp_add(&R->y, modulus, &R->y);
ashleymills 0:e979170e02e7 574 }
ashleymills 0:e979170e02e7 575 /* Y = Y * T1 */
ashleymills 0:e979170e02e7 576 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 577 err = mp_mul(&R->y, &t1, &R->y);
ashleymills 0:e979170e02e7 578 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 579 err = mp_montgomery_reduce(&R->y, modulus, *mp);
ashleymills 0:e979170e02e7 580
ashleymills 0:e979170e02e7 581 /* Y = Y - T2 */
ashleymills 0:e979170e02e7 582 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 583 err = mp_sub(&R->y, &t2, &R->y);
ashleymills 0:e979170e02e7 584 if (err == MP_OKAY) {
ashleymills 0:e979170e02e7 585 if (mp_cmp_d(&R->y, 0) == MP_LT)
ashleymills 0:e979170e02e7 586 err = mp_add(&R->y, modulus, &R->y);
ashleymills 0:e979170e02e7 587 }
ashleymills 0:e979170e02e7 588
ashleymills 0:e979170e02e7 589 /* clean up */
ashleymills 0:e979170e02e7 590 mp_clear(&t1);
ashleymills 0:e979170e02e7 591 mp_clear(&t2);
ashleymills 0:e979170e02e7 592
ashleymills 0:e979170e02e7 593 return err;
ashleymills 0:e979170e02e7 594 }
ashleymills 0:e979170e02e7 595
ashleymills 0:e979170e02e7 596
ashleymills 0:e979170e02e7 597 /**
ashleymills 0:e979170e02e7 598 Map a projective jacbobian point back to affine space
ashleymills 0:e979170e02e7 599 P [in/out] The point to map
ashleymills 0:e979170e02e7 600 modulus The modulus of the field the ECC curve is in
ashleymills 0:e979170e02e7 601 mp The "b" value from montgomery_setup()
ashleymills 0:e979170e02e7 602 return MP_OKAY on success
ashleymills 0:e979170e02e7 603 */
ashleymills 0:e979170e02e7 604 int ecc_map(ecc_point* P, mp_int* modulus, mp_digit* mp)
ashleymills 0:e979170e02e7 605 {
ashleymills 0:e979170e02e7 606 mp_int t1;
ashleymills 0:e979170e02e7 607 mp_int t2;
ashleymills 0:e979170e02e7 608 int err;
ashleymills 0:e979170e02e7 609
ashleymills 0:e979170e02e7 610 if (P == NULL || mp == NULL || modulus == NULL)
ashleymills 0:e979170e02e7 611 return ECC_BAD_ARG_E;
ashleymills 0:e979170e02e7 612
ashleymills 0:e979170e02e7 613 if ((err = mp_init_multi(&t1, &t2, NULL, NULL, NULL, NULL)) != MP_OKAY) {
ashleymills 0:e979170e02e7 614 return MEMORY_E;
ashleymills 0:e979170e02e7 615 }
ashleymills 0:e979170e02e7 616
ashleymills 0:e979170e02e7 617 /* first map z back to normal */
ashleymills 0:e979170e02e7 618 err = mp_montgomery_reduce(&P->z, modulus, *mp);
ashleymills 0:e979170e02e7 619
ashleymills 0:e979170e02e7 620 /* get 1/z */
ashleymills 0:e979170e02e7 621 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 622 err = mp_invmod(&P->z, modulus, &t1);
ashleymills 0:e979170e02e7 623
ashleymills 0:e979170e02e7 624 /* get 1/z^2 and 1/z^3 */
ashleymills 0:e979170e02e7 625 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 626 err = mp_sqr(&t1, &t2);
ashleymills 0:e979170e02e7 627 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 628 err = mp_mod(&t2, modulus, &t2);
ashleymills 0:e979170e02e7 629 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 630 err = mp_mul(&t1, &t2, &t1);
ashleymills 0:e979170e02e7 631 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 632 err = mp_mod(&t1, modulus, &t1);
ashleymills 0:e979170e02e7 633
ashleymills 0:e979170e02e7 634 /* multiply against x/y */
ashleymills 0:e979170e02e7 635 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 636 err = mp_mul(&P->x, &t2, &P->x);
ashleymills 0:e979170e02e7 637 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 638 err = mp_montgomery_reduce(&P->x, modulus, *mp);
ashleymills 0:e979170e02e7 639 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 640 err = mp_mul(&P->y, &t1, &P->y);
ashleymills 0:e979170e02e7 641 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 642 err = mp_montgomery_reduce(&P->y, modulus, *mp);
ashleymills 0:e979170e02e7 643
ashleymills 0:e979170e02e7 644 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 645 mp_set(&P->z, 1);
ashleymills 0:e979170e02e7 646
ashleymills 0:e979170e02e7 647 /* clean up */
ashleymills 0:e979170e02e7 648 mp_clear(&t1);
ashleymills 0:e979170e02e7 649 mp_clear(&t2);
ashleymills 0:e979170e02e7 650
ashleymills 0:e979170e02e7 651 return err;
ashleymills 0:e979170e02e7 652 }
ashleymills 0:e979170e02e7 653
ashleymills 0:e979170e02e7 654
ashleymills 0:e979170e02e7 655 #ifndef ECC_TIMING_RESISTANT
ashleymills 0:e979170e02e7 656
ashleymills 0:e979170e02e7 657 /* size of sliding window, don't change this! */
ashleymills 0:e979170e02e7 658 #define WINSIZE 4
ashleymills 0:e979170e02e7 659
ashleymills 0:e979170e02e7 660 /**
ashleymills 0:e979170e02e7 661 Perform a point multiplication
ashleymills 0:e979170e02e7 662 k The scalar to multiply by
ashleymills 0:e979170e02e7 663 G The base point
ashleymills 0:e979170e02e7 664 R [out] Destination for kG
ashleymills 0:e979170e02e7 665 modulus The modulus of the field the ECC curve is in
ashleymills 0:e979170e02e7 666 map Boolean whether to map back to affine or not
ashleymills 0:e979170e02e7 667 (1==map, 0 == leave in projective)
ashleymills 0:e979170e02e7 668 return MP_OKAY on success
ashleymills 0:e979170e02e7 669 */
ashleymills 0:e979170e02e7 670 static int ecc_mulmod(mp_int* k, ecc_point *G, ecc_point *R, mp_int* modulus,
ashleymills 0:e979170e02e7 671 int map)
ashleymills 0:e979170e02e7 672 {
ashleymills 0:e979170e02e7 673 ecc_point *tG, *M[8];
ashleymills 0:e979170e02e7 674 int i, j, err;
ashleymills 0:e979170e02e7 675 mp_int mu;
ashleymills 0:e979170e02e7 676 mp_digit mp;
ashleymills 0:e979170e02e7 677 unsigned long buf;
ashleymills 0:e979170e02e7 678 int first, bitbuf, bitcpy, bitcnt, mode, digidx;
ashleymills 0:e979170e02e7 679
ashleymills 0:e979170e02e7 680 if (k == NULL || G == NULL || R == NULL || modulus == NULL)
ashleymills 0:e979170e02e7 681 return ECC_BAD_ARG_E;
ashleymills 0:e979170e02e7 682
ashleymills 0:e979170e02e7 683 /* init montgomery reduction */
ashleymills 0:e979170e02e7 684 if ((err = mp_montgomery_setup(modulus, &mp)) != MP_OKAY) {
ashleymills 0:e979170e02e7 685 return err;
ashleymills 0:e979170e02e7 686 }
ashleymills 0:e979170e02e7 687 if ((err = mp_init(&mu)) != MP_OKAY) {
ashleymills 0:e979170e02e7 688 return err;
ashleymills 0:e979170e02e7 689 }
ashleymills 0:e979170e02e7 690 if ((err = mp_montgomery_calc_normalization(&mu, modulus)) != MP_OKAY) {
ashleymills 0:e979170e02e7 691 mp_clear(&mu);
ashleymills 0:e979170e02e7 692 return err;
ashleymills 0:e979170e02e7 693 }
ashleymills 0:e979170e02e7 694
ashleymills 0:e979170e02e7 695 /* alloc ram for window temps */
ashleymills 0:e979170e02e7 696 for (i = 0; i < 8; i++) {
ashleymills 0:e979170e02e7 697 M[i] = ecc_new_point();
ashleymills 0:e979170e02e7 698 if (M[i] == NULL) {
ashleymills 0:e979170e02e7 699 for (j = 0; j < i; j++) {
ashleymills 0:e979170e02e7 700 ecc_del_point(M[j]);
ashleymills 0:e979170e02e7 701 }
ashleymills 0:e979170e02e7 702 mp_clear(&mu);
ashleymills 0:e979170e02e7 703 return MEMORY_E;
ashleymills 0:e979170e02e7 704 }
ashleymills 0:e979170e02e7 705 }
ashleymills 0:e979170e02e7 706
ashleymills 0:e979170e02e7 707 /* make a copy of G incase R==G */
ashleymills 0:e979170e02e7 708 tG = ecc_new_point();
ashleymills 0:e979170e02e7 709 if (tG == NULL)
ashleymills 0:e979170e02e7 710 err = MEMORY_E;
ashleymills 0:e979170e02e7 711
ashleymills 0:e979170e02e7 712 /* tG = G and convert to montgomery */
ashleymills 0:e979170e02e7 713 if (err == MP_OKAY) {
ashleymills 0:e979170e02e7 714 if (mp_cmp_d(&mu, 1) == MP_EQ) {
ashleymills 0:e979170e02e7 715 err = mp_copy(&G->x, &tG->x);
ashleymills 0:e979170e02e7 716 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 717 err = mp_copy(&G->y, &tG->y);
ashleymills 0:e979170e02e7 718 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 719 err = mp_copy(&G->z, &tG->z);
ashleymills 0:e979170e02e7 720 } else {
ashleymills 0:e979170e02e7 721 err = mp_mulmod(&G->x, &mu, modulus, &tG->x);
ashleymills 0:e979170e02e7 722 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 723 err = mp_mulmod(&G->y, &mu, modulus, &tG->y);
ashleymills 0:e979170e02e7 724 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 725 err = mp_mulmod(&G->z, &mu, modulus, &tG->z);
ashleymills 0:e979170e02e7 726 }
ashleymills 0:e979170e02e7 727 }
ashleymills 0:e979170e02e7 728 mp_clear(&mu);
ashleymills 0:e979170e02e7 729
ashleymills 0:e979170e02e7 730 /* calc the M tab, which holds kG for k==8..15 */
ashleymills 0:e979170e02e7 731 /* M[0] == 8G */
ashleymills 0:e979170e02e7 732 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 733 err = ecc_projective_dbl_point(tG, M[0], modulus, &mp);
ashleymills 0:e979170e02e7 734 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 735 err = ecc_projective_dbl_point(M[0], M[0], modulus, &mp);
ashleymills 0:e979170e02e7 736 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 737 err = ecc_projective_dbl_point(M[0], M[0], modulus, &mp);
ashleymills 0:e979170e02e7 738
ashleymills 0:e979170e02e7 739 /* now find (8+k)G for k=1..7 */
ashleymills 0:e979170e02e7 740 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 741 for (j = 9; j < 16; j++) {
ashleymills 0:e979170e02e7 742 err = ecc_projective_add_point(M[j-9], tG, M[j-8], modulus, &mp);
ashleymills 0:e979170e02e7 743 if (err != MP_OKAY) break;
ashleymills 0:e979170e02e7 744 }
ashleymills 0:e979170e02e7 745
ashleymills 0:e979170e02e7 746 /* setup sliding window */
ashleymills 0:e979170e02e7 747 if (err == MP_OKAY) {
ashleymills 0:e979170e02e7 748 mode = 0;
ashleymills 0:e979170e02e7 749 bitcnt = 1;
ashleymills 0:e979170e02e7 750 buf = 0;
ashleymills 0:e979170e02e7 751 digidx = get_digit_count(k) - 1;
ashleymills 0:e979170e02e7 752 bitcpy = bitbuf = 0;
ashleymills 0:e979170e02e7 753 first = 1;
ashleymills 0:e979170e02e7 754
ashleymills 0:e979170e02e7 755 /* perform ops */
ashleymills 0:e979170e02e7 756 for (;;) {
ashleymills 0:e979170e02e7 757 /* grab next digit as required */
ashleymills 0:e979170e02e7 758 if (--bitcnt == 0) {
ashleymills 0:e979170e02e7 759 if (digidx == -1) {
ashleymills 0:e979170e02e7 760 break;
ashleymills 0:e979170e02e7 761 }
ashleymills 0:e979170e02e7 762 buf = get_digit(k, digidx);
ashleymills 0:e979170e02e7 763 bitcnt = (int) DIGIT_BIT;
ashleymills 0:e979170e02e7 764 --digidx;
ashleymills 0:e979170e02e7 765 }
ashleymills 0:e979170e02e7 766
ashleymills 0:e979170e02e7 767 /* grab the next msb from the ltiplicand */
ashleymills 0:e979170e02e7 768 i = (int)(buf >> (DIGIT_BIT - 1)) & 1;
ashleymills 0:e979170e02e7 769 buf <<= 1;
ashleymills 0:e979170e02e7 770
ashleymills 0:e979170e02e7 771 /* skip leading zero bits */
ashleymills 0:e979170e02e7 772 if (mode == 0 && i == 0)
ashleymills 0:e979170e02e7 773 continue;
ashleymills 0:e979170e02e7 774
ashleymills 0:e979170e02e7 775 /* if the bit is zero and mode == 1 then we double */
ashleymills 0:e979170e02e7 776 if (mode == 1 && i == 0) {
ashleymills 0:e979170e02e7 777 err = ecc_projective_dbl_point(R, R, modulus, &mp);
ashleymills 0:e979170e02e7 778 if (err != MP_OKAY) break;
ashleymills 0:e979170e02e7 779 continue;
ashleymills 0:e979170e02e7 780 }
ashleymills 0:e979170e02e7 781
ashleymills 0:e979170e02e7 782 /* else we add it to the window */
ashleymills 0:e979170e02e7 783 bitbuf |= (i << (WINSIZE - ++bitcpy));
ashleymills 0:e979170e02e7 784 mode = 2;
ashleymills 0:e979170e02e7 785
ashleymills 0:e979170e02e7 786 if (bitcpy == WINSIZE) {
ashleymills 0:e979170e02e7 787 /* if this is the first window we do a simple copy */
ashleymills 0:e979170e02e7 788 if (first == 1) {
ashleymills 0:e979170e02e7 789 /* R = kG [k = first window] */
ashleymills 0:e979170e02e7 790 err = mp_copy(&M[bitbuf-8]->x, &R->x);
ashleymills 0:e979170e02e7 791 if (err != MP_OKAY) break;
ashleymills 0:e979170e02e7 792
ashleymills 0:e979170e02e7 793 err = mp_copy(&M[bitbuf-8]->y, &R->y);
ashleymills 0:e979170e02e7 794 if (err != MP_OKAY) break;
ashleymills 0:e979170e02e7 795
ashleymills 0:e979170e02e7 796 err = mp_copy(&M[bitbuf-8]->z, &R->z);
ashleymills 0:e979170e02e7 797 first = 0;
ashleymills 0:e979170e02e7 798 } else {
ashleymills 0:e979170e02e7 799 /* normal window */
ashleymills 0:e979170e02e7 800 /* ok window is filled so double as required and add */
ashleymills 0:e979170e02e7 801 /* double first */
ashleymills 0:e979170e02e7 802 for (j = 0; j < WINSIZE; j++) {
ashleymills 0:e979170e02e7 803 err = ecc_projective_dbl_point(R, R, modulus, &mp);
ashleymills 0:e979170e02e7 804 if (err != MP_OKAY) break;
ashleymills 0:e979170e02e7 805 }
ashleymills 0:e979170e02e7 806 if (err != MP_OKAY) break; /* out of first for(;;) */
ashleymills 0:e979170e02e7 807
ashleymills 0:e979170e02e7 808 /* then add, bitbuf will be 8..15 [8..2^WINSIZE] guaranted */
ashleymills 0:e979170e02e7 809 err = ecc_projective_add_point(R,M[bitbuf-8],R,modulus,&mp);
ashleymills 0:e979170e02e7 810 }
ashleymills 0:e979170e02e7 811 if (err != MP_OKAY) break;
ashleymills 0:e979170e02e7 812 /* empty window and reset */
ashleymills 0:e979170e02e7 813 bitcpy = bitbuf = 0;
ashleymills 0:e979170e02e7 814 mode = 1;
ashleymills 0:e979170e02e7 815 }
ashleymills 0:e979170e02e7 816 }
ashleymills 0:e979170e02e7 817 }
ashleymills 0:e979170e02e7 818
ashleymills 0:e979170e02e7 819 /* if bits remain then double/add */
ashleymills 0:e979170e02e7 820 if (err == MP_OKAY) {
ashleymills 0:e979170e02e7 821 if (mode == 2 && bitcpy > 0) {
ashleymills 0:e979170e02e7 822 /* double then add */
ashleymills 0:e979170e02e7 823 for (j = 0; j < bitcpy; j++) {
ashleymills 0:e979170e02e7 824 /* only double if we have had at least one add first */
ashleymills 0:e979170e02e7 825 if (first == 0) {
ashleymills 0:e979170e02e7 826 err = ecc_projective_dbl_point(R, R, modulus, &mp);
ashleymills 0:e979170e02e7 827 if (err != MP_OKAY) break;
ashleymills 0:e979170e02e7 828 }
ashleymills 0:e979170e02e7 829
ashleymills 0:e979170e02e7 830 bitbuf <<= 1;
ashleymills 0:e979170e02e7 831 if ((bitbuf & (1 << WINSIZE)) != 0) {
ashleymills 0:e979170e02e7 832 if (first == 1) {
ashleymills 0:e979170e02e7 833 /* first add, so copy */
ashleymills 0:e979170e02e7 834 err = mp_copy(&tG->x, &R->x);
ashleymills 0:e979170e02e7 835 if (err != MP_OKAY) break;
ashleymills 0:e979170e02e7 836
ashleymills 0:e979170e02e7 837 err = mp_copy(&tG->y, &R->y);
ashleymills 0:e979170e02e7 838 if (err != MP_OKAY) break;
ashleymills 0:e979170e02e7 839
ashleymills 0:e979170e02e7 840 err = mp_copy(&tG->z, &R->z);
ashleymills 0:e979170e02e7 841 if (err != MP_OKAY) break;
ashleymills 0:e979170e02e7 842 first = 0;
ashleymills 0:e979170e02e7 843 } else {
ashleymills 0:e979170e02e7 844 /* then add */
ashleymills 0:e979170e02e7 845 err = ecc_projective_add_point(R, tG, R, modulus, &mp);
ashleymills 0:e979170e02e7 846 if (err != MP_OKAY) break;
ashleymills 0:e979170e02e7 847 }
ashleymills 0:e979170e02e7 848 }
ashleymills 0:e979170e02e7 849 }
ashleymills 0:e979170e02e7 850 }
ashleymills 0:e979170e02e7 851 }
ashleymills 0:e979170e02e7 852
ashleymills 0:e979170e02e7 853 /* map R back from projective space */
ashleymills 0:e979170e02e7 854 if (err == MP_OKAY && map)
ashleymills 0:e979170e02e7 855 err = ecc_map(R, modulus, &mp);
ashleymills 0:e979170e02e7 856
ashleymills 0:e979170e02e7 857 mp_clear(&mu);
ashleymills 0:e979170e02e7 858 ecc_del_point(tG);
ashleymills 0:e979170e02e7 859 for (i = 0; i < 8; i++) {
ashleymills 0:e979170e02e7 860 ecc_del_point(M[i]);
ashleymills 0:e979170e02e7 861 }
ashleymills 0:e979170e02e7 862 return err;
ashleymills 0:e979170e02e7 863 }
ashleymills 0:e979170e02e7 864
ashleymills 0:e979170e02e7 865 #undef WINSIZE
ashleymills 0:e979170e02e7 866 #endif /* ECC_TIMING_RESISTANT */
ashleymills 0:e979170e02e7 867
ashleymills 0:e979170e02e7 868
ashleymills 0:e979170e02e7 869 /**
ashleymills 0:e979170e02e7 870 Allocate a new ECC point
ashleymills 0:e979170e02e7 871 return A newly allocated point or NULL on error
ashleymills 0:e979170e02e7 872 */
ashleymills 0:e979170e02e7 873 ecc_point* ecc_new_point(void)
ashleymills 0:e979170e02e7 874 {
ashleymills 0:e979170e02e7 875 ecc_point* p;
ashleymills 0:e979170e02e7 876 p = (ecc_point*)XMALLOC(sizeof(ecc_point), 0, DYNAMIC_TYPE_BIGINT);
ashleymills 0:e979170e02e7 877 if (p == NULL) {
ashleymills 0:e979170e02e7 878 return NULL;
ashleymills 0:e979170e02e7 879 }
ashleymills 0:e979170e02e7 880 XMEMSET(p, 0, sizeof(ecc_point));
ashleymills 0:e979170e02e7 881 if (mp_init_multi(&p->x, &p->y, &p->z, NULL, NULL, NULL) != MP_OKAY) {
ashleymills 0:e979170e02e7 882 XFREE(p, 0, DYNAMIC_TYPE_BIGINT);
ashleymills 0:e979170e02e7 883 return NULL;
ashleymills 0:e979170e02e7 884 }
ashleymills 0:e979170e02e7 885 return p;
ashleymills 0:e979170e02e7 886 }
ashleymills 0:e979170e02e7 887
ashleymills 0:e979170e02e7 888 /** Free an ECC point from memory
ashleymills 0:e979170e02e7 889 p The point to free
ashleymills 0:e979170e02e7 890 */
ashleymills 0:e979170e02e7 891 void ecc_del_point(ecc_point* p)
ashleymills 0:e979170e02e7 892 {
ashleymills 0:e979170e02e7 893 /* prevents free'ing null arguments */
ashleymills 0:e979170e02e7 894 if (p != NULL) {
ashleymills 0:e979170e02e7 895 mp_clear(&p->x);
ashleymills 0:e979170e02e7 896 mp_clear(&p->y);
ashleymills 0:e979170e02e7 897 mp_clear(&p->z);
ashleymills 0:e979170e02e7 898 XFREE(p, 0, DYNAMIC_TYPE_BIGINT);
ashleymills 0:e979170e02e7 899 }
ashleymills 0:e979170e02e7 900 }
ashleymills 0:e979170e02e7 901
ashleymills 0:e979170e02e7 902
ashleymills 0:e979170e02e7 903 /** Returns whether an ECC idx is valid or not
ashleymills 0:e979170e02e7 904 n The idx number to check
ashleymills 0:e979170e02e7 905 return 1 if valid, 0 if not
ashleymills 0:e979170e02e7 906 */
ashleymills 0:e979170e02e7 907 static int ecc_is_valid_idx(int n)
ashleymills 0:e979170e02e7 908 {
ashleymills 0:e979170e02e7 909 int x;
ashleymills 0:e979170e02e7 910
ashleymills 0:e979170e02e7 911 for (x = 0; ecc_sets[x].size != 0; x++)
ashleymills 0:e979170e02e7 912 ;
ashleymills 0:e979170e02e7 913 /* -1 is a valid index --- indicating that the domain params
ashleymills 0:e979170e02e7 914 were supplied by the user */
ashleymills 0:e979170e02e7 915 if ((n >= -1) && (n < x)) {
ashleymills 0:e979170e02e7 916 return 1;
ashleymills 0:e979170e02e7 917 }
ashleymills 0:e979170e02e7 918 return 0;
ashleymills 0:e979170e02e7 919 }
ashleymills 0:e979170e02e7 920
ashleymills 0:e979170e02e7 921
ashleymills 0:e979170e02e7 922 /**
ashleymills 0:e979170e02e7 923 Create an ECC shared secret between two keys
ashleymills 0:e979170e02e7 924 private_key The private ECC key
ashleymills 0:e979170e02e7 925 public_key The public key
ashleymills 0:e979170e02e7 926 out [out] Destination of the shared secret
ashleymills 0:e979170e02e7 927 Conforms to EC-DH from ANSI X9.63
ashleymills 0:e979170e02e7 928 outlen [in/out] The max size and resulting size of the shared secret
ashleymills 0:e979170e02e7 929 return MP_OKAY if successful
ashleymills 0:e979170e02e7 930 */
ashleymills 0:e979170e02e7 931 int ecc_shared_secret(ecc_key* private_key, ecc_key* public_key, byte* out,
ashleymills 0:e979170e02e7 932 word32* outlen)
ashleymills 0:e979170e02e7 933 {
ashleymills 0:e979170e02e7 934 word32 x = 0;
ashleymills 0:e979170e02e7 935 ecc_point* result;
ashleymills 0:e979170e02e7 936 mp_int prime;
ashleymills 0:e979170e02e7 937 int err;
ashleymills 0:e979170e02e7 938
ashleymills 0:e979170e02e7 939 if (private_key == NULL || public_key == NULL || out == NULL ||
ashleymills 0:e979170e02e7 940 outlen == NULL)
ashleymills 0:e979170e02e7 941 return BAD_FUNC_ARG;
ashleymills 0:e979170e02e7 942
ashleymills 0:e979170e02e7 943 /* type valid? */
ashleymills 0:e979170e02e7 944 if (private_key->type != ECC_PRIVATEKEY) {
ashleymills 0:e979170e02e7 945 return ECC_BAD_ARG_E;
ashleymills 0:e979170e02e7 946 }
ashleymills 0:e979170e02e7 947
ashleymills 0:e979170e02e7 948 if (ecc_is_valid_idx(private_key->idx) == 0 ||
ashleymills 0:e979170e02e7 949 ecc_is_valid_idx(public_key->idx) == 0)
ashleymills 0:e979170e02e7 950 return ECC_BAD_ARG_E;
ashleymills 0:e979170e02e7 951
ashleymills 0:e979170e02e7 952 if (XSTRNCMP(private_key->dp->name, public_key->dp->name, ECC_MAXNAME) != 0)
ashleymills 0:e979170e02e7 953 return ECC_BAD_ARG_E;
ashleymills 0:e979170e02e7 954
ashleymills 0:e979170e02e7 955 /* make new point */
ashleymills 0:e979170e02e7 956 result = ecc_new_point();
ashleymills 0:e979170e02e7 957 if (result == NULL) {
ashleymills 0:e979170e02e7 958 return MEMORY_E;
ashleymills 0:e979170e02e7 959 }
ashleymills 0:e979170e02e7 960
ashleymills 0:e979170e02e7 961 if ((err = mp_init(&prime)) != MP_OKAY) {
ashleymills 0:e979170e02e7 962 ecc_del_point(result);
ashleymills 0:e979170e02e7 963 return err;
ashleymills 0:e979170e02e7 964 }
ashleymills 0:e979170e02e7 965
ashleymills 0:e979170e02e7 966 err = mp_read_radix(&prime, (char *)private_key->dp->prime, 16);
ashleymills 0:e979170e02e7 967
ashleymills 0:e979170e02e7 968 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 969 err = ecc_mulmod(&private_key->k, &public_key->pubkey, result, &prime,1);
ashleymills 0:e979170e02e7 970
ashleymills 0:e979170e02e7 971 if (err == MP_OKAY) {
ashleymills 0:e979170e02e7 972 x = mp_unsigned_bin_size(&prime);
ashleymills 0:e979170e02e7 973 if (*outlen < x)
ashleymills 0:e979170e02e7 974 err = BUFFER_E;
ashleymills 0:e979170e02e7 975 }
ashleymills 0:e979170e02e7 976
ashleymills 0:e979170e02e7 977 if (err == MP_OKAY) {
ashleymills 0:e979170e02e7 978 XMEMSET(out, 0, x);
ashleymills 0:e979170e02e7 979 err = mp_to_unsigned_bin(&result->x,out + (x -
ashleymills 0:e979170e02e7 980 mp_unsigned_bin_size(&result->x)));
ashleymills 0:e979170e02e7 981 *outlen = x;
ashleymills 0:e979170e02e7 982 }
ashleymills 0:e979170e02e7 983
ashleymills 0:e979170e02e7 984 mp_clear(&prime);
ashleymills 0:e979170e02e7 985 ecc_del_point(result);
ashleymills 0:e979170e02e7 986
ashleymills 0:e979170e02e7 987 return err;
ashleymills 0:e979170e02e7 988 }
ashleymills 0:e979170e02e7 989
ashleymills 0:e979170e02e7 990
ashleymills 0:e979170e02e7 991 int ecc_make_key_ex(RNG* rng, ecc_key* key, const ecc_set_type* dp);
ashleymills 0:e979170e02e7 992
ashleymills 0:e979170e02e7 993 /**
ashleymills 0:e979170e02e7 994 Make a new ECC key
ashleymills 0:e979170e02e7 995 rng An active RNG state
ashleymills 0:e979170e02e7 996 keysize The keysize for the new key (in octets from 20 to 65 bytes)
ashleymills 0:e979170e02e7 997 key [out] Destination of the newly created key
ashleymills 0:e979170e02e7 998 return MP_OKAY if successful,
ashleymills 0:e979170e02e7 999 upon error all allocated memory will be freed
ashleymills 0:e979170e02e7 1000 */
ashleymills 0:e979170e02e7 1001 int ecc_make_key(RNG* rng, int keysize, ecc_key* key)
ashleymills 0:e979170e02e7 1002 {
ashleymills 0:e979170e02e7 1003 int x, err;
ashleymills 0:e979170e02e7 1004
ashleymills 0:e979170e02e7 1005 /* find key size */
ashleymills 0:e979170e02e7 1006 for (x = 0; (keysize > ecc_sets[x].size) && (ecc_sets[x].size != 0); x++)
ashleymills 0:e979170e02e7 1007 ;
ashleymills 0:e979170e02e7 1008 keysize = ecc_sets[x].size;
ashleymills 0:e979170e02e7 1009
ashleymills 0:e979170e02e7 1010 if (keysize > ECC_MAXSIZE || ecc_sets[x].size == 0) {
ashleymills 0:e979170e02e7 1011 return BAD_FUNC_ARG;
ashleymills 0:e979170e02e7 1012 }
ashleymills 0:e979170e02e7 1013 err = ecc_make_key_ex(rng, key, &ecc_sets[x]);
ashleymills 0:e979170e02e7 1014 key->idx = x;
ashleymills 0:e979170e02e7 1015
ashleymills 0:e979170e02e7 1016 return err;
ashleymills 0:e979170e02e7 1017 }
ashleymills 0:e979170e02e7 1018
ashleymills 0:e979170e02e7 1019 int ecc_make_key_ex(RNG* rng, ecc_key* key, const ecc_set_type* dp)
ashleymills 0:e979170e02e7 1020 {
ashleymills 0:e979170e02e7 1021 int err;
ashleymills 0:e979170e02e7 1022 ecc_point* base;
ashleymills 0:e979170e02e7 1023 mp_int prime;
ashleymills 0:e979170e02e7 1024 mp_int order;
ashleymills 0:e979170e02e7 1025 byte buf[ECC_MAXSIZE];
ashleymills 0:e979170e02e7 1026 int keysize;
ashleymills 0:e979170e02e7 1027
ashleymills 0:e979170e02e7 1028 if (key == NULL || rng == NULL || dp == NULL)
ashleymills 0:e979170e02e7 1029 return ECC_BAD_ARG_E;
ashleymills 0:e979170e02e7 1030
ashleymills 0:e979170e02e7 1031 key->idx = -1;
ashleymills 0:e979170e02e7 1032 key->dp = dp;
ashleymills 0:e979170e02e7 1033 keysize = dp->size;
ashleymills 0:e979170e02e7 1034
ashleymills 0:e979170e02e7 1035 /* allocate ram */
ashleymills 0:e979170e02e7 1036 base = NULL;
ashleymills 0:e979170e02e7 1037
ashleymills 0:e979170e02e7 1038 /* make up random string */
ashleymills 0:e979170e02e7 1039 RNG_GenerateBlock(rng, buf, keysize);
ashleymills 0:e979170e02e7 1040 buf[0] |= 0x0c;
ashleymills 0:e979170e02e7 1041
ashleymills 0:e979170e02e7 1042 /* setup the key variables */
ashleymills 0:e979170e02e7 1043 if ((err = mp_init_multi(&key->pubkey.x, &key->pubkey.y, &key->pubkey.z,
ashleymills 0:e979170e02e7 1044 &key->k, &prime, &order)) != MP_OKAY)
ashleymills 0:e979170e02e7 1045 return MEMORY_E;
ashleymills 0:e979170e02e7 1046
ashleymills 0:e979170e02e7 1047 base = ecc_new_point();
ashleymills 0:e979170e02e7 1048 if (base == NULL)
ashleymills 0:e979170e02e7 1049 err = MEMORY_E;
ashleymills 0:e979170e02e7 1050
ashleymills 0:e979170e02e7 1051 /* read in the specs for this key */
ashleymills 0:e979170e02e7 1052 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 1053 err = mp_read_radix(&prime, (char *)key->dp->prime, 16);
ashleymills 0:e979170e02e7 1054 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 1055 err = mp_read_radix(&order, (char *)key->dp->order, 16);
ashleymills 0:e979170e02e7 1056 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 1057 err = mp_read_radix(&base->x, (char *)key->dp->Gx, 16);
ashleymills 0:e979170e02e7 1058 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 1059 err = mp_read_radix(&base->y, (char *)key->dp->Gy, 16);
ashleymills 0:e979170e02e7 1060
ashleymills 0:e979170e02e7 1061 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 1062 mp_set(&base->z, 1);
ashleymills 0:e979170e02e7 1063 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 1064 err = mp_read_unsigned_bin(&key->k, (byte*)buf, keysize);
ashleymills 0:e979170e02e7 1065
ashleymills 0:e979170e02e7 1066 /* the key should be smaller than the order of base point */
ashleymills 0:e979170e02e7 1067 if (err == MP_OKAY) {
ashleymills 0:e979170e02e7 1068 if (mp_cmp(&key->k, &order) != MP_LT)
ashleymills 0:e979170e02e7 1069 err = mp_mod(&key->k, &order, &key->k);
ashleymills 0:e979170e02e7 1070 }
ashleymills 0:e979170e02e7 1071 /* make the public key */
ashleymills 0:e979170e02e7 1072 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 1073 err = ecc_mulmod(&key->k, base, &key->pubkey, &prime, 1);
ashleymills 0:e979170e02e7 1074 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 1075 key->type = ECC_PRIVATEKEY;
ashleymills 0:e979170e02e7 1076
ashleymills 0:e979170e02e7 1077 if (err != MP_OKAY) {
ashleymills 0:e979170e02e7 1078 /* clean up */
ashleymills 0:e979170e02e7 1079 mp_clear(&key->pubkey.x);
ashleymills 0:e979170e02e7 1080 mp_clear(&key->pubkey.y);
ashleymills 0:e979170e02e7 1081 mp_clear(&key->pubkey.z);
ashleymills 0:e979170e02e7 1082 mp_clear(&key->k);
ashleymills 0:e979170e02e7 1083 }
ashleymills 0:e979170e02e7 1084 ecc_del_point(base);
ashleymills 0:e979170e02e7 1085 mp_clear(&prime);
ashleymills 0:e979170e02e7 1086 mp_clear(&order);
ashleymills 0:e979170e02e7 1087 #ifdef ECC_CLEAN_STACK
ashleymills 0:e979170e02e7 1088 XMEMSET(buff, 0, ECC_MAXSIZE);
ashleymills 0:e979170e02e7 1089 #endif
ashleymills 0:e979170e02e7 1090 return err;
ashleymills 0:e979170e02e7 1091 }
ashleymills 0:e979170e02e7 1092
ashleymills 0:e979170e02e7 1093
ashleymills 0:e979170e02e7 1094 /* Setup dynamic pointers is using normal math for proper freeing */
ashleymills 0:e979170e02e7 1095 void ecc_init(ecc_key* key)
ashleymills 0:e979170e02e7 1096 {
ashleymills 0:e979170e02e7 1097 (void)key;
ashleymills 0:e979170e02e7 1098 #ifndef USE_FAST_MATH
ashleymills 0:e979170e02e7 1099 key->pubkey.x.dp = NULL;
ashleymills 0:e979170e02e7 1100 key->pubkey.y.dp = NULL;
ashleymills 0:e979170e02e7 1101 key->pubkey.z.dp = NULL;
ashleymills 0:e979170e02e7 1102
ashleymills 0:e979170e02e7 1103 key->k.dp = NULL;
ashleymills 0:e979170e02e7 1104 #endif
ashleymills 0:e979170e02e7 1105 }
ashleymills 0:e979170e02e7 1106
ashleymills 0:e979170e02e7 1107
ashleymills 0:e979170e02e7 1108 /**
ashleymills 0:e979170e02e7 1109 Sign a message digest
ashleymills 0:e979170e02e7 1110 in The message digest to sign
ashleymills 0:e979170e02e7 1111 inlen The length of the digest
ashleymills 0:e979170e02e7 1112 out [out] The destination for the signature
ashleymills 0:e979170e02e7 1113 outlen [in/out] The max size and resulting size of the signature
ashleymills 0:e979170e02e7 1114 key A private ECC key
ashleymills 0:e979170e02e7 1115 return MP_OKAY if successful
ashleymills 0:e979170e02e7 1116 */
ashleymills 0:e979170e02e7 1117 int ecc_sign_hash(const byte* in, word32 inlen, byte* out, word32 *outlen,
ashleymills 0:e979170e02e7 1118 RNG* rng, ecc_key* key)
ashleymills 0:e979170e02e7 1119 {
ashleymills 0:e979170e02e7 1120 mp_int r;
ashleymills 0:e979170e02e7 1121 mp_int s;
ashleymills 0:e979170e02e7 1122 mp_int e;
ashleymills 0:e979170e02e7 1123 mp_int p;
ashleymills 0:e979170e02e7 1124 int err;
ashleymills 0:e979170e02e7 1125
ashleymills 0:e979170e02e7 1126 if (in == NULL || out == NULL || outlen == NULL || key == NULL || rng ==NULL)
ashleymills 0:e979170e02e7 1127 return ECC_BAD_ARG_E;
ashleymills 0:e979170e02e7 1128
ashleymills 0:e979170e02e7 1129 /* is this a private key? */
ashleymills 0:e979170e02e7 1130 if (key->type != ECC_PRIVATEKEY) {
ashleymills 0:e979170e02e7 1131 return ECC_BAD_ARG_E;
ashleymills 0:e979170e02e7 1132 }
ashleymills 0:e979170e02e7 1133
ashleymills 0:e979170e02e7 1134 /* is the IDX valid ? */
ashleymills 0:e979170e02e7 1135 if (ecc_is_valid_idx(key->idx) != 1) {
ashleymills 0:e979170e02e7 1136 return ECC_BAD_ARG_E;
ashleymills 0:e979170e02e7 1137 }
ashleymills 0:e979170e02e7 1138
ashleymills 0:e979170e02e7 1139 /* get the hash and load it as a bignum into 'e' */
ashleymills 0:e979170e02e7 1140 /* init the bignums */
ashleymills 0:e979170e02e7 1141 if ((err = mp_init_multi(&r, &s, &p, &e, NULL, NULL)) != MP_OKAY) {
ashleymills 0:e979170e02e7 1142 return err;
ashleymills 0:e979170e02e7 1143 }
ashleymills 0:e979170e02e7 1144 err = mp_read_radix(&p, (char *)key->dp->order, 16);
ashleymills 0:e979170e02e7 1145
ashleymills 0:e979170e02e7 1146 if (err == MP_OKAY) {
ashleymills 0:e979170e02e7 1147 int truncLen = (int)inlen;
ashleymills 0:e979170e02e7 1148 if (truncLen > ecc_size(key))
ashleymills 0:e979170e02e7 1149 truncLen = ecc_size(key);
ashleymills 0:e979170e02e7 1150 err = mp_read_unsigned_bin(&e, (byte*)in, truncLen);
ashleymills 0:e979170e02e7 1151 }
ashleymills 0:e979170e02e7 1152
ashleymills 0:e979170e02e7 1153 /* make up a key and export the public copy */
ashleymills 0:e979170e02e7 1154 if (err == MP_OKAY) {
ashleymills 0:e979170e02e7 1155 ecc_key pubkey;
ashleymills 0:e979170e02e7 1156 ecc_init(&pubkey);
ashleymills 0:e979170e02e7 1157 for (;;) {
ashleymills 0:e979170e02e7 1158 err = ecc_make_key_ex(rng, &pubkey, key->dp);
ashleymills 0:e979170e02e7 1159 if (err != MP_OKAY) break;
ashleymills 0:e979170e02e7 1160
ashleymills 0:e979170e02e7 1161 /* find r = x1 mod n */
ashleymills 0:e979170e02e7 1162 err = mp_mod(&pubkey.pubkey.x, &p, &r);
ashleymills 0:e979170e02e7 1163 if (err != MP_OKAY) break;
ashleymills 0:e979170e02e7 1164
ashleymills 0:e979170e02e7 1165 if (mp_iszero(&r) == MP_YES)
ashleymills 0:e979170e02e7 1166 ecc_free(&pubkey);
ashleymills 0:e979170e02e7 1167 else {
ashleymills 0:e979170e02e7 1168 /* find s = (e + xr)/k */
ashleymills 0:e979170e02e7 1169 err = mp_invmod(&pubkey.k, &p, &pubkey.k);
ashleymills 0:e979170e02e7 1170 if (err != MP_OKAY) break;
ashleymills 0:e979170e02e7 1171
ashleymills 0:e979170e02e7 1172 err = mp_mulmod(&key->k, &r, &p, &s); /* s = xr */
ashleymills 0:e979170e02e7 1173 if (err != MP_OKAY) break;
ashleymills 0:e979170e02e7 1174
ashleymills 0:e979170e02e7 1175 err = mp_add(&e, &s, &s); /* s = e + xr */
ashleymills 0:e979170e02e7 1176 if (err != MP_OKAY) break;
ashleymills 0:e979170e02e7 1177
ashleymills 0:e979170e02e7 1178 err = mp_mod(&s, &p, &s); /* s = e + xr */
ashleymills 0:e979170e02e7 1179 if (err != MP_OKAY) break;
ashleymills 0:e979170e02e7 1180
ashleymills 0:e979170e02e7 1181 err = mp_mulmod(&s, &pubkey.k, &p, &s); /* s = (e + xr)/k */
ashleymills 0:e979170e02e7 1182 if (err != MP_OKAY) break;
ashleymills 0:e979170e02e7 1183
ashleymills 0:e979170e02e7 1184 ecc_free(&pubkey);
ashleymills 0:e979170e02e7 1185 if (mp_iszero(&s) == MP_NO)
ashleymills 0:e979170e02e7 1186 break;
ashleymills 0:e979170e02e7 1187 }
ashleymills 0:e979170e02e7 1188 }
ashleymills 0:e979170e02e7 1189 ecc_free(&pubkey);
ashleymills 0:e979170e02e7 1190 }
ashleymills 0:e979170e02e7 1191
ashleymills 0:e979170e02e7 1192 /* store as SEQUENCE { r, s -- integer } */
ashleymills 0:e979170e02e7 1193 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 1194 err = StoreECC_DSA_Sig(out, outlen, &r, &s);
ashleymills 0:e979170e02e7 1195
ashleymills 0:e979170e02e7 1196 mp_clear(&r);
ashleymills 0:e979170e02e7 1197 mp_clear(&s);
ashleymills 0:e979170e02e7 1198 mp_clear(&p);
ashleymills 0:e979170e02e7 1199 mp_clear(&e);
ashleymills 0:e979170e02e7 1200
ashleymills 0:e979170e02e7 1201 return err;
ashleymills 0:e979170e02e7 1202 }
ashleymills 0:e979170e02e7 1203
ashleymills 0:e979170e02e7 1204
ashleymills 0:e979170e02e7 1205 /**
ashleymills 0:e979170e02e7 1206 Free an ECC key from memory
ashleymills 0:e979170e02e7 1207 key The key you wish to free
ashleymills 0:e979170e02e7 1208 */
ashleymills 0:e979170e02e7 1209 void ecc_free(ecc_key* key)
ashleymills 0:e979170e02e7 1210 {
ashleymills 0:e979170e02e7 1211 if (key == NULL)
ashleymills 0:e979170e02e7 1212 return;
ashleymills 0:e979170e02e7 1213
ashleymills 0:e979170e02e7 1214 mp_clear(&key->pubkey.x);
ashleymills 0:e979170e02e7 1215 mp_clear(&key->pubkey.y);
ashleymills 0:e979170e02e7 1216 mp_clear(&key->pubkey.z);
ashleymills 0:e979170e02e7 1217 mp_clear(&key->k);
ashleymills 0:e979170e02e7 1218 }
ashleymills 0:e979170e02e7 1219
ashleymills 0:e979170e02e7 1220
ashleymills 0:e979170e02e7 1221 /* verify
ashleymills 0:e979170e02e7 1222 *
ashleymills 0:e979170e02e7 1223 * w = s^-1 mod n
ashleymills 0:e979170e02e7 1224 * u1 = xw
ashleymills 0:e979170e02e7 1225 * u2 = rw
ashleymills 0:e979170e02e7 1226 * X = u1*G + u2*Q
ashleymills 0:e979170e02e7 1227 * v = X_x1 mod n
ashleymills 0:e979170e02e7 1228 * accept if v == r
ashleymills 0:e979170e02e7 1229 */
ashleymills 0:e979170e02e7 1230
ashleymills 0:e979170e02e7 1231 /**
ashleymills 0:e979170e02e7 1232 Verify an ECC signature
ashleymills 0:e979170e02e7 1233 sig The signature to verify
ashleymills 0:e979170e02e7 1234 siglen The length of the signature (octets)
ashleymills 0:e979170e02e7 1235 hash The hash (message digest) that was signed
ashleymills 0:e979170e02e7 1236 hashlen The length of the hash (octets)
ashleymills 0:e979170e02e7 1237 stat Result of signature, 1==valid, 0==invalid
ashleymills 0:e979170e02e7 1238 key The corresponding public ECC key
ashleymills 0:e979170e02e7 1239 return MP_OKAY if successful (even if the signature is not valid)
ashleymills 0:e979170e02e7 1240 */
ashleymills 0:e979170e02e7 1241 int ecc_verify_hash(const byte* sig, word32 siglen, byte* hash, word32 hashlen,
ashleymills 0:e979170e02e7 1242 int* stat, ecc_key* key)
ashleymills 0:e979170e02e7 1243 {
ashleymills 0:e979170e02e7 1244 ecc_point *mG, *mQ;
ashleymills 0:e979170e02e7 1245 mp_int r;
ashleymills 0:e979170e02e7 1246 mp_int s;
ashleymills 0:e979170e02e7 1247 mp_int v;
ashleymills 0:e979170e02e7 1248 mp_int w;
ashleymills 0:e979170e02e7 1249 mp_int u1;
ashleymills 0:e979170e02e7 1250 mp_int u2;
ashleymills 0:e979170e02e7 1251 mp_int e;
ashleymills 0:e979170e02e7 1252 mp_int p;
ashleymills 0:e979170e02e7 1253 mp_int m;
ashleymills 0:e979170e02e7 1254 mp_digit mp;
ashleymills 0:e979170e02e7 1255 int err;
ashleymills 0:e979170e02e7 1256
ashleymills 0:e979170e02e7 1257 if (sig == NULL || hash == NULL || stat == NULL || key == NULL)
ashleymills 0:e979170e02e7 1258 return ECC_BAD_ARG_E;
ashleymills 0:e979170e02e7 1259
ashleymills 0:e979170e02e7 1260 /* default to invalid signature */
ashleymills 0:e979170e02e7 1261 *stat = 0;
ashleymills 0:e979170e02e7 1262
ashleymills 0:e979170e02e7 1263 /* is the IDX valid ? */
ashleymills 0:e979170e02e7 1264 if (ecc_is_valid_idx(key->idx) != 1) {
ashleymills 0:e979170e02e7 1265 return ECC_BAD_ARG_E;
ashleymills 0:e979170e02e7 1266 }
ashleymills 0:e979170e02e7 1267
ashleymills 0:e979170e02e7 1268 /* allocate ints */
ashleymills 0:e979170e02e7 1269 if ((err = mp_init_multi(&v, &w, &u1, &u2, &p, &e)) != MP_OKAY) {
ashleymills 0:e979170e02e7 1270 return MEMORY_E;
ashleymills 0:e979170e02e7 1271 }
ashleymills 0:e979170e02e7 1272
ashleymills 0:e979170e02e7 1273 if ((err = mp_init(&m)) != MP_OKAY) {
ashleymills 0:e979170e02e7 1274 mp_clear(&v);
ashleymills 0:e979170e02e7 1275 mp_clear(&w);
ashleymills 0:e979170e02e7 1276 mp_clear(&u1);
ashleymills 0:e979170e02e7 1277 mp_clear(&u2);
ashleymills 0:e979170e02e7 1278 mp_clear(&p);
ashleymills 0:e979170e02e7 1279 mp_clear(&e);
ashleymills 0:e979170e02e7 1280 return MEMORY_E;
ashleymills 0:e979170e02e7 1281 }
ashleymills 0:e979170e02e7 1282
ashleymills 0:e979170e02e7 1283 /* allocate points */
ashleymills 0:e979170e02e7 1284 mG = ecc_new_point();
ashleymills 0:e979170e02e7 1285 mQ = ecc_new_point();
ashleymills 0:e979170e02e7 1286 if (mQ == NULL || mG == NULL)
ashleymills 0:e979170e02e7 1287 err = MEMORY_E;
ashleymills 0:e979170e02e7 1288
ashleymills 0:e979170e02e7 1289 /* Note, DecodeECC_DSA_Sig() calls mp_init() on r and s.
ashleymills 0:e979170e02e7 1290 * If either of those don't allocate correctly, none of
ashleymills 0:e979170e02e7 1291 * the rest of this function will execute, and everything
ashleymills 0:e979170e02e7 1292 * gets cleaned up at the end. */
ashleymills 0:e979170e02e7 1293 XMEMSET(&r, 0, sizeof(r));
ashleymills 0:e979170e02e7 1294 XMEMSET(&s, 0, sizeof(s));
ashleymills 0:e979170e02e7 1295 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 1296 err = DecodeECC_DSA_Sig(sig, siglen, &r, &s);
ashleymills 0:e979170e02e7 1297
ashleymills 0:e979170e02e7 1298 /* get the order */
ashleymills 0:e979170e02e7 1299 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 1300 err = mp_read_radix(&p, (char *)key->dp->order, 16);
ashleymills 0:e979170e02e7 1301
ashleymills 0:e979170e02e7 1302 /* get the modulus */
ashleymills 0:e979170e02e7 1303 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 1304 err = mp_read_radix(&m, (char *)key->dp->prime, 16);
ashleymills 0:e979170e02e7 1305
ashleymills 0:e979170e02e7 1306 /* check for zero */
ashleymills 0:e979170e02e7 1307 if (err == MP_OKAY) {
ashleymills 0:e979170e02e7 1308 if (mp_iszero(&r) || mp_iszero(&s) || mp_cmp(&r, &p) != MP_LT ||
ashleymills 0:e979170e02e7 1309 mp_cmp(&s, &p) != MP_LT)
ashleymills 0:e979170e02e7 1310 err = MP_ZERO_E;
ashleymills 0:e979170e02e7 1311 }
ashleymills 0:e979170e02e7 1312 /* read hash */
ashleymills 0:e979170e02e7 1313 if (err == MP_OKAY) {
ashleymills 0:e979170e02e7 1314 int truncLen = (int)hashlen;
ashleymills 0:e979170e02e7 1315 if (truncLen > ecc_size(key))
ashleymills 0:e979170e02e7 1316 truncLen = ecc_size(key);
ashleymills 0:e979170e02e7 1317 err = mp_read_unsigned_bin(&e, (byte*)hash, truncLen);
ashleymills 0:e979170e02e7 1318 }
ashleymills 0:e979170e02e7 1319
ashleymills 0:e979170e02e7 1320 /* w = s^-1 mod n */
ashleymills 0:e979170e02e7 1321 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 1322 err = mp_invmod(&s, &p, &w);
ashleymills 0:e979170e02e7 1323
ashleymills 0:e979170e02e7 1324 /* u1 = ew */
ashleymills 0:e979170e02e7 1325 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 1326 err = mp_mulmod(&e, &w, &p, &u1);
ashleymills 0:e979170e02e7 1327
ashleymills 0:e979170e02e7 1328 /* u2 = rw */
ashleymills 0:e979170e02e7 1329 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 1330 err = mp_mulmod(&r, &w, &p, &u2);
ashleymills 0:e979170e02e7 1331
ashleymills 0:e979170e02e7 1332 /* find mG and mQ */
ashleymills 0:e979170e02e7 1333 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 1334 err = mp_read_radix(&mG->x, (char *)key->dp->Gx, 16);
ashleymills 0:e979170e02e7 1335
ashleymills 0:e979170e02e7 1336 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 1337 err = mp_read_radix(&mG->y, (char *)key->dp->Gy, 16);
ashleymills 0:e979170e02e7 1338 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 1339 mp_set(&mG->z, 1);
ashleymills 0:e979170e02e7 1340
ashleymills 0:e979170e02e7 1341 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 1342 err = mp_copy(&key->pubkey.x, &mQ->x);
ashleymills 0:e979170e02e7 1343 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 1344 err = mp_copy(&key->pubkey.y, &mQ->y);
ashleymills 0:e979170e02e7 1345 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 1346 err = mp_copy(&key->pubkey.z, &mQ->z);
ashleymills 0:e979170e02e7 1347
ashleymills 0:e979170e02e7 1348 #ifndef ECC_SHAMIR
ashleymills 0:e979170e02e7 1349 /* compute u1*mG + u2*mQ = mG */
ashleymills 0:e979170e02e7 1350 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 1351 err = ecc_mulmod(&u1, mG, mG, &m, 0);
ashleymills 0:e979170e02e7 1352 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 1353 err = ecc_mulmod(&u2, mQ, mQ, &m, 0);
ashleymills 0:e979170e02e7 1354
ashleymills 0:e979170e02e7 1355 /* find the montgomery mp */
ashleymills 0:e979170e02e7 1356 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 1357 err = mp_montgomery_setup(&m, &mp);
ashleymills 0:e979170e02e7 1358
ashleymills 0:e979170e02e7 1359 /* add them */
ashleymills 0:e979170e02e7 1360 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 1361 err = ecc_projective_add_point(mQ, mG, mG, &m, &mp);
ashleymills 0:e979170e02e7 1362
ashleymills 0:e979170e02e7 1363 /* reduce */
ashleymills 0:e979170e02e7 1364 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 1365 err = ecc_map(mG, &m, &mp);
ashleymills 0:e979170e02e7 1366 #else
ashleymills 0:e979170e02e7 1367 /* use Shamir's trick to compute u1*mG + u2*mQ using half the doubles */
ashleymills 0:e979170e02e7 1368 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 1369 err = ecc_mul2add(mG, &u1, mQ, &u2, mG, &m);
ashleymills 0:e979170e02e7 1370 #endif /* ECC_SHAMIR */
ashleymills 0:e979170e02e7 1371
ashleymills 0:e979170e02e7 1372 /* v = X_x1 mod n */
ashleymills 0:e979170e02e7 1373 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 1374 err = mp_mod(&mG->x, &p, &v);
ashleymills 0:e979170e02e7 1375
ashleymills 0:e979170e02e7 1376 /* does v == r */
ashleymills 0:e979170e02e7 1377 if (err == MP_OKAY) {
ashleymills 0:e979170e02e7 1378 if (mp_cmp(&v, &r) == MP_EQ)
ashleymills 0:e979170e02e7 1379 *stat = 1;
ashleymills 0:e979170e02e7 1380 }
ashleymills 0:e979170e02e7 1381
ashleymills 0:e979170e02e7 1382 ecc_del_point(mG);
ashleymills 0:e979170e02e7 1383 ecc_del_point(mQ);
ashleymills 0:e979170e02e7 1384
ashleymills 0:e979170e02e7 1385 mp_clear(&r);
ashleymills 0:e979170e02e7 1386 mp_clear(&s);
ashleymills 0:e979170e02e7 1387 mp_clear(&v);
ashleymills 0:e979170e02e7 1388 mp_clear(&w);
ashleymills 0:e979170e02e7 1389 mp_clear(&u1);
ashleymills 0:e979170e02e7 1390 mp_clear(&u2);
ashleymills 0:e979170e02e7 1391 mp_clear(&p);
ashleymills 0:e979170e02e7 1392 mp_clear(&e);
ashleymills 0:e979170e02e7 1393 mp_clear(&m);
ashleymills 0:e979170e02e7 1394
ashleymills 0:e979170e02e7 1395 return err;
ashleymills 0:e979170e02e7 1396 }
ashleymills 0:e979170e02e7 1397
ashleymills 0:e979170e02e7 1398
ashleymills 0:e979170e02e7 1399 /* export public ECC key in ANSI X9.63 format */
ashleymills 0:e979170e02e7 1400 int ecc_export_x963(ecc_key* key, byte* out, word32* outLen)
ashleymills 0:e979170e02e7 1401 {
ashleymills 0:e979170e02e7 1402 byte buf[ECC_BUFSIZE];
ashleymills 0:e979170e02e7 1403 word32 numlen;
ashleymills 0:e979170e02e7 1404
ashleymills 0:e979170e02e7 1405 if (key == NULL || out == NULL || outLen == NULL)
ashleymills 0:e979170e02e7 1406 return ECC_BAD_ARG_E;
ashleymills 0:e979170e02e7 1407
ashleymills 0:e979170e02e7 1408 if (ecc_is_valid_idx(key->idx) == 0) {
ashleymills 0:e979170e02e7 1409 return ECC_BAD_ARG_E;
ashleymills 0:e979170e02e7 1410 }
ashleymills 0:e979170e02e7 1411 numlen = key->dp->size;
ashleymills 0:e979170e02e7 1412
ashleymills 0:e979170e02e7 1413 if (*outLen < (1 + 2*numlen)) {
ashleymills 0:e979170e02e7 1414 *outLen = 1 + 2*numlen;
ashleymills 0:e979170e02e7 1415 return BUFFER_E;
ashleymills 0:e979170e02e7 1416 }
ashleymills 0:e979170e02e7 1417
ashleymills 0:e979170e02e7 1418 /* store byte 0x04 */
ashleymills 0:e979170e02e7 1419 out[0] = 0x04;
ashleymills 0:e979170e02e7 1420
ashleymills 0:e979170e02e7 1421 /* pad and store x */
ashleymills 0:e979170e02e7 1422 XMEMSET(buf, 0, sizeof(buf));
ashleymills 0:e979170e02e7 1423 mp_to_unsigned_bin(&key->pubkey.x,
ashleymills 0:e979170e02e7 1424 buf + (numlen - mp_unsigned_bin_size(&key->pubkey.x)));
ashleymills 0:e979170e02e7 1425 XMEMCPY(out+1, buf, numlen);
ashleymills 0:e979170e02e7 1426
ashleymills 0:e979170e02e7 1427 /* pad and store y */
ashleymills 0:e979170e02e7 1428 XMEMSET(buf, 0, sizeof(buf));
ashleymills 0:e979170e02e7 1429 mp_to_unsigned_bin(&key->pubkey.y,
ashleymills 0:e979170e02e7 1430 buf + (numlen - mp_unsigned_bin_size(&key->pubkey.y)));
ashleymills 0:e979170e02e7 1431 XMEMCPY(out+1+numlen, buf, numlen);
ashleymills 0:e979170e02e7 1432
ashleymills 0:e979170e02e7 1433 *outLen = 1 + 2*numlen;
ashleymills 0:e979170e02e7 1434
ashleymills 0:e979170e02e7 1435 return 0;
ashleymills 0:e979170e02e7 1436 }
ashleymills 0:e979170e02e7 1437
ashleymills 0:e979170e02e7 1438
ashleymills 0:e979170e02e7 1439 /* import public ECC key in ANSI X9.63 format */
ashleymills 0:e979170e02e7 1440 int ecc_import_x963(const byte* in, word32 inLen, ecc_key* key)
ashleymills 0:e979170e02e7 1441 {
ashleymills 0:e979170e02e7 1442 int x, err;
ashleymills 0:e979170e02e7 1443
ashleymills 0:e979170e02e7 1444
ashleymills 0:e979170e02e7 1445 if (in == NULL || key == NULL)
ashleymills 0:e979170e02e7 1446 return ECC_BAD_ARG_E;
ashleymills 0:e979170e02e7 1447
ashleymills 0:e979170e02e7 1448 /* must be odd */
ashleymills 0:e979170e02e7 1449 if ((inLen & 1) == 0) {
ashleymills 0:e979170e02e7 1450 return ECC_BAD_ARG_E;
ashleymills 0:e979170e02e7 1451 }
ashleymills 0:e979170e02e7 1452
ashleymills 0:e979170e02e7 1453 /* init key */
ashleymills 0:e979170e02e7 1454 if (mp_init_multi(&key->pubkey.x, &key->pubkey.y, &key->pubkey.z, &key->k,
ashleymills 0:e979170e02e7 1455 NULL, NULL) != MP_OKAY) {
ashleymills 0:e979170e02e7 1456 return MEMORY_E;
ashleymills 0:e979170e02e7 1457 }
ashleymills 0:e979170e02e7 1458 err = MP_OKAY;
ashleymills 0:e979170e02e7 1459
ashleymills 0:e979170e02e7 1460 /* check for 4, 6 or 7 */
ashleymills 0:e979170e02e7 1461 if (in[0] != 4 && in[0] != 6 && in[0] != 7) {
ashleymills 0:e979170e02e7 1462 err = ASN_PARSE_E;
ashleymills 0:e979170e02e7 1463 }
ashleymills 0:e979170e02e7 1464
ashleymills 0:e979170e02e7 1465 /* read data */
ashleymills 0:e979170e02e7 1466 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 1467 err = mp_read_unsigned_bin(&key->pubkey.x, (byte*)in+1, (inLen-1)>>1);
ashleymills 0:e979170e02e7 1468
ashleymills 0:e979170e02e7 1469 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 1470 err = mp_read_unsigned_bin(&key->pubkey.y, (byte*)in+1+((inLen-1)>>1),
ashleymills 0:e979170e02e7 1471 (inLen-1)>>1);
ashleymills 0:e979170e02e7 1472
ashleymills 0:e979170e02e7 1473 if (err == MP_OKAY)
ashleymills 0:e979170e02e7 1474 mp_set(&key->pubkey.z, 1);
ashleymills 0:e979170e02e7 1475
ashleymills 0:e979170e02e7 1476 if (err == MP_OKAY) {
ashleymills 0:e979170e02e7 1477 /* determine the idx */
ashleymills 0:e979170e02e7 1478 for (x = 0; ecc_sets[x].size != 0; x++) {
ashleymills 0:e979170e02e7 1479 if ((unsigned)ecc_sets[x].size >= ((inLen-1)>>1)) {
ashleymills 0:e979170e02e7 1480 break;
ashleymills 0:e979170e02e7 1481 }
ashleymills 0:e979170e02e7 1482 }
ashleymills 0:e979170e02e7 1483 if (ecc_sets[x].size == 0) {
ashleymills 0:e979170e02e7 1484 err = ASN_PARSE_E;
ashleymills 0:e979170e02e7 1485 } else {
ashleymills 0:e979170e02e7 1486 /* set the idx */
ashleymills 0:e979170e02e7 1487 key->idx = x;
ashleymills 0:e979170e02e7 1488 key->dp = &ecc_sets[x];
ashleymills 0:e979170e02e7 1489 key->type = ECC_PUBLICKEY;
ashleymills 0:e979170e02e7 1490 }
ashleymills 0:e979170e02e7 1491 }
ashleymills 0:e979170e02e7 1492
ashleymills 0:e979170e02e7 1493 if (err != MP_OKAY) {
ashleymills 0:e979170e02e7 1494 mp_clear(&key->pubkey.x);
ashleymills 0:e979170e02e7 1495 mp_clear(&key->pubkey.y);
ashleymills 0:e979170e02e7 1496 mp_clear(&key->pubkey.z);
ashleymills 0:e979170e02e7 1497 mp_clear(&key->k);
ashleymills 0:e979170e02e7 1498 }
ashleymills 0:e979170e02e7 1499
ashleymills 0:e979170e02e7 1500 return err;
ashleymills 0:e979170e02e7 1501 }
ashleymills 0:e979170e02e7 1502
ashleymills 0:e979170e02e7 1503
ashleymills 0:e979170e02e7 1504 /* ecc private key import, public key in ANSI X9.63 format, private raw */
ashleymills 0:e979170e02e7 1505 int ecc_import_private_key(const byte* priv, word32 privSz, const byte* pub,
ashleymills 0:e979170e02e7 1506 word32 pubSz, ecc_key* key)
ashleymills 0:e979170e02e7 1507 {
ashleymills 0:e979170e02e7 1508 int ret = ecc_import_x963(pub, pubSz, key);
ashleymills 0:e979170e02e7 1509 if (ret != 0)
ashleymills 0:e979170e02e7 1510 return ret;
ashleymills 0:e979170e02e7 1511
ashleymills 0:e979170e02e7 1512 key->type = ECC_PRIVATEKEY;
ashleymills 0:e979170e02e7 1513
ashleymills 0:e979170e02e7 1514 return mp_read_unsigned_bin(&key->k, priv, privSz);
ashleymills 0:e979170e02e7 1515 }
ashleymills 0:e979170e02e7 1516
ashleymills 0:e979170e02e7 1517
ashleymills 0:e979170e02e7 1518 /* key size in octets */
ashleymills 0:e979170e02e7 1519 int ecc_size(ecc_key* key)
ashleymills 0:e979170e02e7 1520 {
ashleymills 0:e979170e02e7 1521 if (key == NULL) return 0;
ashleymills 0:e979170e02e7 1522
ashleymills 0:e979170e02e7 1523 return key->dp->size;
ashleymills 0:e979170e02e7 1524 }
ashleymills 0:e979170e02e7 1525
ashleymills 0:e979170e02e7 1526
ashleymills 0:e979170e02e7 1527 /* signature size in octets */
ashleymills 0:e979170e02e7 1528 int ecc_sig_size(ecc_key* key)
ashleymills 0:e979170e02e7 1529 {
ashleymills 0:e979170e02e7 1530 int sz = ecc_size(key);
ashleymills 0:e979170e02e7 1531 if (sz < 0)
ashleymills 0:e979170e02e7 1532 return sz;
ashleymills 0:e979170e02e7 1533
ashleymills 0:e979170e02e7 1534 return sz * 2 + SIG_HEADER_SZ;
ashleymills 0:e979170e02e7 1535 }
ashleymills 0:e979170e02e7 1536
ashleymills 0:e979170e02e7 1537 #endif /* HAVE_ECC */