@ -5,15 +5,34 @@
# include "key.h"
# include "key.h"
# include "crypto/sha2.h"
# include "crypto/sha2.h"
# include <openssl/rand.h>
# ifdef USE_SECP256K1
# include <secp256k1.h>
# else
# include <openssl/bn.h>
# include <openssl/bn.h>
# include <openssl/ecdsa.h>
# include <openssl/ecdsa.h>
# include <openssl/obj_mac.h>
# include <openssl/obj_mac.h>
# include <openssl/rand.h>
# endif
// anonymous namespace with local implementation code (OpenSSL interaction)
// anonymous namespace with local implementation code (OpenSSL interaction)
namespace {
namespace {
# ifdef USE_SECP256K1
# include <secp256k1.h>
class CSecp256k1Init {
public :
CSecp256k1Init ( ) {
secp256k1_start ( ) ;
}
~ CSecp256k1Init ( ) {
secp256k1_stop ( ) ;
}
} ;
static CSecp256k1Init instance_of_csecp256k1 ;
# else
// Generate a private key from just the secret parameter
// Generate a private key from just the secret parameter
int EC_KEY_regenerate_key ( EC_KEY * eckey , BIGNUM * priv_key )
int EC_KEY_regenerate_key ( EC_KEY * eckey , BIGNUM * priv_key )
{
{
@ -334,6 +353,8 @@ public:
}
}
} ;
} ;
# endif
int CompareBigEndian ( const unsigned char * c1 , size_t c1len , const unsigned char * c2 , size_t c2len ) {
int CompareBigEndian ( const unsigned char * c1 , size_t c1len , const unsigned char * c2 , size_t c2len ) {
while ( c1len > c2len ) {
while ( c1len > c2len ) {
if ( * c1 )
if ( * c1 )
@ -398,10 +419,15 @@ void CKey::MakeNewKey(bool fCompressedIn) {
}
}
bool CKey : : SetPrivKey ( const CPrivKey & privkey , bool fCompressedIn ) {
bool CKey : : SetPrivKey ( const CPrivKey & privkey , bool fCompressedIn ) {
# ifdef USE_SECP256K1
if ( ! secp256k1_ecdsa_privkey_import ( ( unsigned char * ) begin ( ) , & privkey [ 0 ] , privkey . size ( ) ) )
return false ;
# else
CECKey key ;
CECKey key ;
if ( ! key . SetPrivKey ( privkey ) )
if ( ! key . SetPrivKey ( privkey ) )
return false ;
return false ;
key . GetSecretBytes ( vch ) ;
key . GetSecretBytes ( vch ) ;
# endif
fCompressed = fCompressedIn ;
fCompressed = fCompressedIn ;
fValid = true ;
fValid = true ;
return true ;
return true ;
@ -409,50 +435,92 @@ bool CKey::SetPrivKey(const CPrivKey &privkey, bool fCompressedIn) {
CPrivKey CKey : : GetPrivKey ( ) const {
CPrivKey CKey : : GetPrivKey ( ) const {
assert ( fValid ) ;
assert ( fValid ) ;
CPrivKey privkey ;
# ifdef USE_SECP256K1
privkey . resize ( 279 ) ;
int privkeylen = 279 ;
int ret = secp256k1_ecdsa_privkey_export ( begin ( ) , ( unsigned char * ) & privkey [ 0 ] , & privkeylen , fCompressed ) ;
assert ( ret ) ;
privkey . resize ( privkeylen ) ;
# else
CECKey key ;
CECKey key ;
key . SetSecretBytes ( vch ) ;
key . SetSecretBytes ( vch ) ;
CPrivKey privkey ;
key . GetPrivKey ( privkey , fCompressed ) ;
key . GetPrivKey ( privkey , fCompressed ) ;
# endif
return privkey ;
return privkey ;
}
}
CPubKey CKey : : GetPubKey ( ) const {
CPubKey CKey : : GetPubKey ( ) const {
assert ( fValid ) ;
assert ( fValid ) ;
CPubKey pubkey ;
# ifdef USE_SECP256K1
int clen = 65 ;
int ret = secp256k1_ecdsa_pubkey_create ( ( unsigned char * ) pubkey . begin ( ) , & clen , begin ( ) , fCompressed ) ;
assert ( ret ) ;
assert ( pubkey . IsValid ( ) ) ;
assert ( ( int ) pubkey . size ( ) = = clen ) ;
# else
CECKey key ;
CECKey key ;
key . SetSecretBytes ( vch ) ;
key . SetSecretBytes ( vch ) ;
CPubKey pubkey ;
key . GetPubKey ( pubkey , fCompressed ) ;
key . GetPubKey ( pubkey , fCompressed ) ;
# endif
return pubkey ;
return pubkey ;
}
}
bool CKey : : Sign ( const uint256 & hash , std : : vector < unsigned char > & vchSig ) const {
bool CKey : : Sign ( const uint256 & hash , std : : vector < unsigned char > & vchSig ) const {
if ( ! fValid )
if ( ! fValid )
return false ;
return false ;
# ifdef USE_SECP256K1
vchSig . resize ( 72 ) ;
int nSigLen = 72 ;
CKey nonce ;
do {
nonce . MakeNewKey ( true ) ;
if ( secp256k1_ecdsa_sign ( ( const unsigned char * ) & hash , 32 , ( unsigned char * ) & vchSig [ 0 ] , & nSigLen , begin ( ) , nonce . begin ( ) ) )
break ;
} while ( true ) ;
vchSig . resize ( nSigLen ) ;
return true ;
# else
CECKey key ;
CECKey key ;
key . SetSecretBytes ( vch ) ;
key . SetSecretBytes ( vch ) ;
return key . Sign ( hash , vchSig ) ;
return key . Sign ( hash , vchSig ) ;
# endif
}
}
bool CKey : : SignCompact ( const uint256 & hash , std : : vector < unsigned char > & vchSig ) const {
bool CKey : : SignCompact ( const uint256 & hash , std : : vector < unsigned char > & vchSig ) const {
if ( ! fValid )
if ( ! fValid )
return false ;
return false ;
CECKey key ;
key . SetSecretBytes ( vch ) ;
vchSig . resize ( 65 ) ;
vchSig . resize ( 65 ) ;
int rec = - 1 ;
int rec = - 1 ;
# ifdef USE_SECP256K1
CKey nonce ;
do {
nonce . MakeNewKey ( true ) ;
if ( secp256k1_ecdsa_sign_compact ( ( const unsigned char * ) & hash , 32 , & vchSig [ 1 ] , begin ( ) , nonce . begin ( ) , & rec ) )
break ;
} while ( true ) ;
# else
CECKey key ;
key . SetSecretBytes ( vch ) ;
if ( ! key . SignCompact ( hash , & vchSig [ 1 ] , rec ) )
if ( ! key . SignCompact ( hash , & vchSig [ 1 ] , rec ) )
return false ;
return false ;
# endif
assert ( rec ! = - 1 ) ;
assert ( rec ! = - 1 ) ;
vchSig [ 0 ] = 27 + rec + ( fCompressed ? 4 : 0 ) ;
vchSig [ 0 ] = 27 + rec + ( fCompressed ? 4 : 0 ) ;
return true ;
return true ;
}
}
bool CKey : : Load ( CPrivKey & privkey , CPubKey & vchPubKey , bool fSkipCheck = false ) {
bool CKey : : Load ( CPrivKey & privkey , CPubKey & vchPubKey , bool fSkipCheck = false ) {
# ifdef USE_SECP256K1
if ( ! secp256k1_ecdsa_privkey_import ( ( unsigned char * ) begin ( ) , & privkey [ 0 ] , privkey . size ( ) ) )
return false ;
# else
CECKey key ;
CECKey key ;
if ( ! key . SetPrivKey ( privkey , fSkipCheck ) )
if ( ! key . SetPrivKey ( privkey , fSkipCheck ) )
return false ;
return false ;
key . GetSecretBytes ( vch ) ;
key . GetSecretBytes ( vch ) ;
# endif
fCompressed = vchPubKey . IsCompressed ( ) ;
fCompressed = vchPubKey . IsCompressed ( ) ;
fValid = true ;
fValid = true ;
@ -468,40 +536,66 @@ bool CKey::Load(CPrivKey &privkey, CPubKey &vchPubKey, bool fSkipCheck=false) {
bool CPubKey : : Verify ( const uint256 & hash , const std : : vector < unsigned char > & vchSig ) const {
bool CPubKey : : Verify ( const uint256 & hash , const std : : vector < unsigned char > & vchSig ) const {
if ( ! IsValid ( ) )
if ( ! IsValid ( ) )
return false ;
return false ;
# ifdef USE_SECP256K1
if ( secp256k1_ecdsa_verify ( ( const unsigned char * ) & hash , 32 , & vchSig [ 0 ] , vchSig . size ( ) , begin ( ) , size ( ) ) ! = 1 )
return false ;
# else
CECKey key ;
CECKey key ;
if ( ! key . SetPubKey ( * this ) )
if ( ! key . SetPubKey ( * this ) )
return false ;
return false ;
if ( ! key . Verify ( hash , vchSig ) )
if ( ! key . Verify ( hash , vchSig ) )
return false ;
return false ;
# endif
return true ;
return true ;
}
}
bool CPubKey : : RecoverCompact ( const uint256 & hash , const std : : vector < unsigned char > & vchSig ) {
bool CPubKey : : RecoverCompact ( const uint256 & hash , const std : : vector < unsigned char > & vchSig ) {
if ( vchSig . size ( ) ! = 65 )
if ( vchSig . size ( ) ! = 65 )
return false ;
return false ;
int recid = ( vchSig [ 0 ] - 27 ) & 3 ;
bool fComp = ( vchSig [ 0 ] - 27 ) & 4 ;
# ifdef USE_SECP256K1
int pubkeylen = 65 ;
if ( ! secp256k1_ecdsa_recover_compact ( ( const unsigned char * ) & hash , 32 , & vchSig [ 1 ] , ( unsigned char * ) begin ( ) , & pubkeylen , fComp , recid ) )
return false ;
assert ( ( int ) size ( ) = = pubkeylen ) ;
# else
CECKey key ;
CECKey key ;
if ( ! key . Recover ( hash , & vchSig [ 1 ] , ( vchSig [ 0 ] - 27 ) & ~ 4 ) )
if ( ! key . Recover ( hash , & vchSig [ 1 ] , recid ) )
return false ;
return false ;
key . GetPubKey ( * this , ( vchSig [ 0 ] - 27 ) & 4 ) ;
key . GetPubKey ( * this , fComp ) ;
# endif
return true ;
return true ;
}
}
bool CPubKey : : IsFullyValid ( ) const {
bool CPubKey : : IsFullyValid ( ) const {
if ( ! IsValid ( ) )
if ( ! IsValid ( ) )
return false ;
return false ;
# ifdef USE_SECP256K1
if ( ! secp256k1_ecdsa_pubkey_verify ( begin ( ) , size ( ) ) )
return false ;
# else
CECKey key ;
CECKey key ;
if ( ! key . SetPubKey ( * this ) )
if ( ! key . SetPubKey ( * this ) )
return false ;
return false ;
# endif
return true ;
return true ;
}
}
bool CPubKey : : Decompress ( ) {
bool CPubKey : : Decompress ( ) {
if ( ! IsValid ( ) )
if ( ! IsValid ( ) )
return false ;
return false ;
# ifdef USE_SECP256K1
int clen = size ( ) ;
int ret = secp256k1_ecdsa_pubkey_decompress ( ( unsigned char * ) begin ( ) , & clen ) ;
assert ( ret ) ;
assert ( clen = = ( int ) size ( ) ) ;
# else
CECKey key ;
CECKey key ;
if ( ! key . SetPubKey ( * this ) )
if ( ! key . SetPubKey ( * this ) )
return false ;
return false ;
key . GetPubKey ( * this , false ) ;
key . GetPubKey ( * this , false ) ;
# endif
return true ;
return true ;
}
}
@ -531,7 +625,12 @@ bool CKey::Derive(CKey& keyChild, unsigned char ccChild[32], unsigned int nChild
BIP32Hash ( cc , nChild , 0 , begin ( ) , out ) ;
BIP32Hash ( cc , nChild , 0 , begin ( ) , out ) ;
}
}
memcpy ( ccChild , out + 32 , 32 ) ;
memcpy ( ccChild , out + 32 , 32 ) ;
# ifdef USE_SECP256K1
memcpy ( ( unsigned char * ) keyChild . begin ( ) , begin ( ) , 32 ) ;
bool ret = secp256k1_ecdsa_privkey_tweak_add ( ( unsigned char * ) keyChild . begin ( ) , out ) ;
# else
bool ret = CECKey : : TweakSecret ( ( unsigned char * ) keyChild . begin ( ) , begin ( ) , out ) ;
bool ret = CECKey : : TweakSecret ( ( unsigned char * ) keyChild . begin ( ) , begin ( ) , out ) ;
# endif
UnlockObject ( out ) ;
UnlockObject ( out ) ;
keyChild . fCompressed = true ;
keyChild . fCompressed = true ;
keyChild . fValid = ret ;
keyChild . fValid = ret ;
@ -545,10 +644,15 @@ bool CPubKey::Derive(CPubKey& pubkeyChild, unsigned char ccChild[32], unsigned i
unsigned char out [ 64 ] ;
unsigned char out [ 64 ] ;
BIP32Hash ( cc , nChild , * begin ( ) , begin ( ) + 1 , out ) ;
BIP32Hash ( cc , nChild , * begin ( ) , begin ( ) + 1 , out ) ;
memcpy ( ccChild , out + 32 , 32 ) ;
memcpy ( ccChild , out + 32 , 32 ) ;
# ifdef USE_SECP256K1
pubkeyChild = * this ;
bool ret = secp256k1_ecdsa_pubkey_tweak_add ( ( unsigned char * ) pubkeyChild . begin ( ) , pubkeyChild . size ( ) , out ) ;
# else
CECKey key ;
CECKey key ;
bool ret = key . SetPubKey ( * this ) ;
bool ret = key . SetPubKey ( * this ) ;
ret & = key . TweakPublic ( out ) ;
ret & = key . TweakPublic ( out ) ;
key . GetPubKey ( pubkeyChild , true ) ;
key . GetPubKey ( pubkeyChild , true ) ;
# endif
return ret ;
return ret ;
}
}
@ -629,6 +733,9 @@ bool CExtPubKey::Derive(CExtPubKey &out, unsigned int nChild) const {
}
}
bool ECC_InitSanityCheck ( ) {
bool ECC_InitSanityCheck ( ) {
# ifdef USE_SECP256K1
return true ;
# else
EC_KEY * pkey = EC_KEY_new_by_curve_name ( NID_secp256k1 ) ;
EC_KEY * pkey = EC_KEY_new_by_curve_name ( NID_secp256k1 ) ;
if ( pkey = = NULL )
if ( pkey = = NULL )
return false ;
return false ;
@ -636,6 +743,7 @@ bool ECC_InitSanityCheck() {
// TODO Is there more EC functionality that could be missing?
// TODO Is there more EC functionality that could be missing?
return true ;
return true ;
# endif
}
}