]>
Commit | Line | Data |
---|---|---|
f914f1a7 | 1 | // Copyright (c) 2009-2014 The Bitcoin Core developers |
ffd8edda | 2 | // Distributed under the MIT software license, see the accompanying |
3a25a2b9 | 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. |
93db3fce | 4 | |
51ed9ec9 BD |
5 | #include "key.h" |
6 | ||
734f85c4 | 7 | #include "arith_uint256.h" |
437ada3e | 8 | #include "crypto/common.h" |
36fa4a78 | 9 | #include "crypto/hmac_sha512.h" |
900078ae | 10 | #include "eccryptoverify.h" |
d2e74c55 | 11 | #include "pubkey.h" |
001a53d7 | 12 | #include "random.h" |
977cdade | 13 | |
fda3fed1 | 14 | #include <secp256k1.h> |
50f71cd5 | 15 | #include "ecwrapper.h" |
dfa23b94 | 16 | |
a56054be | 17 | static secp256k1_context_t* secp256k1_context = NULL; |
dfa23b94 PW |
18 | |
19 | bool CKey::Check(const unsigned char *vch) { | |
900078ae | 20 | return eccrypto::Check(vch); |
096e06db GA |
21 | } |
22 | ||
dfa23b94 | 23 | void CKey::MakeNewKey(bool fCompressedIn) { |
146c0a7c | 24 | RandAddSeedPerfmon(); |
dfa23b94 | 25 | do { |
001a53d7 | 26 | GetRandBytes(vch, sizeof(vch)); |
dfa23b94 PW |
27 | } while (!Check(vch)); |
28 | fValid = true; | |
29 | fCompressed = fCompressedIn; | |
096e06db GA |
30 | } |
31 | ||
dfa23b94 | 32 | bool CKey::SetPrivKey(const CPrivKey &privkey, bool fCompressedIn) { |
a56054be | 33 | if (!secp256k1_ec_privkey_import(secp256k1_context, (unsigned char*)begin(), &privkey[0], privkey.size())) |
dfa23b94 | 34 | return false; |
dfa23b94 PW |
35 | fCompressed = fCompressedIn; |
36 | fValid = true; | |
37 | return true; | |
096e06db GA |
38 | } |
39 | ||
dfa23b94 PW |
40 | CPrivKey CKey::GetPrivKey() const { |
41 | assert(fValid); | |
fda3fed1 | 42 | CPrivKey privkey; |
e405aa48 | 43 | int privkeylen, ret; |
fda3fed1 | 44 | privkey.resize(279); |
e405aa48 | 45 | privkeylen = 279; |
a56054be | 46 | ret = secp256k1_ec_privkey_export(secp256k1_context, begin(), (unsigned char*)&privkey[0], &privkeylen, fCompressed); |
fda3fed1 PW |
47 | assert(ret); |
48 | privkey.resize(privkeylen); | |
dfa23b94 | 49 | return privkey; |
096e06db GA |
50 | } |
51 | ||
dfa23b94 PW |
52 | CPubKey CKey::GetPubKey() const { |
53 | assert(fValid); | |
bdaec6ab | 54 | CPubKey result; |
fda3fed1 | 55 | int clen = 65; |
a56054be | 56 | int ret = secp256k1_ec_pubkey_create(secp256k1_context, (unsigned char*)result.begin(), &clen, begin(), fCompressed); |
bdaec6ab | 57 | assert((int)result.size() == clen); |
fda3fed1 | 58 | assert(ret); |
bdaec6ab CF |
59 | assert(result.IsValid()); |
60 | return result; | |
096e06db GA |
61 | } |
62 | ||
a53fd414 | 63 | bool CKey::Sign(const uint256 &hash, std::vector<unsigned char>& vchSig, uint32_t test_case) const { |
dfa23b94 | 64 | if (!fValid) |
096e06db | 65 | return false; |
fda3fed1 | 66 | vchSig.resize(72); |
1a9576de | 67 | int nSigLen = 72; |
437ada3e PW |
68 | unsigned char extra_entropy[32] = {0}; |
69 | WriteLE32(extra_entropy, test_case); | |
a56054be | 70 | int ret = secp256k1_ecdsa_sign(secp256k1_context, hash.begin(), (unsigned char*)&vchSig[0], &nSigLen, begin(), secp256k1_nonce_function_rfc6979, test_case ? extra_entropy : NULL); |
1a9576de PW |
71 | assert(ret); |
72 | vchSig.resize(nSigLen); | |
73 | return true; | |
096e06db GA |
74 | } |
75 | ||
d0c41a73 PW |
76 | bool CKey::VerifyPubKey(const CPubKey& pubkey) const { |
77 | if (pubkey.IsCompressed() != fCompressed) { | |
78 | return false; | |
79 | } | |
80 | unsigned char rnd[8]; | |
81 | std::string str = "Bitcoin key verification\n"; | |
82 | GetRandBytes(rnd, sizeof(rnd)); | |
83 | uint256 hash; | |
1a9576de | 84 | CHash256().Write((unsigned char*)str.data(), str.size()).Write(rnd, sizeof(rnd)).Finalize(hash.begin()); |
d0c41a73 PW |
85 | std::vector<unsigned char> vchSig; |
86 | Sign(hash, vchSig); | |
87 | return pubkey.Verify(hash, vchSig); | |
88 | } | |
89 | ||
dfa23b94 PW |
90 | bool CKey::SignCompact(const uint256 &hash, std::vector<unsigned char>& vchSig) const { |
91 | if (!fValid) | |
096e06db | 92 | return false; |
dfa23b94 PW |
93 | vchSig.resize(65); |
94 | int rec = -1; | |
a56054be | 95 | int ret = secp256k1_ecdsa_sign_compact(secp256k1_context, hash.begin(), &vchSig[1], begin(), secp256k1_nonce_function_rfc6979, NULL, &rec); |
1a9576de | 96 | assert(ret); |
dfa23b94 PW |
97 | assert(rec != -1); |
98 | vchSig[0] = 27 + rec + (fCompressed ? 4 : 0); | |
99 | return true; | |
100 | } | |
096e06db | 101 | |
6e51b3bd | 102 | bool CKey::Load(CPrivKey &privkey, CPubKey &vchPubKey, bool fSkipCheck=false) { |
a56054be | 103 | if (!secp256k1_ec_privkey_import(secp256k1_context, (unsigned char*)begin(), &privkey[0], privkey.size())) |
6e51b3bd | 104 | return false; |
6e51b3bd | 105 | fCompressed = vchPubKey.IsCompressed(); |
106 | fValid = true; | |
fda3fed1 | 107 | |
a42eef6f | 108 | if (fSkipCheck) |
109 | return true; | |
fda3fed1 | 110 | |
d0c41a73 | 111 | return VerifyPubKey(vchPubKey); |
6e51b3bd | 112 | } |
113 | ||
a5748996 | 114 | bool CKey::Derive(CKey& keyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc) const { |
eb2c9990 PW |
115 | assert(IsValid()); |
116 | assert(IsCompressed()); | |
117 | unsigned char out[64]; | |
118 | LockObject(out); | |
119 | if ((nChild >> 31) == 0) { | |
120 | CPubKey pubkey = GetPubKey(); | |
121 | assert(pubkey.begin() + 33 == pubkey.end()); | |
122 | BIP32Hash(cc, nChild, *pubkey.begin(), pubkey.begin()+1, out); | |
123 | } else { | |
124 | assert(begin() + 32 == end()); | |
125 | BIP32Hash(cc, nChild, 0, begin(), out); | |
126 | } | |
a5748996 | 127 | memcpy(ccChild.begin(), out+32, 32); |
fda3fed1 | 128 | memcpy((unsigned char*)keyChild.begin(), begin(), 32); |
a56054be | 129 | bool ret = secp256k1_ec_privkey_tweak_add(secp256k1_context, (unsigned char*)keyChild.begin(), out); |
eb2c9990 PW |
130 | UnlockObject(out); |
131 | keyChild.fCompressed = true; | |
132 | keyChild.fValid = ret; | |
133 | return ret; | |
134 | } | |
135 | ||
eb2c9990 PW |
136 | bool CExtKey::Derive(CExtKey &out, unsigned int nChild) const { |
137 | out.nDepth = nDepth + 1; | |
138 | CKeyID id = key.GetPubKey().GetID(); | |
139 | memcpy(&out.vchFingerprint[0], &id, 4); | |
140 | out.nChild = nChild; | |
a5748996 | 141 | return key.Derive(out.key, out.chaincode, nChild, chaincode); |
eb2c9990 PW |
142 | } |
143 | ||
144 | void CExtKey::SetMaster(const unsigned char *seed, unsigned int nSeedLen) { | |
977cdade | 145 | static const unsigned char hashkey[] = {'B','i','t','c','o','i','n',' ','s','e','e','d'}; |
eb2c9990 PW |
146 | unsigned char out[64]; |
147 | LockObject(out); | |
977cdade | 148 | CHMAC_SHA512(hashkey, sizeof(hashkey)).Write(seed, nSeedLen).Finalize(out); |
eb2c9990 | 149 | key.Set(&out[0], &out[32], true); |
a5748996 | 150 | memcpy(chaincode.begin(), &out[32], 32); |
eb2c9990 PW |
151 | UnlockObject(out); |
152 | nDepth = 0; | |
153 | nChild = 0; | |
154 | memset(vchFingerprint, 0, sizeof(vchFingerprint)); | |
155 | } | |
156 | ||
157 | CExtPubKey CExtKey::Neuter() const { | |
158 | CExtPubKey ret; | |
159 | ret.nDepth = nDepth; | |
160 | memcpy(&ret.vchFingerprint[0], &vchFingerprint[0], 4); | |
161 | ret.nChild = nChild; | |
162 | ret.pubkey = key.GetPubKey(); | |
a5748996 | 163 | ret.chaincode = chaincode; |
eb2c9990 PW |
164 | return ret; |
165 | } | |
166 | ||
167 | void CExtKey::Encode(unsigned char code[74]) const { | |
168 | code[0] = nDepth; | |
169 | memcpy(code+1, vchFingerprint, 4); | |
170 | code[5] = (nChild >> 24) & 0xFF; code[6] = (nChild >> 16) & 0xFF; | |
171 | code[7] = (nChild >> 8) & 0xFF; code[8] = (nChild >> 0) & 0xFF; | |
a5748996 | 172 | memcpy(code+9, chaincode.begin(), 32); |
eb2c9990 PW |
173 | code[41] = 0; |
174 | assert(key.size() == 32); | |
175 | memcpy(code+42, key.begin(), 32); | |
176 | } | |
177 | ||
178 | void CExtKey::Decode(const unsigned char code[74]) { | |
179 | nDepth = code[0]; | |
180 | memcpy(vchFingerprint, code+1, 4); | |
181 | nChild = (code[5] << 24) | (code[6] << 16) | (code[7] << 8) | code[8]; | |
a5748996 | 182 | memcpy(chaincode.begin(), code+9, 32); |
eb2c9990 PW |
183 | key.Set(code+42, code+74, true); |
184 | } | |
185 | ||
4a09e1df | 186 | bool ECC_InitSanityCheck() { |
f321d6bf PW |
187 | if (!CECKey::SanityCheck()) { |
188 | return false; | |
189 | } | |
f321d6bf PW |
190 | CKey key; |
191 | key.MakeNewKey(true); | |
192 | CPubKey pubkey = key.GetPubKey(); | |
193 | return key.VerifyPubKey(pubkey); | |
4a09e1df | 194 | } |
a56054be PW |
195 | |
196 | ||
197 | void ECC_Start() { | |
198 | assert(secp256k1_context == NULL); | |
199 | ||
200 | secp256k1_context_t *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); | |
201 | assert(ctx != NULL); | |
202 | ||
203 | { | |
204 | // Pass in a random blinding seed to the secp256k1 context. | |
205 | unsigned char seed[32]; | |
206 | LockObject(seed); | |
207 | GetRandBytes(seed, 32); | |
208 | bool ret = secp256k1_context_randomize(ctx, seed); | |
209 | assert(ret); | |
210 | UnlockObject(seed); | |
211 | } | |
212 | ||
213 | secp256k1_context = ctx; | |
214 | } | |
215 | ||
216 | void ECC_Stop() { | |
217 | secp256k1_context_t *ctx = secp256k1_context; | |
218 | secp256k1_context = NULL; | |
219 | ||
220 | if (ctx) { | |
221 | secp256k1_context_destroy(ctx); | |
222 | } | |
223 | } |