Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update libsecp256k1 subtree #4332

Merged
merged 8 commits into from
Aug 11, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -1634,7 +1634,7 @@ if test x$need_bundled_univalue = xyes; then
AC_CONFIG_SUBDIRS([src/univalue])
fi

ac_configure_args="${ac_configure_args} --disable-shared --with-pic --enable-benchmark=no --with-bignum=no --enable-module-recovery --disable-jni"
ac_configure_args="${ac_configure_args} --disable-shared --with-pic --enable-benchmark=no --enable-module-recovery"
AC_CONFIG_SUBDIRS([src/secp256k1])

AC_OUTPUT
Expand Down
2 changes: 2 additions & 0 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,8 @@ crypto_libdash_crypto_base_a_SOURCES = \
crypto/chacha20.h \
crypto/chacha20.cpp \
crypto/common.h \
crypto/hkdf_sha256_32.cpp \
crypto/hkdf_sha256_32.h \
crypto/hmac_sha256.cpp \
crypto/hmac_sha256.h \
crypto/hmac_sha512.cpp \
Expand Down
21 changes: 21 additions & 0 deletions src/crypto/hkdf_sha256_32.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright (c) 2018 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <crypto/hkdf_sha256_32.h>

#include <assert.h>
#include <string.h>

CHKDF_HMAC_SHA256_L32::CHKDF_HMAC_SHA256_L32(const unsigned char* ikm, size_t ikmlen, const std::string& salt)
{
CHMAC_SHA256((const unsigned char*)salt.c_str(), salt.size()).Write(ikm, ikmlen).Finalize(m_prk);
}

void CHKDF_HMAC_SHA256_L32::Expand32(const std::string& info, unsigned char hash[OUTPUT_SIZE])
{
// expand a 32byte key (single round)
assert(info.size() <= 128);
static const unsigned char one[1] = {1};
CHMAC_SHA256(m_prk, 32).Write((const unsigned char*)info.data(), info.size()).Write(one, 1).Finalize(hash);
}
25 changes: 25 additions & 0 deletions src/crypto/hkdf_sha256_32.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright (c) 2018 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#ifndef BITCOIN_CRYPTO_HKDF_SHA256_32_H
#define BITCOIN_CRYPTO_HKDF_SHA256_32_H

#include <crypto/hmac_sha256.h>

#include <stdint.h>
#include <stdlib.h>

/** A rfc5869 HKDF implementation with HMAC_SHA256 and fixed key output length of 32 bytes (L=32) */
class CHKDF_HMAC_SHA256_L32
{
private:
unsigned char m_prk[32];
static const size_t OUTPUT_SIZE = 32;

public:
CHKDF_HMAC_SHA256_L32(const unsigned char* ikm, size_t ikmlen, const std::string& salt);
void Expand32(const std::string& info, unsigned char hash[OUTPUT_SIZE]);
};

