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