Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of MiniTLS-GPL by
Diff: crypto/crypto_ecc.c
- Revision:
- 0:35aa5be3b78d
diff -r 000000000000 -r 35aa5be3b78d crypto/crypto_ecc.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/crypto/crypto_ecc.c Fri Jun 06 10:49:02 2014 +0000
@@ -0,0 +1,618 @@
+/*
+MuTLS - A super trimmed down TLS/SSL Library for embedded devices
+Author: Donatien Garnier
+Copyright (C) 2013-2014 AppNearMe Ltd
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*//**
+ * \file crypto_ecc.c
+ * \copyright Copyright (c) AppNearMe Ltd 2013
+ * \author Donatien Garnier
+ */
+
+#define __DEBUG__ 0//4
+#ifndef __MODULE__
+#define __MODULE__ "crypto_ecc.c"
+#endif
+
+#include "core/fwk.h"
+#include "crypto_ecc.h"
+#include "inc/mutls_errors.h"
+#include "inc/mutls_config.h"
+
+#include "crypto_math.h"
+#include "ltc/ltc.h"
+
+static mutls_err_t crypto_ecc_dsa_check_get_asn1_rs(void* r, void* s, const uint8_t* signature, size_t signature_size);
+
+static const crypto_ecc_curve_t crypto_ecc_curves[];
+
+mutls_err_t crypto_ecc_curve_get(const crypto_ecc_curve_t** curve, crypto_ecc_curve_type_t type)
+{
+ /*
+GNUTLS supports:
+SECP192R1 = ECC-192 in libtomcrypt
+SECP224R1 = ECC-224 in libtomcrypt
+SECP256R1 = ECC-256 in libtomcrypt
+SECP384R1 = ECC-384 in libtomcrypt
+SECP521R1 = ECC-521 in libtomcrypt
+
+So let's support the same ones!
+ */
+
+ int i = 0;
+ while(true)
+ {
+ const crypto_ecc_curve_t* current_curve = &crypto_ecc_curves[i];
+ if(current_curve->size == 0)
+ {
+ return MUTLS_ERR_NOT_IMPLEMENTED;
+ }
+ if(current_curve->type == type)
+ {
+ *curve = current_curve;
+ break;
+ }
+ }
+ return MUTLS_OK;
+}
+
+mutls_err_t crypto_ecc_ansi_x963_import(crypto_ecc_public_key_t* key, const crypto_ecc_curve_t* curve, const uint8_t* x963, size_t size)
+{
+ int err;
+
+ /* must be odd */
+ if ((size & 1) == 0) {
+ return MUTLS_ERR_PARAMETERS;
+ }
+
+ /* init key */
+ if (mp_init_multi(&key->pubkey.x, &key->pubkey.y, &key->pubkey.z, NULL) != MUTLS_OK) {
+ return MUTLS_ERR_MEMORY;
+ }
+
+ /* check for 4, 6 or 7 */
+ if (x963[0] != 4 && x963[0] != 6 && x963[0] != 7) {
+ err = MUTLS_ERR_PARAMETERS;
+ goto error;
+ }
+
+ /* read data */
+ mp_read_unsigned_bin(&key->pubkey.x, (unsigned char *)x963+1, (size-1)>>1);
+
+ mp_read_unsigned_bin(&key->pubkey.y, (unsigned char *)x963+1+((size-1)>>1), (size-1)>>1);
+
+ mp_set(&key->pubkey.z, 1);
+
+ if (((size-1)>>1) != (unsigned long) curve->size) {
+ err = MUTLS_ERR_PARAMETERS;
+ goto error;
+ }
+
+ key->curve = curve;
+
+ /* we're done */
+ return MUTLS_OK;
+error:
+ mp_clear_multi(&key->pubkey.x, &key->pubkey.y, &key->pubkey.z, NULL);
+ return err;
+}
+
+mutls_err_t crypto_ecc_ansi_x963_export(const crypto_ecc_public_key_t* key, uint8_t* x963, size_t max_size, size_t* size)
+{
+
+ unsigned char buf[ECC_BUF_SIZE];
+ unsigned long numlen;
+
+ numlen = crypto_ecc_get_key_size_for_curve(key->curve);
+
+ if (max_size < (1 + 2*numlen)) {
+ *size = 1 + 2*numlen;
+ return MUTLS_ERR_BUFFER_TOO_SMALL;
+ }
+
+ /* store byte 0x04 */
+ x963[0] = 0x04;
+
+ /* pad and store x */
+ zeromem(buf, sizeof(buf));
+ mp_to_unsigned_bin(&key->pubkey.x, buf + (numlen - mp_unsigned_bin_size(&key->pubkey.x)));
+ memcpy(x963+1, buf, numlen);
+
+ /* pad and store y */
+ zeromem(buf, sizeof(buf));
+ mp_to_unsigned_bin(&key->pubkey.y, buf + (numlen - mp_unsigned_bin_size(&key->pubkey.y)));
+ memcpy(x963+1+numlen, buf, numlen);
+
+ *size = 1 + 2*numlen;
+ return MUTLS_OK;
+}
+
+mutls_err_t crypto_ecc_generate_key(crypto_ecc_private_key_t* key, const crypto_ecc_curve_t* curve, crypto_prng_t* prng)
+{
+ ecc_point base;
+ fp_int prime, order;
+ int ret;
+
+ size_t keysize = crypto_ecc_get_key_size_for_curve(curve);
+
+ DBG("Generating key of size %d", keysize);
+
+ uint8_t buf[keysize];
+
+ /* make up random string */
+ DBG("Getting data from PRNG");
+ crypto_prng_get(prng, buf, keysize);
+#if 0
+ if( crypto_prng_get(prng, buf, keysize) != MUTLS_OK ) {
+ ret = MUTLS_ERR_PRNG;
+ goto errbuf;
+ }
+#endif
+
+ DBG("Initializing numbers");
+ /* setup the key variables */
+ if ((ret = mp_init_multi(&key->pub.pubkey.x, &key->pub.pubkey.y, &key->pub.pubkey.z, &key->privkey, &prime, &order, NULL)) != MUTLS_OK) {
+ goto errbuf;
+ }
+ if ((ret = mp_init_multi(&base.x, &base.y, &base.z, NULL)) != MUTLS_OK) {
+ ret = MUTLS_ERR_MEMORY;
+ goto errkey;
+ }
+
+ DBG("Reading the key specs");
+ /* read in the specs for this key */
+ if ((ret = mp_read_radix(&prime, (char *)curve->prime, 16)) != MUTLS_OK) { goto errkey; }
+ if ((ret = mp_read_radix(&order, (char *)curve->order, 16)) != MUTLS_OK) { goto errkey; }
+ if ((ret = mp_read_radix(&base.x, (char *)curve->Gx, 16)) != MUTLS_OK) { goto errkey; }
+ if ((ret = mp_read_radix(&base.y, (char *)curve->Gy, 16)) != MUTLS_OK) { goto errkey; }
+ /*if ((ret = */mp_set(&base.z, 1); /*) != MUTLS_OK) { goto errkey; }*/
+ /*if ((ret =*/ mp_read_unsigned_bin(&key->privkey, (unsigned char *)buf, keysize);/*) != MUTLS_OK) { goto errkey; }*/
+
+ /* the key should be smaller than the order of base point */
+ if (mp_cmp(&key->privkey, &order) != MP_LT) {
+ if((ret = mp_mod(&key->privkey, &order, &key->privkey)) != MUTLS_OK) { goto errkey; }
+ }
+
+ DBG("Compute public key");
+ /* make the public key */
+ if ((ret = ltc_ecc_mulmod(&key->privkey, &base, &key->pub.pubkey, &prime, 1)) != MUTLS_OK) { goto errkey; }
+
+ //Save curve
+ key->pub.curve = curve;
+
+ DBG("Done");
+ /* free up ram */
+ ret = MUTLS_OK;
+ goto cleanup;
+errkey:
+ mp_clear_multi(&key->pub.pubkey.x, &key->pub.pubkey.y, &key->pub.pubkey.z, &key->privkey, NULL);
+cleanup:
+ mp_clear_multi(&base.x, &base.y, &base.z, &prime, &order, NULL);
+errbuf:
+#ifdef MUTLS_CLEAN_STACK
+ zeromem(buf, &key->pub.curve->size);
+#endif
+
+ return ret;
+}
+
+size_t crypto_ecc_get_key_size_for_curve(const crypto_ecc_curve_t* curve)
+{
+ switch(curve->type)
+ {
+ case secp192r1:
+ return 192 / 8;
+ case secp224r1:
+ return 224 / 8;
+ case secp256r1:
+ return 256 / 8;
+ case secp384r1:
+ return 384 / 8;
+ case secp521r1:
+ return 512 / 8;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+const crypto_ecc_public_key_t* crypto_ecc_get_public_key(const crypto_ecc_private_key_t* private_key)
+{
+ return &private_key->pub;
+}
+
+mutls_err_t crypto_ecc_dsa_check(const crypto_ecc_public_key_t* key, const uint8_t* hash, size_t hash_size, const uint8_t* signature, size_t signature_size)
+{
+ crypto_ecc_point_t mG, mQ;
+ fp_int r, s, v, w, u1, u2, e, p, m;
+ fp_digit mp;
+ int err;
+
+ bool valid = false;
+
+ /* default to invalid signature */
+ valid = false;
+
+
+ /* allocate ints */
+ if ((err = mp_init_multi(&r, &s, &v, &w, &u1, &u2, &p, &e, &m, NULL)) != MUTLS_OK) {
+ return MUTLS_ERR_MEMORY;
+ }
+
+ /* allocate points */
+ err = mp_init_multi(&mG.x, &mG.y, &mG.z, &mQ.x, &mQ.y, &mQ.z, NULL);
+ if (err) {
+ mp_clear_multi(&r, &s, &v, &w, &u1, &u2, &p, &e, &m, NULL);
+ return MUTLS_ERR_MEMORY;
+ }
+
+#if 0
+ /* parse header */
+ //TODO
+ if ((err = der_decode_sequence_multi(signature, signature_size,
+ LTC_ASN1_INTEGER, 1UL, &r,
+ LTC_ASN1_INTEGER, 1UL, &s,
+ LTC_ASN1_EOL, 0UL, NULL)) != MUTLS_OK) {
+ goto error;
+ }
+#endif
+
+ //Decode ASN.1 sequence: [INTEGER:&r, INTEGER:&s]
+ if( (err = crypto_ecc_dsa_check_get_asn1_rs(&r, &s, signature, signature_size) ) != MUTLS_OK )
+ {
+ goto error;
+ }
+
+ /* get the order */
+ if ((err = mp_read_radix(&p, (char *)key->curve->order, 16)) != MUTLS_OK) { goto error; }
+
+ /* get the modulus */
+ if ((err = mp_read_radix(&m, (char *)key->curve->prime, 16)) != MUTLS_OK) { goto error; }
+
+ /* check for zero */
+ if (mp_iszero(&r) || mp_iszero(&s) || mp_cmp(&r, &p) != MP_LT || mp_cmp(&s, &p) != MP_LT) {
+ err = MUTLS_ERR_PARAMETERS;
+ goto error;
+ }
+
+ /* read hash */
+ /*if ((err =*/ mp_read_unsigned_bin(&e, (unsigned char *)hash, (int)hash_size);/*) != MUTLS_OK) { goto error; }*/
+
+ /* &w = &s^-1 mod n */
+ if ((err = mp_invmod(&s, &p, &w)) != MUTLS_OK) { goto error; }
+
+ /* &u1 = ew */
+ if ((err = mp_mulmod(&e, &w, &p, &u1)) != MUTLS_OK) { goto error; }
+
+ /* &u2 = rw */
+ if ((err = mp_mulmod(&r, &w, &p, &u2)) != MUTLS_OK) { goto error; }
+
+ /* find mG and mQ */
+ if ((err = mp_read_radix(&mG.x, (char *)key->curve->Gx, 16)) != MUTLS_OK) { goto error; }
+ if ((err = mp_read_radix(&mG.y, (char *)key->curve->Gy, 16)) != MUTLS_OK) { goto error; }
+ /*if ((err = */mp_set(&mG.z, 1);/*) != MUTLS_OK) { goto error; }*/
+
+ /*if ((err = */mp_copy(&key->pubkey.x, &mQ.x);/*) != MUTLS_OK) { goto error; }*/
+ /*if ((err = */mp_copy(&key->pubkey.y, &mQ.y);/*) != MUTLS_OK) { goto error; }*/
+ /*if ((err = */mp_copy(&key->pubkey.z, &mQ.z);/*) != MUTLS_OK) { goto error; }*/
+
+ /* compute &u1*mG + &u2*mQ = mG */
+#ifndef LTC_ECC_SHAMIR
+// if (ltc_mp.ecc_mul2add == NULL) {
+#endif
+ if ((err = ltc_ecc_mulmod(&u1, &mG, &mG, &m, 0)) != MUTLS_OK) { goto error; }
+ if ((err = ltc_ecc_mulmod(&u2, &mQ, &mQ, &m, 0)) != MUTLS_OK) { goto error; }
+
+ /* find the montgomery mp */
+ if ((err = mp_montgomery_setup(&m, &mp)) != MUTLS_OK) { goto error; }
+
+ /* add them */
+ if ((err = ltc_ecc_projective_add_point(&mQ, &mG, &mG, &m, &mp)) != MUTLS_OK) { goto error; }
+
+ /* reduce */
+ if ((err = ltc_ecc_map(&mG, &m, &mp)) != MUTLS_OK) { goto error; }
+#ifdef LTC_ECC_SHAMIR
+ /* use Shamir'&s trick to compute &u1*mG + &u2*mQ using half of the doubles */
+ if ((err = ltc_ecc_mul2add(&mG, &u1, &mQ, &u2, &mG, &m)) != MUTLS_OK) { goto error; }
+#endif
+
+ /* &v = X_x1 mod n */
+ if ((err = mp_mod(&mG.x, &p, &v)) != MUTLS_OK) { goto error; }
+
+ /* does &v == &r */
+ if (mp_cmp(&v, &r) == MP_EQ) {
+ valid = true;
+ }
+
+error:
+ mp_clear_multi(&mG.x, &mG.y, &mG.z, &mQ.x, &mQ.y, &mQ.z, &r, &s, &v, &w, &u1, &u2, &p, &e, &m, NULL);
+ mp_montgomery_free(&mp);
+ if(err == MUTLS_OK)
+ {
+ if(valid)
+ {
+ return MUTLS_OK;
+ }
+ else
+ {
+ return MUTLS_ERR_WRONG_ECDSA;
+ }
+ }
+ else
+ {
+ return err;
+ }
+}
+
+mutls_err_t crypto_ecc_dh_generate_shared_secret(const crypto_ecc_private_key_t* private_key, const crypto_ecc_public_key_t* public_key, uint8_t* secret, size_t max_secret_size, size_t* secret_size)
+{
+ unsigned long x;
+ ecc_point result;
+ fp_int prime;
+ int err;
+
+ //Check that keys match the same curve
+ if (private_key->pub.curve->type != public_key->curve->type) {
+ return MUTLS_ERR_WRONG_CURVE;
+ }
+
+ /* make new point */
+ if (mp_init_multi(&result.x, &result.y, &result.z, NULL) != MUTLS_OK) {
+ return MUTLS_ERR_MEMORY;
+ }
+
+ /*if ((err = */mp_init(&prime);/*) != MUTLS_OK) {
+ mp_clear_multi(&result->x, &result->y, &result->z, NULL);
+ return err;
+ }*/
+
+ if ((err = mp_read_radix(&prime, (char *)private_key->pub.curve->prime, 16)) != MUTLS_OK) { goto done; }
+ if ((err = ltc_ecc_mulmod(&private_key->privkey, &public_key->pubkey, &result, &prime, 1)) != MUTLS_OK) { goto done; }
+
+ x = (unsigned long)mp_unsigned_bin_size(&prime);
+ if (max_secret_size < x) {
+ *secret_size = x;
+ err = MUTLS_ERR_BUFFER_TOO_SMALL;
+ goto done;
+ }
+ zeromem(secret, x);
+ /*if ((err =*/ mp_to_unsigned_bin(&result.x, secret + (x - mp_unsigned_bin_size(&result.x)));/*) != MUTLS_OK) { goto done; }*/
+
+ err = MUTLS_OK;
+ *secret_size = x;
+done:
+ mp_clear(&prime);
+ mp_clear_multi(&result.x, &result.y, &result.z, NULL);
+ return err;
+}
+
+//Decode (&r,&s) integers from ASN.1 Signature
+#define ENSURE_SIZE(actual_size, min_size) do{ if( (actual_size) < (min_size) ) { return MUTLS_ERR_PARAMETERS; } }while(0)
+mutls_err_t crypto_ecc_dsa_check_get_asn1_rs(void* r, void* s, const uint8_t* signature, size_t signature_size)
+{
+ const uint8_t* p = signature;
+ size_t sz = signature_size;
+
+ ENSURE_SIZE(sz, 1);
+
+ if( (p[0] != 0x30) && (p[0] != 0x31) ) //Sequence, SET types
+ {
+ return MUTLS_ERR_PARAMETERS;
+ }
+
+ p++;
+ sz--;
+
+ ENSURE_SIZE(sz, 1);
+
+ size_t seq_size;
+ //Get sequence length
+ if(*p < 0x80)
+ {
+ seq_size = p[0];
+ p++;
+ sz--;
+ }
+ else if(*p == 0x81)
+ {
+ ENSURE_SIZE(sz, 2);
+ seq_size = p[1];
+ p+=2;
+ sz-=2;
+ }
+ else if(*p == 0x82)
+ {
+ ENSURE_SIZE(sz, 3);
+ seq_size = (p[1] << 8) | p[2];
+ p+=3;
+ sz-=3;
+ }
+ else if(*p == 0x83)
+ {
+ ENSURE_SIZE(sz, 4);
+ seq_size = (p[1] << 16) | (p[2] << 8) | p[3];
+ p+=4;
+ sz-=4;
+ }
+ else if(*p == 0x84)
+ {
+ ENSURE_SIZE(sz, 5);
+ seq_size = (p[1] << 24) |(p[2] << 16) | (p[3] << 8) | p[4];
+ p+=5;
+ sz-=5;
+ }
+ else
+ {
+ return MUTLS_ERR_PARAMETERS;
+ }
+
+ //Check that sequence size == remaining bytes size
+ if( seq_size != sz )
+ {
+ return MUTLS_ERR_PARAMETERS;
+ }
+
+ //Read integers
+ for(int i = 0; i < 2; i++)
+ {
+ ENSURE_SIZE(sz, 1);
+
+ if( p[0] != 2 ) //Integer type
+ {
+ return MUTLS_ERR_PARAMETERS;
+ }
+
+ p++;
+ sz--;
+
+ ENSURE_SIZE(sz, 1);
+
+ size_t integer_size;
+ //Get sequence length
+ if(*p < 0x80)
+ {
+ integer_size = p[0];
+ p++;
+ sz--;
+ }
+ else if(*p == 0x81)
+ {
+ ENSURE_SIZE(sz, 2);
+ integer_size = p[1];
+ p+=2;
+ sz-=2;
+ }
+ else if(*p == 0x82)
+ {
+ ENSURE_SIZE(sz, 3);
+ integer_size = (p[1] << 8) | p[2];
+ p+=3;
+ sz-=3;
+ }
+ else if(*p == 0x83)
+ {
+ ENSURE_SIZE(sz, 4);
+ integer_size = (p[1] << 16) | (p[2] << 8) | p[3];
+ p+=4;
+ sz-=4;
+ }
+ else if(*p == 0x84)
+ {
+ ENSURE_SIZE(sz, 5);
+ integer_size = (p[1] << 24) |(p[2] << 16) | (p[3] << 8) | p[4];
+ p+=5;
+ sz-=5;
+ }
+ else
+ {
+ return MUTLS_ERR_PARAMETERS;
+ }
+
+ //Check that we have enough bytes remaining
+ ENSURE_SIZE(sz, integer_size);
+
+ //Read integer
+ void* integer = (i==0)?r:s;
+
+ /*int err;*/
+ /*if ((err = */mp_read_unsigned_bin(integer, (unsigned char *)p, integer_size);/*) != MUTLS_OK) {
+ return err;
+ }*/
+
+ p+=integer_size;
+ sz-=integer_size;
+ }
+
+ if(sz > 0)
+ {
+ //Unread parameters left in sequence
+ return MUTLS_ERR_PARAMETERS;
+ }
+
+ return MUTLS_OK;
+}
+
+//List of curves -- storing in strings is not optimal, TODO will have to be addressed at some point
+static const crypto_ecc_curve_t crypto_ecc_curves[] = {
+#if CRYPTO_ECC160
+{
+ 20,
+ secp160r1,
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF",
+ "1C97BEFC54BD7A8B65ACF89F81D4D4ADC565FA45",
+ "0100000000000000000001F4C8F927AED3CA752257",
+ "4A96B5688EF573284664698968C38BB913CBFC82",
+ "23A628553168947D59DCC912042351377AC5FB32",
+},
+#endif
+#if CRYPTO_ECC192
+{
+ 24,
+ secp192r1,
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF",
+ "64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1",
+ "FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831",
+ "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012",
+ "7192B95FFC8DA78631011ED6B24CDD573F977A11E794811",
+},
+#endif
+#if CRYPTO_ECC224
+{
+ 28,
+ secp224r1,
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001",
+ "B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4",
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D",
+ "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21",
+ "BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34",
+},
+#endif
+#if CRYPTO_ECC256
+{
+ 32,
+ secp256r1,
+ "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF",
+ "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B",
+ "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551",
+ "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296",
+ "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5",
+},
+#endif
+#if CRYPTO_ECC384
+{
+ 48,
+ secp384r1,
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF",
+ "B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF",
+ "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973",
+ "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7",
+ "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F",
+},
+#endif
+#if CRYPTO_ECC521
+{
+ 66,
+ secp521r1,
+ "1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
+ "51953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00",
+ "1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409",
+ "C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66",
+ "11839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650",
+},
+#endif
+{0,},
+};
