rev122, 40x faster openssl based sign verify, Openssl verify benchmark, Socket objects stat, Dont trace notification stack, uiserver memory leak fix

This commit is contained in:
HelloZeroNet 2015-04-28 00:43:17 +02:00
parent eb79556bb8
commit 71be41ade0
15 changed files with 636 additions and 12 deletions

View File

@ -42,7 +42,8 @@ Decentralized websites using Bitcoin crypto and the BitTorrent network
After the peers have verified the `content.json` integrity (using the
signature), they download the modified files and publish the new content to
other peers.
* More details: [Slideshow about how ZeroNet works](https://docs.google.com/presentation/d/1_2qK1IuOKJ51pgBvllZ9Yu7Au2l551t3XBgyTSvilew/pub?start=false&loop=false&delayms=3000)
#### [Slideshow about ZeroNet cryptography, site updates, multi-user sites »](https://docs.google.com/presentation/d/1_2qK1IuOKJ51pgBvllZ9Yu7Au2l551t3XBgyTSvilew/pub?start=false&loop=false&delayms=3000)

View File

@ -155,6 +155,11 @@ class UiRequestPlugin(object):
for obj in objs:
yield " - %.1fkb: %s<br>" % (self.getObjSize(obj, hpy), cgi.escape(repr(obj)))
from socket import socket
objs = [obj for obj in gc.get_objects() if isinstance(obj, socket)]
yield "<br>Sockets (%s):<br>" % len(objs)
for obj in objs:
yield " - %.1fkb: %s<br>" % (self.getObjSize(obj, hpy), cgi.escape(repr(obj)))
from msgpack import Unpacker
objs = [obj for obj in gc.get_objects() if isinstance(obj, Unpacker)]
@ -305,11 +310,23 @@ class UiRequestPlugin(object):
address = CryptBitcoin.privatekeyToAddress(privatekey)
with benchmark("verify x 10", 1.6):
if CryptBitcoin.opensslVerify: # Openssl avalible
with benchmark("openssl verify x 100", 0.37):
for i in range(100):
if i%10==0: yield "."
ok = CryptBitcoin.verify(data, address, sign)
assert ok, "does not verify from %s" % address
else:
yield " - openssl verify x 100...not avalible :(<br>"
opensslVerify_bk = CryptBitcoin.opensslVerify # Emulate openssl not found in any way
CryptBitcoin.opensslVerify = None
with benchmark("pure-python verify x 10", 1.6):
for i in range(10):
yield "."
ok = CryptBitcoin.verify(data, address, sign)
assert ok, "does not verify from %s" % address
CryptBitcoin.opensslVerify = opensslVerify_bk
yield "<br>CryptHash:<br>"

View File

@ -27,7 +27,6 @@ class UiRequestPlugin(object):
if self.isProxyRequest(): # Match to site domain
referer = re.sub("^http://zero[/]+", "http://", referer) # Allow /zero access
print referer
referer_site_address = re.match("http[s]{0,1}://(.*?)(/|$)", referer).group(1)
else: # Match to request path
referer_site_address = re.match("/(?P<address>[A-Za-z0-9\.]+)(?P<inner_path>/.*|$)", referer_path).group("address")

View File

@ -4,7 +4,7 @@ import ConfigParser
class Config(object):
def __init__(self):
self.version = "0.2.9"
self.rev = 120
self.rev = 122
self.parser = self.createArguments()
argv = sys.argv[:] # Copy command line arguments
argv = self.parseConfig(argv) # Add arguments from config file

View File

@ -1,5 +1,13 @@
from lib.BitcoinECC import BitcoinECC
from lib.pybitcointools import bitcoin as btctools
import logging
# Try to load openssl
try:
from lib.opensslVerify import opensslVerify
logging.info("OpenSSL loaded, version: %s" % opensslVerify.openssl_version)
except Exception, err:
logging.info("OpenSSL load failed: %s, falling back to slow bitcoin verify" % err)
opensslVerify = None
def newPrivatekey(uncompressed=True): # Return new private key
@ -45,8 +53,12 @@ def signOld(data, privatekey): # Return sign to data using private key (backward
def verify(data, address, sign): # Verify data using address and sign
if hasattr(sign, "endswith"):
pub = btctools.ecdsa_recover(data, sign)
sign_address = btctools.pubtoaddr(pub)
if opensslVerify: # Use the faster method if avalible
pub = opensslVerify.getMessagePubkey(data, sign)
sign_address = btctools.pubtoaddr(pub)
else: # Use pure-python
pub = btctools.ecdsa_recover(data, sign)
sign_address = btctools.pubtoaddr(pub)
return sign_address == address
else: # Backward compatible old style
bitcoin = BitcoinECC.Bitcoin()

View File

@ -10,6 +10,7 @@ class Notify(Exception):
def formatException(err=None):
if type(err) == Notify: return err
exc_type, exc_obj, exc_tb = sys.exc_info()
if not err: err = exc_obj.message
tb = []
@ -21,6 +22,7 @@ def formatException(err=None):
if __name__ == "__main__":
try:
print 1/0
except Exception, err:
@ -36,4 +38,10 @@ if __name__ == "__main__":
except Exception, err:
print err
print "Json load error: %s" % formatException(err)
try:
raise Notify("nothing...")
except Exception, err:
print "Notify: %s" % formatException(err)
loadJson()

View File

@ -20,17 +20,25 @@ class UiWSGIHandler(WSGIHandler):
def run_application(self):
self.server.sockets[self.client_address] = self.socket
if "HTTP_UPGRADE" in self.environ: # Websocket request
ws_handler = WebSocketHandler(*self.args, **self.kwargs)
ws_handler.__dict__ = self.__dict__ # Match class variables
ws_handler.run_application()
try:
ws_handler = WebSocketHandler(*self.args, **self.kwargs)
ws_handler.__dict__ = self.__dict__ # Match class variables
ws_handler.run_application()
except Exception, err:
logging.error("UiWSGIHandler websocket error: %s" % Debug.formatException(err))
if config.debug: # Allow websocket errors to appear on /Debug
import sys
del self.server.sockets[self.client_address]
sys.modules["main"].DebugHook.handleError()
else: # Standard HTTP request
#print self.application.__class__.__name__
try:
return super(UiWSGIHandler, self).run_application()
super(UiWSGIHandler, self).run_application()
except Exception, err:
logging.error("UiWSGIHandler error: %s" % Debug.formatException(err))
if config.debug: # Allow websocket errors to appear on /Debug
import sys
del self.server.sockets[self.client_address]
sys.modules["main"].DebugHook.handleError()
del self.server.sockets[self.client_address]

Binary file not shown.

View File

@ -0,0 +1,126 @@
LICENSE ISSUES
==============
The OpenSSL toolkit stays under a dual license, i.e. both the conditions of
the OpenSSL License and the original SSLeay license apply to the toolkit.
See below for the actual license texts. Actually both licenses are BSD-style
Open Source licenses. In case of any license issues related to OpenSSL
please contact openssl-core@openssl.org.
OpenSSL License
---------------
/* ====================================================================
* Copyright (c) 1998-2011 The OpenSSL Project. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. All advertising materials mentioning features or use of this
* software must display the following acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
*
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* openssl-core@openssl.org.
*
* 5. Products derived from this software may not be called "OpenSSL"
* nor may "OpenSSL" appear in their names without prior written
* permission of the OpenSSL Project.
*
* 6. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the OpenSSL Project
* for use in the OpenSSL Toolkit (http://www.openssl.org/)"
*
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*
* This product includes cryptographic software written by Eric Young
* (eay@cryptsoft.com). This product includes software written by Tim
* Hudson (tjh@cryptsoft.com).
*
*/
Original SSLeay License
-----------------------
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
* This package is an SSL implementation written
* by Eric Young (eay@cryptsoft.com).
* The implementation was written so as to conform with Netscapes SSL.
*
* This library is free for commercial and non-commercial use as long as
* the following conditions are aheared to. The following conditions
* apply to all code found in this distribution, be it the RC4, RSA,
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
* included with this distribution is covered by the same copyright terms
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
*
* Copyright remains Eric Young's, and as such any Copyright notices in
* the code are not to be removed.
* If this package is used in a product, Eric Young should be given attribution
* as the author of the parts of the library used.
* This can be in the form of a textual message at program startup or
* in documentation (online or textual) provided with the package.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* "This product includes cryptographic software written by
* Eric Young (eay@cryptsoft.com)"
* The word 'cryptographic' can be left out if the rouines from the library
* being used are not cryptographic related :-).
* 4. If you include any Windows specific code (or a derivative thereof) from
* the apps directory (application code) you must include an acknowledgement:
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
*
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* The licence and distribution terms for any publically available version or
* derivative of this code cannot be changed. i.e. this code cannot simply be
* copied and put under another distribution licence
* [including the GNU Public Licence.]
*/

