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();
genesis 293 unsigned char pchSig[10000];
genesis 294 unsigned int nSize = 0;
genesis 295 if (!ECDSA_sign(0, (unsigned char*)&hash, sizeof(hash), pchSig, &nSize, pkey))
genesis 296 return false;
genesis 297 vchSig.resize(nSize);
genesis 298 memcpy(&vchSig[0], pchSig, nSize);
genesis 299 return true;
genesis 300 }
genesis 301
genesis 302
genesis 303
genesis 304
genesis 305
genesis 306 bool SignCompact(uint256 hash, std::vector<unsigned char>& vchSig)
genesis 307 {
genesis 308 bool fOk = false;
genesis 309 ECDSA_SIG *sig = ECDSA_do_sign((unsigned char*)&hash, sizeof(hash), pkey);
genesis 310 if (sig==NULL)
genesis 311 return false;
genesis 312 vchSig.clear();
genesis 313 vchSig.resize(65,0);
genesis 314 int nBitsR = BN_num_bits(sig->r);
genesis 315 int nBitsS = BN_num_bits(sig->s);
genesis 316 if (nBitsR <= 256 && nBitsS <= 256)
genesis 317 {
genesis 318 int nRecId = -1;
genesis 319 for (int i=0; i<4; i++)
genesis 320 {
genesis 321 CKey keyRec;
genesis 322 keyRec.fSet = true;
genesis 323 if (ECDSA_SIG_recover_key_GFp(keyRec.pkey, sig, (unsigned char*)&hash, sizeof(hash), i, 1) == 1)
genesis 324 if (keyRec.GetPubKey() == this->GetPubKey())
genesis 325 {
genesis 326 nRecId = i;
genesis 327 break;
genesis 328 }
genesis 329 }
genesis 330
genesis 331 if (nRecId == -1)
genesis 332 throw key_error("CKey::SignCompact() : unable to construct recoverable key");
genesis 333
genesis 334 vchSig[0] = nRecId+27;
genesis 335 BN_bn2bin(sig->r,&vchSig[33-(nBitsR+7)/8]);
genesis 336 BN_bn2bin(sig->s,&vchSig[65-(nBitsS+7)/8]);
genesis 337 fOk = true;
genesis 338 }
genesis 339 ECDSA_SIG_free(sig);
genesis 340 return fOk;
genesis 341 }
genesis 342
genesis 343
genesis 344
genesis 345
genesis 346
genesis 347 bool SetCompactSignature(uint256 hash, const std::vector<unsigned char>& vchSig)
genesis 348 {
genesis 349 if (vchSig.size() != 65)
genesis 350 return false;
genesis 351 if (vchSig[0]<27 || vchSig[0]>=31)
genesis 352 return false;
genesis 353 ECDSA_SIG *sig = ECDSA_SIG_new();
genesis 354 BN_bin2bn(&vchSig[1],32,sig->r);
genesis 355 BN_bin2bn(&vchSig[33],32,sig->s);
genesis 356
genesis 357 EC_KEY_free(pkey);
genesis 358 pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
genesis 359 if (ECDSA_SIG_recover_key_GFp(pkey, sig, (unsigned char*)&hash, sizeof(hash), vchSig[0] - 27, 0) == 1)
genesis 360 {
genesis 361 fSet = true;
genesis 362 ECDSA_SIG_free(sig);
genesis 363 return true;
genesis 364 }
genesis 365 return false;
genesis 366 }
genesis 367
genesis 368 bool Verify(uint256 hash, const std::vector<unsigned char>& vchSig)
genesis 369 {
genesis 370
genesis 371 if (ECDSA_verify(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], vchSig.size(), pkey) != 1)
genesis 372 return false;
genesis 373 return true;
genesis 374 }
genesis 375
genesis 376
genesis 377 bool VerifyCompact(uint256 hash, const std::vector<unsigned char>& vchSig)
genesis 378 {
genesis 379 CKey key;
genesis 380 if (!key.SetCompactSignature(hash, vchSig))
genesis 381 return false;
genesis 382 if (GetPubKey() != key.GetPubKey())
genesis 383 return false;
genesis 384 return true;
genesis 385 }
genesis 386
genesis 387 bool IsValid()
genesis 388 {
genesis 389 if (!fSet)
genesis 390 return false;
genesis 391
genesis 392 CSecret secret = GetSecret();
genesis 393 CKey key2;
genesis 394 key2.SetSecret(secret);
genesis 395 return GetPubKey() == key2.GetPubKey();
genesis 396 }
genesis 397 };
genesis 398
genesis 399 #endif