Rev665, Fix OpenSSL dll search on cygwin, Remove unnecessary files
This commit is contained in:
parent
5b316180e6
commit
394a8b16b7
7 changed files with 52 additions and 654 deletions
|
@ -8,7 +8,7 @@ class Config(object):
|
||||||
|
|
||||||
def __init__(self, argv):
|
def __init__(self, argv):
|
||||||
self.version = "0.3.4"
|
self.version = "0.3.4"
|
||||||
self.rev = 664
|
self.rev = 665
|
||||||
self.argv = argv
|
self.argv = argv
|
||||||
self.action = None
|
self.action = None
|
||||||
self.createParser()
|
self.createParser()
|
||||||
|
|
|
@ -1,393 +0,0 @@
|
||||||
# Code is borrowed from https://github.com/blocktrail/python-bitcoinlib
|
|
||||||
# Thanks!
|
|
||||||
|
|
||||||
import base64, hashlib
|
|
||||||
|
|
||||||
import ctypes
|
|
||||||
import ctypes.util
|
|
||||||
_bchr = chr
|
|
||||||
_bord = ord
|
|
||||||
try:
|
|
||||||
_ssl = ctypes.CDLL("src/lib/opensslVerify/libeay32.dll")
|
|
||||||
except:
|
|
||||||
_ssl = ctypes.cdll.LoadLibrary(ctypes.util.find_library('ssl') or ctypes.util.find_library('crypto') or 'libeay32')
|
|
||||||
|
|
||||||
import sys
|
|
||||||
|
|
||||||
openssl_version = "%.9X" % _ssl.SSLeay()
|
|
||||||
|
|
||||||
|
|
||||||
# this specifies the curve used with ECDSA.
|
|
||||||
_NID_secp256k1 = 714 # from openssl/obj_mac.h
|
|
||||||
|
|
||||||
# Thx to Sam Devlin for the ctypes magic 64-bit fix.
|
|
||||||
def _check_result (val, func, args):
|
|
||||||
if val == 0:
|
|
||||||
raise ValueError
|
|
||||||
else:
|
|
||||||
return ctypes.c_void_p(val)
|
|
||||||
|
|
||||||
_ssl.EC_KEY_new_by_curve_name.restype = ctypes.c_void_p
|
|
||||||
_ssl.EC_KEY_new_by_curve_name.errcheck = _check_result
|
|
||||||
|
|
||||||
# From openssl/ecdsa.h
|
|
||||||
class ECDSA_SIG_st(ctypes.Structure):
|
|
||||||
_fields_ = [("r", ctypes.c_void_p),
|
|
||||||
("s", ctypes.c_void_p)]
|
|
||||||
|
|
||||||
class CECKey:
|
|
||||||
"""Wrapper around OpenSSL's EC_KEY"""
|
|
||||||
|
|
||||||
POINT_CONVERSION_COMPRESSED = 2
|
|
||||||
POINT_CONVERSION_UNCOMPRESSED = 4
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
self.k = _ssl.EC_KEY_new_by_curve_name(_NID_secp256k1)
|
|
||||||
|
|
||||||
def __del__(self):
|
|
||||||
if _ssl:
|
|
||||||
_ssl.EC_KEY_free(self.k)
|
|
||||||
self.k = None
|
|
||||||
|
|
||||||
def set_secretbytes(self, secret):
|
|
||||||
priv_key = _ssl.BN_bin2bn(secret, 32, _ssl.BN_new())
|
|
||||||
group = _ssl.EC_KEY_get0_group(self.k)
|
|
||||||
pub_key = _ssl.EC_POINT_new(group)
|
|
||||||
ctx = _ssl.BN_CTX_new()
|
|
||||||
if not _ssl.EC_POINT_mul(group, pub_key, priv_key, None, None, ctx):
|
|
||||||
raise ValueError("Could not derive public key from the supplied secret.")
|
|
||||||
_ssl.EC_POINT_mul(group, pub_key, priv_key, None, None, ctx)
|
|
||||||
_ssl.EC_KEY_set_private_key(self.k, priv_key)
|
|
||||||
_ssl.EC_KEY_set_public_key(self.k, pub_key)
|
|
||||||
_ssl.EC_POINT_free(pub_key)
|
|
||||||
_ssl.BN_CTX_free(ctx)
|
|
||||||
return self.k
|
|
||||||
|
|
||||||
def set_privkey(self, key):
|
|
||||||
self.mb = ctypes.create_string_buffer(key)
|
|
||||||
return _ssl.d2i_ECPrivateKey(ctypes.byref(self.k), ctypes.byref(ctypes.pointer(self.mb)), len(key))
|
|
||||||
|
|
||||||
def set_pubkey(self, key):
|
|
||||||
self.mb = ctypes.create_string_buffer(key)
|
|
||||||
return _ssl.o2i_ECPublicKey(ctypes.byref(self.k), ctypes.byref(ctypes.pointer(self.mb)), len(key))
|
|
||||||
|
|
||||||
def get_privkey(self):
|
|
||||||
size = _ssl.i2d_ECPrivateKey(self.k, 0)
|
|
||||||
mb_pri = ctypes.create_string_buffer(size)
|
|
||||||
_ssl.i2d_ECPrivateKey(self.k, ctypes.byref(ctypes.pointer(mb_pri)))
|
|
||||||
return mb_pri.raw
|
|
||||||
|
|
||||||
def get_pubkey(self):
|
|
||||||
size = _ssl.i2o_ECPublicKey(self.k, 0)
|
|
||||||
mb = ctypes.create_string_buffer(size)
|
|
||||||
_ssl.i2o_ECPublicKey(self.k, ctypes.byref(ctypes.pointer(mb)))
|
|
||||||
return mb.raw
|
|
||||||
|
|
||||||
def get_raw_ecdh_key(self, other_pubkey):
|
|
||||||
ecdh_keybuffer = ctypes.create_string_buffer(32)
|
|
||||||
r = _ssl.ECDH_compute_key(ctypes.pointer(ecdh_keybuffer), 32,
|
|
||||||
_ssl.EC_KEY_get0_public_key(other_pubkey.k),
|
|
||||||
self.k, 0)
|
|
||||||
if r != 32:
|
|
||||||
raise Exception('CKey.get_ecdh_key(): ECDH_compute_key() failed')
|
|
||||||
return ecdh_keybuffer.raw
|
|
||||||
|
|
||||||
def get_ecdh_key(self, other_pubkey, kdf=lambda k: hashlib.sha256(k).digest()):
|
|
||||||
# FIXME: be warned it's not clear what the kdf should be as a default
|
|
||||||
r = self.get_raw_ecdh_key(other_pubkey)
|
|
||||||
return kdf(r)
|
|
||||||
|
|
||||||
def sign(self, hash):
|
|
||||||
if not isinstance(hash, bytes):
|
|
||||||
raise TypeError('Hash must be bytes instance; got %r' % hash.__class__)
|
|
||||||
if len(hash) != 32:
|
|
||||||
raise ValueError('Hash must be exactly 32 bytes long')
|
|
||||||
|
|
||||||
sig_size0 = ctypes.c_uint32()
|
|
||||||
sig_size0.value = _ssl.ECDSA_size(self.k)
|
|
||||||
mb_sig = ctypes.create_string_buffer(sig_size0.value)
|
|
||||||
result = _ssl.ECDSA_sign(0, hash, len(hash), mb_sig, ctypes.byref(sig_size0), self.k)
|
|
||||||
assert 1 == result
|
|
||||||
if bitcoin.core.script.IsLowDERSignature(mb_sig.raw[:sig_size0.value]):
|
|
||||||
return mb_sig.raw[:sig_size0.value]
|
|
||||||
else:
|
|
||||||
return self.signature_to_low_s(mb_sig.raw[:sig_size0.value])
|
|
||||||
|
|
||||||
def sign_compact(self, hash):
|
|
||||||
if not isinstance(hash, bytes):
|
|
||||||
raise TypeError('Hash must be bytes instance; got %r' % hash.__class__)
|
|
||||||
if len(hash) != 32:
|
|
||||||
raise ValueError('Hash must be exactly 32 bytes long')
|
|
||||||
|
|
||||||
sig_size0 = ctypes.c_uint32()
|
|
||||||
sig_size0.value = _ssl.ECDSA_size(self.k)
|
|
||||||
mb_sig = ctypes.create_string_buffer(sig_size0.value)
|
|
||||||
result = _ssl.ECDSA_sign(0, hash, len(hash), mb_sig, ctypes.byref(sig_size0), self.k)
|
|
||||||
assert 1 == result
|
|
||||||
|
|
||||||
if bitcoin.core.script.IsLowDERSignature(mb_sig.raw[:sig_size0.value]):
|
|
||||||
sig = mb_sig.raw[:sig_size0.value]
|
|
||||||
else:
|
|
||||||
sig = self.signature_to_low_s(mb_sig.raw[:sig_size0.value])
|
|
||||||
|
|
||||||
sig = bitcoin.core.DERSignature.deserialize(sig)
|
|
||||||
|
|
||||||
r_val = sig.r
|
|
||||||
s_val = sig.s
|
|
||||||
|
|
||||||
# assert that the r and s are less than 32 long, excluding leading 0s
|
|
||||||
assert len(r_val) <= 32 or r_val[0:-32] == b'\x00'
|
|
||||||
assert len(s_val) <= 32 or s_val[0:-32] == b'\x00'
|
|
||||||
|
|
||||||
# ensure r and s are always 32 chars long by 0padding
|
|
||||||
r_val = ((b'\x00' * 32) + r_val)[-32:]
|
|
||||||
s_val = ((b'\x00' * 32) + s_val)[-32:]
|
|
||||||
|
|
||||||
# tmp pubkey of self, but always compressed
|
|
||||||
pubkey = CECKey()
|
|
||||||
pubkey.set_pubkey(self.get_pubkey())
|
|
||||||
pubkey.set_compressed(True)
|
|
||||||
|
|
||||||
# bitcoin core does <4, but I've seen other places do <2 and I've never seen a i > 1 so far
|
|
||||||
for i in range(0, 4):
|
|
||||||
cec_key = CECKey()
|
|
||||||
cec_key.set_compressed(True)
|
|
||||||
|
|
||||||
result = cec_key.recover(r_val, s_val, hash, len(hash), i, 1)
|
|
||||||
if result == 1:
|
|
||||||
if cec_key.get_pubkey() == pubkey.get_pubkey():
|
|
||||||
return r_val + s_val, i
|
|
||||||
|
|
||||||
raise ValueError
|
|
||||||
|
|
||||||
def signature_to_low_s(self, sig):
|
|
||||||
der_sig = ECDSA_SIG_st()
|
|
||||||
_ssl.d2i_ECDSA_SIG(ctypes.byref(ctypes.pointer(der_sig)), ctypes.byref(ctypes.c_char_p(sig)), len(sig))
|
|
||||||
group = _ssl.EC_KEY_get0_group(self.k)
|
|
||||||
order = _ssl.BN_new()
|
|
||||||
halforder = _ssl.BN_new()
|
|
||||||
ctx = _ssl.BN_CTX_new()
|
|
||||||
_ssl.EC_GROUP_get_order(group, order, ctx)
|
|
||||||
_ssl.BN_rshift1(halforder, order)
|
|
||||||
|
|
||||||
# Verify that s is over half the order of the curve before we actually subtract anything from it
|
|
||||||
if _ssl.BN_cmp(der_sig.s, halforder) > 0:
|
|
||||||
_ssl.BN_sub(der_sig.s, order, der_sig.s)
|
|
||||||
|
|
||||||
_ssl.BN_free(halforder)
|
|
||||||
_ssl.BN_free(order)
|
|
||||||
_ssl.BN_CTX_free(ctx)
|
|
||||||
|
|
||||||
derlen = _ssl.i2d_ECDSA_SIG(ctypes.pointer(der_sig), 0)
|
|
||||||
if derlen == 0:
|
|
||||||
_ssl.ECDSA_SIG_free(der_sig)
|
|
||||||
return None
|
|
||||||
new_sig = ctypes.create_string_buffer(derlen)
|
|
||||||
_ssl.i2d_ECDSA_SIG(ctypes.pointer(der_sig), ctypes.byref(ctypes.pointer(new_sig)))
|
|
||||||
_ssl.BN_free(der_sig.r)
|
|
||||||
_ssl.BN_free(der_sig.s)
|
|
||||||
|
|
||||||
return new_sig.raw
|
|
||||||
|
|
||||||
def verify(self, hash, sig):
|
|
||||||
"""Verify a DER signature"""
|
|
||||||
if not sig:
|
|
||||||
return false
|
|
||||||
|
|
||||||
# New versions of OpenSSL will reject non-canonical DER signatures. de/re-serialize first.
|
|
||||||
norm_sig = ctypes.c_void_p(0)
|
|
||||||
_ssl.d2i_ECDSA_SIG(ctypes.byref(norm_sig), ctypes.byref(ctypes.c_char_p(sig)), len(sig))
|
|
||||||
|
|
||||||
derlen = _ssl.i2d_ECDSA_SIG(norm_sig, 0)
|
|
||||||
if derlen == 0:
|
|
||||||
_ssl.ECDSA_SIG_free(norm_sig)
|
|
||||||
return false
|
|
||||||
|
|
||||||
norm_der = ctypes.create_string_buffer(derlen)
|
|
||||||
_ssl.i2d_ECDSA_SIG(norm_sig, ctypes.byref(ctypes.pointer(norm_der)))
|
|
||||||
_ssl.ECDSA_SIG_free(norm_sig)
|
|
||||||
|
|
||||||
# -1 = error, 0 = bad sig, 1 = good
|
|
||||||
return _ssl.ECDSA_verify(0, hash, len(hash), norm_der, derlen, self.k) == 1
|
|
||||||
|
|
||||||
def set_compressed(self, compressed):
|
|
||||||
if compressed:
|
|
||||||
form = self.POINT_CONVERSION_COMPRESSED
|
|
||||||
else:
|
|
||||||
form = self.POINT_CONVERSION_UNCOMPRESSED
|
|
||||||
_ssl.EC_KEY_set_conv_form(self.k, form)
|
|
||||||
|
|
||||||
def recover(self, sigR, sigS, msg, msglen, recid, check):
|
|
||||||
"""
|
|
||||||
Perform ECDSA key recovery (see SEC1 4.1.6) for curves over (mod p)-fields
|
|
||||||
recid selects which key is recovered
|
|
||||||
if check is non-zero, additional checks are performed
|
|
||||||
"""
|
|
||||||
i = int(recid / 2)
|
|
||||||
|
|
||||||
r = None
|
|
||||||
s = None
|
|
||||||
ctx = None
|
|
||||||
R = None
|
|
||||||
O = None
|
|
||||||
Q = None
|
|
||||||
|
|
||||||
assert len(sigR) == 32, len(sigR)
|
|
||||||
assert len(sigS) == 32, len(sigS)
|
|
||||||
|
|
||||||
try:
|
|
||||||
r = _ssl.BN_bin2bn(bytes(sigR), len(sigR), _ssl.BN_new())
|
|
||||||
s = _ssl.BN_bin2bn(bytes(sigS), len(sigS), _ssl.BN_new())
|
|
||||||
|
|
||||||
group = _ssl.EC_KEY_get0_group(self.k)
|
|
||||||
ctx = _ssl.BN_CTX_new()
|
|
||||||
order = _ssl.BN_CTX_get(ctx)
|
|
||||||
ctx = _ssl.BN_CTX_new()
|
|
||||||
|
|
||||||
if not _ssl.EC_GROUP_get_order(group, order, ctx):
|
|
||||||
return -2
|
|
||||||
|
|
||||||
x = _ssl.BN_CTX_get(ctx)
|
|
||||||
if not _ssl.BN_copy(x, order):
|
|
||||||
return -1
|
|
||||||
if not _ssl.BN_mul_word(x, i):
|
|
||||||
return -1
|
|
||||||
if not _ssl.BN_add(x, x, r):
|
|
||||||
return -1
|
|
||||||
|
|
||||||
field = _ssl.BN_CTX_get(ctx)
|
|
||||||
if not _ssl.EC_GROUP_get_curve_GFp(group, field, None, None, ctx):
|
|
||||||
return -2
|
|
||||||
|
|
||||||
if _ssl.BN_cmp(x, field) >= 0:
|
|
||||||
return 0
|
|
||||||
|
|
||||||
R = _ssl.EC_POINT_new(group)
|
|
||||||
if R is None:
|
|
||||||
return -2
|
|
||||||
if not _ssl.EC_POINT_set_compressed_coordinates_GFp(group, R, x, recid % 2, ctx):
|
|
||||||
return 0
|
|
||||||
|
|
||||||
if check:
|
|
||||||
O = _ssl.EC_POINT_new(group)
|
|
||||||
if O is None:
|
|
||||||
return -2
|
|
||||||
if not _ssl.EC_POINT_mul(group, O, None, R, order, ctx):
|
|
||||||
return -2
|
|
||||||
if not _ssl.EC_POINT_is_at_infinity(group, O):
|
|
||||||
return 0
|
|
||||||
|
|
||||||
Q = _ssl.EC_POINT_new(group)
|
|
||||||
if Q is None:
|
|
||||||
return -2
|
|
||||||
|
|
||||||
n = _ssl.EC_GROUP_get_degree(group)
|
|
||||||
e = _ssl.BN_CTX_get(ctx)
|
|
||||||
if not _ssl.BN_bin2bn(msg, msglen, e):
|
|
||||||
return -1
|
|
||||||
|
|
||||||
if 8 * msglen > n:
|
|
||||||
_ssl.BN_rshift(e, e, 8 - (n & 7))
|
|
||||||
|
|
||||||
zero = _ssl.BN_CTX_get(ctx)
|
|
||||||
# if not _ssl.BN_zero(zero):
|
|
||||||
# return -1
|
|
||||||
if not _ssl.BN_mod_sub(e, zero, e, order, ctx):
|
|
||||||
return -1
|
|
||||||
rr = _ssl.BN_CTX_get(ctx)
|
|
||||||
if not _ssl.BN_mod_inverse(rr, r, order, ctx):
|
|
||||||
return -1
|
|
||||||
sor = _ssl.BN_CTX_get(ctx)
|
|
||||||
if not _ssl.BN_mod_mul(sor, s, rr, order, ctx):
|
|
||||||
return -1
|
|
||||||
eor = _ssl.BN_CTX_get(ctx)
|
|
||||||
if not _ssl.BN_mod_mul(eor, e, rr, order, ctx):
|
|
||||||
return -1
|
|
||||||
if not _ssl.EC_POINT_mul(group, Q, eor, R, sor, ctx):
|
|
||||||
return -2
|
|
||||||
|
|
||||||
if not _ssl.EC_KEY_set_public_key(self.k, Q):
|
|
||||||
return -2
|
|
||||||
|
|
||||||
return 1
|
|
||||||
finally:
|
|
||||||
if r: _ssl.BN_free(r)
|
|
||||||
if s: _ssl.BN_free(s)
|
|
||||||
if ctx: _ssl.BN_CTX_free(ctx)
|
|
||||||
if R: _ssl.EC_POINT_free(R)
|
|
||||||
if O: _ssl.EC_POINT_free(O)
|
|
||||||
if Q: _ssl.EC_POINT_free(Q)
|
|
||||||
|
|
||||||
|
|
||||||
def recover_compact(hash, sig):
|
|
||||||
"""Recover a public key from a compact signature."""
|
|
||||||
if len(sig) != 65:
|
|
||||||
raise ValueError("Signature should be 65 characters, not [%d]" % (len(sig), ))
|
|
||||||
|
|
||||||
recid = (_bord(sig[0]) - 27) & 3
|
|
||||||
compressed = (_bord(sig[0]) - 27) & 4 != 0
|
|
||||||
|
|
||||||
cec_key = CECKey()
|
|
||||||
cec_key.set_compressed(compressed)
|
|
||||||
|
|
||||||
sigR = sig[1:33]
|
|
||||||
sigS = sig[33:65]
|
|
||||||
|
|
||||||
result = cec_key.recover(sigR, sigS, hash, len(hash), recid, 0)
|
|
||||||
|
|
||||||
if result < 1:
|
|
||||||
return False
|
|
||||||
|
|
||||||
pubkey = cec_key.get_pubkey()
|
|
||||||
|
|
||||||
return pubkey
|
|
||||||
|
|
||||||
def encode(val, base, minlen=0):
|
|
||||||
base, minlen = int(base), int(minlen)
|
|
||||||
code_string = ''.join([chr(x) for x in range(256)])
|
|
||||||
result = ""
|
|
||||||
while val > 0:
|
|
||||||
result = code_string[val % base] + result
|
|
||||||
val //= base
|
|
||||||
return code_string[0] * max(minlen - len(result), 0) + result
|
|
||||||
|
|
||||||
def num_to_var_int(x):
|
|
||||||
x = int(x)
|
|
||||||
if x < 253: return chr(x)
|
|
||||||
elif x < 65536: return chr(253)+encode(x, 256, 2)[::-1]
|
|
||||||
elif x < 4294967296: return chr(254) + encode(x, 256, 4)[::-1]
|
|
||||||
else: return chr(255) + encode(x, 256, 8)[::-1]
|
|
||||||
|
|
||||||
|
|
||||||
def msg_magic(message):
|
|
||||||
return "\x18Bitcoin Signed Message:\n" + num_to_var_int( len(message) ) + message
|
|
||||||
|
|
||||||
|
|
||||||
def getMessagePubkey(message, sig):
|
|
||||||
message = msg_magic(message)
|
|
||||||
hash = hashlib.sha256(hashlib.sha256(message).digest()).digest()
|
|
||||||
sig = base64.b64decode(sig)
|
|
||||||
|
|
||||||
pubkey = recover_compact(hash, sig)
|
|
||||||
return pubkey
|
|
||||||
|
|
||||||
def test():
|
|
||||||
sign = "HGbib2kv9gm9IJjDt1FXbXFczZi35u0rZR3iPUIt5GglDDCeIQ7v8eYXVNIaLoJRI4URGZrhwmsYQ9aVtRTnTfQ="
|
|
||||||
pubkey = "044827c756561b8ef6b28b5e53a000805adbf4938ab82e1c2b7f7ea16a0d6face9a509a0a13e794d742210b00581f3e249ebcc705240af2540ea19591091ac1d41"
|
|
||||||
assert getMessagePubkey("hello", sign).encode("hex") == pubkey
|
|
||||||
|
|
||||||
test() # Make sure it working right
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
import time, sys
|
|
||||||
sys.path.append("..")
|
|
||||||
from pybitcointools import bitcoin as btctools
|
|
||||||
priv = "5JsunC55XGVqFQj5kPGK4MWgTL26jKbnPhjnmchSNPo75XXCwtk"
|
|
||||||
address = "1N2XWu5soeppX2qUjvrf81rpdbShKJrjTr"
|
|
||||||
sign = btctools.ecdsa_sign("hello", priv) # HGbib2kv9gm9IJjDt1FXbXFczZi35u0rZR3iPUIt5GglDDCeIQ7v8eYXVNIaLoJRI4URGZrhwmsYQ9aVtRTnTfQ=
|
|
||||||
|
|
||||||
s = time.time()
|
|
||||||
for i in range(100):
|
|
||||||
pubkey = getMessagePubkey("hello", sign)
|
|
||||||
verified = btctools.pubkey_to_address(pubkey) == address
|
|
||||||
print "100x Verified", verified, time.time()-s
|
|
|
@ -1,207 +0,0 @@
|
||||||
#!/usr/bin/env python
|
|
||||||
##
|
|
||||||
## @file contrib/verifymessage/python/terracoin_verifymessage.py
|
|
||||||
## @brief terracoin signed message verification sample script.
|
|
||||||
## @author unknown author ; found on pastebin
|
|
||||||
##
|
|
||||||
|
|
||||||
import ctypes
|
|
||||||
import ctypes.util
|
|
||||||
import hashlib
|
|
||||||
import base64
|
|
||||||
addrtype = 0
|
|
||||||
|
|
||||||
try:
|
|
||||||
ssl = ctypes.CDLL("src/lib/opensslVerify/libeay32.dll")
|
|
||||||
except:
|
|
||||||
ssl = ctypes.cdll.LoadLibrary(ctypes.util.find_library('ssl') or ctypes.util.find_library('crypto') or 'libeay32')
|
|
||||||
|
|
||||||
openssl_version = "%.9X" % ssl.SSLeay()
|
|
||||||
|
|
||||||
NID_secp256k1 = 714
|
|
||||||
|
|
||||||
def check_result (val, func, args):
|
|
||||||
if val == 0:
|
|
||||||
raise ValueError
|
|
||||||
else:
|
|
||||||
return ctypes.c_void_p (val)
|
|
||||||
|
|
||||||
ssl.EC_KEY_new_by_curve_name.restype = ctypes.c_void_p
|
|
||||||
ssl.EC_KEY_new_by_curve_name.errcheck = check_result
|
|
||||||
|
|
||||||
POINT_CONVERSION_COMPRESSED = 2
|
|
||||||
POINT_CONVERSION_UNCOMPRESSED = 4
|
|
||||||
|
|
||||||
__b58chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
|
|
||||||
__b58base = len(__b58chars)
|
|
||||||
|
|
||||||
def b58encode(v):
|
|
||||||
""" encode v, which is a string of bytes, to base58.
|
|
||||||
"""
|
|
||||||
|
|
||||||
long_value = 0L
|
|
||||||
for (i, c) in enumerate(v[::-1]):
|
|
||||||
long_value += (256**i) * ord(c)
|
|
||||||
|
|
||||||
result = ''
|
|
||||||
while long_value >= __b58base:
|
|
||||||
div, mod = divmod(long_value, __b58base)
|
|
||||||
result = __b58chars[mod] + result
|
|
||||||
long_value = div
|
|
||||||
result = __b58chars[long_value] + result
|
|
||||||
|
|
||||||
# Bitcoin does a little leading-zero-compression:
|
|
||||||
# leading 0-bytes in the input become leading-1s
|
|
||||||
nPad = 0
|
|
||||||
for c in v:
|
|
||||||
if c == '\0': nPad += 1
|
|
||||||
else: break
|
|
||||||
|
|
||||||
return (__b58chars[0]*nPad) + result
|
|
||||||
|
|
||||||
def hash_160(public_key):
|
|
||||||
md = hashlib.new('ripemd160')
|
|
||||||
md.update(hashlib.sha256(public_key).digest())
|
|
||||||
return md.digest()
|
|
||||||
|
|
||||||
def hash_160_to_bc_address(h160):
|
|
||||||
vh160 = chr(addrtype) + h160
|
|
||||||
h = Hash(vh160)
|
|
||||||
addr = vh160 + h[0:4]
|
|
||||||
return b58encode(addr)
|
|
||||||
|
|
||||||
def public_key_to_bc_address(public_key):
|
|
||||||
h160 = hash_160(public_key)
|
|
||||||
return hash_160_to_bc_address(h160)
|
|
||||||
|
|
||||||
def encode(val, base, minlen=0):
|
|
||||||
base, minlen = int(base), int(minlen)
|
|
||||||
code_string = ''.join([chr(x) for x in range(256)])
|
|
||||||
result = ""
|
|
||||||
while val > 0:
|
|
||||||
result = code_string[val % base] + result
|
|
||||||
val //= base
|
|
||||||
return code_string[0] * max(minlen - len(result), 0) + result
|
|
||||||
|
|
||||||
def num_to_var_int(x):
|
|
||||||
x = int(x)
|
|
||||||
if x < 253: return chr(x)
|
|
||||||
elif x < 65536: return chr(253)+encode(x, 256, 2)[::-1]
|
|
||||||
elif x < 4294967296: return chr(254) + encode(x, 256, 4)[::-1]
|
|
||||||
else: return chr(255) + encode(x, 256, 8)[::-1]
|
|
||||||
|
|
||||||
def msg_magic(message):
|
|
||||||
return "\x18Bitcoin Signed Message:\n" + num_to_var_int( len(message) ) + message
|
|
||||||
|
|
||||||
def get_address(eckey):
|
|
||||||
size = ssl.i2o_ECPublicKey (eckey, 0)
|
|
||||||
mb = ctypes.create_string_buffer (size)
|
|
||||||
ssl.i2o_ECPublicKey (eckey, ctypes.byref (ctypes.pointer (mb)))
|
|
||||||
return public_key_to_bc_address(mb.raw)
|
|
||||||
|
|
||||||
def Hash(data):
|
|
||||||
return hashlib.sha256(hashlib.sha256(data).digest()).digest()
|
|
||||||
|
|
||||||
def bx(bn, size=32):
|
|
||||||
b = ctypes.create_string_buffer(size)
|
|
||||||
ssl.BN_bn2bin(bn, b);
|
|
||||||
return b.raw.encode('hex')
|
|
||||||
|
|
||||||
def verify_message(address, signature, message):
|
|
||||||
pkey = ssl.EC_KEY_new_by_curve_name (NID_secp256k1)
|
|
||||||
eckey = SetCompactSignature(pkey, Hash(msg_magic(message)), signature)
|
|
||||||
addr = get_address(eckey)
|
|
||||||
return (address == addr)
|
|
||||||
|
|
||||||
def SetCompactSignature(pkey, hash, signature):
|
|
||||||
sig = base64.b64decode(signature)
|
|
||||||
if len(sig) != 65:
|
|
||||||
raise BaseException("Wrong encoding")
|
|
||||||
nV = ord(sig[0])
|
|
||||||
if nV < 27 or nV >= 35:
|
|
||||||
return False
|
|
||||||
if nV >= 31:
|
|
||||||
ssl.EC_KEY_set_conv_form(pkey, POINT_CONVERSION_COMPRESSED)
|
|
||||||
nV -= 4
|
|
||||||
r = ssl.BN_bin2bn (sig[1:33], 32, ssl.BN_new())
|
|
||||||
s = ssl.BN_bin2bn (sig[33:], 32, ssl.BN_new())
|
|
||||||
eckey = ECDSA_SIG_recover_key_GFp(pkey, r, s, hash, len(hash), nV - 27, False);
|
|
||||||
return eckey
|
|
||||||
|
|
||||||
def ECDSA_SIG_recover_key_GFp(eckey, r, s, msg, msglen, recid, check):
|
|
||||||
n = 0
|
|
||||||
i = recid / 2
|
|
||||||
|
|
||||||
group = ssl.EC_KEY_get0_group(eckey)
|
|
||||||
ctx = ssl.BN_CTX_new()
|
|
||||||
ssl.BN_CTX_start(ctx)
|
|
||||||
order = ssl.BN_CTX_get(ctx)
|
|
||||||
ssl.EC_GROUP_get_order(group, order, ctx)
|
|
||||||
x = ssl.BN_CTX_get(ctx)
|
|
||||||
ssl.BN_copy(x, order);
|
|
||||||
ssl.BN_mul_word(x, i);
|
|
||||||
ssl.BN_add(x, x, r)
|
|
||||||
field = ssl.BN_CTX_get(ctx)
|
|
||||||
ssl.EC_GROUP_get_curve_GFp(group, field, None, None, ctx)
|
|
||||||
|
|
||||||
if (ssl.BN_cmp(x, field) >= 0):
|
|
||||||
return False
|
|
||||||
|
|
||||||
R = ssl.EC_POINT_new(group)
|
|
||||||
ssl.EC_POINT_set_compressed_coordinates_GFp(group, R, x, recid % 2, ctx)
|
|
||||||
|
|
||||||
if check:
|
|
||||||
O = ssl.EC_POINT_new(group)
|
|
||||||
ssl.EC_POINT_mul(group, O, None, R, order, ctx)
|
|
||||||
if ssl.EC_POINT_is_at_infinity(group, O):
|
|
||||||
return False
|
|
||||||
|
|
||||||
Q = ssl.EC_POINT_new(group)
|
|
||||||
n = ssl.EC_GROUP_get_degree(group)
|
|
||||||
e = ssl.BN_CTX_get(ctx)
|
|
||||||
ssl.BN_bin2bn(msg, msglen, e)
|
|
||||||
if 8 * msglen > n: ssl.BN_rshift(e, e, 8 - (n & 7))
|
|
||||||
|
|
||||||
|
|
||||||
zero = ssl.BN_CTX_get(ctx)
|
|
||||||
ssl.BN_set_word(zero, 0)
|
|
||||||
ssl.BN_mod_sub(e, zero, e, order, ctx)
|
|
||||||
rr = ssl.BN_CTX_get(ctx);
|
|
||||||
ssl.BN_mod_inverse(rr, r, order, ctx)
|
|
||||||
sor = ssl.BN_CTX_get(ctx)
|
|
||||||
ssl.BN_mod_mul(sor, s, rr, order, ctx)
|
|
||||||
eor = ssl.BN_CTX_get(ctx)
|
|
||||||
ssl.BN_mod_mul(eor, e, rr, order, ctx)
|
|
||||||
ssl.EC_POINT_mul(group, Q, eor, R, sor, ctx)
|
|
||||||
ssl.EC_KEY_set_public_key(eckey, Q)
|
|
||||||
return eckey
|
|
||||||
|
|
||||||
|
|
||||||
def getMessagePubkey(message, sig):
|
|
||||||
pkey = ssl.EC_KEY_new_by_curve_name(NID_secp256k1)
|
|
||||||
eckey = SetCompactSignature(pkey, Hash(msg_magic(message)), sig)
|
|
||||||
size = ssl.i2o_ECPublicKey (eckey, 0)
|
|
||||||
mb = ctypes.create_string_buffer (size)
|
|
||||||
ssl.i2o_ECPublicKey (eckey, ctypes.byref (ctypes.pointer (mb)))
|
|
||||||
return mb.raw
|
|
||||||
|
|
||||||
def test():
|
|
||||||
sign = "HGbib2kv9gm9IJjDt1FXbXFczZi35u0rZR3iPUIt5GglDDCeIQ7v8eYXVNIaLoJRI4URGZrhwmsYQ9aVtRTnTfQ="
|
|
||||||
pubkey = "044827c756561b8ef6b28b5e53a000805adbf4938ab82e1c2b7f7ea16a0d6face9a509a0a13e794d742210b00581f3e249ebcc705240af2540ea19591091ac1d41"
|
|
||||||
assert getMessagePubkey("hello", sign).encode("hex") == pubkey
|
|
||||||
|
|
||||||
test() # Make sure it working right
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
import time, os, sys
|
|
||||||
sys.path.append("..")
|
|
||||||
from pybitcointools import bitcoin as btctools
|
|
||||||
priv = "5JsunC55XGVqFQj5kPGK4MWgTL26jKbnPhjnmchSNPo75XXCwtk"
|
|
||||||
address = "1N2XWu5soeppX2qUjvrf81rpdbShKJrjTr"
|
|
||||||
sign = btctools.ecdsa_sign("hello", priv) # HGbib2kv9gm9IJjDt1FXbXFczZi35u0rZR3iPUIt5GglDDCeIQ7v8eYXVNIaLoJRI4URGZrhwmsYQ9aVtRTnTfQ=
|
|
||||||
|
|
||||||
s = time.time()
|
|
||||||
for i in range(100):
|
|
||||||
pubkey = getMessagePubkey("hello", sign)
|
|
||||||
verified = btctools.pubkey_to_address(pubkey) == address
|
|
||||||
print "100x Verified", verified, time.time()-s
|
|
|
@ -14,6 +14,8 @@ import base64
|
||||||
import time
|
import time
|
||||||
import logging
|
import logging
|
||||||
import sys
|
import sys
|
||||||
|
import os
|
||||||
|
|
||||||
addrtype = 0
|
addrtype = 0
|
||||||
|
|
||||||
|
|
||||||
|
@ -190,16 +192,20 @@ class _OpenSSL:
|
||||||
|
|
||||||
ssl = None
|
ssl = None
|
||||||
|
|
||||||
|
|
||||||
def openLibrary():
|
def openLibrary():
|
||||||
global ssl
|
global ssl
|
||||||
try:
|
try:
|
||||||
if sys.platform.startswith("win"):
|
dll_paths = [
|
||||||
ssl = _OpenSSL("src/lib/opensslVerify/libeay32.dll")
|
"src/lib/opensslVerify/libeay32.dll",
|
||||||
else: # Try to use self-compiled first
|
"/usr/local/ssl/lib/libcrypto.so",
|
||||||
ssl = _OpenSSL("/usr/local/ssl/lib/libcrypto.so")
|
"/bin/cygcrypto-1.0.0.dll"
|
||||||
except:
|
]
|
||||||
ssl = _OpenSSL(ctypes.util.find_library('ssl') or ctypes.util.find_library('crypto') or 'libeay32')
|
for dll_path in dll_paths :
|
||||||
|
if os.path.isfile(dll_path):
|
||||||
|
ssl = _OpenSSL(dll_path)
|
||||||
|
assert ssl
|
||||||
|
except Exception, err:
|
||||||
|
ssl = _OpenSSL(ctypes.util.find_library('ssl') or ctypes.util.find_library('crypto') or ctypes.util.find_library('libcrypto') or 'libeay32')
|
||||||
|
|
||||||
openLibrary()
|
openLibrary()
|
||||||
openssl_version = "%.9X" % ssl._lib.SSLeay()
|
openssl_version = "%.9X" % ssl._lib.SSLeay()
|
||||||
|
|
|
@ -1,35 +0,0 @@
|
||||||
import opensslVerify, gevent, time
|
|
||||||
from gevent import monkey
|
|
||||||
monkey.patch_all(thread=False, ssl=False)
|
|
||||||
|
|
||||||
def test():
|
|
||||||
data = "A"*1024
|
|
||||||
sign = "G2Jo8dDa+jqvJipft9E3kfrAxjESWLBpVtuGIiEBCD/UUyHmRMYNqnlWeOiaHHpja5LOP+U5CanRALfOjCSYIa8="
|
|
||||||
for i in range(2*1000):
|
|
||||||
if i%1000 == 0:
|
|
||||||
print i, len(data)
|
|
||||||
#data += data+"A"
|
|
||||||
time.sleep(0)
|
|
||||||
pub = opensslVerify.getMessagePubkey(data, sign)
|
|
||||||
|
|
||||||
print repr(pub), len(data)
|
|
||||||
|
|
||||||
while 1:
|
|
||||||
s = time.time()
|
|
||||||
gevent.joinall([gevent.spawn(test), gevent.spawn(test)])
|
|
||||||
try:
|
|
||||||
import psutil, os
|
|
||||||
process = psutil.Process(os.getpid())
|
|
||||||
print "Mem:", process.get_memory_info()[0] / float(2 ** 20)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
raw_input("finished, in %.2fs, check memory usage" % (time.time()-s))
|
|
||||||
opensslVerify.close()
|
|
||||||
opensslVerify.open()
|
|
||||||
try:
|
|
||||||
import psutil, os
|
|
||||||
process = psutil.Process(os.getpid())
|
|
||||||
print "Mem:", process.get_memory_info()[0] / float(2 ** 20)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
raw_input("closed and openssl, check memory again, press enter to start again")
|
|
|
@ -431,12 +431,19 @@ class _OpenSSL:
|
||||||
def openLibrary():
|
def openLibrary():
|
||||||
global OpenSSL
|
global OpenSSL
|
||||||
try:
|
try:
|
||||||
if sys.platform.startswith("win"):
|
dll_paths = [
|
||||||
OpenSSL = _OpenSSL("src/lib/opensslVerify/libeay32.dll")
|
"src/lib/opensslVerify/libeay32.dll",
|
||||||
else: # Try to use self-compiled first
|
"/usr/local/ssl/lib/libcrypto.so",
|
||||||
OpenSSL = _OpenSSL("/usr/local/ssl/lib/libcrypto.so")
|
"/bin/cygcrypto-1.0.0.dll"
|
||||||
except:
|
]
|
||||||
OpenSSL = _OpenSSL(ctypes.util.find_library('ssl') or ctypes.util.find_library('crypto') or 'libeay32')
|
for dll_path in dll_paths :
|
||||||
|
print dll_path
|
||||||
|
if os.path.isfile(dll_path):
|
||||||
|
ssl = _OpenSSL(dll_path)
|
||||||
|
assert ssl
|
||||||
|
except Exception, err:
|
||||||
|
ssl = _OpenSSL(ctypes.util.find_library('ssl') or ctypes.util.find_library('crypto') or ctypes.util.find_library('libcrypto') or 'libeay32')
|
||||||
|
OpenSSL = ssl
|
||||||
|
|
||||||
|
|
||||||
def closeLibrary():
|
def closeLibrary():
|
||||||
|
|
|
@ -2,18 +2,35 @@
|
||||||
# Disable SSL compression to save massive memory and cpu
|
# Disable SSL compression to save massive memory and cpu
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
from Config import config
|
from Config import config
|
||||||
|
|
||||||
|
|
||||||
|
def openLibrary():
|
||||||
|
import ctypes
|
||||||
|
import ctypes.util
|
||||||
|
try:
|
||||||
|
dll_paths = [
|
||||||
|
"src/lib/opensslVerify/libeay32.dll",
|
||||||
|
"/usr/local/ssl/lib/libcrypto.so",
|
||||||
|
"/bin/cygcrypto-1.0.0.dll"
|
||||||
|
]
|
||||||
|
for dll_path in dll_paths:
|
||||||
|
if os.path.isfile(dll_path):
|
||||||
|
ssl = ctypes.CDLL(dll_path, ctypes.RTLD_GLOBAL)
|
||||||
|
assert ssl
|
||||||
|
except:
|
||||||
|
dll_path = ctypes.util.find_library('ssl') or ctypes.util.find_library('crypto') or ctypes.util.find_library('libcrypto')
|
||||||
|
ssl = ctypes.CDLL(dll_path or 'libeay32', ctypes.RTLD_GLOBAL)
|
||||||
|
return ssl
|
||||||
|
|
||||||
|
|
||||||
def disableSSLCompression():
|
def disableSSLCompression():
|
||||||
import ctypes
|
import ctypes
|
||||||
import ctypes.util
|
import ctypes.util
|
||||||
try:
|
try:
|
||||||
openssl = ctypes.CDLL(
|
openssl = openLibrary()
|
||||||
ctypes.util.find_library('ssl') or ctypes.util.find_library('crypto') or 'libeay32',
|
|
||||||
ctypes.RTLD_GLOBAL
|
|
||||||
)
|
|
||||||
openssl.SSL_COMP_get_compression_methods.restype = ctypes.c_void_p
|
openssl.SSL_COMP_get_compression_methods.restype = ctypes.c_void_p
|
||||||
except Exception, err:
|
except Exception, err:
|
||||||
logging.debug("Disable SSL compression failed: %s (normal on Windows)" % err)
|
logging.debug("Disable SSL compression failed: %s (normal on Windows)" % err)
|
||||||
|
@ -25,7 +42,10 @@ def disableSSLCompression():
|
||||||
|
|
||||||
|
|
||||||
if config.disable_sslcompression:
|
if config.disable_sslcompression:
|
||||||
disableSSLCompression()
|
try:
|
||||||
|
disableSSLCompression()
|
||||||
|
except Exception, err:
|
||||||
|
logging.debug("Error disabling SSL compression: %s" % err)
|
||||||
|
|
||||||
|
|
||||||
# https://github.com/gevent/gevent/issues/477
|
# https://github.com/gevent/gevent/issues/477
|
||||||
|
|
Loading…
Reference in a new issue