View File

@ -0,0 +1,59 @@
=============================================================================
OpenSSL v1.0.2a Precompiled Binaries for Win32
-----------------------------------------------------------------------------
*** Release Information ***
Release Date: Mrz 20, 2015
Author: Frederik A. Winkelsdorf (opendec.wordpress.com)
for the Indy Project (www.indyproject.org)
Requirements: Indy 10.5.5+ (SVN Version or Delphi 2009 and newer)
Dependencies: The libraries have no noteworthy dependencies
Installation: Copy both DLL files into your application directory
Supported OS: Windows 2000 up to Windows 8
-----------------------------------------------------------------------------
*** Legal Disclaimer ***
THIS SOFTWARE IS PROVIDED BY ITS AUTHOR AND THE INDY PROJECT "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
OpenSSL license terms are provided in the file "OpenSSL License.txt".
PLEASE CHECK IF YOU NEED TO COMPLY WITH EXPORT RESTRICTIONS FOR CRYPTOGRAPHIC
SOFTWARE AND/OR PATENTS.
-----------------------------------------------------------------------------
*** Build Information Win32 ***
Built with: Microsoft Visual C++ 2008 Express Edition
The Netwide Assembler (NASM) v2.11.05 Win32
Strawberry Perl v5.20.0.1 Win32 Portable
Windows PowerShell
FinalBuilder 7 Embarcadero Edition
Commands: perl configure VC-WIN32
ms\do_nasm
adjusted ms\ntdll.mak (replaced "/MD" with "/MT")
adjusted ms\version32.rc (Indy Information inserted)
nmake -f ms\ntdll.mak
nmake -f ms\ntdll.mak test
editbin.exe /rebase:base=0x11000000 libeay32.dll
editbin.exe /rebase:base=0x12000000 ssleay32.dll
=============================================================================

View File

Binary file not shown.

View File

@ -0,0 +1,392 @@
# 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
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

View File

@ -124,7 +124,9 @@ class Actions:
def siteVerify(self, address):
import time
from Site import Site
s = time.time()
logging.info("Verifing site: %s..." % address)
site = Site(address)
@ -138,7 +140,7 @@ class Actions:
logging.info("Verifying site files...")
bad_files = site.storage.verifyFiles()
if not bad_files:
logging.info("[OK] All file sha512sum matches!")
logging.info("[OK] All file sha512sum matches! (%.3fs)" % (time.time()-s))
else:
logging.error("[ERROR] Error during verifying site files!")

View File

@ -1,7 +1,7 @@
#!/usr/bin/env python
def main():
print " - Starting ZeroNet..."
print "- Starting ZeroNet..."
import sys, os
try:
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "src")) # Imports relative to src