diff --git a/src/key.cpp b/src/key.cpp index 1ab4c62..2b4dd78 100644 --- a/src/key.cpp +++ b/src/key.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "key.h" @@ -12,6 +13,191 @@ // anonymous namespace with local implementation code (OpenSSL interaction) namespace { +typedef struct { + int field_type, /* either NID_X9_62_prime_field or + * NID_X9_62_characteristic_two_field */ + seed_len, + param_len; + unsigned int cofactor; /* promoted to BN_ULONG */ +} EC_CURVE_DATA; + +// Local implementation of NID_secp256k1 derived from patch +// http://pastebin.com/raw.php?i=GSdYL8jz + +// this data is identical to that found in openssl-1.0.1f/crypto/ec/ec_curve.c +static const struct { EC_CURVE_DATA h; unsigned char data[0+32*6]; } + _EC_SECG_PRIME_256K1 = { + { NID_X9_62_prime_field,0,32,1 }, + { /* no seed */ + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* p */ + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF, + 0xFC,0x2F, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* a */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* b */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x07, + 0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0, /* x */ + 0x62,0x95,0xCE,0x87,0x0B,0x07,0x02,0x9B,0xFC,0xDB, + 0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8, + 0x17,0x98, + 0x48,0x3a,0xda,0x77,0x26,0xa3,0xc4,0x65,0x5d,0xa4, /* y */ + 0xfb,0xfc,0x0e,0x11,0x08,0xa8,0xfd,0x17,0xb4,0x48, + 0xa6,0x85,0x54,0x19,0x9c,0x47,0xd0,0x8f,0xfb,0x10, + 0xd4,0xb8, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, /* order */ + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6, + 0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E,0x8C,0xD0,0x36, + 0x41,0x41 } + }; + + +// Apart from spacing and the lack of some new functionality recently +// added to openssl, this function matches the openssl-1.0.1f version. +// diff --ignore-all-space -u20 +// <(grep -A121 'static EC_GROUP \*ec_group_new_from_data +// openssl-1.0.1f/crypto/ec/ec_curve.c | indent) +// <(grep -A85 'static EC_GROUP \*ec_group_new_from_data' +// vertcoin/src/key.cpp | indent) +static EC_GROUP *ec_group_new_from_data(const EC_CURVE_DATA *data) +{ + EC_GROUP *group=NULL; + EC_POINT *P=NULL; + BN_CTX *ctx=NULL; + BIGNUM *p=NULL, *a=NULL, *b=NULL, *x=NULL, *y=NULL, *order=NULL; + int ok=0; + int seed_len,param_len; + const unsigned char *params; + + if ((ctx = BN_CTX_new()) == NULL) { + ECerr(EC_F_EC_GROUP_NEW_FROM_DATA, ERR_R_MALLOC_FAILURE); + goto err; + } + + seed_len = data->seed_len; + param_len = data->param_len; + params = (const unsigned char *)(data+1); /* skip header */ + params += seed_len; /* skip seed */ + + if (!(p = BN_bin2bn(params+0*param_len, param_len, NULL)) + || !(a = BN_bin2bn(params+1*param_len, param_len, NULL)) + || !(b = BN_bin2bn(params+2*param_len, param_len, NULL))) { + ECerr(EC_F_EC_GROUP_NEW_FROM_DATA, ERR_R_BN_LIB); + goto err; + } + + if ((group = EC_GROUP_new_curve_GFp(p, a, b, ctx)) == NULL) { + ECerr(EC_F_EC_GROUP_NEW_FROM_DATA, ERR_R_EC_LIB); + goto err; + } + + if ((P = EC_POINT_new(group)) == NULL) { + ECerr(EC_F_EC_GROUP_NEW_FROM_DATA, ERR_R_EC_LIB); + goto err; + } + + if (!(x = BN_bin2bn(params+3*param_len, param_len, NULL)) + || !(y = BN_bin2bn(params+4*param_len, param_len, NULL))) { + ECerr(EC_F_EC_GROUP_NEW_FROM_DATA, ERR_R_BN_LIB); + goto err; + } + if (!EC_POINT_set_affine_coordinates_GFp(group, P, x, y, ctx)) { + ECerr(EC_F_EC_GROUP_NEW_FROM_DATA, ERR_R_EC_LIB); + goto err; + } + if (!(order = BN_bin2bn(params+5*param_len, param_len, NULL)) + || !BN_set_word(x, (BN_ULONG)data->cofactor)) + { + ECerr(EC_F_EC_GROUP_NEW_FROM_DATA, ERR_R_BN_LIB); + goto err; + } + if (!EC_GROUP_set_generator(group, P, order, x)) { + ECerr(EC_F_EC_GROUP_NEW_FROM_DATA, ERR_R_EC_LIB); + goto err; + } + if (seed_len) { + if (!EC_GROUP_set_seed(group, params-seed_len, seed_len)) { + ECerr(EC_F_EC_GROUP_NEW_FROM_DATA, ERR_R_EC_LIB); + goto err; + } + } + ok=1; +err: + if (!ok) { + EC_GROUP_free(group); + group = NULL; + } + if (P) + EC_POINT_free(P); + if (ctx) + BN_CTX_free(ctx); + if (p) + BN_free(p); + if (a) + BN_free(a); + if (b) + BN_free(b); + if (order) + BN_free(order); + if (x) + BN_free(x); + if (y) + BN_free(y); + return group; +} + + +// EC_GROUP_new_by_curve_name_NID_secp256k1() is functionally identical +// to EC_GROUP_new_by_curve_name(NID_secp256k1) in openssl-1.0.1f/crypto/ec/ec_curve.c +EC_GROUP *EC_GROUP_new_by_curve_name_NID_secp256k1(void) +{ + static EC_GROUP *group = NULL; + + if (group == NULL) { + group = EC_GROUP_new_by_curve_name(NID_secp256k1); + } + if (group == NULL) { + fprintf(stderr, + "Your openssl library lacks the elliptic curve chosen by Satoshi for bitcoin.\n" + "Using implementation identical to that in openssl version 1.0.1f.\n"); + group = ec_group_new_from_data(&_EC_SECG_PRIME_256K1.h); + EC_GROUP_set_curve_name (group, NID_secp256k1); + } + + return group; +} + + +// EC_KEY_new_by_curve_name_NID_secp256k1() is functionally identical +// to EC_KEY_new_by_curve_name(NID_secp256k1) in openssl-1.0.1f/crypto/ec/ec_key.c +// diff -u10 --ignore-all-space +// <(grep -A12 '\*EC_KEY_new_by_curve_name' +// openssl-1.0.1f/crypto/ec/ec_key.c | indent) +// <(grep -A16 '\*EC_KEY_new_by_curve_name' +// vertcoin/src/key.cpp | indent) +EC_KEY *EC_KEY_new_by_curve_name_NID_secp256k1(void) +{ + EC_KEY *ret = NULL; + EC_GROUP *group = EC_GROUP_new_by_curve_name_NID_secp256k1(); + + if (group == NULL) + return NULL; + + ret = EC_KEY_new(); + + if (ret == NULL) + return NULL; + + EC_KEY_set_group(ret, group); + + return ret; +} + + // Generate a private key from just the secret parameter int EC_KEY_regenerate_key(EC_KEY *eckey, BIGNUM *priv_key) { @@ -130,7 +316,7 @@ private: public: CECKey() { - pkey = EC_KEY_new_by_curve_name(NID_secp256k1); + pkey = EC_KEY_new_by_curve_name_NID_secp256k1(); assert(pkey != NULL); }