Update copyrights to 2012 for files modified this year
[novacoin.git] / src / key.h
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.
5 #ifndef BITCOIN_KEY_H
6 #define BITCOIN_KEY_H
7
8 #include <stdexcept>
9 #include <vector>
10
11 #include <openssl/ec.h>
12 #include <openssl/ecdsa.h>
13 #include <openssl/obj_mac.h>
14
15 #include "serialize.h"
16 #include "uint256.h"
17 #include "base58.h"
18
19 // secp160k1
20 // const unsigned int PRIVATE_KEY_SIZE = 192;
21 // const unsigned int PUBLIC_KEY_SIZE  = 41;
22 // const unsigned int SIGNATURE_SIZE   = 48;
23 //
24 // secp192k1
25 // const unsigned int PRIVATE_KEY_SIZE = 222;
26 // const unsigned int PUBLIC_KEY_SIZE  = 49;
27 // const unsigned int SIGNATURE_SIZE   = 57;
28 //
29 // secp224k1
30 // const unsigned int PRIVATE_KEY_SIZE = 250;
31 // const unsigned int PUBLIC_KEY_SIZE  = 57;
32 // const unsigned int SIGNATURE_SIZE   = 66;
33 //
34 // secp256k1:
35 // const unsigned int PRIVATE_KEY_SIZE = 279;
36 // const unsigned int PUBLIC_KEY_SIZE  = 65;
37 // const unsigned int SIGNATURE_SIZE   = 72;
38 //
39 // see www.keylength.com
40 // script supports up to 75 for single byte push
41
42 int static inline EC_KEY_regenerate_key(EC_KEY *eckey, BIGNUM *priv_key)
43 {
44     int ok = 0;
45     BN_CTX *ctx = NULL;
46     EC_POINT *pub_key = NULL;
47
48     if (!eckey) return 0;
49
50     const EC_GROUP *group = EC_KEY_get0_group(eckey);
51
52     if ((ctx = BN_CTX_new()) == NULL)
53         goto err;
54
55     pub_key = EC_POINT_new(group);
56
57     if (pub_key == NULL)
58         goto err;
59
60     if (!EC_POINT_mul(group, pub_key, priv_key, NULL, NULL, ctx))
61         goto err;
62
63     EC_KEY_set_private_key(eckey,priv_key);
64     EC_KEY_set_public_key(eckey,pub_key);
65
66     ok = 1;
67
68 err:
69
70     if (pub_key)
71         EC_POINT_free(pub_key);
72     if (ctx != NULL)
73         BN_CTX_free(ctx);
74
75     return(ok);
76 }
77
78
79 class key_error : public std::runtime_error
80 {
81 public:
82     explicit key_error(const std::string& str) : std::runtime_error(str) {}
83 };
84
85
86 // secure_allocator is defined in serialize.h
87 typedef std::vector<unsigned char, secure_allocator<unsigned char> > CPrivKey;
88 typedef std::vector<unsigned char, secure_allocator<unsigned char> > CSecret;
89
90 class CKey
91 {
92 protected:
93     EC_KEY* pkey;
94     bool fSet;
95
96 public:
97     CKey()
98     {
99         pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
100         if (pkey == NULL)
101             throw key_error("CKey::CKey() : EC_KEY_new_by_curve_name failed");
102         fSet = false;
103     }
104
105     CKey(const CKey& b)
106     {
107         pkey = EC_KEY_dup(b.pkey);
108         if (pkey == NULL)
109             throw key_error("CKey::CKey(const CKey&) : EC_KEY_dup failed");
110         fSet = b.fSet;
111     }
112
113     CKey& operator=(const CKey& b)
114     {
115         if (!EC_KEY_copy(pkey, b.pkey))
116             throw key_error("CKey::operator=(const CKey&) : EC_KEY_copy failed");
117         fSet = b.fSet;
118         return (*this);
119     }
120
121     ~CKey()
122     {
123         EC_KEY_free(pkey);
124     }
125
126     bool IsNull() const
127     {
128         return !fSet;
129     }
130
131     void MakeNewKey()
132     {
133         if (!EC_KEY_generate_key(pkey))
134             throw key_error("CKey::MakeNewKey() : EC_KEY_generate_key failed");
135         fSet = true;
136     }
137
138     bool SetPrivKey(const CPrivKey& vchPrivKey)
139     {
140         const unsigned char* pbegin = &vchPrivKey[0];
141         if (!d2i_ECPrivateKey(&pkey, &pbegin, vchPrivKey.size()))
142             return false;
143         fSet = true;
144         return true;
145     }
146
147     bool SetSecret(const CSecret& vchSecret)
148     {
149         EC_KEY_free(pkey);
150         pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
151         if (pkey == NULL)
152             throw key_error("CKey::SetSecret() : EC_KEY_new_by_curve_name failed");
153         if (vchSecret.size() != 32)
154             throw key_error("CKey::SetSecret() : secret must be 32 bytes");
155         BIGNUM *bn = BN_bin2bn(&vchSecret[0],32,BN_new());
156         if (bn == NULL) 
157             throw key_error("CKey::SetSecret() : BN_bin2bn failed");
158         if (!EC_KEY_regenerate_key(pkey,bn))
159             throw key_error("CKey::SetSecret() : EC_KEY_regenerate_key failed");
160         BN_clear_free(bn);
161         fSet = true;
162         return true;
163     }
164
165     CSecret GetSecret() const
166     {
167         CSecret vchRet;
168         vchRet.resize(32);
169         const BIGNUM *bn = EC_KEY_get0_private_key(pkey);
170         int nBytes = BN_num_bytes(bn);
171         if (bn == NULL)
172             throw key_error("CKey::GetSecret() : EC_KEY_get0_private_key failed");
173         int n=BN_bn2bin(bn,&vchRet[32 - nBytes]);
174         if (n != nBytes) 
175             throw key_error("CKey::GetSecret(): BN_bn2bin failed");
176         return vchRet;
177     }
178
179     CPrivKey GetPrivKey() const
180     {
181         unsigned int nSize = i2d_ECPrivateKey(pkey, NULL);
182         if (!nSize)
183             throw key_error("CKey::GetPrivKey() : i2d_ECPrivateKey failed");
184         CPrivKey vchPrivKey(nSize, 0);
185         unsigned char* pbegin = &vchPrivKey[0];
186         if (i2d_ECPrivateKey(pkey, &pbegin) != nSize)
187             throw key_error("CKey::GetPrivKey() : i2d_ECPrivateKey returned unexpected size");
188         return vchPrivKey;
189     }
190
191     bool SetPubKey(const std::vector<unsigned char>& vchPubKey)
192     {
193         const unsigned char* pbegin = &vchPubKey[0];
194         if (!o2i_ECPublicKey(&pkey, &pbegin, vchPubKey.size()))
195             return false;
196         fSet = true;
197         return true;
198     }
199
200     std::vector<unsigned char> GetPubKey() const
201     {
202         unsigned int nSize = i2o_ECPublicKey(pkey, NULL);
203         if (!nSize)
204             throw key_error("CKey::GetPubKey() : i2o_ECPublicKey failed");
205         std::vector<unsigned char> vchPubKey(nSize, 0);
206         unsigned char* pbegin = &vchPubKey[0];
207         if (i2o_ECPublicKey(pkey, &pbegin) != nSize)
208             throw key_error("CKey::GetPubKey() : i2o_ECPublicKey returned unexpected size");
209         return vchPubKey;
210     }
211
212     bool Sign(uint256 hash, std::vector<unsigned char>& vchSig)
213     {
214         vchSig.clear();
215         unsigned char pchSig[10000];
216         unsigned int nSize = 0;
217         if (!ECDSA_sign(0, (unsigned char*)&hash, sizeof(hash), pchSig, &nSize, pkey))
218             return false;
219         vchSig.resize(nSize);
220         memcpy(&vchSig[0], pchSig, nSize);
221         return true;
222     }
223
224     bool Verify(uint256 hash, const std::vector<unsigned char>& vchSig)
225     {
226         // -1 = error, 0 = bad sig, 1 = good
227         if (ECDSA_verify(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], vchSig.size(), pkey) != 1)
228             return false;
229         return true;
230     }
231
232     CBitcoinAddress GetAddress() const
233     {
234         return CBitcoinAddress(GetPubKey());
235     }
236
237     bool IsValid()
238     {
239         if (!fSet)
240             return false;
241
242         CSecret secret = GetSecret();
243         CKey key2;
244         key2.SetSecret(secret);
245         return GetPubKey() == key2.GetPubKey();
246     }
247 };
248
249 #endif