1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2012 The Bitcoin developers
3 // Distributed under the MIT/X11 software license, see the accompanying
4 // file license.txt or http://www.opensource.org/licenses/mit-license.php.
11 #include <openssl/ec.h>
12 #include <openssl/ecdsa.h>
13 #include <openssl/obj_mac.h>
15 #include "serialize.h"
19 // const unsigned int PRIVATE_KEY_SIZE = 192;
20 // const unsigned int PUBLIC_KEY_SIZE = 41;
21 // const unsigned int SIGNATURE_SIZE = 48;
24 // const unsigned int PRIVATE_KEY_SIZE = 222;
25 // const unsigned int PUBLIC_KEY_SIZE = 49;
26 // const unsigned int SIGNATURE_SIZE = 57;
29 // const unsigned int PRIVATE_KEY_SIZE = 250;
30 // const unsigned int PUBLIC_KEY_SIZE = 57;
31 // const unsigned int SIGNATURE_SIZE = 66;
34 // const unsigned int PRIVATE_KEY_SIZE = 279;
35 // const unsigned int PUBLIC_KEY_SIZE = 65;
36 // const unsigned int SIGNATURE_SIZE = 72;
38 // see www.keylength.com
39 // script supports up to 75 for single byte push
41 int extern EC_KEY_regenerate_key(EC_KEY
*eckey
, BIGNUM
*priv_key
);
42 int extern ECDSA_SIG_recover_key_GFp(EC_KEY
*eckey
, ECDSA_SIG
*ecsig
, const unsigned char *msg
, int msglen
, int recid
, int check
);
44 class key_error
: public std::runtime_error
47 explicit key_error(const std::string
& str
) : std::runtime_error(str
) {}
51 // secure_allocator is defined in serialize.h
52 // CPrivKey is a serialized private key, with all parameters included (279 bytes)
53 typedef std::vector
<unsigned char, secure_allocator
<unsigned char> > CPrivKey
;
54 // CSecret is a serialization of just the secret parameter (32 bytes)
55 typedef std::vector
<unsigned char, secure_allocator
<unsigned char> > CSecret
;
62 bool fCompressedPubKey
;
64 void SetCompressedPubKey()
66 EC_KEY_set_conv_form(pkey
, POINT_CONVERSION_COMPRESSED
);
67 fCompressedPubKey
= true;
74 fCompressedPubKey
= false;
75 pkey
= EC_KEY_new_by_curve_name(NID_secp256k1
);
77 throw key_error("CKey::CKey() : EC_KEY_new_by_curve_name failed");
88 pkey
= EC_KEY_dup(b
.pkey
);
90 throw key_error("CKey::CKey(const CKey&) : EC_KEY_dup failed");
94 CKey
& operator=(const CKey
& b
)
96 if (!EC_KEY_copy(pkey
, b
.pkey
))
97 throw key_error("CKey::operator=(const CKey&) : EC_KEY_copy failed");
112 bool IsCompressed() const
114 return fCompressedPubKey
;
117 void MakeNewKey(bool fCompressed
)
119 if (!EC_KEY_generate_key(pkey
))
120 throw key_error("CKey::MakeNewKey() : EC_KEY_generate_key failed");
122 SetCompressedPubKey();
126 bool SetPrivKey(const CPrivKey
& vchPrivKey
)
128 const unsigned char* pbegin
= &vchPrivKey
[0];
129 if (!d2i_ECPrivateKey(&pkey
, &pbegin
, vchPrivKey
.size()))
135 bool SetSecret(const CSecret
& vchSecret
, bool fCompressed
= false)
138 pkey
= EC_KEY_new_by_curve_name(NID_secp256k1
);
140 throw key_error("CKey::SetSecret() : EC_KEY_new_by_curve_name failed");
141 if (vchSecret
.size() != 32)
142 throw key_error("CKey::SetSecret() : secret must be 32 bytes");
143 BIGNUM
*bn
= BN_bin2bn(&vchSecret
[0],32,BN_new());
145 throw key_error("CKey::SetSecret() : BN_bin2bn failed");
146 if (!EC_KEY_regenerate_key(pkey
,bn
))
149 throw key_error("CKey::SetSecret() : EC_KEY_regenerate_key failed");
153 if (fCompressed
|| fCompressedPubKey
)
154 SetCompressedPubKey();
158 CSecret
GetSecret(bool &fCompressed
) const
162 const BIGNUM
*bn
= EC_KEY_get0_private_key(pkey
);
163 int nBytes
= BN_num_bytes(bn
);
165 throw key_error("CKey::GetSecret() : EC_KEY_get0_private_key failed");
166 int n
=BN_bn2bin(bn
,&vchRet
[32 - nBytes
]);
168 throw key_error("CKey::GetSecret(): BN_bn2bin failed");
169 fCompressed
= fCompressedPubKey
;
173 CPrivKey
GetPrivKey() const
175 unsigned int nSize
= i2d_ECPrivateKey(pkey
, NULL
);
177 throw key_error("CKey::GetPrivKey() : i2d_ECPrivateKey failed");
178 CPrivKey
vchPrivKey(nSize
, 0);
179 unsigned char* pbegin
= &vchPrivKey
[0];
180 if (i2d_ECPrivateKey(pkey
, &pbegin
) != nSize
)
181 throw key_error("CKey::GetPrivKey() : i2d_ECPrivateKey returned unexpected size");
185 bool SetPubKey(const std::vector
<unsigned char>& vchPubKey
)
187 const unsigned char* pbegin
= &vchPubKey
[0];
188 if (!o2i_ECPublicKey(&pkey
, &pbegin
, vchPubKey
.size()))
191 if (vchPubKey
.size() == 33)
192 SetCompressedPubKey();
196 std::vector
<unsigned char> GetPubKey() const
198 unsigned int nSize
= i2o_ECPublicKey(pkey
, NULL
);
200 throw key_error("CKey::GetPubKey() : i2o_ECPublicKey failed");
201 std::vector
<unsigned char> vchPubKey(nSize
, 0);
202 unsigned char* pbegin
= &vchPubKey
[0];
203 if (i2o_ECPublicKey(pkey
, &pbegin
) != nSize
)
204 throw key_error("CKey::GetPubKey() : i2o_ECPublicKey returned unexpected size");
208 bool Sign(uint256 hash
, std::vector
<unsigned char>& vchSig
)
210 unsigned int nSize
= ECDSA_size(pkey
);
211 vchSig
.resize(nSize
); // Make sure it is big enough
212 if (!ECDSA_sign(0, (unsigned char*)&hash
, sizeof(hash
), &vchSig
[0], &nSize
, pkey
))
217 vchSig
.resize(nSize
); // Shrink to fit actual size
221 // create a compact signature (65 bytes), which allows reconstructing the used public key
222 // The format is one header byte, followed by two times 32 bytes for the serialized r and s values.
223 // The header byte: 0x1B = first key with even y, 0x1C = first key with odd y,
224 // 0x1D = second key with even y, 0x1E = second key with odd y
225 bool SignCompact(uint256 hash
, std::vector
<unsigned char>& vchSig
)
228 ECDSA_SIG
*sig
= ECDSA_do_sign((unsigned char*)&hash
, sizeof(hash
), pkey
);
233 int nBitsR
= BN_num_bits(sig
->r
);
234 int nBitsS
= BN_num_bits(sig
->s
);
235 if (nBitsR
<= 256 && nBitsS
<= 256)
238 for (int i
=0; i
<4; i
++)
242 if (fCompressedPubKey
)
243 keyRec
.SetCompressedPubKey();
244 if (ECDSA_SIG_recover_key_GFp(keyRec
.pkey
, sig
, (unsigned char*)&hash
, sizeof(hash
), i
, 1) == 1)
245 if (keyRec
.GetPubKey() == this->GetPubKey())
253 throw key_error("CKey::SignCompact() : unable to construct recoverable key");
255 vchSig
[0] = nRecId
+27+(fCompressedPubKey
? 4 : 0);
256 BN_bn2bin(sig
->r
,&vchSig
[33-(nBitsR
+7)/8]);
257 BN_bn2bin(sig
->s
,&vchSig
[65-(nBitsS
+7)/8]);
264 // reconstruct public key from a compact signature
265 // This is only slightly more CPU intensive than just verifying it.
266 // If this function succeeds, the recovered public key is guaranteed to be valid
267 // (the signature is a valid signature of the given data for that key)
268 bool SetCompactSignature(uint256 hash
, const std::vector
<unsigned char>& vchSig
)
270 if (vchSig
.size() != 65)
275 ECDSA_SIG
*sig
= ECDSA_SIG_new();
276 BN_bin2bn(&vchSig
[1],32,sig
->r
);
277 BN_bin2bn(&vchSig
[33],32,sig
->s
);
280 pkey
= EC_KEY_new_by_curve_name(NID_secp256k1
);
283 SetCompressedPubKey();
286 if (ECDSA_SIG_recover_key_GFp(pkey
, sig
, (unsigned char*)&hash
, sizeof(hash
), nV
- 27, 0) == 1)
295 bool Verify(uint256 hash
, const std::vector
<unsigned char>& vchSig
)
297 // -1 = error, 0 = bad sig, 1 = good
298 if (ECDSA_verify(0, (unsigned char*)&hash
, sizeof(hash
), &vchSig
[0], vchSig
.size(), pkey
) != 1)
303 // Verify a compact signature
304 bool VerifyCompact(uint256 hash
, const std::vector
<unsigned char>& vchSig
)
307 if (!key
.SetCompactSignature(hash
, vchSig
))
309 if (GetPubKey() != key
.GetPubKey())
320 CSecret secret
= GetSecret(fCompr
);
322 key2
.SetSecret(secret
, fCompr
);
323 return GetPubKey() == key2
.GetPubKey();