Update License in File Headers
[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 COPYING 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 "allocators.h"
16 #include "uint256.h"
17
18 // secp160k1
19 // const unsigned int PRIVATE_KEY_SIZE = 192;
20 // const unsigned int PUBLIC_KEY_SIZE  = 41;
21 // const unsigned int SIGNATURE_SIZE   = 48;
22 //
23 // secp192k1
24 // const unsigned int PRIVATE_KEY_SIZE = 222;
25 // const unsigned int PUBLIC_KEY_SIZE  = 49;
26 // const unsigned int SIGNATURE_SIZE   = 57;
27 //
28 // secp224k1
29 // const unsigned int PRIVATE_KEY_SIZE = 250;
30 // const unsigned int PUBLIC_KEY_SIZE  = 57;
31 // const unsigned int SIGNATURE_SIZE   = 66;
32 //
33 // secp256k1:
34 // const unsigned int PRIVATE_KEY_SIZE = 279;
35 // const unsigned int PUBLIC_KEY_SIZE  = 65;
36 // const unsigned int SIGNATURE_SIZE   = 72;
37 //
38 // see www.keylength.com
39 // script supports up to 75 for single byte push
40
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);
43
44 class key_error : public std::runtime_error
45 {
46 public:
47     explicit key_error(const std::string& str) : std::runtime_error(str) {}
48 };
49
50
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;
56
57 /** An encapsulated OpenSSL Elliptic Curve key (public and/or private) */
58 class CKey
59 {
60 protected:
61     EC_KEY* pkey;
62     bool fSet;
63     bool fCompressedPubKey;
64
65     void SetCompressedPubKey()
66     {
67         EC_KEY_set_conv_form(pkey, POINT_CONVERSION_COMPRESSED);
68         fCompressedPubKey = true;
69     }
70
71 public:
72
73     void Reset()
74     {
75         fCompressedPubKey = false;
76         pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
77         if (pkey == NULL)
78             throw key_error("CKey::CKey() : EC_KEY_new_by_curve_name failed");
79         fSet = false;
80     }
81
82     CKey()
83     {
84         Reset();
85     }
86
87     CKey(const CKey& b)
88     {
89         pkey = EC_KEY_dup(b.pkey);
90         if (pkey == NULL)
91             throw key_error("CKey::CKey(const CKey&) : EC_KEY_dup failed");
92         fSet = b.fSet;
93     }
94
95     CKey& operator=(const CKey& b)
96     {
97         if (!EC_KEY_copy(pkey, b.pkey))
98             throw key_error("CKey::operator=(const CKey&) : EC_KEY_copy failed");
99         fSet = b.fSet;
100         return (*this);
101     }
102
103     ~CKey()
104     {
105         EC_KEY_free(pkey);
106     }
107
108     bool IsNull() const
109     {
110         return !fSet;
111     }
112
113     bool IsCompressed() const
114     {
115         return fCompressedPubKey;
116     }
117
118     void MakeNewKey(bool fCompressed)
119     {
120         if (!EC_KEY_generate_key(pkey))
121             throw key_error("CKey::MakeNewKey() : EC_KEY_generate_key failed");
122         if (fCompressed)
123             SetCompressedPubKey();
124         fSet = true;
125     }
126
127     bool SetPrivKey(const CPrivKey& vchPrivKey)
128     {
129         const unsigned char* pbegin = &vchPrivKey[0];
130         if (!d2i_ECPrivateKey(&pkey, &pbegin, vchPrivKey.size()))
131             return false;
132         fSet = true;
133         return true;
134     }
135
136     bool SetSecret(const CSecret& vchSecret, bool fCompressed = false)
137     {
138         EC_KEY_free(pkey);
139         pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
140         if (pkey == NULL)
141             throw key_error("CKey::SetSecret() : EC_KEY_new_by_curve_name failed");
142         if (vchSecret.size() != 32)
143             throw key_error("CKey::SetSecret() : secret must be 32 bytes");
144         BIGNUM *bn = BN_bin2bn(&vchSecret[0],32,BN_new());
145         if (bn == NULL)
146             throw key_error("CKey::SetSecret() : BN_bin2bn failed");
147         if (!EC_KEY_regenerate_key(pkey,bn))
148         {
149             BN_clear_free(bn);
150             throw key_error("CKey::SetSecret() : EC_KEY_regenerate_key failed");
151         }
152         BN_clear_free(bn);
153         fSet = true;
154         if (fCompressed || fCompressedPubKey)
155             SetCompressedPubKey();
156         return true;
157     }
158
159     CSecret GetSecret(bool &fCompressed) const
160     {
161         CSecret vchRet;
162         vchRet.resize(32);
163         const BIGNUM *bn = EC_KEY_get0_private_key(pkey);
164         int nBytes = BN_num_bytes(bn);
165         if (bn == NULL)
166             throw key_error("CKey::GetSecret() : EC_KEY_get0_private_key failed");
167         int n=BN_bn2bin(bn,&vchRet[32 - nBytes]);
168         if (n != nBytes) 
169             throw key_error("CKey::GetSecret(): BN_bn2bin failed");
170         fCompressed = fCompressedPubKey;
171         return vchRet;
172     }
173
174     CPrivKey GetPrivKey() const
175     {
176         int nSize = i2d_ECPrivateKey(pkey, NULL);
177         if (!nSize)
178             throw key_error("CKey::GetPrivKey() : i2d_ECPrivateKey failed");
179         CPrivKey vchPrivKey(nSize, 0);
180         unsigned char* pbegin = &vchPrivKey[0];
181         if (i2d_ECPrivateKey(pkey, &pbegin) != nSize)
182             throw key_error("CKey::GetPrivKey() : i2d_ECPrivateKey returned unexpected size");
183         return vchPrivKey;
184     }
185
186     bool SetPubKey(const std::vector<unsigned char>& vchPubKey)
187     {
188         const unsigned char* pbegin = &vchPubKey[0];
189         if (!o2i_ECPublicKey(&pkey, &pbegin, vchPubKey.size()))
190             return false;
191         fSet = true;
192         if (vchPubKey.size() == 33)
193             SetCompressedPubKey();
194         return true;
195     }
196
197     std::vector<unsigned char> GetPubKey() const
198     {
199         int nSize = i2o_ECPublicKey(pkey, NULL);
200         if (!nSize)
201             throw key_error("CKey::GetPubKey() : i2o_ECPublicKey failed");
202         std::vector<unsigned char> vchPubKey(nSize, 0);
203         unsigned char* pbegin = &vchPubKey[0];
204         if (i2o_ECPublicKey(pkey, &pbegin) != nSize)
205             throw key_error("CKey::GetPubKey() : i2o_ECPublicKey returned unexpected size");
206         return vchPubKey;
207     }
208
209     bool Sign(uint256 hash, std::vector<unsigned char>& vchSig)
210     {
211         unsigned int nSize = ECDSA_size(pkey);
212         vchSig.resize(nSize); // Make sure it is big enough
213         if (!ECDSA_sign(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], &nSize, pkey))
214         {
215             vchSig.clear();
216             return false;
217         }
218         vchSig.resize(nSize); // Shrink to fit actual size
219         return true;
220     }
221
222     // create a compact signature (65 bytes), which allows reconstructing the used public key
223     // The format is one header byte, followed by two times 32 bytes for the serialized r and s values.
224     // The header byte: 0x1B = first key with even y, 0x1C = first key with odd y,
225     //                  0x1D = second key with even y, 0x1E = second key with odd y
226     bool SignCompact(uint256 hash, std::vector<unsigned char>& vchSig)
227     {
228         bool fOk = false;
229         ECDSA_SIG *sig = ECDSA_do_sign((unsigned char*)&hash, sizeof(hash), pkey);
230         if (sig==NULL)
231             return false;
232         vchSig.clear();
233         vchSig.resize(65,0);
234         int nBitsR = BN_num_bits(sig->r);
235         int nBitsS = BN_num_bits(sig->s);
236         if (nBitsR <= 256 && nBitsS <= 256)
237         {
238             int nRecId = -1;
239             for (int i=0; i<4; i++)
240             {
241                 CKey keyRec;
242                 keyRec.fSet = true;
243                 if (fCompressedPubKey)
244                     keyRec.SetCompressedPubKey();
245                 if (ECDSA_SIG_recover_key_GFp(keyRec.pkey, sig, (unsigned char*)&hash, sizeof(hash), i, 1) == 1)
246                     if (keyRec.GetPubKey() == this->GetPubKey())
247                     {
248                         nRecId = i;
249                         break;
250                     }
251             }
252
253             if (nRecId == -1)
254                 throw key_error("CKey::SignCompact() : unable to construct recoverable key");
255
256             vchSig[0] = nRecId+27+(fCompressedPubKey ? 4 : 0);
257             BN_bn2bin(sig->r,&vchSig[33-(nBitsR+7)/8]);
258             BN_bn2bin(sig->s,&vchSig[65-(nBitsS+7)/8]);
259             fOk = true;
260         }
261         ECDSA_SIG_free(sig);
262         return fOk;
263     }
264
265     // reconstruct public key from a compact signature
266     // This is only slightly more CPU intensive than just verifying it.
267     // If this function succeeds, the recovered public key is guaranteed to be valid
268     // (the signature is a valid signature of the given data for that key)
269     bool SetCompactSignature(uint256 hash, const std::vector<unsigned char>& vchSig)
270     {
271         if (vchSig.size() != 65)
272             return false;
273         int nV = vchSig[0];
274         if (nV<27 || nV>=35)
275             return false;
276         ECDSA_SIG *sig = ECDSA_SIG_new();
277         BN_bin2bn(&vchSig[1],32,sig->r);
278         BN_bin2bn(&vchSig[33],32,sig->s);
279
280         EC_KEY_free(pkey);
281         pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
282         if (nV >= 31)
283         {
284             SetCompressedPubKey();
285             nV -= 4;
286         }
287         if (ECDSA_SIG_recover_key_GFp(pkey, sig, (unsigned char*)&hash, sizeof(hash), nV - 27, 0) == 1)
288         {
289             fSet = true;
290             ECDSA_SIG_free(sig);
291             return true;
292         }
293         return false;
294     }
295
296     bool Verify(uint256 hash, const std::vector<unsigned char>& vchSig)
297     {
298         // -1 = error, 0 = bad sig, 1 = good
299         if (ECDSA_verify(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], vchSig.size(), pkey) != 1)
300             return false;
301         return true;
302     }
303
304     // Verify a compact signature
305     bool VerifyCompact(uint256 hash, const std::vector<unsigned char>& vchSig)
306     {
307         CKey key;
308         if (!key.SetCompactSignature(hash, vchSig))
309             return false;
310         if (GetPubKey() != key.GetPubKey())
311             return false;
312         return true;
313     }
314
315     bool IsValid()
316     {
317         if (!fSet)
318             return false;
319
320         bool fCompr;
321         CSecret secret = GetSecret(fCompr);
322         CKey key2;
323         key2.SetSecret(secret, fCompr);
324         return GetPubKey() == key2.GetPubKey();
325     }
326 };
327
328 #endif