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