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