|
@@ -65,6 +65,7 @@ const ecc_set_type ecc_sets[] = {
|
|
|
14,
|
|
|
"SECP112R1",
|
|
|
"DB7C2ABF62E35E668076BEAD208B",
|
|
|
+ "DB7C2ABF62E35E668076BEAD2088",
|
|
|
"659EF8BA043916EEDE8911702B22",
|
|
|
"DB7C2ABF62E35E7628DFAC6561C5",
|
|
|
"09487239995A5EE76B55F9C2F098",
|
|
@@ -76,6 +77,7 @@ const ecc_set_type ecc_sets[] = {
|
|
|
16,
|
|
|
"SECP128R1",
|
|
|
"FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF",
|
|
|
+ "FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFC",
|
|
|
"E87579C11079F43DD824993C2CEE5ED3",
|
|
|
"FFFFFFFE0000000075A30D1B9038A115",
|
|
|
"161FF7528B899B2D0C28607CA52C5B86",
|
|
@@ -87,6 +89,7 @@ const ecc_set_type ecc_sets[] = {
|
|
|
20,
|
|
|
"SECP160R1",
|
|
|
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF",
|
|
|
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFC",
|
|
|
"1C97BEFC54BD7A8B65ACF89F81D4D4ADC565FA45",
|
|
|
"0100000000000000000001F4C8F927AED3CA752257",
|
|
|
"4A96B5688EF573284664698968C38BB913CBFC82",
|
|
@@ -98,6 +101,7 @@ const ecc_set_type ecc_sets[] = {
|
|
|
24,
|
|
|
"ECC-192",
|
|
|
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF",
|
|
|
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC",
|
|
|
"64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1",
|
|
|
"FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831",
|
|
|
"188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012",
|
|
@@ -109,6 +113,7 @@ const ecc_set_type ecc_sets[] = {
|
|
|
28,
|
|
|
"ECC-224",
|
|
|
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001",
|
|
|
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE",
|
|
|
"B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4",
|
|
|
"FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D",
|
|
|
"B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21",
|
|
@@ -120,6 +125,7 @@ const ecc_set_type ecc_sets[] = {
|
|
|
32,
|
|
|
"ECC-256",
|
|
|
"FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF",
|
|
|
+ "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC",
|
|
|
"5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B",
|
|
|
"FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551",
|
|
|
"6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296",
|
|
@@ -131,6 +137,7 @@ const ecc_set_type ecc_sets[] = {
|
|
|
48,
|
|
|
"ECC-384",
|
|
|
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF",
|
|
|
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC",
|
|
|
"B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF",
|
|
|
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973",
|
|
|
"AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7",
|
|
@@ -142,6 +149,7 @@ const ecc_set_type ecc_sets[] = {
|
|
|
66,
|
|
|
"ECC-521",
|
|
|
"1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
|
|
|
+ "1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC",
|
|
|
"51953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00",
|
|
|
"1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409",
|
|
|
"C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66",
|
|
@@ -150,7 +158,7 @@ const ecc_set_type ecc_sets[] = {
|
|
|
#endif
|
|
|
{
|
|
|
0,
|
|
|
- NULL, NULL, NULL, NULL, NULL, NULL
|
|
|
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL
|
|
|
}
|
|
|
};
|
|
|
|
|
@@ -169,6 +177,13 @@ static int ecc_mul2add(ecc_point* A, mp_int* kA, ecc_point* B, mp_int* kB,
|
|
|
ecc_point* C, mp_int* modulus);
|
|
|
#endif
|
|
|
|
|
|
+int mp_jacobi(mp_int* a, mp_int* p, int* c);
|
|
|
+int mp_sqrtmod_prime(mp_int* n, mp_int* prime, mp_int* ret);
|
|
|
+int mp_submod(mp_int* a, mp_int* b, mp_int* c, mp_int* d);
|
|
|
+
|
|
|
+#ifdef HAVE_COMP_KEY
|
|
|
+static int ecc_export_x963_compressed(ecc_key*, byte* out, word32* outLen);
|
|
|
+#endif
|
|
|
|
|
|
/* helper for either lib */
|
|
|
static int get_digit_count(mp_int* a)
|
|
@@ -2197,10 +2212,26 @@ int ecc_export_x963(ecc_key* key, byte* out, word32* outLen)
|
|
|
}
|
|
|
|
|
|
|
|
|
+/* export public ECC key in ANSI X9.63 format, extended with
|
|
|
+ * compression option */
|
|
|
+int ecc_export_x963_ex(ecc_key* key, byte* out, word32* outLen, int compressed)
|
|
|
+{
|
|
|
+ if (compressed == 0)
|
|
|
+ return ecc_export_x963(key, out, outLen);
|
|
|
+#ifdef HAVE_COMP_KEY
|
|
|
+ else
|
|
|
+ return ecc_export_x963_compressed(key, out, outLen);
|
|
|
+#endif
|
|
|
+
|
|
|
+ return NOT_COMPILED_IN;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
/* import public ECC key in ANSI X9.63 format */
|
|
|
int ecc_import_x963(const byte* in, word32 inLen, ecc_key* key)
|
|
|
{
|
|
|
int x, err;
|
|
|
+ int compressed = 0;
|
|
|
|
|
|
if (in == NULL || key == NULL)
|
|
|
return ECC_BAD_ARG_E;
|
|
@@ -2217,24 +2248,25 @@ int ecc_import_x963(const byte* in, word32 inLen, ecc_key* key)
|
|
|
}
|
|
|
err = MP_OKAY;
|
|
|
|
|
|
- /* check for 4, 6 or 7 */
|
|
|
- if (in[0] != 4 && in[0] != 6 && in[0] != 7) {
|
|
|
+ /* check for 4, 2, or 3 */
|
|
|
+ if (in[0] != 0x04 && in[0] != 0x02 && in[0] != 0x03) {
|
|
|
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 (in[0] == 0x02 || in[0] == 0x03) {
|
|
|
+#ifdef HAVE_COMP_KEY
|
|
|
+ compressed = 1;
|
|
|
+#else
|
|
|
+ err = NOT_COMPILED_IN;
|
|
|
+#endif
|
|
|
+ }
|
|
|
|
|
|
if (err == MP_OKAY) {
|
|
|
- /* determine the idx */
|
|
|
+ /* determine the idx */
|
|
|
+
|
|
|
+ if (compressed)
|
|
|
+ inLen = (inLen-1)*2 + 1; /* used uncompressed len */
|
|
|
+
|
|
|
for (x = 0; ecc_sets[x].size != 0; x++) {
|
|
|
if ((unsigned)ecc_sets[x].size >= ((inLen-1)>>1)) {
|
|
|
break;
|
|
@@ -2250,6 +2282,74 @@ int ecc_import_x963(const byte* in, word32 inLen, ecc_key* key)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /* read data */
|
|
|
+ if (err == MP_OKAY)
|
|
|
+ err = mp_read_unsigned_bin(&key->pubkey.x, (byte*)in+1, (inLen-1)>>1);
|
|
|
+
|
|
|
+#ifdef HAVE_COMP_KEY
|
|
|
+ if (err == MP_OKAY && compressed == 1) { /* build y */
|
|
|
+ mp_int t1, t2, prime, a, b;
|
|
|
+
|
|
|
+ if (mp_init_multi(&t1, &t2, &prime, &a, &b, NULL) != MP_OKAY)
|
|
|
+ err = MEMORY_E;
|
|
|
+
|
|
|
+ /* load prime */
|
|
|
+ if (err == MP_OKAY)
|
|
|
+ err = mp_read_radix(&prime, (char *)key->dp->prime, 16);
|
|
|
+
|
|
|
+ /* load a */
|
|
|
+ if (err == MP_OKAY)
|
|
|
+ err = mp_read_radix(&a, (char *)key->dp->Af, 16);
|
|
|
+
|
|
|
+ /* load b */
|
|
|
+ if (err == MP_OKAY)
|
|
|
+ err = mp_read_radix(&b, (char *)key->dp->Bf, 16);
|
|
|
+
|
|
|
+ /* compute x^3 */
|
|
|
+ if (err == MP_OKAY)
|
|
|
+ err = mp_sqr(&key->pubkey.x, &t1);
|
|
|
+
|
|
|
+ if (err == MP_OKAY)
|
|
|
+ err = mp_mulmod(&t1, &key->pubkey.x, &prime, &t1);
|
|
|
+
|
|
|
+ /* compute x^3 + a*x */
|
|
|
+ if (err == MP_OKAY)
|
|
|
+ err = mp_mulmod(&a, &key->pubkey.x, &prime, &t2);
|
|
|
+
|
|
|
+ if (err == MP_OKAY)
|
|
|
+ err = mp_add(&t1, &t2, &t1);
|
|
|
+
|
|
|
+ /* compute x^3 + a*x + b */
|
|
|
+ if (err == MP_OKAY)
|
|
|
+ err = mp_add(&t1, &b, &t1);
|
|
|
+
|
|
|
+ /* compute sqrt(x^3 + a*x + b) */
|
|
|
+ if (err == MP_OKAY)
|
|
|
+ err = mp_sqrtmod_prime(&t1, &prime, &t2);
|
|
|
+
|
|
|
+ /* adjust y */
|
|
|
+ if (err == MP_OKAY) {
|
|
|
+ if ((mp_isodd(&t2) && in[0] == 0x03) ||
|
|
|
+ (!mp_isodd(&t2) && in[0] == 0x02)) {
|
|
|
+ err = mp_mod(&t2, &prime, &key->pubkey.y);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ err = mp_submod(&prime, &t2, &prime, &key->pubkey.y);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ mp_clear(&prime);
|
|
|
+ mp_clear(&t2);
|
|
|
+ mp_clear(&t1);
|
|
|
+ }
|
|
|
+#endif
|
|
|
+
|
|
|
+ if (err == MP_OKAY && compressed == 0)
|
|
|
+ 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) {
|
|
|
mp_clear(&key->pubkey.x);
|
|
|
mp_clear(&key->pubkey.y);
|
|
@@ -4315,4 +4415,308 @@ int ecc_decrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
|
|
|
|
|
|
#endif /* HAVE_ECC_ENCRYPT */
|
|
|
|
|
|
+
|
|
|
+#ifdef HAVE_COMP_KEY
|
|
|
+
|
|
|
+/* computes the jacobi c = (a | n) (or Legendre if n is prime)
|
|
|
+ * HAC pp. 73 Algorithm 2.149
|
|
|
+ */
|
|
|
+int mp_jacobi(mp_int* a, mp_int* p, int* c)
|
|
|
+{
|
|
|
+ mp_int a1, p1;
|
|
|
+ int k, s, r, res;
|
|
|
+ mp_digit residue;
|
|
|
+
|
|
|
+ /* if p <= 0 return MP_VAL */
|
|
|
+ if (mp_cmp_d(p, 0) != MP_GT) {
|
|
|
+ return MP_VAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* step 1. if a == 0, return 0 */
|
|
|
+ if (mp_iszero (a) == 1) {
|
|
|
+ *c = 0;
|
|
|
+ return MP_OKAY;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* step 2. if a == 1, return 1 */
|
|
|
+ if (mp_cmp_d (a, 1) == MP_EQ) {
|
|
|
+ *c = 1;
|
|
|
+ return MP_OKAY;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* default */
|
|
|
+ s = 0;
|
|
|
+
|
|
|
+ /* step 3. write a = a1 * 2**k */
|
|
|
+ if ((res = mp_init_copy (&a1, a)) != MP_OKAY) {
|
|
|
+ return res;
|
|
|
+ }
|
|
|
+
|
|
|
+ if ((res = mp_init (&p1)) != MP_OKAY) {
|
|
|
+ mp_clear(&a1);
|
|
|
+ return res;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* divide out larger power of two */
|
|
|
+ k = mp_cnt_lsb(&a1);
|
|
|
+ res = mp_div_2d(&a1, k, &a1, NULL);
|
|
|
+
|
|
|
+ if (res == MP_OKAY) {
|
|
|
+ /* step 4. if e is even set s=1 */
|
|
|
+ if ((k & 1) == 0) {
|
|
|
+ s = 1;
|
|
|
+ } else {
|
|
|
+ /* else set s=1 if p = 1/7 (mod 8) or s=-1 if p = 3/5 (mod 8) */
|
|
|
+ residue = p->dp[0] & 7;
|
|
|
+
|
|
|
+ if (residue == 1 || residue == 7) {
|
|
|
+ s = 1;
|
|
|
+ } else if (residue == 3 || residue == 5) {
|
|
|
+ s = -1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* step 5. if p == 3 (mod 4) *and* a1 == 3 (mod 4) then s = -s */
|
|
|
+ if ( ((p->dp[0] & 3) == 3) && ((a1.dp[0] & 3) == 3)) {
|
|
|
+ s = -s;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (res == MP_OKAY) {
|
|
|
+ /* if a1 == 1 we're done */
|
|
|
+ if (mp_cmp_d (&a1, 1) == MP_EQ) {
|
|
|
+ *c = s;
|
|
|
+ } else {
|
|
|
+ /* n1 = n mod a1 */
|
|
|
+ res = mp_mod (p, &a1, &p1);
|
|
|
+ if (res == MP_OKAY)
|
|
|
+ res = mp_jacobi (&p1, &a1, &r);
|
|
|
+
|
|
|
+ if (res == MP_OKAY)
|
|
|
+ *c = s * r;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* done */
|
|
|
+ mp_clear (&p1);
|
|
|
+ mp_clear (&a1);
|
|
|
+
|
|
|
+ return res;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+int mp_sqrtmod_prime(mp_int* n, mp_int* prime, mp_int* ret)
|
|
|
+{
|
|
|
+ int res, legendre, done = 0;
|
|
|
+ mp_int t1, C, Q, S, Z, M, T, R, two;
|
|
|
+ mp_digit i;
|
|
|
+
|
|
|
+ /* first handle the simple cases */
|
|
|
+ if (mp_cmp_d(n, 0) == MP_EQ) {
|
|
|
+ mp_zero(ret);
|
|
|
+ return MP_OKAY;
|
|
|
+ }
|
|
|
+ if (mp_cmp_d(prime, 2) == MP_EQ) return MP_VAL; /* prime must be odd */
|
|
|
+ /* TAO removed
|
|
|
+ if ((res = mp_jacobi(n, prime, &legendre)) != MP_OKAY) return res;
|
|
|
+ if (legendre == -1) return MP_VAL; */ /* quadratic non-residue mod prime */
|
|
|
+
|
|
|
+ if ((res = mp_init_multi(&t1, &C, &Q, &S, &Z, &M)) != MP_OKAY)
|
|
|
+ return res;
|
|
|
+
|
|
|
+ if ((res = mp_init_multi(&T, &R, &two, NULL, NULL, NULL))
|
|
|
+ != MP_OKAY) {
|
|
|
+ mp_clear(&t1); mp_clear(&C); mp_clear(&Q); mp_clear(&S); mp_clear(&Z);
|
|
|
+ mp_clear(&M);
|
|
|
+ return res;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* SPECIAL CASE: if prime mod 4 == 3
|
|
|
+ * compute directly: res = n^(prime+1)/4 mod prime
|
|
|
+ * Handbook of Applied Cryptography algorithm 3.36
|
|
|
+ */
|
|
|
+ res = mp_mod_d(prime, 4, &i);
|
|
|
+ if (res == MP_OKAY && i == 3) {
|
|
|
+ res = mp_add_d(prime, 1, &t1);
|
|
|
+
|
|
|
+ if (res == MP_OKAY)
|
|
|
+ res = mp_div_2(&t1, &t1);
|
|
|
+ if (res == MP_OKAY)
|
|
|
+ res = mp_div_2(&t1, &t1);
|
|
|
+ if (res == MP_OKAY)
|
|
|
+ res = mp_exptmod(n, &t1, prime, ret);
|
|
|
+
|
|
|
+ done = 1;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /* NOW: TonelliShanks algorithm */
|
|
|
+
|
|
|
+ if (res == MP_OKAY && done == 0) {
|
|
|
+
|
|
|
+ /* factor out powers of 2 from prime-1, defining Q and S
|
|
|
+ * as: prime-1 = Q*2^S */
|
|
|
+
|
|
|
+ res = mp_copy(prime, &Q);
|
|
|
+ if (res == MP_OKAY)
|
|
|
+ res = mp_sub_d(&Q, 1, &Q);
|
|
|
+ /* Q = prime - 1 */
|
|
|
+ if (res == MP_OKAY)
|
|
|
+ mp_zero(&S);
|
|
|
+ /* S = 0 */
|
|
|
+ while (res == MP_OKAY && mp_iseven(&Q)) {
|
|
|
+ res = mp_div_2(&Q, &Q);
|
|
|
+ /* Q = Q / 2 */
|
|
|
+ if (res == MP_OKAY)
|
|
|
+ res = mp_add_d(&S, 1, &S);
|
|
|
+ /* S = S + 1 */
|
|
|
+ }
|
|
|
+
|
|
|
+ /* find a Z such that the Legendre symbol (Z|prime) == -1 */
|
|
|
+ if (res == MP_OKAY)
|
|
|
+ res = mp_set_int(&Z, 2);
|
|
|
+ /* Z = 2 */
|
|
|
+ while (res == MP_OKAY) {
|
|
|
+ res = mp_jacobi(&Z, prime, &legendre);
|
|
|
+ if (legendre == -1)
|
|
|
+ break;
|
|
|
+ if (res == MP_OKAY)
|
|
|
+ res = mp_add_d(&Z, 1, &Z);
|
|
|
+ /* Z = Z + 1 */
|
|
|
+ }
|
|
|
+
|
|
|
+ if (res == MP_OKAY)
|
|
|
+ res = mp_exptmod(&Z, &Q, prime, &C);
|
|
|
+ /* C = Z ^ Q mod prime */
|
|
|
+ if (res == MP_OKAY)
|
|
|
+ res = mp_add_d(&Q, 1, &t1);
|
|
|
+ if (res == MP_OKAY)
|
|
|
+ res = mp_div_2(&t1, &t1);
|
|
|
+ /* t1 = (Q + 1) / 2 */
|
|
|
+ if (res == MP_OKAY)
|
|
|
+ res = mp_exptmod(n, &t1, prime, &R);
|
|
|
+ /* R = n ^ ((Q + 1) / 2) mod prime */
|
|
|
+ if (res == MP_OKAY)
|
|
|
+ res = mp_exptmod(n, &Q, prime, &T);
|
|
|
+ /* T = n ^ Q mod prime */
|
|
|
+ if (res == MP_OKAY)
|
|
|
+ res = mp_copy(&S, &M);
|
|
|
+ /* M = S */
|
|
|
+ if (res == MP_OKAY)
|
|
|
+ res = mp_set_int(&two, 2);
|
|
|
+
|
|
|
+ if (res == MP_OKAY)
|
|
|
+ res = MP_VAL;
|
|
|
+ while (res == MP_OKAY && done == 0) {
|
|
|
+ res = mp_copy(&T, &t1);
|
|
|
+ i = 0;
|
|
|
+ while (res == MP_OKAY) {
|
|
|
+ if (mp_cmp_d(&t1, 1) == MP_EQ)
|
|
|
+ break;
|
|
|
+ res = mp_exptmod(&t1, &two, prime, &t1);
|
|
|
+ if (res == MP_OKAY)
|
|
|
+ i++;
|
|
|
+ }
|
|
|
+ if (res == MP_OKAY && i == 0) {
|
|
|
+ mp_copy(&R, ret);
|
|
|
+ res = MP_OKAY;
|
|
|
+ done = 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (done == 0) {
|
|
|
+ if (res == MP_OKAY)
|
|
|
+ res = mp_sub_d(&M, i, &t1);
|
|
|
+ if (res == MP_OKAY)
|
|
|
+ res = mp_sub_d(&t1, 1, &t1);
|
|
|
+ if (res == MP_OKAY)
|
|
|
+ res = mp_exptmod(&two, &t1, prime, &t1);
|
|
|
+ /* t1 = 2 ^ (M - i - 1) */
|
|
|
+ if (res == MP_OKAY)
|
|
|
+ res = mp_exptmod(&C, &t1, prime, &t1);
|
|
|
+ /* t1 = C ^ (2 ^ (M - i - 1)) mod prime */
|
|
|
+ if (res == MP_OKAY)
|
|
|
+ res = mp_sqrmod(&t1, prime, &C);
|
|
|
+ /* C = (t1 * t1) mod prime */
|
|
|
+ if (res == MP_OKAY)
|
|
|
+ res = mp_mulmod(&R, &t1, prime, &R);
|
|
|
+ /* R = (R * t1) mod prime */
|
|
|
+ if (res == MP_OKAY)
|
|
|
+ res = mp_mulmod(&T, &C, prime, &T);
|
|
|
+ /* T = (T * C) mod prime */
|
|
|
+ if (res == MP_OKAY)
|
|
|
+ mp_set(&M, i);
|
|
|
+ /* M = i */
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* done */
|
|
|
+ mp_clear(&t1);
|
|
|
+ mp_clear(&C);
|
|
|
+ mp_clear(&Q);
|
|
|
+ mp_clear(&S);
|
|
|
+ mp_clear(&Z);
|
|
|
+ mp_clear(&M);
|
|
|
+ mp_clear(&T);
|
|
|
+ mp_clear(&R);
|
|
|
+ mp_clear(&two);
|
|
|
+
|
|
|
+ return res;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/* export public ECC key in ANSI X9.63 format compressed */
|
|
|
+int ecc_export_x963_compressed(ecc_key* key, byte* out, word32* outLen)
|
|
|
+{
|
|
|
+ word32 numlen;
|
|
|
+ int ret = MP_OKAY;
|
|
|
+
|
|
|
+ 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 + numlen)) {
|
|
|
+ *outLen = 1 + numlen;
|
|
|
+ return BUFFER_E;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* store first byte */
|
|
|
+ out[0] = mp_isodd(&key->pubkey.y) ? 0x03 : 0x02;
|
|
|
+
|
|
|
+ /* pad and store x */
|
|
|
+ XMEMSET(out+1, 0, numlen);
|
|
|
+ ret = mp_to_unsigned_bin(&key->pubkey.x,
|
|
|
+ out+1 + (numlen - mp_unsigned_bin_size(&key->pubkey.x)));
|
|
|
+ *outLen = 1 + numlen;
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/* d = a - b (mod c) */
|
|
|
+int mp_submod(mp_int* a, mp_int* b, mp_int* c, mp_int* d)
|
|
|
+{
|
|
|
+ int res;
|
|
|
+ mp_int t;
|
|
|
+
|
|
|
+ if ((res = mp_init (&t)) != MP_OKAY) {
|
|
|
+ return res;
|
|
|
+ }
|
|
|
+
|
|
|
+ if ((res = mp_sub (a, b, &t)) != MP_OKAY) {
|
|
|
+ mp_clear (&t);
|
|
|
+ return res;
|
|
|
+ }
|
|
|
+ res = mp_mod (&t, c, d);
|
|
|
+ mp_clear (&t);
|
|
|
+
|
|
|
+ return res;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+#endif /* HAVE_COMP_KEY */
|
|
|
+
|
|
|
#endif /* HAVE_ECC */
|