Browse Source

add compressed key support

toddouska 9 years ago
parent
commit
3072edb696

+ 4 - 0
certs/ecc-key-comp.pem

@@ -0,0 +1,4 @@
+-----BEGIN EC PRIVATE KEY-----
+MFcCAQEEIEW2aQJznGyFoThbcujox6zEA41TNQT6bCjcNI3hqAmMoAoGCCqGSM49
+AwEHoSQDIgACuzOsTCdQSsZKpQTDPN6fNttyLc6U6iv6yyAJOSwW6GE=
+-----END EC PRIVATE KEY-----

+ 2 - 0
certs/include.am

@@ -9,6 +9,7 @@ EXTRA_DIST += \
 	     certs/client-keyEnc.pem \
 	     certs/client-key.pem \
 	     certs/ecc-key.pem \
+	     certs/ecc-key-comp.pem \
 	     certs/ecc-keyPkcs8.pem \
 	     certs/ecc-client-key.pem \
 	     certs/client-ecc-cert.pem \
@@ -16,6 +17,7 @@ EXTRA_DIST += \
 	     certs/dh2048.pem \
 	     certs/server-cert.pem \
 	     certs/server-ecc.pem \
+	     certs/server-ecc-comp.pem \
 	     certs/server-ecc-rsa.pem \
 	     certs/server-keyEnc.pem \
 	     certs/server-key.pem \

+ 15 - 0
certs/server-ecc-comp.pem

@@ -0,0 +1,15 @@
+-----BEGIN CERTIFICATE-----
+MIICZzCCAg2gAwIBAgIJAOpbhU0jW8ssMAoGCCqGSM49BAMCMIGfMQswCQYDVQQG
+EwJVUzETMBEGA1UECAwKV2FzaGluZ3RvbjEQMA4GA1UEBwwHRWRtb25kczEcMBoG
+A1UECgwTRWxsaXB0aWMgQ29tcHJlc3NlZDERMA8GA1UECwwIRUNDIENvbXAxGDAW
+BgNVBAMMD3d3dy53b2xmc3NsLmNvbTEeMBwGCSqGSIb3DQEJARYPd3d3LndvbGZz
+c2wuY29tMB4XDTE0MDgyNzIyNTczOVoXDTE3MDUyMzIyNTczOVowgZ8xCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIDApXYXNoaW5ndG9uMRAwDgYDVQQHDAdFZG1vbmRzMRww
+GgYDVQQKDBNFbGxpcHRpYyBDb21wcmVzc2VkMREwDwYDVQQLDAhFQ0MgQ29tcDEY
+MBYGA1UEAwwPd3d3LndvbGZzc2wuY29tMR4wHAYJKoZIhvcNAQkBFg93d3cud29s
+ZnNzbC5jb20wOTATBgcqhkjOPQIBBggqhkjOPQMBBwMiAAK7M6xMJ1BKxkqlBMM8
+3p8223ItzpTqK/rLIAk5LBboYaNQME4wHQYDVR0OBBYEFIw4Omu4JLffbvRZrFZO
+quJYploYMB8GA1UdIwQYMBaAFIw4Omu4JLffbvRZrFZOquJYploYMAwGA1UdEwQF
+MAMBAf8wCgYIKoZIzj0EAwIDSAAwRQIgCNYOU7G50eHWoHoaadAXswKrN5Vj6nyh
+YUGS3zttSk4CIQD1Abqc61PBUQF6LO4OmBy79zEtWv9PRNH95iJ7V58vXA==
+-----END CERTIFICATE-----

+ 2 - 0
certs/taoCert.txt

@@ -123,6 +123,8 @@ openssl dhparam -in dh2048.param -text > dh2048.pem
     make a new key
         openssl ecparam -genkey -text -name secp256r1 -out ecc-key.pem
 
+    convert to compressed
+        openssl ec -in ecc-key.pem -conv_form compressed -out ecc-key-comp.pem 
 
 *** CRL ***
 

+ 1 - 1
configure.ac

@@ -6,7 +6,7 @@
 #
 #
 
