genesis 1
genesis 2
genesis 3
genesis 4
genesis 5 #ifndef BITCOIN_KEY_H
genesis 6 #define BITCOIN_KEY_H
genesis 7
genesis 8 #include <stdexcept>
genesis 9 #include <vector>
genesis 10
genesis 11 #include <openssl/ec.h>
genesis 12 #include <openssl/ecdsa.h>
genesis 13 #include <openssl/obj_mac.h>
genesis 14
genesis 15 #include "serialize.h"
genesis 16 #include "uint256.h"
genesis 17
genesis 18
genesis 19
genesis 20
genesis 21
genesis 22
genesis 23
genesis 24
genesis 25
genesis 26
genesis 27
genesis 28
genesis 29
genesis 30
genesis 31
genesis 32
genesis 33
genesis 34
genesis 35
genesis 36
genesis 37
genesis 38
genesis 39
genesis 40
genesis 41
genesis 42 int static inline EC_KEY_regenerate_key(EC_KEY *eckey, BIGNUM *priv_key)
genesis 43 {
genesis 44 int ok = 0;
genesis 45 BN_CTX *ctx = NULL;
genesis 46 EC_POINT *pub_key = NULL;
genesis 47
genesis 48 if (!eckey) return 0;
genesis 49
genesis 50 const EC_GROUP *group = EC_KEY_get0_group(eckey);
genesis 51
genesis 52 if ((ctx = BN_CTX_new()) == NULL)
genesis 53 goto err;
genesis 54
genesis 55 pub_key = EC_POINT_new(group);
genesis 56
genesis 57 if (pub_key == NULL)
genesis 58 goto err;
genesis 59
genesis 60 if (!EC_POINT_mul(group, pub_key, priv_key, NULL, NULL, ctx))
genesis 61 goto err;
genesis 62
genesis 63 EC_KEY_set_private_key(eckey,priv_key);
genesis 64 EC_KEY_set_public_key(eckey,pub_key);
genesis 65
genesis 66 ok = 1;
genesis 67
genesis 68 err:
genesis 69
genesis 70 if (pub_key)
genesis 71 EC_POINT_free(pub_key);
genesis 72 if (ctx != NULL)
genesis 73 BN_CTX_free(ctx);
genesis 74
genesis 75 return(ok);
genesis 76 }
genesis 77
genesis 78
genesis 79
genesis 80
genesis 81 int static inline ECDSA_SIG_recover_key_GFp(EC_KEY *eckey, ECDSA_SIG *ecsig, const unsigned char *msg, int msglen, int recid, int check)
genesis 82 {
genesis 83 if (!eckey) return 0;
genesis 84
genesis 85 int ret = 0;
genesis 86 BN_CTX *ctx = NULL;
genesis 87
genesis 88 BIGNUM *x = NULL;
genesis 89 BIGNUM *e = NULL;
genesis 90 BIGNUM *order = NULL;
genesis 91 BIGNUM *sor = NULL;
genesis 92 BIGNUM *eor = NULL;
genesis 93 BIGNUM *field = NULL;
genesis 94 EC_POINT *R = NULL;
genesis 95 EC_POINT *O = NULL;
genesis 96 EC_POINT *Q = NULL;
genesis 97 BIGNUM *rr = NULL;
genesis 98 BIGNUM *zero = NULL;
genesis 99 int n = 0;
genesis 100 int i = recid / 2;
genesis 101
genesis 102 const EC_GROUP *group = EC_KEY_get0_group(eckey);
genesis 103 if ((ctx = BN_CTX_new()) == NULL) { ret = -1; goto err; }
genesis 104 BN_CTX_start(ctx);
genesis 105 order = BN_CTX_get(ctx);
genesis 106 if (!EC_GROUP_get_order(group, order, ctx)) { ret = -2; goto err; }
genesis 107 x = BN_CTX_get(ctx);
genesis 108 if (!BN_copy(x, order)) { ret=-1; goto err; }
genesis 109 if (!BN_mul_word(x, i)) { ret=-1; goto err; }
genesis 110 if (!BN_add(x, x, ecsig->r)) { ret=-1; goto err; }
genesis 111 field = BN_CTX_get(ctx);
genesis 112 if (!EC_GROUP_get_curve_GFp(group, field, NULL, NULL, ctx)) { ret=-2; goto err; }
genesis 113 if (BN_cmp(x, field) >= 0) { ret=0; goto err; }
genesis 114 if ((R = EC_POINT_new(group)) == NULL) { ret = -2; goto err; }
genesis 115 if (!EC_POINT_set_compressed_coordinates_GFp(group, R, x, recid % 2, ctx)) { ret=0; goto err; }
genesis 116 if (check)
genesis 117 {
genesis 118 if ((O = EC_POINT_new(group)) == NULL) { ret = -2; goto err; }
genesis 119 if (!EC_POINT_mul(group, O, NULL, R, order, ctx)) { ret=-2; goto err; }
genesis 120 if (!EC_POINT_is_at_infinity(group, O)) { ret = 0; goto err; }
genesis 121 }
genesis 122 if ((Q = EC_POINT_new(group)) == NULL) { ret = -2; goto err; }
genesis 123 n = EC_GROUP_get_degree(group);
genesis 124 e = BN_CTX_get(ctx);
genesis 125 if (!BN_bin2bn(msg, msglen, e)) { ret=-1; goto err; }
genesis 126 if (8*msglen > n) BN_rshift(e, e, 8-(n & 7));
genesis 127 zero = BN_CTX_get(ctx);
genesis 128 if (!BN_zero(zero)) { ret=-1; goto err; }
genesis 129 if (!BN_mod_sub(e, zero, e, order, ctx)) { ret=-1; goto err; }
genesis 130 rr = BN_CTX_get(ctx);
genesis 131 if (!BN_mod_inverse(rr, ecsig->r, order, ctx)) { ret=-1; goto err; }
genesis 132 sor = BN_CTX_get(ctx);
genesis 133 if (!BN_mod_mul(sor, ecsig->s, rr, order, ctx)) { ret=-1; goto err; }
genesis 134 eor = BN_CTX_get(ctx);
genesis 135 if (!BN_mod_mul(eor, e, rr, order, ctx)) { ret=-1; goto err; }
genesis 136 if (!EC_POINT_mul(group, Q, eor, R, sor, ctx)) { ret=-2; goto err; }
genesis 137 if (!EC_KEY_set_public_key(eckey, Q)) { ret=-2; goto err; }
genesis 138
genesis 139 ret = 1;
genesis 140
genesis 141 err:
genesis 142 if (ctx) {
genesis 143 BN_CTX_end(ctx);
genesis 144 BN_CTX_free(ctx);
genesis 145 }
genesis 146 if (R != NULL) EC_POINT_free(R);
genesis 147 if (O != NULL) EC_POINT_free(O);
genesis 148 if (Q != NULL) EC_POINT_free(Q);
genesis 149 return ret;
genesis 150 }
genesis 151
genesis 152 class key_error : public std::runtime_error
genesis 153 {
genesis 154 public:
genesis 155 explicit key_error(const std::string& str) : std::runtime_error(str) {}
genesis 156 };
genesis 157
genesis 158
genesis 159
genesis 160
genesis 161 typedef std::vector<unsigned char, secure_allocator<unsigned char> > CPrivKey;
genesis 162
genesis 163 typedef std::vector<unsigned char, secure_allocator<unsigned char> > CSecret;
genesis 164
genesis 165 class CKey
genesis 166 {
genesis 167 protected:
genesis 168 EC_KEY* pkey;
genesis 169 bool fSet;
genesis 170
genesis 171 public:
genesis 172 CKey()
genesis 173 {
genesis 174 pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
genesis 175 if (pkey == NULL)
genesis 176 throw key_error("CKey::CKey() : EC_KEY_new_by_curve_name failed");
genesis 177 fSet = false;
genesis 178 }
genesis 179
genesis 180 CKey(const CKey& b)
genesis 181 {
genesis 182 pkey = EC_KEY_dup(b.pkey);
genesis 183 if (pkey == NULL)
genesis 184 throw key_error("CKey::CKey(const CKey&) : EC_KEY_dup failed");
genesis 185 fSet = b.fSet;
genesis 186 }
genesis 187
genesis 188 CKey& operator=(const CKey& b)
genesis 189 {
genesis 190 if (!EC_KEY_copy(pkey, b.pkey))
genesis 191 throw key_error("CKey::operator=(const CKey&) : EC_KEY_copy failed");
genesis 192 fSet = b.fSet;
genesis 193 return (*this);
genesis 194 }
genesis 195
genesis 196 ~CKey()
genesis 197 {
genesis 198 EC_KEY_free(pkey);
genesis 199 }
genesis 200
genesis 201 bool IsNull() const
genesis 202 {
genesis 203 return !fSet;
genesis 204 }
genesis 205
genesis 206 void MakeNewKey()
genesis 207 {
genesis 208 if (!EC_KEY_generate_key(pkey))
genesis 209 throw key_error("CKey::MakeNewKey() : EC_KEY_generate_key failed");
genesis 210 fSet = true;
genesis 211 }
genesis 212
genesis 213 bool SetPrivKey(const CPrivKey& vchPrivKey)
genesis 214 {
genesis 215 const unsigned char* pbegin = &vchPrivKey[0];
genesis 216 if (!d2i_ECPrivateKey(&pkey, &pbegin, vchPrivKey.size()))
genesis 217 return false;
genesis 218 fSet = true;
genesis 219 return true;
genesis 220 }
genesis 221
genesis 222 bool SetSecret(const CSecret& vchSecret)
genesis 223 {
genesis 224 EC_KEY_free(pkey);
genesis 225 pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
genesis 226 if (pkey == NULL)
genesis 227 throw key_error("CKey::SetSecret() : EC_KEY_new_by_curve_name failed");
genesis 228 if (vchSecret.size() != 32)
genesis 229 throw key_error("CKey::SetSecret() : secret must be 32 bytes");
genesis 230 BIGNUM *bn = BN_bin2bn(&vchSecret[0],32,BN_new());
genesis 231 if (bn == NULL)
genesis 232 throw key_error("CKey::SetSecret() : BN_bin2bn failed");
genesis 233 if (!EC_KEY_regenerate_key(pkey,bn))
genesis 234 {
genesis 235 BN_clear_free(bn);
genesis 236 throw key_error("CKey::SetSecret() : EC_KEY_regenerate_key failed");
genesis 237 }
genesis 238 BN_clear_free(bn);
genesis 239 fSet = true;
genesis 240 return true;
genesis 241 }
genesis 242
genesis 243 CSecret GetSecret() const
genesis 244 {
genesis 245 CSecret vchRet;
genesis 246 vchRet.resize(32);
genesis 247 const BIGNUM *bn = EC_KEY_get0_private_key(pkey);
genesis 248 int nBytes = BN_num_bytes(bn);
genesis 249 if (bn == NULL)
genesis 250 throw key_error("CKey::GetSecret() : EC_KEY_get0_private_key failed");
genesis 251 int n=BN_bn2bin(bn,&vchRet[32 - nBytes]);
genesis 252 if (n != nBytes)
genesis 253 throw key_error("CKey::GetSecret(): BN_bn2bin failed");
genesis 254 return vchRet;
genesis 255 }
genesis 256
genesis 257 CPrivKey GetPrivKey() const
genesis 258 {
genesis 259 unsigned int nSize = i2d_ECPrivateKey(pkey, NULL);
genesis 260 if (!nSize)
genesis 261 throw key_error("CKey::GetPrivKey() : i2d_ECPrivateKey failed");
genesis 262 CPrivKey vchPrivKey(nSize, 0);
genesis 263 unsigned char* pbegin = &vchPrivKey[0];
genesis 264 if (i2d_ECPrivateKey(pkey, &pbegin) != nSize)
genesis 265 throw key_error("CKey::GetPrivKey() : i2d_ECPrivateKey returned unexpected size");
genesis 266 return vchPrivKey;
genesis 267 }
genesis 268
genesis 269 bool SetPubKey(const std::vector<unsigned char>& vchPubKey)
genesis 270 {
genesis 271 const unsigned char* pbegin = &vchPubKey[0];
genesis 272 if (!o2i_ECPublicKey(&pkey, &pbegin, vchPubKey.size()))
genesis 273 return false;
genesis 274 fSet = true;
genesis 275 return true;
genesis 276 }
genesis 277
genesis 278 std::vector<unsigned char> GetPubKey() const
genesis 279 {
genesis 280 unsigned int nSize = i2o_ECPublicKey(pkey, NULL);
genesis 281 if (!nSize)
genesis 282 throw key_error("CKey::GetPubKey() : i2o_ECPublicKey failed");
genesis 283 std::vector<unsigned char> vchPubKey(nSize, 0);
genesis 284 unsigned char* pbegin = &vchPubKey[0];
genesis 285 if (i2o_ECPublicKey(pkey, &pbegin) != nSize)
genesis 286 throw key_error("CKey::GetPubKey() : i2o_ECPublicKey returned unexpected size");
genesis 287 return vchPubKey;
genesis 288 }
genesis 289
genesis 290 bool Sign(uint256 hash, std::vector<unsigned char>& vchSig)
genesis 291 {
genesis 292 vchSig.clear();
mod6_der_high_low_s 293 ECDSA_SIG *sig = ECDSA_do_sign((unsigned char *) &hash, sizeof(hash), pkey);
mod6_der_high_low_s 294
mod6_der_high_low_s 295 if (sig == NULL)
mod6_der_high_low_s 296 {
mod6_der_high_low_s 297 printf("ERROR, ECDSA_sign failed in key.h:Sign()\n");
genesis 298 return false;
mod6_der_high_low_s 299 }
mod6_der_high_low_s 300
mod6_der_high_low_s 301 BN_CTX *ctx = BN_CTX_new();
mod6_der_high_low_s 302 BN_CTX_start(ctx);
mod6_der_high_low_s 303 const EC_GROUP *group = EC_KEY_get0_group(pkey);
mod6_der_high_low_s 304 BIGNUM *order = BN_CTX_get(ctx);
mod6_der_high_low_s 305 BIGNUM *halforder = BN_CTX_get(ctx);
mod6_der_high_low_s 306 EC_GROUP_get_order(group, order, ctx);
mod6_der_high_low_s 307 BN_rshift1(halforder, order);
mod6_der_high_low_s 308
mod6_der_high_low_s 309 if (fHighS && (BN_cmp(sig->s, halforder) < 0))
mod6_der_high_low_s 310 {
mod6_der_high_low_s 311
mod6_der_high_low_s 312 BN_sub(sig->s, order, sig->s);
mod6_der_high_low_s 313 }
mod6_der_high_low_s 314
mod6_der_high_low_s 315 if (fLowS && (BN_cmp(sig->s, halforder) > 0))
mod6_der_high_low_s 316 {
mod6_der_high_low_s 317
mod6_der_high_low_s 318 BN_sub(sig->s, order, sig->s);
mod6_der_high_low_s 319 }
mod6_der_high_low_s 320
mod6_der_high_low_s 321 BN_CTX_end(ctx);
mod6_der_high_low_s 322 BN_CTX_free(ctx);
mod6_der_high_low_s 323 unsigned int nSize = ECDSA_size(pkey);
mod6_der_high_low_s 324 vchSig.resize(nSize);
mod6_der_high_low_s 325 unsigned char *pos = &vchSig[0];
mod6_der_high_low_s 326 nSize = i2d_ECDSA_SIG(sig, &pos);
mod6_der_high_low_s 327
mod6_der_high_low_s 328
mod6_der_high_low_s 329
mod6_der_high_low_s 330
mod6_der_high_low_s 331 ECDSA_SIG_free(sig);
mod6_der_high_low_s 332 vchSig.resize(nSize);
genesis 333 return true;
genesis 334 }
genesis 335
genesis 336
genesis 337
genesis 338
genesis 339
genesis 340 bool SignCompact(uint256 hash, std::vector<unsigned char>& vchSig)
genesis 341 {
genesis 342 bool fOk = false;
genesis 343 ECDSA_SIG *sig = ECDSA_do_sign((unsigned char*)&hash, sizeof(hash), pkey);
genesis 344 if (sig==NULL)
genesis 345 return false;
genesis 346 vchSig.clear();
genesis 347 vchSig.resize(65,0);
genesis 348 int nBitsR = BN_num_bits(sig->r);
genesis 349 int nBitsS = BN_num_bits(sig->s);
genesis 350 if (nBitsR <= 256 && nBitsS <= 256)
genesis 351 {
genesis 352 int nRecId = -1;
genesis 353 for (int i=0; i<4; i++)
genesis 354 {
genesis 355 CKey keyRec;
genesis 356 keyRec.fSet = true;
genesis 357 if (ECDSA_SIG_recover_key_GFp(keyRec.pkey, sig, (unsigned char*)&hash, sizeof(hash), i, 1) == 1)
genesis 358 if (keyRec.GetPubKey() == this->GetPubKey())
genesis 359 {
genesis 360 nRecId = i;
genesis 361 break;
genesis 362 }
genesis 363 }
genesis 364
genesis 365 if (nRecId == -1)
genesis 366 throw key_error("CKey::SignCompact() : unable to construct recoverable key");
genesis 367
genesis 368 vchSig[0] = nRecId+27;
genesis 369 BN_bn2bin(sig->r,&vchSig[33-(nBitsR+7)/8]);
genesis 370 BN_bn2bin(sig->s,&vchSig[65-(nBitsS+7)/8]);
genesis 371 fOk = true;
genesis 372 }
genesis 373 ECDSA_SIG_free(sig);
genesis 374 return fOk;
genesis 375 }
genesis 376
genesis 377
genesis 378
genesis 379
genesis 380
genesis 381 bool SetCompactSignature(uint256 hash, const std::vector<unsigned char>& vchSig)
genesis 382 {
genesis 383 if (vchSig.size() != 65)
genesis 384 return false;
genesis 385 if (vchSig[0]<27 || vchSig[0]>=31)
genesis 386 return false;
genesis 387 ECDSA_SIG *sig = ECDSA_SIG_new();
genesis 388 BN_bin2bn(&vchSig[1],32,sig->r);
genesis 389 BN_bin2bn(&vchSig[33],32,sig->s);
genesis 390
genesis 391 EC_KEY_free(pkey);
genesis 392 pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
genesis 393 if (ECDSA_SIG_recover_key_GFp(pkey, sig, (unsigned char*)&hash, sizeof(hash), vchSig[0] - 27, 0) == 1)
genesis 394 {
genesis 395 fSet = true;
genesis 396 ECDSA_SIG_free(sig);
genesis 397 return true;
genesis 398 }
genesis 399 return false;
genesis 400 }
genesis 401
genesis 402 bool Verify(uint256 hash, const std::vector<unsigned char>& vchSig)
genesis 403 {
genesis 404
genesis 405 if (ECDSA_verify(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], vchSig.size(), pkey) != 1)
genesis 406 return false;
genesis 407 return true;
genesis 408 }
genesis 409
genesis 410
genesis 411 bool VerifyCompact(uint256 hash, const std::vector<unsigned char>& vchSig)
genesis 412 {
genesis 413 CKey key;
genesis 414 if (!key.SetCompactSignature(hash, vchSig))
genesis 415 return false;
genesis 416 if (GetPubKey() != key.GetPubKey())
genesis 417 return false;
genesis 418 return true;
genesis 419 }
genesis 420
genesis 421 bool IsValid()
genesis 422 {
genesis 423 if (!fSet)
genesis 424 return false;
genesis 425
genesis 426 CSecret secret = GetSecret();
genesis 427 CKey key2;
genesis 428 key2.SetSecret(secret);
genesis 429 return GetPubKey() == key2.GetPubKey();
genesis 430 }
genesis 431 };
genesis 432
genesis 433 #endif