#endif // BITCOIN_CRYPTO_HKDF_SHA256_32_H
90 changes: 48 additions & 42 deletions src/key.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,46 +32,46 @@ static secp256k1_context* secp256k1_context_sign = nullptr;
*
* out32 must point to an output buffer of length at least 32 bytes.
*/
static int ec_privkey_import_der(const secp256k1_context* ctx, unsigned char *out32, const unsigned char *privkey, size_t privkeylen) {
const unsigned char *end = privkey + privkeylen;
static int ec_seckey_import_der(const secp256k1_context* ctx, unsigned char *out32, const unsigned char *seckey, size_t seckeylen) {
const unsigned char *end = seckey + seckeylen;
memset(out32, 0, 32);
/* sequence header */
if (end - privkey < 1 || *privkey != 0x30u) {
if (end - seckey < 1 || *seckey != 0x30u) {
return 0;
}
privkey++;
seckey++;
/* sequence length constructor */
if (end - privkey < 1 || !(*privkey & 0x80u)) {
if (end - seckey < 1 || !(*seckey & 0x80u)) {
return 0;
}
ptrdiff_t lenb = *privkey & ~0x80u; privkey++;
ptrdiff_t lenb = *seckey & ~0x80u; seckey++;
if (lenb < 1 || lenb > 2) {
return 0;
}
if (end - privkey < lenb) {
if (end - seckey < lenb) {
return 0;
}
/* sequence length */
ptrdiff_t len = privkey[lenb-1] | (lenb > 1 ? privkey[lenb-2] << 8 : 0u);
privkey += lenb;
if (end - privkey < len) {
ptrdiff_t len = seckey[lenb-1] | (lenb > 1 ? seckey[lenb-2] << 8 : 0u);
seckey += lenb;
if (end - seckey < len) {
return 0;
}
/* sequence element 0: version number (=1) */
if (end - privkey < 3 || privkey[0] != 0x02u || privkey[1] != 0x01u || privkey[2] != 0x01u) {
if (end - seckey < 3 || seckey[0] != 0x02u || seckey[1] != 0x01u || seckey[2] != 0x01u) {
return 0;
}
privkey += 3;
seckey += 3;
/* sequence element 1: octet string, up to 32 bytes */
if (end - privkey < 2 || privkey[0] != 0x04u) {
if (end - seckey < 2 || seckey[0] != 0x04u) {
return 0;
}
ptrdiff_t oslen = privkey[1];
privkey += 2;
if (oslen > 32 || end - privkey < oslen) {
ptrdiff_t oslen = seckey[1];
seckey += 2;
if (oslen > 32 || end - seckey < oslen) {
return 0;
}
memcpy(out32 + (32 - oslen), privkey, oslen);
memcpy(out32 + (32 - oslen), seckey, oslen);
if (!secp256k1_ec_seckey_verify(ctx, out32)) {
memset(out32, 0, 32);
return 0;
Expand All @@ -84,17 +84,17 @@ static int ec_privkey_import_der(const secp256k1_context* ctx, unsigned char *ou
* <http://www.secg.org/sec1-v2.pdf>. The optional parameters and publicKey fields are
* included.
*
* privkey must point to an output buffer of length at least CKey::PRIVATE_KEY_SIZE bytes.
* privkeylen must initially be set to the size of the privkey buffer. Upon return it
* seckey must point to an output buffer of length at least CKey::SIZE bytes.
* seckeylen must initially be set to the size of the seckey buffer. Upon return it
* will be set to the number of bytes used in the buffer.
* key32 must point to a 32-byte raw private key.
*/
static int ec_privkey_export_der(const secp256k1_context *ctx, unsigned char *privkey, size_t *privkeylen, const unsigned char *key32, bool compressed) {
assert(*privkeylen >= CKey::PRIVATE_KEY_SIZE);
static int ec_seckey_export_der(const secp256k1_context *ctx, unsigned char *seckey, size_t *seckeylen, const unsigned char *key32, bool compressed) {
assert(*seckeylen >= CKey::SIZE);
secp256k1_pubkey pubkey;
size_t pubkeylen = 0;
if (!secp256k1_ec_pubkey_create(ctx, &pubkey, key32)) {
*privkeylen = 0;
*seckeylen = 0;
return 0;
}
if (compressed) {
Expand All @@ -112,15 +112,15 @@ static int ec_privkey_export_der(const secp256k1_context *ctx, unsigned char *pr
0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E,
0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x24,0x03,0x22,0x00
};
unsigned char *ptr = privkey;
unsigned char *ptr = seckey;
memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin);
memcpy(ptr, key32, 32); ptr += 32;
memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle);
pubkeylen = CPubKey::COMPRESSED_PUBLIC_KEY_SIZE;
pubkeylen = CPubKey::COMPRESSED_SIZE;
secp256k1_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED);
ptr += pubkeylen;
*privkeylen = ptr - privkey;
assert(*privkeylen == CKey::COMPRESSED_PRIVATE_KEY_SIZE);
*seckeylen = ptr - seckey;
assert(*seckeylen == CKey::COMPRESSED_SIZE);
} else {
static const unsigned char begin[] = {
0x30,0x82,0x01,0x13,0x02,0x01,0x01,0x04,0x20
Expand All @@ -138,15 +138,15 @@ static int ec_privkey_export_der(const secp256k1_context *ctx, unsigned char *pr
0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E,
0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x44,0x03,0x42,0x00
};
unsigned char *ptr = privkey;
unsigned char *ptr = seckey;
memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin);
memcpy(ptr, key32, 32); ptr += 32;
memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle);
pubkeylen = CPubKey::PUBLIC_KEY_SIZE;
pubkeylen = CPubKey::SIZE;
secp256k1_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_UNCOMPRESSED);
ptr += pubkeylen;
*privkeylen = ptr - privkey;
assert(*privkeylen == CKey::PRIVATE_KEY_SIZE);
*seckeylen = ptr - seckey;
assert(*seckeylen == CKey::SIZE);
}
return 1;
}
Expand All @@ -163,23 +163,29 @@ void CKey::MakeNewKey(bool fCompressedIn) {
fCompressed = fCompressedIn;
}

bool CKey::Negate()
{
assert(fValid);
return secp256k1_ec_seckey_negate(secp256k1_context_sign, keydata.data());
}

CPrivKey CKey::GetPrivKey() const {
assert(fValid);
CPrivKey privkey;
CPrivKey seckey;
int ret;
size_t privkeylen;
privkey.resize(PRIVATE_KEY_SIZE);
privkeylen = PRIVATE_KEY_SIZE;
ret = ec_privkey_export_der(secp256k1_context_sign, privkey.data(), &privkeylen, begin(), fCompressed);
size_t seckeylen;
seckey.resize(SIZE);
seckeylen = SIZE;
ret = ec_seckey_export_der(secp256k1_context_sign, seckey.data(), &seckeylen, begin(), fCompressed);
assert(ret);
privkey.resize(privkeylen);
return privkey;
seckey.resize(seckeylen);
return seckey;
}

CPubKey CKey::GetPubKey() const {
assert(fValid);
secp256k1_pubkey pubkey;
size_t clen = CPubKey::PUBLIC_KEY_SIZE;
size_t clen = CPubKey::SIZE;
CPubKey result;
int ret = secp256k1_ec_pubkey_create(secp256k1_context_sign, &pubkey, begin());
assert(ret);
Expand Down Expand Up @@ -253,8 +259,8 @@ bool CKey::SignCompact(const uint256 &hash, std::vector<unsigned char>& vchSig)
return true;
}

bool CKey::Load(const CPrivKey &privkey, const CPubKey &vchPubKey, bool fSkipCheck=false) {
if (!ec_privkey_import_der(secp256k1_context_sign, (unsigned char*)begin(), privkey.data(), privkey.size()))
bool CKey::Load(const CPrivKey &seckey, const CPubKey &vchPubKey, bool fSkipCheck=false) {
if (!ec_seckey_import_der(secp256k1_context_sign, (unsigned char*)begin(), seckey.data(), seckey.size()))
return false;
fCompressed = vchPubKey.IsCompressed();
fValid = true;
Expand All @@ -271,15 +277,15 @@ bool CKey::Derive(CKey& keyChild, ChainCode &ccChild, unsigned int nChild, const
std::vector<unsigned char, secure_allocator<unsigned char>> vout(64);
if ((nChild >> 31) == 0) {
CPubKey pubkey = GetPubKey();
assert(pubkey.size() == CPubKey::COMPRESSED_PUBLIC_KEY_SIZE);
assert(pubkey.size() == CPubKey::COMPRESSED_SIZE);
BIP32Hash(cc, nChild, *pubkey.begin(), pubkey.begin()+1, vout.data());
} else {
assert(size() == 32);
BIP32Hash(cc, nChild, 0, begin(), vout.data());
}
memcpy(ccChild.begin(), vout.data()+32, 32);
memcpy((unsigned char*)keyChild.begin(), begin(), 32);
bool ret = secp256k1_ec_privkey_tweak_add(secp256k1_context_sign, (unsigned char*)keyChild.begin(), vout.data());
bool ret = secp256k1_ec_seckey_tweak_add(secp256k1_context_sign, (unsigned char*)keyChild.begin(), vout.data());
keyChild.fCompressed = true;
keyChild.fValid = ret;
return ret;
Expand Down
13 changes: 8 additions & 5 deletions src/key.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
/**
* secure_allocator is defined in allocators.h
* CPrivKey is a serialized private key, with all parameters included
* (PRIVATE_KEY_SIZE bytes)
* (SIZE bytes)
*/
typedef std::vector<unsigned char, secure_allocator<unsigned char> > CPrivKey;

Expand All @@ -30,15 +30,15 @@ class CKey
/**
* secp256k1:
*/
static const unsigned int PRIVATE_KEY_SIZE = 279;
static const unsigned int COMPRESSED_PRIVATE_KEY_SIZE = 214;
static const unsigned int SIZE = 279;
static const unsigned int COMPRESSED_SIZE = 214;
/**
* see www.keylength.com
* script supports up to 75 for single byte push
*/
static_assert(
PRIVATE_KEY_SIZE >= COMPRESSED_PRIVATE_KEY_SIZE,
"COMPRESSED_PRIVATE_KEY_SIZE is larger than PRIVATE_KEY_SIZE");
SIZE >= COMPRESSED_SIZE,
"COMPRESSED_SIZE is larger than SIZE");

private:
//! Whether this private key is valid. We check for correctness when modifying the key
Expand Down Expand Up @@ -98,6 +98,9 @@ class CKey
//! Generate a new private key using a cryptographic PRNG.
void MakeNewKey(bool fCompressed);

//! Negate private key
bool Negate();

/**
* Convert the private key to a CPrivKey (serialized OpenSSL private key data).
* This is expensive.
Expand Down
2 changes: 1 addition & 1 deletion src/psbt.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ struct PSBTInput
case PSBT_IN_PARTIAL_SIG:
{
// Make sure that the key is the size of pubkey + 1
if (key.size() != CPubKey::PUBLIC_KEY_SIZE + 1 && key.size() != CPubKey::COMPRESSED_PUBLIC_KEY_SIZE + 1) {
if (key.size() != CPubKey::SIZE + 1 && key.size() != CPubKey::COMPRESSED_SIZE + 1) {
throw std::ios_base::failure("Size of key was not the expected size for the type partial signature pubkey");
}
// Read in the pubkey from key
Expand Down
18 changes: 9 additions & 9 deletions src/pubkey.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -198,8 +198,8 @@ bool CPubKey::RecoverCompact(const uint256 &hash, const std::vector<unsigned cha
if (!secp256k1_ecdsa_recover(secp256k1_context_verify, &pubkey, &sig, hash.begin())) {
return false;
}
unsigned char pub[PUBLIC_KEY_SIZE];
size_t publen = PUBLIC_KEY_SIZE;
unsigned char pub[SIZE];
size_t publen = SIZE;
secp256k1_ec_pubkey_serialize(secp256k1_context_verify, pub, &publen, &pubkey, fComp ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED);
Set(pub, pub + publen);
return true;
Expand All @@ -221,8 +221,8 @@ bool CPubKey::Decompress() {
if (!secp256k1_ec_pubkey_parse(secp256k1_context_verify, &pubkey, vch, size())) {
return false;
}
unsigned char pub[PUBLIC_KEY_SIZE];
size_t publen = PUBLIC_KEY_SIZE;
unsigned char pub[SIZE];
size_t publen = SIZE;
secp256k1_ec_pubkey_serialize(secp256k1_context_verify, pub, &publen, &pubkey, SECP256K1_EC_UNCOMPRESSED);
Set(pub, pub + publen);
return true;
Expand All @@ -231,7 +231,7 @@ bool CPubKey::Decompress() {
bool CPubKey::Derive(CPubKey& pubkeyChild, ChainCode &ccChild, unsigned int nChild, const ChainCode& cc) const {
assert(IsValid());
assert((nChild >> 31) == 0);
assert(size() == COMPRESSED_PUBLIC_KEY_SIZE);
assert(size() == COMPRESSED_SIZE);
unsigned char out[64];
BIP32Hash(cc, nChild, *begin(), begin()+1, out);
memcpy(ccChild.begin(), out+32, 32);
Expand All @@ -243,8 +243,8 @@ bool CPubKey::Derive(CPubKey& pubkeyChild, ChainCode &ccChild, unsigned int nChi
if (!secp256k1_ec_pubkey_tweak_add(secp256k1_context_verify, &pubkey, out)) {
return false;
}
unsigned char pub[COMPRESSED_PUBLIC_KEY_SIZE];
size_t publen = COMPRESSED_PUBLIC_KEY_SIZE;
unsigned char pub[COMPRESSED_SIZE];
size_t publen = COMPRESSED_SIZE;
secp256k1_ec_pubkey_serialize(secp256k1_context_verify, pub, &publen, &pubkey, SECP256K1_EC_COMPRESSED);
pubkeyChild.Set(pub, pub + publen);
return true;
Expand All @@ -256,8 +256,8 @@ void CExtPubKey::Encode(unsigned char code[BIP32_EXTKEY_SIZE]) const {
code[5] = (nChild >> 24) & 0xFF; code[6] = (nChild >> 16) & 0xFF;
code[7] = (nChild >> 8) & 0xFF; code[8] = (nChild >> 0) & 0xFF;
memcpy(code+9, chaincode.begin(), 32);
assert(pubkey.size() == CPubKey::COMPRESSED_PUBLIC_KEY_SIZE);
memcpy(code+41, pubkey.begin(), CPubKey::COMPRESSED_PUBLIC_KEY_SIZE);
assert(pubkey.size() == CPubKey::COMPRESSED_SIZE);
memcpy(code+41, pubkey.begin(), CPubKey::COMPRESSED_SIZE);
}

void CExtPubKey::Decode(const unsigned char code[BIP32_EXTKEY_SIZE]) {
Expand Down
Loading