-AC_INIT([cyassl],[3.1.1],[https://github.com/cyassl/cyassl/issues],[cyassl],[http://www.wolfssl.com])
+AC_INIT([cyassl],[3.1.2],[https://github.com/cyassl/cyassl/issues],[cyassl],[http://www.wolfssl.com])
 
 AC_CONFIG_AUX_DIR([build-aux])
 

+ 418 - 14
ctaocrypt/src/ecc.c

@@ -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 */

+ 38 - 34
ctaocrypt/src/integer.c

@@ -3932,9 +3932,41 @@ int mp_sub_d (mp_int * a, mp_digit b, mp_int * c)
 #endif /* defined(HAVE_ECC) || !defined(NO_PWDBASED) */
 
 
-#ifdef CYASSL_KEY_GEN
+#if defined(CYASSL_KEY_GEN) || defined(HAVE_COMP_KEY)
+
+static const int lnz[16] = {
+   4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
+};
+
+/* Counts the number of lsbs which are zero before the first zero bit */
+int mp_cnt_lsb(mp_int *a)
+{
+    int x;
+    mp_digit q, qq;
+
+    /* easy out */
+    if (mp_iszero(a) == 1) {
+        return 0;
+    }
+
+    /* scan lower digits until non-zero */
+    for (x = 0; x < a->used && a->dp[x] == 0; x++);
+    q = a->dp[x];
+    x *= DIGIT_BIT;
+
+    /* now scan this digit until a 1 is found */
+    if ((q & 1) == 0) {
+        do {
+            qq  = q & 15;
+            x  += lnz[qq];
+            q >>= 4;
+        } while (qq == 0);
+    }
+    return x;
+}
+
+
 
-int mp_cnt_lsb(mp_int *a);
 
 static int s_is_power_of_two(mp_digit b, int *p)
 {
@@ -4030,11 +4062,14 @@ static int mp_div_d (mp_int * a, mp_digit b, mp_int * c, mp_digit * d)
 }
 
 
-static int mp_mod_d (mp_int * a, mp_digit b, mp_digit * c)
+int mp_mod_d (mp_int * a, mp_digit b, mp_digit * c)
 {
   return mp_div_d(a, b, NULL, c);
 }
 
+#endif /* defined(CYASSL_KEY_GEN) || defined(HAVE_COMP_KEY) */
+
+#ifdef CYASSL_KEY_GEN
 
 const mp_digit ltm_prime_tab[] = {
   0x0002, 0x0003, 0x0005, 0x0007, 0x000B, 0x000D, 0x0011, 0x0013,
@@ -4291,37 +4326,6 @@ LBL_T:
 }
 
 
-static const int lnz[16] = { 
-   4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
-};
-
-/* Counts the number of lsbs which are zero before the first zero bit */
-int mp_cnt_lsb(mp_int *a)
-{
-    int x;
-    mp_digit q, qq;
-
-    /* easy out */
-    if (mp_iszero(a) == 1) {
-        return 0;
-    }
-
-    /* scan lower digits until non-zero */
-    for (x = 0; x < a->used && a->dp[x] == 0; x++);
-    q = a->dp[x];
-    x *= DIGIT_BIT;
-
-    /* now scan this digit until a 1 is found */
-    if ((q & 1) == 0) {
-        do {
-            qq  = q & 15;
-            x  += lnz[qq];
-            q >>= 4;
-        } while (qq == 0);
-    }
-    return x;
-}
-
 
 /* Greatest Common Divisor using the binary method */
 int mp_gcd (mp_int * a, mp_int * b, mp_int * c)

+ 75 - 51
ctaocrypt/src/tfm.c

@@ -2035,36 +2035,42 @@ int mp_montgomery_calc_normalization(mp_int *a, mp_int *b)
 #endif /* CYASSL_KEYGEN || HAVE_ECC */
 
 
-#ifdef CYASSL_KEY_GEN
+#if defined(CYASSL_KEY_GEN) || defined(HAVE_COMP_KEY)
 
-void fp_gcd(fp_int *a, fp_int *b, fp_int *c);
-void fp_lcm(fp_int *a, fp_int *b, fp_int *c);
-int  fp_isprime(fp_int *a);
-int  fp_cnt_lsb(fp_int *a);
+static const int lnz[16] = {
+   4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
+};
 
-int mp_gcd(fp_int *a, fp_int *b, fp_int *c)
+/* Counts the number of lsbs which are zero before the first zero bit */
+int fp_cnt_lsb(fp_int *a)
 {
-    fp_gcd(a, b, c);
-    return MP_OKAY;
-}
-
+   int x;
+   fp_digit q, qq;
 
-int mp_lcm(fp_int *a, fp_int *b, fp_int *c)
-{
-    fp_lcm(a, b, c);
-    return MP_OKAY;
-}
+   /* easy out */
+   if (fp_iszero(a) == 1) {
+      return 0;
+   }
 
+   /* scan lower digits until non-zero */
+   for (x = 0; x < a->used && a->dp[x] == 0; x++);
+   q = a->dp[x];
+   x *= DIGIT_BIT;
 
-int mp_prime_is_prime(mp_int* a, int t, int* result)
-{
-    (void)t;
-    *result = fp_isprime(a);
-    return MP_OKAY;
+   /* now scan this digit until a 1 is found */
+   if ((q & 1) == 0) {
+      do {
+         qq  = q & 15;
+         x  += lnz[qq];
+         q >>= 4;
+      } while (qq == 0);
+   }
+   return x;
 }
 
 
 
+
 static int s_is_power_of_two(fp_digit b, int *p)
 {
    int x;
@@ -2155,6 +2161,39 @@ static int fp_mod_d(fp_int *a, fp_digit b, fp_digit *c)
    return fp_div_d(a, b, NULL, c);
 }
 
+int mp_mod_d(fp_int *a, fp_digit b, fp_digit *c)
+{
+   return fp_mod_d(a, b, c);
+}
+
+#endif /* defined(CYASSL_KEY_GEN) || defined(HAVE_COMP_KEY) */
+
+#ifdef CYASSL_KEY_GEN
+
+void fp_gcd(fp_int *a, fp_int *b, fp_int *c);
+void fp_lcm(fp_int *a, fp_int *b, fp_int *c);
+int  fp_isprime(fp_int *a);
+
+int mp_gcd(fp_int *a, fp_int *b, fp_int *c)
+{
+    fp_gcd(a, b, c);
+    return MP_OKAY;
+}
+
+
+int mp_lcm(fp_int *a, fp_int *b, fp_int *c)
+{
+    fp_lcm(a, b, c);
+    return MP_OKAY;
+}
+
+
+int mp_prime_is_prime(mp_int* a, int t, int* result)
+{
+    (void)t;
+    *result = fp_isprime(a);
+    return MP_OKAY;
+}
 
 /* Miller-Rabin test of "a" to the base of "b" as described in 
  * HAC pp. 139 Algorithm 4.24
@@ -2304,37 +2343,6 @@ void fp_lcm(fp_int *a, fp_int *b, fp_int *c)
 }
 
 
-static const int lnz[16] = {
-   4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
-};
-
-/* Counts the number of lsbs which are zero before the first zero bit */
-int fp_cnt_lsb(fp_int *a)
-{
-   int x;
-   fp_digit q, qq;
-
-   /* easy out */
-   if (fp_iszero(a) == 1) {
-      return 0;
-   }
-
-   /* scan lower digits until non-zero */
-   for (x = 0; x < a->used && a->dp[x] == 0; x++);
-   q = a->dp[x];
-   x *= DIGIT_BIT;
-
-   /* now scan this digit until a 1 is found */
-   if ((q & 1) == 0) {
-      do {
-         qq  = q & 15;
-         x  += lnz[qq];
-         q >>= 4;
-      } while (qq == 0);
-   }
-   return x;
-}
-
 
 /* c = (a, b) */
 void fp_gcd(fp_int *a, fp_int *b, fp_int *c)
@@ -2508,6 +2516,22 @@ int mp_init_copy(fp_int * a, fp_int * b)
 }
 
 
+#ifdef HAVE_COMP_KEY
+
+int mp_cnt_lsb(fp_int* a)
+{
+    fp_cnt_lsb(a);
+    return MP_OKAY;
+}
+
+int mp_div_2d(fp_int* a, int b, fp_int* c, fp_int* d)
+{
+    fp_div_2d(a, b, c, d);
+    return MP_OKAY;
+}
+
+#endif /* HAVE_COMP_KEY */
+
 
 #endif /* HAVE_ECC */
 

+ 28 - 4
ctaocrypt/test/test.c

@@ -4472,8 +4472,32 @@ int ecc_test(void)
         return -1008;
 
     if (memcmp(sharedA, sharedB, y))
+        return -1009;
+
+#ifdef HAVE_COMP_KEY
+    /* try compressed export / import too */
+    x = sizeof(exportBuf);
+    ret = ecc_export_x963_ex(&userA, exportBuf, &x, 1);
+    if (ret != 0)
         return -1010;
 
+    ecc_free(&pubKey);
+    ecc_init(&pubKey);
+    ret = ecc_import_x963(exportBuf, x, &pubKey);
+
+    if (ret != 0)
+        return -1011;
+#endif
+
+    y = sizeof(sharedB);
+    ret = ecc_shared_secret(&userB, &pubKey, sharedB, &y);
+
+    if (ret != 0)
+        return -1012;
+
+    if (memcmp(sharedA, sharedB, y))
+        return -1013;
+
     /* test DSA sign hash */
     for (i = 0; i < (int)sizeof(digest); i++)
         digest[i] = (byte)i;
@@ -4482,21 +4506,21 @@ int ecc_test(void)
     ret = ecc_sign_hash(digest, sizeof(digest), sig, &x, &rng, &userA);
 
     if (ret != 0)
-        return -1016;
+        return -1014;
 
     verify = 0;
     ret = ecc_verify_hash(sig, x, digest, sizeof(digest), &verify, &userA);
 
     if (ret != 0)
-        return -1011;
+        return -1015;
 
     if (verify != 1)
-        return -1012;
+        return -1016;
 
     x = sizeof(exportBuf);
     ret = ecc_export_private_only(&userA, exportBuf, &x);
     if (ret != 0)
-        return -1013;
+        return -1017;
 
     ecc_free(&pubKey);
     ecc_free(&userB);

+ 4 - 0
cyassl/ctaocrypt/ecc.h

@@ -49,6 +49,7 @@ typedef struct {
     int size;       /* The size of the curve in octets */
     const char* name;     /* name of this curve */
     const char* prime;    /* prime that defines the field, curve is in (hex) */
+    const char* Af;       /* fields A param (hex) */
     const char* Bf;       /* fields B param (hex) */
     const char* order;    /* order of the curve (hex) */
     const char* Gx;       /* x coordinate of the base point on curve (hex) */
@@ -105,6 +106,9 @@ void ecc_fp_free(void);
 CYASSL_API
 int ecc_export_x963(ecc_key*, byte* out, word32* outLen);
 CYASSL_API
+int ecc_export_x963_ex(ecc_key*, byte* out, word32* outLen, int compressed);
+    /* extended functionality with compressed option */
+CYASSL_API
 int ecc_import_x963(const byte* in, word32 inLen, ecc_key* key);
 CYASSL_API
 int ecc_import_private_key(const byte* priv, word32 privSz, const byte* pub,

+ 3 - 0
cyassl/ctaocrypt/integer.h

@@ -310,6 +310,9 @@ int mp_init_multi(mp_int* a, mp_int* b, mp_int* c, mp_int* d, mp_int* e,
     int mp_lcm (mp_int * a, mp_int * b, mp_int * c);
 #endif
 
+int mp_cnt_lsb(mp_int *a);
+int mp_mod_d(mp_int* a, mp_digit b, mp_digit* c);
+
 #ifdef __cplusplus
    }
 #endif

+ 8 - 1
cyassl/ctaocrypt/tfm.h

@@ -398,7 +398,7 @@ void fp_mul_2(fp_int *a, fp_int *c);
 void fp_div_2(fp_int *a, fp_int *c);
 
 /* Counts the number of lsbs which are zero before the first zero bit */
-/*int fp_cnt_lsb(fp_int *a);*/
+int fp_cnt_lsb(fp_int *a);
 
 /* c = a + b */
 void fp_add(fp_int *a, fp_int *b, fp_int *c);
@@ -630,11 +630,14 @@ void fp_sqr_comba64(fp_int *a, fp_int *b);
     #define MP_LT   FP_LT   /* less than    */
     #define MP_EQ   FP_EQ   /* equal to     */
     #define MP_GT   FP_GT   /* greater than */
+    #define MP_VAL  FP_VAL  /* invalid */
     #define MP_OKAY FP_OKAY /* ok result    */
     #define MP_NO   FP_NO   /* yes/no result */
     #define MP_YES  FP_YES  /* yes/no result */
 
 /* Prototypes */
+#define mp_zero(a)  fp_zero(a)
+#define mp_iseven(a)  fp_iseven(a)
 int  mp_init (mp_int * a);
 void mp_clear (mp_int * a);
 int mp_init_multi(mp_int* a, mp_int* b, mp_int* c, mp_int* d, mp_int* e, mp_int* f);
@@ -686,6 +689,10 @@ int  mp_lcm(fp_int *a, fp_int *b, fp_int *c);
 int  mp_prime_is_prime(mp_int* a, int t, int* result);
 #endif /* CYASSL_KEY_GEN */
 
+int  mp_cnt_lsb(fp_int *a);
+int  mp_div_2d(fp_int *a, int b, fp_int *c, fp_int *d);
+int  mp_mod_d(fp_int* a, fp_digit b, fp_digit* c);
+
 CYASSL_API word32 CheckRunTimeFastMath(void);
 
 /* If user uses RSA, DH, DSA, or ECC math lib directly then fast math FP_SIZE

+ 2 - 2
cyassl/version.h

@@ -26,8 +26,8 @@
 extern "C" {
 #endif
 
-#define LIBCYASSL_VERSION_STRING "3.1.1"
-#define LIBCYASSL_VERSION_HEX 0x03001001
+#define LIBCYASSL_VERSION_STRING "3.1.2"
+#define LIBCYASSL_VERSION_HEX 0x03001002
 
 #ifdef __cplusplus
 }