Fix sslcrypto thread safety (#2454)
* Use sslcrypto instead of pyelliptic and pybitcointools * Fix CryptMessage * Support Python 3.4 * Fix user creation * Get rid of pyelliptic and pybitcointools * Fix typo * Delete test file * Add sslcrypto to tree * Update sslcrypto * Add pyaes to src/lib * Fix typo in tests * Update sslcrypto version * Use privatekey_bin instead of privatekey for bytes objects * Fix sslcrypto * Fix Benchmark plugin * Don't calculate the same thing twice * Only import sslcrypto once * Handle fallback sslcrypto implementation during tests * Fix sslcrypto fallback implementation selection * Fix thread safety * Add derivation * Bring split back * Fix typo * v3.3 * Fix custom OpenSSL discovery
This commit is contained in:
parent
7ba2c9344d
commit
296e4aab57
57 changed files with 3781 additions and 7306 deletions
|
@ -1,16 +1,21 @@
|
|||
import logging
|
||||
import base64
|
||||
import binascii
|
||||
import time
|
||||
import hashlib
|
||||
|
||||
from util import OpensslFindPatch
|
||||
from lib import pybitcointools as btctools
|
||||
from util.Electrum import dbl_format
|
||||
from Config import config
|
||||
|
||||
lib_verify_best = "btctools"
|
||||
lib_verify_best = "sslcrypto"
|
||||
|
||||
import sslcrypto
|
||||
sslcurve_native = sslcrypto.ecc.get_curve("secp256k1")
|
||||
sslcurve_fallback = sslcrypto.fallback.ecc.get_curve("secp256k1")
|
||||
sslcurve = sslcurve_native
|
||||
|
||||
def loadLib(lib_name, silent=False):
|
||||
global bitcoin, libsecp256k1message, lib_verify_best
|
||||
global sslcurve, libsecp256k1message, lib_verify_best
|
||||
if lib_name == "libsecp256k1":
|
||||
s = time.time()
|
||||
from lib import libsecp256k1message
|
||||
|
@ -21,24 +26,10 @@ def loadLib(lib_name, silent=False):
|
|||
"Libsecpk256k1 loaded: %s in %.3fs" %
|
||||
(type(coincurve._libsecp256k1.lib).__name__, time.time() - s)
|
||||
)
|
||||
elif lib_name == "openssl":
|
||||
s = time.time()
|
||||
import bitcoin.signmessage
|
||||
import bitcoin.core.key
|
||||
import bitcoin.wallet
|
||||
|
||||
try:
|
||||
# OpenSSL 1.1.0
|
||||
ssl_version = bitcoin.core.key._ssl.SSLeay()
|
||||
except AttributeError:
|
||||
# OpenSSL 1.1.1+
|
||||
ssl_version = bitcoin.core.key._ssl.OpenSSL_version_num()
|
||||
|
||||
if not silent:
|
||||
logging.info(
|
||||
"OpenSSL loaded: %s, version: %.9X in %.3fs" %
|
||||
(bitcoin.core.key._ssl, ssl_version, time.time() - s)
|
||||
)
|
||||
elif lib_name == "sslcrypto":
|
||||
sslcurve = sslcurve_native
|
||||
elif lib_name == "sslcrypto_fallback":
|
||||
sslcurve = sslcurve_fallback
|
||||
|
||||
try:
|
||||
if not config.use_libsecp256k1:
|
||||
|
@ -46,35 +37,30 @@ try:
|
|||
loadLib("libsecp256k1")
|
||||
lib_verify_best = "libsecp256k1"
|
||||
except Exception as err:
|
||||
logging.info("Libsecp256k1 load failed: %s, try to load OpenSSL" % err)
|
||||
try:
|
||||
if not config.use_openssl:
|
||||
raise Exception("Disabled by config")
|
||||
loadLib("openssl")
|
||||
lib_verify_best = "openssl"
|
||||
except Exception as err:
|
||||
logging.info("OpenSSL load failed: %s, falling back to slow bitcoin verify" % err)
|
||||
logging.info("Libsecp256k1 load failed: %s" % err)
|
||||
|
||||
|
||||
def newPrivatekey(uncompressed=True): # Return new private key
|
||||
privatekey = btctools.encode_privkey(btctools.random_key(), "wif")
|
||||
return privatekey
|
||||
def newPrivatekey(): # Return new private key
|
||||
return sslcurve.private_to_wif(sslcurve.new_private_key()).decode()
|
||||
|
||||
|
||||
def newSeed():
|
||||
return btctools.random_key()
|
||||
return binascii.hexlify(sslcurve.new_private_key()).decode()
|
||||
|
||||
|
||||
def hdPrivatekey(seed, child):
|
||||
masterkey = btctools.bip32_master_key(bytes(seed, "ascii"))
|
||||
childkey = btctools.bip32_ckd(masterkey, child % 100000000) # Too large child id could cause problems
|
||||
key = btctools.bip32_extract_key(childkey)
|
||||
return btctools.encode_privkey(key, "wif")
|
||||
# Too large child id could cause problems
|
||||
privatekey_bin = sslcurve.derive_child(seed.encode(), child % 100000000)
|
||||
return sslcurve.private_to_wif(privatekey_bin).decode()
|
||||
|
||||
|
||||
def privatekeyToAddress(privatekey): # Return address from private key
|
||||
try:
|
||||
return btctools.privkey_to_address(privatekey)
|
||||
if len(privatekey) == 64:
|
||||
privatekey_bin = bytes.fromhex(privatekey)
|
||||
else:
|
||||
privatekey_bin = sslcurve.wif_to_private(privatekey.encode())
|
||||
return sslcurve.private_to_address(privatekey_bin, is_compressed=False).decode()
|
||||
except Exception: # Invalid privatekey
|
||||
return False
|
||||
|
||||
|
@ -82,8 +68,13 @@ def privatekeyToAddress(privatekey): # Return address from private key
|
|||
def sign(data, privatekey): # Return sign to data using private key
|
||||
if privatekey.startswith("23") and len(privatekey) > 52:
|
||||
return None # Old style private key not supported
|
||||
sign = btctools.ecdsa_sign(data, privatekey)
|
||||
return sign
|
||||
return base64.b64encode(sslcurve.sign(
|
||||
data.encode(),
|
||||
sslcurve.wif_to_private(privatekey.encode()),
|
||||
is_compressed=False,
|
||||
recoverable=True,
|
||||
hash=dbl_format
|
||||
)).decode()
|
||||
|
||||
|
||||
def verify(data, valid_address, sign, lib_verify=None): # Verify data using address and sign
|
||||
|
@ -95,17 +86,9 @@ def verify(data, valid_address, sign, lib_verify=None): # Verify data using add
|
|||
|
||||
if lib_verify == "libsecp256k1":
|
||||
sign_address = libsecp256k1message.recover_address(data.encode("utf8"), sign).decode("utf8")
|
||||
elif lib_verify == "openssl":
|
||||
sig = base64.b64decode(sign)
|
||||
message = bitcoin.signmessage.BitcoinMessage(data)
|
||||
hash = message.GetHash()
|
||||
|
||||
pubkey = bitcoin.core.key.CPubKey.recover_compact(hash, sig)
|
||||
|
||||
sign_address = str(bitcoin.wallet.P2PKHBitcoinAddress.from_pubkey(pubkey))
|
||||
elif lib_verify == "btctools": # Use pure-python
|
||||
pub = btctools.ecdsa_recover(data, sign)
|
||||
sign_address = btctools.pubtoaddr(pub)
|
||||
elif lib_verify in ("sslcrypto", "sslcrypto_fallback"):
|
||||
publickey = sslcurve.recover(base64.b64decode(sign), data.encode(), hash=dbl_format)
|
||||
sign_address = sslcurve.public_to_address(publickey).decode()
|
||||
else:
|
||||
raise Exception("No library enabled for signature verification")
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue