Skip to content

Commit a56054b

Browse files
committed
Update key.cpp to use new libsecp256k1
libsecp256k1's API changed, so update key.cpp to use it. Libsecp256k1 now has explicit context objects, which makes it completely thread-safe. In turn, keep an explicit context object in key.cpp, which is explicitly initialized destroyed. This is not really pretty now, but it's more efficient than the static initialized object in key.cpp (which made for example bitcoin-tx slow, as for most of its calls, libsecp256k1 wasn't actually needed). This also brings in the new blinding support in libsecp256k1. By passing in a random seed, temporary variables during the elliptic curve computations are altered, in such a way that if an attacker does not know the blind, observing the internal operations leaks less information about the keys used. This was implemented by Greg Maxwell.
1 parent 4dda253 commit a56054b

File tree

5 files changed

+63
-24
lines changed

5 files changed

+63
-24
lines changed

src/bitcoin-tx.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -444,9 +444,18 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr)
444444
tx = mergedTx;
445445
}
446446

447+
class Secp256k1Init
448+
{
449+
public:
450+
Secp256k1Init() { ECC_Start(); }
451+
~Secp256k1Init() { ECC_Stop(); }
452+
};
453+
447454
static void MutateTx(CMutableTransaction& tx, const string& command,
448455
const string& commandVal)
449456
{
457+
boost::scoped_ptr<Secp256k1Init> ecc;
458+
450459
if (command == "nversion")
451460
MutateTxVersion(tx, commandVal);
452461
else if (command == "locktime")
@@ -464,8 +473,10 @@ static void MutateTx(CMutableTransaction& tx, const string& command,
464473
else if (command == "outscript")
465474
MutateTxAddOutScript(tx, commandVal);
466475

467-
else if (command == "sign")
476+
else if (command == "sign") {
477+
if (!ecc) { ecc.reset(new Secp256k1Init()); }
468478
MutateTxSign(tx, commandVal);
479+
}
469480

470481
else if (command == "load")
471482
RegisterLoad(commandVal);

src/init.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ void Shutdown()
194194
delete pwalletMain;
195195
pwalletMain = NULL;
196196
#endif
197+
ECC_Stop();
197198
LogPrintf("%s: done\n", __func__);
198199
}
199200

@@ -788,6 +789,9 @@ bool AppInit2(boost::thread_group& threadGroup)
788789

789790
// ********************************************************* Step 4: application initialization: dir lock, daemonize, pidfile, debug log
790791

792+
// Initialize elliptic curve code
793+
ECC_Start();
794+
791795
// Sanity check
792796
if (!InitSanityCheck())
793797
return InitError(_("Initialization sanity check failed. Bitcoin Core is shutting down."));

src/key.cpp

Lines changed: 37 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,7 @@
1414
#include <secp256k1.h>
1515
#include "ecwrapper.h"
1616

17-
//! anonymous namespace
18-
namespace {
19-
20-
class CSecp256k1Init {
21-
public:
22-
CSecp256k1Init() {
23-
secp256k1_start(SECP256K1_START_SIGN);
24-
}
25-
~CSecp256k1Init() {
26-
secp256k1_stop();
27-
}
28-
};
29-
static CSecp256k1Init instance_of_csecp256k1;
30-
31-
} // anon namespace
17+
static secp256k1_context_t* secp256k1_context = NULL;
3218

3319
bool CKey::Check(const unsigned char *vch) {
3420
return eccrypto::Check(vch);
@@ -44,7 +30,7 @@ void CKey::MakeNewKey(bool fCompressedIn) {
4430
}
4531

4632
bool CKey::SetPrivKey(const CPrivKey &privkey, bool fCompressedIn) {
47-
if (!secp256k1_ec_privkey_import((unsigned char*)begin(), &privkey[0], privkey.size()))
33+
if (!secp256k1_ec_privkey_import(secp256k1_context, (unsigned char*)begin(), &privkey[0], privkey.size()))
4834
return false;
4935
fCompressed = fCompressedIn;
5036
fValid = true;
@@ -57,7 +43,7 @@ CPrivKey CKey::GetPrivKey() const {
5743
int privkeylen, ret;
5844
privkey.resize(279);
5945
privkeylen = 279;
60-
ret = secp256k1_ec_privkey_export(begin(), (unsigned char*)&privkey[0], &privkeylen, fCompressed);
46+
ret = secp256k1_ec_privkey_export(secp256k1_context, begin(), (unsigned char*)&privkey[0], &privkeylen, fCompressed);
6147
assert(ret);
6248
privkey.resize(privkeylen);
6349
return privkey;
@@ -67,7 +53,7 @@ CPubKey CKey::GetPubKey() const {
6753
assert(fValid);
6854
CPubKey result;
6955
int clen = 65;
70-
int ret = secp256k1_ec_pubkey_create((unsigned char*)result.begin(), &clen, begin(), fCompressed);
56+
int ret = secp256k1_ec_pubkey_create(secp256k1_context, (unsigned char*)result.begin(), &clen, begin(), fCompressed);
7157
assert((int)result.size() == clen);
7258
assert(ret);
7359
assert(result.IsValid());
@@ -81,7 +67,7 @@ bool CKey::Sign(const uint256 &hash, std::vector<unsigned char>& vchSig, uint32_
8167
int nSigLen = 72;
8268
unsigned char extra_entropy[32] = {0};
8369
WriteLE32(extra_entropy, test_case);
84-
int ret = secp256k1_ecdsa_sign(hash.begin(), (unsigned char*)&vchSig[0], &nSigLen, begin(), secp256k1_nonce_function_rfc6979, test_case ? extra_entropy : NULL);
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);
8571
assert(ret);
8672
vchSig.resize(nSigLen);
8773
return true;
@@ -106,15 +92,15 @@ bool CKey::SignCompact(const uint256 &hash, std::vector<unsigned char>& vchSig)
10692
return false;
10793
vchSig.resize(65);
10894
int rec = -1;
109-
int ret = secp256k1_ecdsa_sign_compact(hash.begin(), &vchSig[1], begin(), secp256k1_nonce_function_rfc6979, NULL, &rec);
95+
int ret = secp256k1_ecdsa_sign_compact(secp256k1_context, hash.begin(), &vchSig[1], begin(), secp256k1_nonce_function_rfc6979, NULL, &rec);
11096
assert(ret);
11197
assert(rec != -1);
11298
vchSig[0] = 27 + rec + (fCompressed ? 4 : 0);
11399
return true;
114100
}
115101

116102
bool CKey::Load(CPrivKey &privkey, CPubKey &vchPubKey, bool fSkipCheck=false) {
117-
if (!secp256k1_ec_privkey_import((unsigned char*)begin(), &privkey[0], privkey.size()))
103+
if (!secp256k1_ec_privkey_import(secp256k1_context, (unsigned char*)begin(), &privkey[0], privkey.size()))
118104
return false;
119105
fCompressed = vchPubKey.IsCompressed();
120106
fValid = true;
@@ -140,7 +126,7 @@ bool CKey::Derive(CKey& keyChild, unsigned char ccChild[32], unsigned int nChild
140126
}
141127
memcpy(ccChild, out+32, 32);
142128
memcpy((unsigned char*)keyChild.begin(), begin(), 32);
143-
bool ret = secp256k1_ec_privkey_tweak_add((unsigned char*)keyChild.begin(), out);
129+
bool ret = secp256k1_ec_privkey_tweak_add(secp256k1_context, (unsigned char*)keyChild.begin(), out);
144130
UnlockObject(out);
145131
keyChild.fCompressed = true;
146132
keyChild.fValid = ret;
@@ -206,3 +192,32 @@ bool ECC_InitSanityCheck() {
206192
CPubKey pubkey = key.GetPubKey();
207193
return key.VerifyPubKey(pubkey);
208194
}
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+
}

src/key.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,13 @@ struct CExtKey {
173173
void SetMaster(const unsigned char* seed, unsigned int nSeedLen);
174174
};
175175

176-
/** Check that required EC support is available at runtime */
176+
/** Initialize the elliptic curve support. May not be called twice without calling ECC_Stop first. */
177+
void ECC_Start(void);
178+
179+
/** Deinitialize the elliptic curve support. No-op if ECC_Start wasn't called first. */
180+
void ECC_Stop(void);
181+
182+
/** Check that required EC support is available at runtime. */
177183
bool ECC_InitSanityCheck(void);
178184

179185
#endif // BITCOIN_KEY_H

src/test/test_bitcoin.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#include "test_bitcoin.h"
88

9+
#include "key.h"
910
#include "main.h"
1011
#include "random.h"
1112
#include "txdb.h"
@@ -28,13 +29,15 @@ extern void noui_connect();
2829

2930
BasicTestingSetup::BasicTestingSetup()
3031
{
32+
ECC_Start();
3133
SetupEnvironment();
3234
fPrintToDebugLog = false; // don't want to write to debug.log file
3335
fCheckBlockIndex = true;
3436
SelectParams(CBaseChainParams::MAIN);
3537
}
3638
BasicTestingSetup::~BasicTestingSetup()
3739
{
40+
ECC_Stop();
3841
}
3942

4043
TestingSetup::TestingSetup()

0 commit comments

Comments
 (0)