diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 00000000..f27b66a8 --- /dev/null +++ b/.coveragerc @@ -0,0 +1,33 @@ +# .coveragerc to control coverage.py +[run] +omit = + bitcoin/main.py + bitcoin/deterministic.py + bitcoin/transaction.py + bitcoin/py3specials.py + test/fee-estimation.py + test/randomfunc-test.py + test/tumbler-test.py + test/test_tumbler.py + test/test_donations.py + +[report] +# Regexes for lines to exclude from consideration +exclude_lines = + # Have to re-enable the standard pragma + pragma: no cover + + # Don't complain about missing debug-only code: + def __repr__ + if self\.debug + + # Don't complain if tests don't hit defensive assertion code: + raise AssertionError + raise NotImplementedError + except ImportError + # Don't complain if non-runnable code isn't run: + if 0: + if __name__ == .__main__.: + +ignore_errors = True + diff --git a/.travis.yml b/.travis.yml index 6fa3e964..69b24d3b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,14 +1,20 @@ language: python python: - "2.7_with_system_site_packages" + before_install: - sudo apt-add-repository ppa:bitcoin/bitcoin -y - sudo apt-get update -q - sudo apt-get install --no-install-recommends --no-upgrade -qq bitcoind - sudo apt-get install -y build-essential - sudo apt-get install -y automake + - sudo apt-get install -y pkg-config + - sudo apt-get install -y libtool + - sudo apt-get install -y libffi-dev + - sudo apt-get install -y libgmp-dev install: - pip install -r requirements-dev.txt + - sudo pip install secp256k1 script: #install and test libsodium - git clone git://github.com/jedisct1/libsodium.git @@ -25,7 +31,7 @@ script: - mkdir /home/travis/.bitcoin - cp test/bitcoin.conf /home/travis/.bitcoin/. - chmod 600 /home/travis/.bitcoin/bitcoin.conf - - PYTHONPATH=.$PYTHONPATH py.test --cov-report html --btcconf=/home/travis/.bitcoin/bitcoin.conf --btcpwd=123456abcdef + - PYTHONPATH=.:$PYTHONPATH py.test --cov-report html --btcconf=/home/travis/.bitcoin/bitcoin.conf --btcpwd=123456abcdef --ignore test/test_tumbler.py - cd logs - for x in `ls`; do tail -50 $x; done - cd .. @@ -34,3 +40,4 @@ after_success: branches: only: - develop + - more_tests diff --git a/bitcoin/__init__.py b/bitcoin/__init__.py index 649946ce..3ca1223a 100644 --- a/bitcoin/__init__.py +++ b/bitcoin/__init__.py @@ -7,7 +7,7 @@ from bitcoin.secp256k1_main import * from bitcoin.secp256k1_transaction import * from bitcoin.secp256k1_deterministic import * -except ImportError: +except ImportError as e: from bitcoin.main import * from bitcoin.deterministic import * from bitcoin.transaction import * diff --git a/bitcoin/bci.py b/bitcoin/bci.py index 4e1956ab..9f4da43c 100644 --- a/bitcoin/bci.py +++ b/bitcoin/bci.py @@ -7,7 +7,6 @@ except: from urllib2 import build_opener - # Makes a request to a given URL (first arg) and optional params (second arg) def make_request(*args): opener = build_opener() @@ -22,189 +21,12 @@ def make_request(*args): p = e raise Exception(p) - -def parse_addr_args(*args): - # Valid input formats: blockr_unspent([addr1, addr2,addr3]) - # blockr_unspent(addr1, addr2, addr3) - # blockr_unspent([addr1, addr2, addr3], network) - # blockr_unspent(addr1, addr2, addr3, network) - # Where network is 'btc' or 'testnet' - network = 'btc' - addr_args = args - if len(args) >= 1 and args[-1] in ('testnet', 'btc'): - network = args[-1] - addr_args = args[:-1] - if len(addr_args) == 1 and isinstance(addr_args, list): - addr_args = addr_args[0] - - return network, addr_args - - -# Gets the unspent outputs of one or more addresses -def bci_unspent(*args): - network, addrs = parse_addr_args(*args) - u = [] - for a in addrs: - try: - data = make_request('https://blockchain.info/unspent?address=' + a) - except Exception as e: - if str(e) == 'No free outputs to spend': - continue - else: - raise Exception(e) - try: - jsonobj = json.loads(data) - for o in jsonobj["unspent_outputs"]: - h = o['tx_hash'].decode('hex')[::-1].encode('hex') - u.append({ - "output": h + ':' + str(o['tx_output_n']), - "value": o['value'] - }) - except: - raise Exception("Failed to decode data: " + data) - return u - - -def blockr_unspent(*args): - # Valid input formats: blockr_unspent([addr1, addr2,addr3]) - # blockr_unspent(addr1, addr2, addr3) - # blockr_unspent([addr1, addr2, addr3], network) - # blockr_unspent(addr1, addr2, addr3, network) - # Where network is 'btc' or 'testnet' - network, addr_args = parse_addr_args(*args) - - if network == 'testnet': - blockr_url = 'https://tbtc.blockr.io/api/v1/address/unspent/' - elif network == 'btc': - blockr_url = 'https://btc.blockr.io/api/v1/address/unspent/' - else: - raise Exception('Unsupported network {0} for blockr_unspent'.format( - network)) - - if len(addr_args) == 0: - return [] - elif isinstance(addr_args[0], list): - addrs = addr_args[0] - else: - addrs = addr_args - res = make_request(blockr_url + ','.join(addrs)) - data = json.loads(res)['data'] - o = [] - if 'unspent' in data: - data = [data] - for dat in data: - for u in dat['unspent']: - o.append({ - "output": u['tx'] + ':' + str(u['n']), - "value": int(u['amount'].replace('.', '')) - }) - return o - - -def helloblock_unspent(*args): - network, addrs = parse_addr_args(*args) - if network == 'testnet': - url = 'http://testnet.helloblock.io/v1/addresses/%s/unspents?limit=500&offset=%s' - elif network == 'btc': - url = 'http://mainnet.helloblock.io/v1/addresses/%s/unspents?limit=500&offset=%s' - o = [] - for addr in addrs: - for offset in xrange(0, 10**9, 500): - res = make_request(url % (addr, offset)) - data = json.loads(res)["data"] - if not len(data["unspents"]): - break - elif offset: - sys.stderr.write("Getting more unspents: %d\n" % offset) - for dat in data["unspents"]: - o.append({ - "output": dat["txHash"] + ':' + str(dat["index"]), - "value": dat["value"], - }) - return o - - -unspent_getters = { - 'bci': bci_unspent, - 'blockr': blockr_unspent, - 'helloblock': helloblock_unspent -} - - -def unspent(*args, **kwargs): - f = unspent_getters.get(kwargs.get('source', ''), bci_unspent) - return f(*args) - - -# Gets the transaction output history of a given set of addresses, -# including whether or not they have been spent -def history(*args): - # Valid input formats: history([addr1, addr2,addr3]) - # history(addr1, addr2, addr3) - if len(args) == 0: - return [] - elif isinstance(args[0], list): - addrs = args[0] - else: - addrs = args - - txs = [] - for addr in addrs: - offset = 0 - while 1: - data = make_request( - 'https://blockchain.info/address/%s?format=json&offset=%s' % - (addr, offset)) - try: - jsonobj = json.loads(data) - except: - raise Exception("Failed to decode data: " + data) - txs.extend(jsonobj["txs"]) - if len(jsonobj["txs"]) < 50: - break - offset += 50 - sys.stderr.write("Fetching more transactions... " + str(offset) + - '\n') - outs = {} - for tx in txs: - for o in tx["out"]: - if o['addr'] in addrs: - key = str(tx["tx_index"]) + ':' + str(o["n"]) - outs[key] = { - "address": o["addr"], - "value": o["value"], - "output": tx["hash"] + ':' + str(o["n"]), - "block_height": tx.get("block_height", None) - } - for tx in txs: - for i, inp in enumerate(tx["inputs"]): - if inp["prev_out"]["addr"] in addrs: - key = str(inp["prev_out"]["tx_index"]) + \ - ':'+str(inp["prev_out"]["n"]) - if outs.get(key): - outs[key]["spend"] = tx["hash"] + ':' + str(i) - return [outs[k] for k in outs] - - # Pushes a transaction to the network using https://blockchain.info/pushtx def bci_pushtx(tx): if not re.match('^[0-9a-fA-F]*$', tx): tx = tx.encode('hex') return make_request('https://blockchain.info/pushtx', 'tx=' + tx) - -def eligius_pushtx(tx): - if not re.match('^[0-9a-fA-F]*$', tx): - tx = tx.encode('hex') - s = make_request('http://eligius.st/~wizkid057/newstats/pushtxn.php', - 'transaction=' + tx + '&send=Push') - strings = re.findall('string[^"]*"[^"]*"', s) - for string in strings: - quote = re.findall('"[^"]*"', string)[0] - if len(quote) >= 5: - return quote[1:-1] - - def blockr_pushtx(tx, network='btc'): if network == 'testnet': blockr_url = 'https://tbtc.blockr.io/api/v1/tx/push' @@ -219,148 +41,8 @@ def blockr_pushtx(tx, network='btc'): return make_request(blockr_url, '{"hex":"%s"}' % tx) -def helloblock_pushtx(tx): - if not re.match('^[0-9a-fA-F]*$', tx): - tx = tx.encode('hex') - return make_request('http://mainnet.helloblock.io/v1/transactions', - 'rawTxHex=' + tx) - - -pushtx_getters = { - 'bci': bci_pushtx, - 'blockr': blockr_pushtx, - 'helloblock': helloblock_pushtx -} - - -def pushtx(*args, **kwargs): - f = pushtx_getters.get(kwargs.get('source', ''), bci_pushtx) - return f(*args) - - -def last_block_height(): - data = make_request('https://blockchain.info/latestblock') - jsonobj = json.loads(data) - return jsonobj["height"] - - -# Gets a specific transaction -def bci_fetchtx(txhash): - if not re.match('^[0-9a-fA-F]*$', txhash): - txhash = txhash.encode('hex') - data = make_request('https://blockchain.info/rawtx/' + txhash + - '?format=hex') - return data - - -def blockr_fetchtx(txhash, network='btc'): - if network == 'testnet': - blockr_url = 'https://tbtc.blockr.io/api/v1/tx/raw/' - elif network == 'btc': - blockr_url = 'https://btc.blockr.io/api/v1/tx/raw/' - else: - raise Exception('Unsupported network {0} for blockr_fetchtx'.format( - network)) - if not re.match('^[0-9a-fA-F]*$', txhash): - txhash = txhash.encode('hex') - jsondata = json.loads(make_request(blockr_url + txhash)) - return jsondata['data']['tx']['hex'] - - -def helloblock_fetchtx(txhash, network='btc'): - if not re.match('^[0-9a-fA-F]*$', txhash): - txhash = txhash.encode('hex') - if network == 'testnet': - url = 'http://testnet.helloblock.io/v1/transactions/' - elif network == 'btc': - url = 'http://mainnet.helloblock.io/v1/transactions/' - else: - raise Exception('Unsupported network {0} for helloblock_fetchtx'.format( - network)) - data = json.loads(make_request(url + txhash))["data"]["transaction"] - o = { - "locktime": data["locktime"], - "version": data["version"], - "ins": [], - "outs": [] - } - for inp in data["inputs"]: - o["ins"].append({ - "script": inp["scriptSig"], - "outpoint": { - "index": inp["prevTxoutIndex"], - "hash": inp["prevTxHash"], - }, - "sequence": 4294967295 - }) - for outp in data["outputs"]: - o["outs"].append({ - "value": outp["value"], - "script": outp["scriptPubKey"] - }) - from bitcoin.transaction import serialize - from bitcoin.transaction import txhash as TXHASH - tx = serialize(o) - assert TXHASH(tx) == txhash - return tx - - -fetchtx_getters = { - 'bci': bci_fetchtx, - 'blockr': blockr_fetchtx, - 'helloblock': helloblock_fetchtx -} - - -def fetchtx(*args, **kwargs): - f = fetchtx_getters.get(kwargs.get('source', ''), bci_fetchtx) - return f(*args) - - -def firstbits(address): - if len(address) >= 25: - return make_request('https://blockchain.info/q/getfirstbits/' + address) - else: - return make_request('https://blockchain.info/q/resolvefirstbits/' + - address) - - -def get_block_at_height(height): - j = json.loads(make_request("https://blockchain.info/block-height/" + str( - height) + "?format=json")) - for b in j['blocks']: - if b['main_chain'] is True: - return b - raise Exception("Block at this height not found") - - -def _get_block(inp): - if len(str(inp)) < 64: - return get_block_at_height(inp) - else: - return json.loads(make_request('https://blockchain.info/rawblock/' + - inp)) - -def get_block_header_data(inp): - j = _get_block(inp) - return { - 'version': j['ver'], - 'hash': j['hash'], - 'prevhash': j['prev_block'], - 'timestamp': j['time'], - 'merkle_root': j['mrkl_root'], - 'bits': j['bits'], - 'nonce': j['nonce'], - } -def get_txs_in_block(inp): - j = _get_block(inp) - hashes = [t['hash'] for t in j['tx']] - return hashes -def get_block_height(txhash): - j = json.loads(make_request('https://blockchain.info/rawtx/' + txhash)) - return j['block_height'] diff --git a/bitcoin/main.py b/bitcoin/main.py index 2d9e4bf0..bf6d67db 100644 --- a/bitcoin/main.py +++ b/bitcoin/main.py @@ -22,19 +22,7 @@ Gy = 32670510020758816978083085130507043184471273380659243275938904335757337482424 G = (Gx, Gy) - -def change_curve(p, n, a, b, gx, gy): - global P, N, A, B, Gx, Gy, G - P, N, A, B, Gx, Gy = p, n, a, b, gx, gy - G = (Gx, Gy) - - -def getG(): - return G - # Extended Euclidean Algorithm - - def inv(a, n): lm, hm = 1, 0 low, high = a % n, n @@ -44,43 +32,9 @@ def inv(a, n): lm, low, hm, high = nm, new, lm, low return lm % n -# JSON access (for pybtctool convenience) - - -def access(obj, prop): - if isinstance(obj, dict): - if prop in obj: - return obj[prop] - elif '.' in prop: - return obj[float(prop)] - else: - return obj[int(prop)] - else: - return obj[int(prop)] - - -def multiaccess(obj, prop): - return [access(o, prop) for o in obj] - - -def slice(obj, start=0, end=2**200): - return obj[int(start):int(end)] - - -def count(obj): - return len(obj) - - -_sum = sum - - -def sum(obj): - return _sum(obj) - # Elliptic curve Jordan form functions # P = (m, n, p, q) where m/n = x, p/q = y - def isinf(p): return p[0] == 0 and p[1] == 0 @@ -158,8 +112,6 @@ def to_jordan(p): def from_jordan(p): return (p[0][0] * inv(p[0][1], P) % P, p[1][0] * inv(p[1][1], P) % P) - return (p[0][0] * inv(p[0][1], P) % P, p[1][0] * inv(p[1][1], P) % P) - def fast_multiply(a, n): return from_jordan(jordan_multiply(to_jordan(a), n)) @@ -449,24 +401,8 @@ def electrum_sig_hash(message): message)) + from_string_to_bytes(message) return bin_dbl_sha256(padded) - -def random_key(): - # Gotta be secure after that java.SecureRandom fiasco... - entropy = random_string(32) \ - + str(random.randrange(2**256)) \ - + str(int(time.time() * 1000000)) - return sha256(entropy) - - -def random_electrum_seed(): - entropy = os.urandom(32) \ - + str(random.randrange(2**256)) \ - + str(int(time.time() * 1000000)) - return sha256(entropy)[:32] - # Encodings - def b58check_to_bin(inp): leadingzbytes = len(re.match('^1*', inp).group(0)) data = b'\x00' * leadingzbytes + changebase(inp, 58, 256) @@ -545,7 +481,6 @@ def ecdsa_raw_sign(msghash, priv): def ecdsa_sign(msg, priv): return encode_sig(*ecdsa_raw_sign(electrum_sig_hash(msg), priv)) - def ecdsa_raw_verify(msghash, vrs, pub): v, r, s = vrs @@ -557,34 +492,9 @@ def ecdsa_raw_verify(msghash, vrs, pub): return r == x - def ecdsa_verify(msg, sig, pub): return ecdsa_raw_verify(electrum_sig_hash(msg), decode_sig(sig), pub) - -def ecdsa_raw_recover(msghash, vrs): - v, r, s = vrs - - x = r - beta = pow(x * x * x + A * x + B, (P + 1) // 4, P) - y = beta if v % 2 ^ beta % 2 else (P - beta) - z = hash_to_int(msghash) - Gz = jordan_multiply(((Gx, 1), (Gy, 1)), (N - z) % N) - XY = jordan_multiply(((x, 1), (y, 1)), s) - Qr = jordan_add(Gz, XY) - Q = jordan_multiply(Qr, inv(r, N)) - Q = from_jordan(Q) - - if ecdsa_raw_verify(msghash, vrs, Q): - return Q - return False - - -def ecdsa_recover(msg, sig): - return encode_pubkey( - ecdsa_raw_recover( - electrum_sig_hash(msg), decode_sig(sig)), 'hex') - def estimate_tx_size(ins, outs, txtype='p2pkh'): '''Estimate transaction size. Assuming p2pkh: diff --git a/bitcoin/py2specials.py b/bitcoin/py2specials.py index e123dc16..96a91e4c 100644 --- a/bitcoin/py2specials.py +++ b/bitcoin/py2specials.py @@ -50,18 +50,12 @@ def bytes_to_hex_string(b): def safe_from_hex(s): return s.decode('hex') - def from_int_representation_to_bytes(a): - return str(a) - def from_int_to_byte(a): return chr(a) def from_byte_to_int(a): return ord(a) - def from_bytes_to_string(s): - return s - def from_string_to_bytes(a): return a @@ -89,5 +83,3 @@ def decode(string, base): string = string[1:] return result - def random_string(x): - return os.urandom(x) diff --git a/bitcoin/py3specials.py b/bitcoin/py3specials.py index 5072ac58..eadb9a1d 100644 --- a/bitcoin/py3specials.py +++ b/bitcoin/py3specials.py @@ -57,9 +57,6 @@ def bytes_to_hex_string(b): def safe_from_hex(s): return bytes.fromhex(s) - def from_int_representation_to_bytes(a): - return bytes(str(a), 'utf-8') - def from_int_to_byte(a): return bytes([a]) @@ -116,5 +113,3 @@ def extract(d, cs): string = string[1:] return result - def random_string(x): - return str(os.urandom(x)) diff --git a/bitcoin/ripemd.py b/bitcoin/ripemd.py deleted file mode 100644 index 0b462b6f..00000000 --- a/bitcoin/ripemd.py +++ /dev/null @@ -1,430 +0,0 @@ -## ripemd.py - pure Python implementation of the RIPEMD-160 algorithm. -## Bjorn Edstrom 16 december 2007. -## -## Copyrights -## ========== -## -## This code is a derived from an implementation by Markus Friedl which is -## subject to the following license. This Python implementation is not -## subject to any other license. -## -##/* -## * Copyright (c) 2001 Markus Friedl. 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. -## * -## * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. -## */ -##/* -## * Preneel, Bosselaers, Dobbertin, "The Cryptographic Hash Function RIPEMD-160", -## * RSA Laboratories, CryptoBytes, Volume 3, Number 2, Autumn 1997, -## * ftp://ftp.rsasecurity.com/pub/cryptobytes/crypto3n2.pdf -## */ - -try: - import psyco - psyco.full() -except ImportError: - pass - -import sys - -is_python2 = sys.version_info.major == 2 -#block_size = 1 -digest_size = 20 -digestsize = 20 - -try: - range = xrange -except: - pass - - -class RIPEMD160: - """Return a new RIPEMD160 object. An optional string argument - may be provided; if present, this string will be automatically - hashed.""" - - def __init__(self, arg=None): - self.ctx = RMDContext() - if arg: - self.update(arg) - self.dig = None - - def update(self, arg): - """update(arg)""" - RMD160Update(self.ctx, arg, len(arg)) - self.dig = None - - def digest(self): - """digest()""" - if self.dig: - return self.dig - ctx = self.ctx.copy() - self.dig = RMD160Final(self.ctx) - self.ctx = ctx - return self.dig - - def hexdigest(self): - """hexdigest()""" - dig = self.digest() - hex_digest = '' - for d in dig: - if (is_python2): - hex_digest += '%02x' % ord(d) - else: - hex_digest += '%02x' % d - return hex_digest - - def copy(self): - """copy()""" - import copy - return copy.deepcopy(self) - - -def new(arg=None): - """Return a new RIPEMD160 object. An optional string argument - may be provided; if present, this string will be automatically - hashed.""" - return RIPEMD160(arg) - -# -# Private. -# - - -class RMDContext: - - def __init__(self): - self.state = [0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, - 0xC3D2E1F0] # uint32 - self.count = 0 # uint64 - self.buffer = [0] * 64 # uchar - - def copy(self): - ctx = RMDContext() - ctx.state = self.state[:] - ctx.count = self.count - ctx.buffer = self.buffer[:] - return ctx - - -K0 = 0x00000000 -K1 = 0x5A827999 -K2 = 0x6ED9EBA1 -K3 = 0x8F1BBCDC -K4 = 0xA953FD4E - -KK0 = 0x50A28BE6 -KK1 = 0x5C4DD124 -KK2 = 0x6D703EF3 -KK3 = 0x7A6D76E9 -KK4 = 0x00000000 - - -def ROL(n, x): - return ((x << n) & 0xffffffff) | (x >> (32 - n)) - - -def F0(x, y, z): - return x ^ y ^ z - - -def F1(x, y, z): - return (x & y) | (((~x) % 0x100000000) & z) - - -def F2(x, y, z): - return (x | ((~y) % 0x100000000)) ^ z - - -def F3(x, y, z): - return (x & z) | (((~z) % 0x100000000) & y) - - -def F4(x, y, z): - return x ^ (y | ((~z) % 0x100000000)) - - -def R(a, b, c, d, e, Fj, Kj, sj, rj, X): - a = ROL(sj, (a + Fj(b, c, d) + X[rj] + Kj) % 0x100000000) + e - c = ROL(10, c) - return a % 0x100000000, c - - -PADDING = [0x80] + [0] * 63 - -import sys -import struct - - -def RMD160Transform(state, block): #uint32 state[5], uchar block[64] - x = [0] * 16 - if sys.byteorder == 'little': - if is_python2: - x = struct.unpack('<16L', ''.join([chr(x) for x in block[0:64]])) - else: - x = struct.unpack('<16L', bytes(block[0:64])) - else: - raise "Error!!" - a = state[0] - b = state[1] - c = state[2] - d = state[3] - e = state[4] - - #/* Round 1 */ - a, c = R(a, b, c, d, e, F0, K0, 11, 0, x) - e, b = R(e, a, b, c, d, F0, K0, 14, 1, x) - d, a = R(d, e, a, b, c, F0, K0, 15, 2, x) - c, e = R(c, d, e, a, b, F0, K0, 12, 3, x) - b, d = R(b, c, d, e, a, F0, K0, 5, 4, x) - a, c = R(a, b, c, d, e, F0, K0, 8, 5, x) - e, b = R(e, a, b, c, d, F0, K0, 7, 6, x) - d, a = R(d, e, a, b, c, F0, K0, 9, 7, x) - c, e = R(c, d, e, a, b, F0, K0, 11, 8, x) - b, d = R(b, c, d, e, a, F0, K0, 13, 9, x) - a, c = R(a, b, c, d, e, F0, K0, 14, 10, x) - e, b = R(e, a, b, c, d, F0, K0, 15, 11, x) - d, a = R(d, e, a, b, c, F0, K0, 6, 12, x) - c, e = R(c, d, e, a, b, F0, K0, 7, 13, x) - b, d = R(b, c, d, e, a, F0, K0, 9, 14, x) - a, c = R(a, b, c, d, e, F0, K0, 8, 15, x) - #/* #15 */ - #/* Round 2 */ - e, b = R(e, a, b, c, d, F1, K1, 7, 7, x) - d, a = R(d, e, a, b, c, F1, K1, 6, 4, x) - c, e = R(c, d, e, a, b, F1, K1, 8, 13, x) - b, d = R(b, c, d, e, a, F1, K1, 13, 1, x) - a, c = R(a, b, c, d, e, F1, K1, 11, 10, x) - e, b = R(e, a, b, c, d, F1, K1, 9, 6, x) - d, a = R(d, e, a, b, c, F1, K1, 7, 15, x) - c, e = R(c, d, e, a, b, F1, K1, 15, 3, x) - b, d = R(b, c, d, e, a, F1, K1, 7, 12, x) - a, c = R(a, b, c, d, e, F1, K1, 12, 0, x) - e, b = R(e, a, b, c, d, F1, K1, 15, 9, x) - d, a = R(d, e, a, b, c, F1, K1, 9, 5, x) - c, e = R(c, d, e, a, b, F1, K1, 11, 2, x) - b, d = R(b, c, d, e, a, F1, K1, 7, 14, x) - a, c = R(a, b, c, d, e, F1, K1, 13, 11, x) - e, b = R(e, a, b, c, d, F1, K1, 12, 8, x) - #/* #31 */ - #/* Round 3 */ - d, a = R(d, e, a, b, c, F2, K2, 11, 3, x) - c, e = R(c, d, e, a, b, F2, K2, 13, 10, x) - b, d = R(b, c, d, e, a, F2, K2, 6, 14, x) - a, c = R(a, b, c, d, e, F2, K2, 7, 4, x) - e, b = R(e, a, b, c, d, F2, K2, 14, 9, x) - d, a = R(d, e, a, b, c, F2, K2, 9, 15, x) - c, e = R(c, d, e, a, b, F2, K2, 13, 8, x) - b, d = R(b, c, d, e, a, F2, K2, 15, 1, x) - a, c = R(a, b, c, d, e, F2, K2, 14, 2, x) - e, b = R(e, a, b, c, d, F2, K2, 8, 7, x) - d, a = R(d, e, a, b, c, F2, K2, 13, 0, x) - c, e = R(c, d, e, a, b, F2, K2, 6, 6, x) - b, d = R(b, c, d, e, a, F2, K2, 5, 13, x) - a, c = R(a, b, c, d, e, F2, K2, 12, 11, x) - e, b = R(e, a, b, c, d, F2, K2, 7, 5, x) - d, a = R(d, e, a, b, c, F2, K2, 5, 12, x) - #/* #47 */ - #/* Round 4 */ - c, e = R(c, d, e, a, b, F3, K3, 11, 1, x) - b, d = R(b, c, d, e, a, F3, K3, 12, 9, x) - a, c = R(a, b, c, d, e, F3, K3, 14, 11, x) - e, b = R(e, a, b, c, d, F3, K3, 15, 10, x) - d, a = R(d, e, a, b, c, F3, K3, 14, 0, x) - c, e = R(c, d, e, a, b, F3, K3, 15, 8, x) - b, d = R(b, c, d, e, a, F3, K3, 9, 12, x) - a, c = R(a, b, c, d, e, F3, K3, 8, 4, x) - e, b = R(e, a, b, c, d, F3, K3, 9, 13, x) - d, a = R(d, e, a, b, c, F3, K3, 14, 3, x) - c, e = R(c, d, e, a, b, F3, K3, 5, 7, x) - b, d = R(b, c, d, e, a, F3, K3, 6, 15, x) - a, c = R(a, b, c, d, e, F3, K3, 8, 14, x) - e, b = R(e, a, b, c, d, F3, K3, 6, 5, x) - d, a = R(d, e, a, b, c, F3, K3, 5, 6, x) - c, e = R(c, d, e, a, b, F3, K3, 12, 2, x) - #/* #63 */ - #/* Round 5 */ - b, d = R(b, c, d, e, a, F4, K4, 9, 4, x) - a, c = R(a, b, c, d, e, F4, K4, 15, 0, x) - e, b = R(e, a, b, c, d, F4, K4, 5, 5, x) - d, a = R(d, e, a, b, c, F4, K4, 11, 9, x) - c, e = R(c, d, e, a, b, F4, K4, 6, 7, x) - b, d = R(b, c, d, e, a, F4, K4, 8, 12, x) - a, c = R(a, b, c, d, e, F4, K4, 13, 2, x) - e, b = R(e, a, b, c, d, F4, K4, 12, 10, x) - d, a = R(d, e, a, b, c, F4, K4, 5, 14, x) - c, e = R(c, d, e, a, b, F4, K4, 12, 1, x) - b, d = R(b, c, d, e, a, F4, K4, 13, 3, x) - a, c = R(a, b, c, d, e, F4, K4, 14, 8, x) - e, b = R(e, a, b, c, d, F4, K4, 11, 11, x) - d, a = R(d, e, a, b, c, F4, K4, 8, 6, x) - c, e = R(c, d, e, a, b, F4, K4, 5, 15, x) - b, d = R(b, c, d, e, a, F4, K4, 6, 13, x) - #/* #79 */ - - aa = a - bb = b - cc = c - dd = d - ee = e - - a = state[0] - b = state[1] - c = state[2] - d = state[3] - e = state[4] - - #/* Parallel round 1 */ - a, c = R(a, b, c, d, e, F4, KK0, 8, 5, x) - e, b = R(e, a, b, c, d, F4, KK0, 9, 14, x) - d, a = R(d, e, a, b, c, F4, KK0, 9, 7, x) - c, e = R(c, d, e, a, b, F4, KK0, 11, 0, x) - b, d = R(b, c, d, e, a, F4, KK0, 13, 9, x) - a, c = R(a, b, c, d, e, F4, KK0, 15, 2, x) - e, b = R(e, a, b, c, d, F4, KK0, 15, 11, x) - d, a = R(d, e, a, b, c, F4, KK0, 5, 4, x) - c, e = R(c, d, e, a, b, F4, KK0, 7, 13, x) - b, d = R(b, c, d, e, a, F4, KK0, 7, 6, x) - a, c = R(a, b, c, d, e, F4, KK0, 8, 15, x) - e, b = R(e, a, b, c, d, F4, KK0, 11, 8, x) - d, a = R(d, e, a, b, c, F4, KK0, 14, 1, x) - c, e = R(c, d, e, a, b, F4, KK0, 14, 10, x) - b, d = R(b, c, d, e, a, F4, KK0, 12, 3, x) - a, c = R(a, b, c, d, e, F4, KK0, 6, 12, x) #/* #15 */ - #/* Parallel round 2 */ - e, b = R(e, a, b, c, d, F3, KK1, 9, 6, x) - d, a = R(d, e, a, b, c, F3, KK1, 13, 11, x) - c, e = R(c, d, e, a, b, F3, KK1, 15, 3, x) - b, d = R(b, c, d, e, a, F3, KK1, 7, 7, x) - a, c = R(a, b, c, d, e, F3, KK1, 12, 0, x) - e, b = R(e, a, b, c, d, F3, KK1, 8, 13, x) - d, a = R(d, e, a, b, c, F3, KK1, 9, 5, x) - c, e = R(c, d, e, a, b, F3, KK1, 11, 10, x) - b, d = R(b, c, d, e, a, F3, KK1, 7, 14, x) - a, c = R(a, b, c, d, e, F3, KK1, 7, 15, x) - e, b = R(e, a, b, c, d, F3, KK1, 12, 8, x) - d, a = R(d, e, a, b, c, F3, KK1, 7, 12, x) - c, e = R(c, d, e, a, b, F3, KK1, 6, 4, x) - b, d = R(b, c, d, e, a, F3, KK1, 15, 9, x) - a, c = R(a, b, c, d, e, F3, KK1, 13, 1, x) - e, b = R(e, a, b, c, d, F3, KK1, 11, 2, x) #/* #31 */ - #/* Parallel round 3 */ - d, a = R(d, e, a, b, c, F2, KK2, 9, 15, x) - c, e = R(c, d, e, a, b, F2, KK2, 7, 5, x) - b, d = R(b, c, d, e, a, F2, KK2, 15, 1, x) - a, c = R(a, b, c, d, e, F2, KK2, 11, 3, x) - e, b = R(e, a, b, c, d, F2, KK2, 8, 7, x) - d, a = R(d, e, a, b, c, F2, KK2, 6, 14, x) - c, e = R(c, d, e, a, b, F2, KK2, 6, 6, x) - b, d = R(b, c, d, e, a, F2, KK2, 14, 9, x) - a, c = R(a, b, c, d, e, F2, KK2, 12, 11, x) - e, b = R(e, a, b, c, d, F2, KK2, 13, 8, x) - d, a = R(d, e, a, b, c, F2, KK2, 5, 12, x) - c, e = R(c, d, e, a, b, F2, KK2, 14, 2, x) - b, d = R(b, c, d, e, a, F2, KK2, 13, 10, x) - a, c = R(a, b, c, d, e, F2, KK2, 13, 0, x) - e, b = R(e, a, b, c, d, F2, KK2, 7, 4, x) - d, a = R(d, e, a, b, c, F2, KK2, 5, 13, x) #/* #47 */ - #/* Parallel round 4 */ - c, e = R(c, d, e, a, b, F1, KK3, 15, 8, x) - b, d = R(b, c, d, e, a, F1, KK3, 5, 6, x) - a, c = R(a, b, c, d, e, F1, KK3, 8, 4, x) - e, b = R(e, a, b, c, d, F1, KK3, 11, 1, x) - d, a = R(d, e, a, b, c, F1, KK3, 14, 3, x) - c, e = R(c, d, e, a, b, F1, KK3, 14, 11, x) - b, d = R(b, c, d, e, a, F1, KK3, 6, 15, x) - a, c = R(a, b, c, d, e, F1, KK3, 14, 0, x) - e, b = R(e, a, b, c, d, F1, KK3, 6, 5, x) - d, a = R(d, e, a, b, c, F1, KK3, 9, 12, x) - c, e = R(c, d, e, a, b, F1, KK3, 12, 2, x) - b, d = R(b, c, d, e, a, F1, KK3, 9, 13, x) - a, c = R(a, b, c, d, e, F1, KK3, 12, 9, x) - e, b = R(e, a, b, c, d, F1, KK3, 5, 7, x) - d, a = R(d, e, a, b, c, F1, KK3, 15, 10, x) - c, e = R(c, d, e, a, b, F1, KK3, 8, 14, x) #/* #63 */ - #/* Parallel round 5 */ - b, d = R(b, c, d, e, a, F0, KK4, 8, 12, x) - a, c = R(a, b, c, d, e, F0, KK4, 5, 15, x) - e, b = R(e, a, b, c, d, F0, KK4, 12, 10, x) - d, a = R(d, e, a, b, c, F0, KK4, 9, 4, x) - c, e = R(c, d, e, a, b, F0, KK4, 12, 1, x) - b, d = R(b, c, d, e, a, F0, KK4, 5, 5, x) - a, c = R(a, b, c, d, e, F0, KK4, 14, 8, x) - e, b = R(e, a, b, c, d, F0, KK4, 6, 7, x) - d, a = R(d, e, a, b, c, F0, KK4, 8, 6, x) - c, e = R(c, d, e, a, b, F0, KK4, 13, 2, x) - b, d = R(b, c, d, e, a, F0, KK4, 6, 13, x) - a, c = R(a, b, c, d, e, F0, KK4, 5, 14, x) - e, b = R(e, a, b, c, d, F0, KK4, 15, 0, x) - d, a = R(d, e, a, b, c, F0, KK4, 13, 3, x) - c, e = R(c, d, e, a, b, F0, KK4, 11, 9, x) - b, d = R(b, c, d, e, a, F0, KK4, 11, 11, x) #/* #79 */ - - t = (state[1] + cc + d) % 0x100000000 - state[1] = (state[2] + dd + e) % 0x100000000 - state[2] = (state[3] + ee + a) % 0x100000000 - state[3] = (state[4] + aa + b) % 0x100000000 - state[4] = (state[0] + bb + c) % 0x100000000 - state[0] = t % 0x100000000 - - pass - - -def RMD160Update(ctx, inp, inplen): - if type(inp) == str: - inp = [ord(i) & 0xff for i in inp] - - have = int((ctx.count // 8) % 64) - inplen = int(inplen) - need = 64 - have - ctx.count += 8 * inplen - off = 0 - if inplen >= need: - if have: - for i in range(need): - ctx.buffer[have + i] = inp[i] - RMD160Transform(ctx.state, ctx.buffer) - off = need - have = 0 - while off + 64 <= inplen: - RMD160Transform(ctx.state, inp[off:]) #<--- - off += 64 - if off < inplen: - # memcpy(ctx->buffer + have, input+off, len-off); - for i in range(inplen - off): - ctx.buffer[have + i] = inp[off + i] - - -def RMD160Final(ctx): - size = struct.pack(" len(newtx["outs"]): + raise Exception( + "Transactions with sighash single should have len in <= len out") + newtx["outs"] = newtx["outs"][:i+1] + for out in newtx["outs"][:i]: + out['value'] = 2**64 - 1 + out['script'] = "" + for j, inp in enumerate(newtx["ins"]): + if j != i: + inp["sequence"] = 0 + if hashcode & SIGHASH_ANYONECANPAY: newtx["ins"] = [newtx["ins"][i]] else: pass @@ -442,33 +450,3 @@ def select(unspent, value): if tv < value: raise Exception("Not enough funds") return low[:i] - -# Only takes inputs of the form { "output": blah, "value": foo } - - -def mksend(*args): - argz, change, fee = args[:-2], args[-2], int(args[-1]) - ins, outs = [], [] - for arg in argz: - if isinstance(arg, list): - for a in arg: - (ins if is_inp(a) else outs).append(a) - else: - (ins if is_inp(arg) else outs).append(arg) - - isum = sum([i["value"] for i in ins]) - osum, outputs2 = 0, [] - for o in outs: - if isinstance(o, string_types): - o2 = {"address": o[:o.find(':')], "value": int(o[o.find(':') + 1:])} - else: - o2 = o - outputs2.append(o2) - osum += o2["value"] - - if isum < osum + fee: - raise Exception("Not enough money") - elif isum > osum + fee + 5430: - outputs2 += [{"address": change, "value": isum - osum - fee}] - - return mktx(ins, outputs2) diff --git a/bitcoin/transaction.py b/bitcoin/transaction.py index 2581776b..4b9be322 100644 --- a/bitcoin/transaction.py +++ b/bitcoin/transaction.py @@ -200,17 +200,8 @@ def ecdsa_tx_sign(tx, priv, hashcode=SIGHASH_ALL): def ecdsa_tx_verify(tx, sig, pub, hashcode=SIGHASH_ALL): return ecdsa_raw_verify(bin_txhash(tx, hashcode), der_decode_sig(sig), pub) - -def ecdsa_tx_recover(tx, sig, hashcode=SIGHASH_ALL): - z = bin_txhash(tx, hashcode) - _, r, s = der_decode_sig(sig) - left = ecdsa_raw_recover(z, (0, r, s)) - right = ecdsa_raw_recover(z, (1, r, s)) - return (encode_pubkey(left, 'hex'), encode_pubkey(right, 'hex')) - # Scripts - def mk_pubkey_script(addr): # Keep the auxiliary functions around for altcoins' sake return '76a914' + b58check_to_hex(addr) + '88ac' diff --git a/joinmarket/blockchaininterface.py b/joinmarket/blockchaininterface.py index abc062ab..64a7510f 100644 --- a/joinmarket/blockchaininterface.py +++ b/joinmarket/blockchaininterface.py @@ -81,23 +81,19 @@ def sync_wallet(self, wallet): def sync_addresses(self, wallet): """Finds which addresses have been used and sets wallet.index appropriately""" - pass @abc.abstractmethod def sync_unspent(self, wallet): """Finds the unspent transaction outputs belonging to this wallet, sets wallet.unspent """ - pass @abc.abstractmethod def add_tx_notify(self, txd, unconfirmfun, confirmfun, notifyaddr): """Invokes unconfirmfun and confirmfun when tx is seen on the network""" - pass @abc.abstractmethod def pushtx(self, txhex): """pushes tx to the network, returns txhash, or None if failed""" - pass @abc.abstractmethod def query_utxo_set(self, txouts): diff --git a/joinmarket/message_channel.py b/joinmarket/message_channel.py index e838fbd8..c3da8ea4 100644 --- a/joinmarket/message_channel.py +++ b/joinmarket/message_channel.py @@ -31,13 +31,13 @@ def __init__(self): self.on_push_tx = None def run(self): - pass #pragma no cover + pass #pragma: no cover def shutdown(self): - pass #pragma no cover + pass #pragma: no cover def send_error(self, nick, errormsg): - pass #pragma no cover + pass #pragma: no cover # callbacks for everyone # some of these many not have meaning in a future channel, like bitmessage @@ -63,7 +63,7 @@ def register_orderbookwatch_callbacks(self, self.on_order_cancel = on_order_cancel def request_orderbook(self): - pass #pragma no cover + pass #pragma: no cover # taker commands def register_taker_callbacks(self, @@ -77,16 +77,16 @@ def register_taker_callbacks(self, self.on_sig = on_sig def fill_orders(self, nickoid_dict, cj_amount, taker_pubkey): - pass #pragma no cover + pass #pragma: no cover def send_auth(self, nick, pubkey, sig): - pass #pragma no cover + pass #pragma: no cover def send_tx(self, nick_list, txhex): - pass #pragma no cover + pass #pragma: no cover def push_tx(self, nick, txhex): - pass #pragma no cover + pass #pragma: no cover # maker commands def register_maker_callbacks(self, @@ -103,16 +103,16 @@ def register_maker_callbacks(self, def announce_orders(self, orderlist, nick=None): # nick=None means announce publicly - pass #pragma no cover + pass #pragma: no cover def cancel_orders(self, oid_list): - pass #pragma no cover + pass #pragma: no cover def send_pubkey(self, nick, pubkey): - pass #pragma no cover + pass #pragma: no cover def send_ioauth(self, nick, utxo_list, cj_pubkey, change_addr, sig): - pass #pragma no cover + pass #pragma: no cover def send_sigs(self, nick, sig_list): - pass #pragma no cover + pass #pragma: no cover diff --git a/joinmarket/slowaes.py b/joinmarket/slowaes.py index 8b8d60ce..b5160941 100644 --- a/joinmarket/slowaes.py +++ b/joinmarket/slowaes.py @@ -658,19 +658,6 @@ def decryptData(key, data, mode=AESModeOfOperation.modeOfOperation["CBC"]): decr = strip_PKCS7_padding(decr) return decr - -def generateRandomKey(keysize): - """Generates a key from random data of length `keysize`. - - The returned key is a string of bytes. - - """ - if keysize not in (16, 24, 32): - emsg = 'Invalid keysize, %s. Should be one of (16, 24, 32).' - raise ValueError, emsg % keysize - return os.urandom(keysize) - - if __name__ == "__main__": moo = AESModeOfOperation() cleartext = "This is a test!" diff --git a/test/commontest.py b/test/commontest.py index 4d14f007..b0239fcb 100644 --- a/test/commontest.py +++ b/test/commontest.py @@ -85,8 +85,8 @@ def make_wallets(n, jm_single().bc_interface.grab_coins( wallets[i + start_index]['wallet'].get_external_addr(j), amt) - #reset the index so the coins can be seen if running in same script - wallets[i + start_index]['wallet'].index[j][0] -= 1 + #reset the index so the coins can be seen if running in same script + wallets[i + start_index]['wallet'].index[j][0] -= wallet_structures[i][j] return wallets diff --git a/test/ecc_sigs_rfc6979_valid.json b/test/ecc_sigs_rfc6979_valid.json new file mode 100644 index 00000000..af161797 --- /dev/null +++ b/test/ecc_sigs_rfc6979_valid.json @@ -0,0 +1,999 @@ +{ + "vectors": [ + { + "msg": "9e5755ec2f328cc8635a55415d0e9a09c2b6f2c9b0343c945fbbfe08247a4cbe", + "sig": "30440220132382ca59240c2e14ee7ff61d90fc63276325f4cbe8169fc53ade4a407c2fc802204d86fbe3bde6975dd5a91fdc95ad6544dcdf0dab206f02224ce7e2b151bd82ab01", + "privkey": "31a84594060e103f5a63eb742bd46cf5f5900d8406e2726dedfc61c7cf43ebad" + }, + { + "msg": "2d46a712699bae19a634563d74d04cc2da497b841456da270dccb75ac2f7c4e7", + "sig": "3045022100d80cf7abc9ab601373780cee3733d2cb5ff69ba1452ec2d2a058adf9645c13be0220011d1213b7d152f72fd8759b45276ba32d9c909602e5ec89550baf3aaa8ed95001", + "privkey": "7177f0d04c79fa0b8c91fe90c1cf1d44772d1fba6e5eb9b281a22cd3aafb51fe" + }, + { + "msg": "c94f4ec84be928017cbbb447d2ab5b5d4d69e5e5fd03da7eae4378a1b1c9c402", + "sig": "3045022100d0f5b740cbe3ee5b098d3c5afdefa61bb0797cb4e7b596afbd38174e1c653bb602200329e9f1a09632de477664814791ac31544e04715db68f4b02657ba35863e71101", + "privkey": "989e500d6b1397f2c5dcdf43c58ac2f14df753eb6089654e07ff946b3f84f3d5" + }, + { + "msg": "dfeb2092955572ce0695aa038f58df5499949e18f58785553c3e83343cd5eb93", + "sig": "30440220692c01edf8aeab271df3ed4e8d57a170f014f8f9d65031aac28b5e1840acfb5602205075f9d1fdbf5079ee052e5f3572d518b3594ef49582899ec44d065f71a5519201", + "privkey": "39dfc615f2b718397f6903b0c46c47c5687e97d3d2a5e1f2b200f459f7b1219b" + }, + { + "msg": "49e558d232ca204ecc27b321b197bfe0e165acd5fe46f986d5b007c68c2dcbd7", + "sig": "30440220330f62769e8e0fd43721029e1343b7f2c2575edc568007aa1b4458b2928dfc530220549c8967e8e8f414be10c6e2d36f451f1c50007c28511f9410fd7a921220190401", + "privkey": "1e17c938ef3754781130edcbe8fa2c8a27ecb43f93d333e64d89af3d9c26c23a" + }, + { + "msg": "12a683325e3063e4d9d32d38f878300d84d4ebb63247607dfb2bd72849e5fb14", + "sig": "3045022100f1391011657e358464165b53f0993a1a637f6e296c1a8f6a984d522b441b470602206c78004f1489c398aeb05b6db63d0839875f4751b117a6bd239b173428f1c2e201", + "privkey": "9120318c2d0792a29516b18a3467051445e5a6c358da577dcf06ea5ddfb8839f" + }, + { + "msg": "06e42f8adc7c2ac118b6e6d1082940c66f7d2544fa2eaae0d2b1d016fea26092", + "sig": "304402202c947ee0cf77bce3c4aab68737f07f9c43733a961552da82798a2628d6650a7c02205bb4a8634e8204bc3da98ddb1c5a7d7f5a2f4d60ee447e6e7ab20cff9dfdc5bc01", + "privkey": "a7433f154076cd9317e048562fe60529140a1155a1497ebd165b081c053e8944" + }, + { + "msg": "43307439480b2d4c3a95e725d1a13a97ec032cdbdda467533dce304513752d46", + "sig": "3045022100ac6123107cc08a63fb80e2af53937cf5aa7dee9f4e233a668d6c15d0b474903b02205bdcd30cae23c89692ee53badd610385b84567f98dc65babf000055f33877ac801", + "privkey": "58a127499af1fa4f6cc95d6b2213171762a3be0d929246f27044d64de24c4db2" + }, + { + "msg": "3a75a427f8311ae278b76bcce9a2ba99b9adc1ee91d653f9f00052b9e154b511", + "sig": "304402202f54a17ffa1b631f67232785b469d794969d3fdb140bb683ae8097217ec12c7d0220159f78ceece7e2fa1dea9e31f53374aebe6b8d893588c27e951bbc40b7ca57cf01", + "privkey": "17449f296f72790a85284a3eead10e775b452a32e7cdf1f0e68f109e5732d8a4" + }, + { + "msg": "d2ae97ae7b0b488f3a9cca6b7ed92832b4a6a7a3546a3ed9964eb51fbb2fcd98", + "sig": "3045022100c842a06f6818768fc3d93d98332affc7160fc2f58ba6fc0239c2c9cf951e6bc302202756c90464f85193a52a29001eaf824d3b0602028d4c8f5abadf6995262bc7e001", + "privkey": "229d075d7a48c5725f21e585e9effb08c80ea768883fc372ed3ad48af60a653d" + }, + { + "msg": "3492a279ef2ddfebc47cc7ee28be41b5ffc03c54b738f657862590237e56841b", + "sig": "30440220708aae22df437d7280fd8e06b9ab043abc26f6286973e94df9ae28982c534fa5022063724a156b0766c59fe75c571a5f47b80f313676f60830699b0f0c171841c32a01", + "privkey": "f2f83ccb7ecd11e6ef61a8a090890b6db56e87810be8f283626f6028843e70c2" + }, + { + "msg": "bab37255a348dcfd8864aa2bd1b964c951da28370743905f892bbf5533b2c881", + "sig": "3044022054cc561ced7052b9b0d709578e691e8e4edb04e2a38d1b79fbdbf16302674c6f022013c9ec89010fe1d9643019c7bb863abd618d4dd492c116d8fb099710e33f5b5101", + "privkey": "c476e1df4d6bc771b23836b58616ed5bb6417baaab3c533dd255562d41cce2df" + }, + { + "msg": "3543080c755844091a26bc812fefa40d00663f57622bdb63334ffbdd70ac8cfd", + "sig": "3044022066b520cb7f51656e610aefb238bfa5a62426953b22cc09689408429b68ff53f902205971ec48692210b050683f9ab2cd4443ade8a9d0ae3f95d32e865458515b8e4601", + "privkey": "e9fd9db20943a760c4cf89a9eb8aa150405686332c8a2ab8789ef19593312ac9" + }, + { + "msg": "aa05ef24738774890500e5d4f25f2801802a4c20f1be4f06721220d065abe042", + "sig": "3045022100d081a3dcc756f91b4c6aaaa5eb57c18ebe733086391c4a0761a9b11a43dd477002205cf7ce2565d977572dd10fc17875d07b2f8e3d824740db45a30f8977f57c7a1d01", + "privkey": "251e11bc1fdf9ce349c904af6f3df523e906e0367e18c96e111104715fbbfcbc" + }, + { + "msg": "57176b5966096a1818148936e1c56bea9717a7b9f4e3decf582b4ae3585e794d", + "sig": "304502210093a5c31daffcaa47b22a1f34dd969510acb76440879e91c51bb1b465fedfa6d302206edf49b1ad26bae5a1c179ae6913d3f3c3fcc0c5a3c7abec07d8adb315a0782a01", + "privkey": "099796458bffc713b89b1332089b093f8ed08039fa1d8323d7a8b198225d89d5" + }, + { + "msg": "8b339212a72cbea99b8e882e4ce7c32a1a1f0e5185d3c8e4b99c9a8ebfe58060", + "sig": "30440220640997e496194c03b7e56fe5b97a44bbad81df5a9c2501138453b86e3d1ad16a02201a1dd1ffdbe9300184b7b1ff7d0a1339dd677a081acc2208050e0dde313f515b01", + "privkey": "00417c436e3f135eb2292eb5d88cab40157b0989dc0d917ab6e87e8faa0f1ee5" + }, + { + "msg": "f1415142ca90a4f6d1f5c63dd0d776642e34bc3fe3a9ea1427afdf9d71d79231", + "sig": "304402202364525dea549ced7856a0551be97d73b1e5f20237e857cd0193f3aacaa6e1100220245974967a1f0a849a3aa7492f044c53fb10a0198c280caf075aad9beb80126401", + "privkey": "1d77dcd3d3631285c0a99a6c669d804fb603cc8a788c4568a46971b46718453a" + }, + { + "msg": "e5a093e9d225f09961f35f44b3171962b2ad3f9c859c3c21d0f03fc7dfadbd51", + "sig": "304402200d2a510384e4ec4d294150598e893ef97827c11c61a081cf694cf53e1c0dfcc102200eed9c0dbe6294f692ead6d729eddfe9267411d67a08031012c4b46230561bb701", + "privkey": "df693dfdca61122d2e633d2a2d8f4270a9199624d06f9230325d82708da5e9d2" + }, + { + "msg": "42f5f89f123967d7ecb0f0ffbac97d1e414d22f8aeea5f61ab18c67d9b05b062", + "sig": "3045022100a251fd56b0630c642143c05cc20fef8979163e85d8dd4413acf97c7f0b21832002206959532ff89b8515c5934f7dedef47c8ea1c3b0f3e1630f85445cc6989b8e61c01", + "privkey": "3e21112d32f27677d715c4f12d4005d551a5a523d7c63717f2166ebea89addc5" + }, + { + "msg": "f1914da938a0c2e8112c769591ee070ac4123b9c487c0ed7fab6b04473bf7714", + "sig": "3044022010c823ef2f6bb11e4a974723499be7a4fc9610da16229ae49e025525eca9088102203e3ae2173dcc83b754e39fbc88eb1b31effda488c1c9632572513146ed5c7dfe01", + "privkey": "ec3eaa66a6ef4b6c31acd75528218e702419bdf1c086431137926fe71daaaea0" + }, + { + "msg": "3cf9fb4cf59c6d37da6c36e0d680b1d364800e94b54f2b9074d755a456a0d7f4", + "sig": "3045022100cd40d40dbef9ac2e27f3c8d40a7f8dd538d417a7bfbcd0c00a6e92c93bcb145202205172d09504b59aeb6d2afc298441615665e4ec8fb7bf064a9364ac5f6ad2171201", + "privkey": "a51997dff0ae72ff3005ae6cad243a5d5c6864691d238fd58123bea364008009" + }, + { + "msg": "ada128dfd83338a8b0f5ead162a0fc7acaa513d5c13b9b1d5d921d2648e674f5", + "sig": "3044022075c1178f1bb941fdfa4fa4e21f056c5717a5a94247030c321ad51ac6d8a2a860022036759348c6e87c3b27388ba92895ccc6c7af659f57b4205a236bebccfe6f3e3f01", + "privkey": "9a8114c3bfe3656290a0d092bb80a9f5c67b3e938ba719424c5c8c83e13ce266" + }, + { + "msg": "d23cdc4accc2566b82fe6270e144f366f08007dffcf9e47c1c66d40708747da0", + "sig": "3045022100fbe82220345d27c870e152048698340e70d701ab868a5482a7cc22977962f8d4022009181b343e76c8645dc640762d49911df336941d79dedccba313ba03dd8c28b701", + "privkey": "f1d7fb29ab98d00f46135b74de1b7ea80f3e38360c9ee0cd7056404c5d1db57b" + }, + { + "msg": "e89e786443b5634afbe711f66530326320a0e5ec27d1c42697e5fbc11e5ce169", + "sig": "3045022100be23de4212c4bca5d1be2882ab339aa8a586dd656daae12aa2287cdfb2809af002200d460339847f0c08311a59343997d5e307136a4fc0494f84aacbbf918deb11ff01", + "privkey": "ab8f7d2eb73af6349990d2b4296d98432da8bbd858863bfa136e234a56351090" + }, + { + "msg": "ba7de66731341e48fca15ef5b62c88f19b2aee7786987d73754be8e339f706aa", + "sig": "304402202c2c1b9bee9b018df561d1f45ec07527ac916e8e56a915862cf80a4fe73779c8022037aff510509b3704390da0db4b647540647f897df5a211648f4180a292b12bca01", + "privkey": "d142f008e4ee702e6ddbf6f5429e4b39e0cd59034018a332635e6fab028f2fbe" + }, + { + "msg": "1ddaa971fd3b025d0566d9bf893a0043329379e2c52561ad3ebd3815bae0e818", + "sig": "30440220110aa7dfe50948e3a8ae149a01d9b3824e7274a6f380e64d8b189b01e71ebc4902207712465f4f09e039f46d06fa949ab5f875a0f612c86c76702c07a4007532122f01", + "privkey": "c03a06e7e3958f790f3d1bbd8c9938e3c1636301a04b15b2774d27381a383d35" + }, + { + "msg": "c5b4b2981c007f5e5b6aceb950985e64f8c5afec77955e973bc65f1a913ccd2d", + "sig": "3045022100d9f8081fc24e267dd5e2a70604277496c9c8a20b7c37f3d788e92e7356754b6e02207ffdafb0ba4efee3211a1d8e4623f13b63141054c942cd47e388faf3489bb8ff01", + "privkey": "795b50f2d308bf999565a084c8f709e6393f69a7842ce889c5addbd17c24ff5c" + }, + { + "msg": "1544d33544fa93334739a60a35bab4390b523bdbaa43ba3956ca450ad03f6201", + "sig": "304402204d74290c6daedc88e3fdae9edac89984065c2774ed69d90668544aacc6e7e16402201ec57cf928279f30d56d8e5a1a46cd976cc7117bf2d03c9123833f08db6132ee01", + "privkey": "fd2190d00de40b004f9a5d6d06829fe87eb1b11e483e94023fa01b41c27da90b" + }, + { + "msg": "cd40650b1d22d7a7777ac3a6d8701c12b485dd3859dacbaca56ad4ee4a3f6024", + "sig": "30450221008c17c93e1aa880c36c87ec08fe52ed68a96ee014a4cb8045fdd08a0537cdb602022045728db5a2bc1860cdf0767122e567f903a0de25f770d3a96b51833b2530e03e01", + "privkey": "3a6857669abb2d6f2f529b548f6386435856ebc98d8760e75642ff30a149454a" + }, + { + "msg": "5817d0ffe477cab901884793ce1e5d40302941ea7460a2b468b7b02f08203527", + "sig": "304402205ab83ee406a958901837e7f155fa8c043558963fcac8156515166bf5d008b21c022026e18000c7050b8d7415337b10eccef395db63c6fdd8b008d2b613ac2583e8d201", + "privkey": "9054a4c8279b1812748c690f7de4a8305e7ba2afa27bb30a70ec2be6cfdcd104" + }, + { + "msg": "082bca2d141957a5bcf2e6f0653557ddb12d0ef393d89c5c41849464cca6b8f3", + "sig": "3045022100d62ef631bc28d285f0ea2bde820c4edd321539e209c3575b139b4fa7fb571e35022015f47f15f24d40900ad13ddcf9809a4f8f45e8c1af2a241cd2641df02772809a01", + "privkey": "eb75f55fc51a5664c46889eb93af6834b8fc4760ffd12f36f2a7a54180765644" + }, + { + "msg": "58a7fca8920df4322b3118241aca431418796937f2dbb32bf36b2c230ac3ce78", + "sig": "3045022100efed6c4c4287746b5870de319fd0fd1e7f39cfe19771764eea8bcc2641bb87120220284f66abc53254d9fce663ecc1648d417251b246c1f72e2668e786d65b01db0a01", + "privkey": "9d6cc489b02c25d0a33f3e2c71dc90c71bb91942bea45d543f41907f026fdf94" + }, + { + "msg": "33cfeae00abc4f593d9499a7e11e314f9ead2bc6d033977d91fa13df224b56c4", + "sig": "304402205d51ef7d53b77f1e4933e38b72e60e2cb505f5c04c4589691c4afb66d45299b302202a9b34129c747c1a98dbbee519ccb8f45354cbe36b4e4bc6e9cb0079d8a8b0df01", + "privkey": "cdeee2375309bcb5cdf33d6e43f8949b3936a0bb776bb20b40087150c4eaaa9d" + }, + { + "msg": "789d7a8a926e65c632dd4ae279c23c7cbbe1938082000a4f7e663dae4d2e6565", + "sig": "3045022100c316f7d0f51e6ea313d2b03805d695ac4426f959d14d9138ef171deddf0e593702203a94ff889daed2b366a17d5b0bbbe46f96faa439f3e0bf3da3755f2313cfd9e501", + "privkey": "f22cce5bfc11406b3c2013be86cda5e5597a10c99f045af275aa5c4136ae8247" + }, + { + "msg": "cad973f4d052f59654c8b714e4c777c297217de855f7e72679ddc4d88353179a", + "sig": "30440220140c11ee563970fd34a31076fb92a81320bad49373682aab2d11ad0e9e71da5902202bc4a45f694e1a25b89e87b21b659afe87e83f57a53a2fe7a4160a93fab4331701", + "privkey": "9056b9aeb9b88e4b2d2cc34a3be77e6120551c9ec9991aeac46d75b3b07307ab" + }, + { + "msg": "08f3306ded0c07980fc8e008c6805fa19582a1c635f892d0027256b8f6e658ef", + "sig": "3045022100ea0f425a8f27a9fc82286ca7545207cfe0ca1e41d54ad3168836086bc097740b022027ede91105e79097d091efa8d3045ee9a2e250ee9029245560caa5b8bb5450fd01", + "privkey": "54f8d7d845453d60ee39167ea8c0b3203487eb9fd7f9aa83f8b92ee41799d3ac" + }, + { + "msg": "ab440f7e37a9ac189e08850866f9fec3fc2c323dc802f5cc13c9b2dd6ea9c366", + "sig": "30450221008e6a5185622e53f986c0f865b376b69cf7e2297b681c7b4baf92396808e90de90220633313c8afcb4bde5d1e099871e75df82245c9f2fe24bcdae86e53a48116f74001", + "privkey": "ee1eda8fc9d0cb958fa518d0b95189c7eb82202e6d07099b8a6a11106797af70" + }, + { + "msg": "c0d12e0b35fa92dd04ca66b9e9537a71c5683a4fe5da9354e9f74cec0746251e", + "sig": "304402201e78c59ad8c6ea7ea75735696271eca86851f7d65b2c6771eb5ebbae2c3a5c0a02203f0e9b34333f544e692f7ae92ef6ad68fc455099760944d3e074bc994f2da7bb01", + "privkey": "56983efa120cfd3a7fb92df780a60463decd5f47c6422c6dd0538a68d3c7bfec" + }, + { + "msg": "98f7eeb9417e950aa953c110b245adba213084db4bbd58978f2aac125ec2e584", + "sig": "3045022100ba311522b51cfceb11f8fadb34a79f5a75e7eb6b5878c907fb63c983feaf695402205b9e0910415722ce1bf94ac5b6c3bcb09919d3497999ecdde7de6fa76f3d00b301", + "privkey": "04dbf45e1b5620e3ca700a82e4e83a971551e25e15abfcf49c8a201a4174bb58" + }, + { + "msg": "2e18fcb984ba778c0017cdf882a862dfcadee1ba4c7ad44937006a7ee0ee90cb", + "sig": "3044022013ccb3f7845476ceea2b990d15ec53253f333ebc1cf392e96590d88aac70dff902202c4874427363f84ab7bf331d2a811d57399237d58fe0ceef34056f26bcd9de2501", + "privkey": "8bfb17789767931b9602e3a1310ae79ffbd5fe7fe1f2583099568a4308cb80c8" + }, + { + "msg": "d6fe1d5d5670b02f399ab0125c57fdaa181ae93aeea97c5ad238e0521dc10873", + "sig": "304402202d633a9bbdf3e486fbcd8dae7afb7b9604cf9a806d72121d08a95895d16db21202202f83e6d1c5d17d676885bc05660271770618acaccd35a30b1d3723176c1b395201", + "privkey": "e74ff299a3e399fc7833799b1591c128102d441361dc2ec77810d99abf280fae" + }, + { + "msg": "798a41c8bc899e458e9e07d3d83410752ea580020accae54a3ff65ebdf607f54", + "sig": "3045022100ac0d8bee62c3aa92ee6f29c98978a7e47d179f6954fb2b04b977489a2d24e7af022057808f4c12d8deb7737827a1543e88bbd44abbafb4d4db43e2b5a6566d0e821801", + "privkey": "cd4d9c04ec290aa6fe5cb0e34e3f585beaddcba4f39d883bcd0a7e989801a778" + }, + { + "msg": "1bafdf652c98542066d53aedf3b0fdd1d3517bc6fcb0155be621ed0032675a1a", + "sig": "304402204ffba8cc994840f5824b2217188bd0e671cc4b787ac33509c774a4075c62a989022041129edaee766692b1c8d9301974f6daeb7139d463bad561f650801f097b4b2601", + "privkey": "51385eadf7238fa581b13905b83ff1c59cb7923d2afdfe2b29396ec9da1f708e" + }, + { + "msg": "6fc96a01cf2e3ab6ab277cce670d446f0da3a25bc4344c02651cda1510bda8cc", + "sig": "30450221008bf5889acf97948be7bf6afd1da1504bab75d841c09e3e6cf1cc445da0ed5cd2022030cf8407f6aabdd056e1d4cc14b4a0e4ac09c6cb45f572788f5353fda223923701", + "privkey": "20dc42c28ec79d4b62d84e2be93945888178a0c29aa9b67cb1afa5e4ff4f1073" + }, + { + "msg": "524fc94cd49f7fb80b5d2a111d7fa9f9022b79f5368608dc5b50d1706e7e7fce", + "sig": "3045022100d391974a51503f4b8675328abdbeecc998b54bf6de23492f57631c15b8f7ef8a022075e1d215853ce491a0efb1b2ca60776142a26b1e8975158988569c2db2af87b601", + "privkey": "8cdfd627ab00b392e38c27ab8eaae73b202f306deea075815bec61a0d2cec7b2" + }, + { + "msg": "d2a53bebeaeb041272699990b027da459ca5badb811e4ad57b3445c56e5112d7", + "sig": "3045022100e2e221910d4ce1fbd7d489a4807a5d11e6fa45f35a997ea5583f8508a1faaf1102200d5fc4fa852eb1b26abfaf6799559a7165b4590707ac446019acf2d468712c1801", + "privkey": "021144fa085375c86c681cd021ad5ed3e7070503309745e97143194248dca839" + }, + { + "msg": "63446421e65a1fde302d32b962dcc75a2286b7c2f0491c25b3fb6f051b208dc4", + "sig": "304402200c792c52f28ffdcccda08d7875b3a62e665dbd65ffdd80b0767fefe7af88bcb102207780c849bbd193e805916fded694b89376136cc7b2b8567f52179fd10c64a48601", + "privkey": "dae1c4edd2a889f677615ba48e22e9144580360cb3c7094495579b3a4c17ee24" + }, + { + "msg": "53751b08cdfd84b6e7a72d9d32f8684efcec290ec4ff53e5d2b66d85fe1075e4", + "sig": "304402206fa2f2ec4f36d3b92f901d6d1935f6167752c13bce38fde71e1cccace629abe802201575d02c1f9599e19e72c1552a1e67c2b84d780bb663cfe26f0200f7857152ac01", + "privkey": "81560d6c8f7f56947e85c05a5bf58247972a91974dc886fda04557e42cf7aeb6" + }, + { + "msg": "a8f00b68747f932865b1e652495e2ee2b962d58ae65a803a83d5dd723b961195", + "sig": "30440220113a2d165fa751a5fbbd96032fe0ba55a9f7395c546c56460c74800206c7689d022037cf2dbd41bfca49004f603aa6476f9a2ead3c0e55f4fe437b4f968379b8951f01", + "privkey": "3648124d1c85eab5ab6a9e48377e1727d1da31b9dafe46844bdbda5381364b16" + }, + { + "msg": "c0c93d49025eba4dcc15427306e598ce42b2b301dfda34e8fc944a10cbdf827d", + "sig": "3045022100fc15d1c1a7ab3647c56aec5fa47f1d3d52d082fb797701e32278ecc0ae93dc3f022074bd65fb1164ce8f856dd8c0d5432bef396357302409ca101f02904b7b7fd44801", + "privkey": "5516f2b53a5e43cc284f074d8960a918e67afc6c0c6fb74246fefdf2ae55b0eb" + }, + { + "msg": "8cf263c83989fa23970f41b30fdaaf226792c0348d21da89d659bca19fd6d26c", + "sig": "3044022072a768ab0f2f878492d56153ee51b170deb652b6b2a8fe940ded965dd32e49180220300b9252ba85a611adb8827c315d47c2cc33627db9be8e283fdf09b527bd21f701", + "privkey": "467904e0c8850c5b84066e2c135096df2374e5a2066c0e94114b1d06eb98c454" + }, + { + "msg": "ab2e3da1e5a5f2acb51e00f7f8e6cda712882080f24bcd9ea43ca555577f3b30", + "sig": "3045022100b1e275667ba42709e6a6da1306df173728b032c42fe955e60721819d7ca77c2302201219d9db72e278fab11dbc80fd14191d2d37a13fb31338280cf2837d64e27b7c01", + "privkey": "6a7536d6733334e204ac5bfa2172c86f7446fd32cd7180027391087f98f18116" + }, + { + "msg": "6eba52cd7a8f859632b2b5e8a6ac69581ce266d82a6b010c7b666d3afd0e19df", + "sig": "3045022100fcaa0e84521f46c9a9dcff5da933c981fd2d0275c2cef76881243c6390077ba702207f7aefa9e2e9d2b27526a34c26bfa57b7cb2e22ddbd9ecd830e7cfaf81a7b10b01", + "privkey": "e814cd0bf690b780f8c615cc6f1202247b5218725e76eca315faf9b438c5e554" + }, + { + "msg": "85b07d8a8d4100a4302ca49cfde58266911ab1ad45368cf7451dbd9b6f45eb78", + "sig": "3045022100fe510f6954ac3f2fba233f109ec7a08dd93aa955336e47fe7b095f1d79cfe198022037925a771d139f2649a5665a3281b4a363ca96fef8843444f23f101400f247f001", + "privkey": "4f4587386955963eaaac84b32eefff63b32dfbb540bfb578ff7b0cf9f01298b1" + }, + { + "msg": "13063f26e50c5b6e62ea39fda446e3beaccf50ad07441241df62e3115f939552", + "sig": "3045022100d44570f08a9e64119d9885d73f688e51176807a4143856d06b684fff4a8ac2da02205f757d21c8c56258c63034d9b169c402889532493cab2c06c697154f44705a9a01", + "privkey": "b6b2e1edbcf892e41285f4ac942a331c4a88d785267c45c8095059c5914d3a98" + }, + { + "msg": "738516a95cdb7d1b374324ab22e642b3b23db43464d898e80789eccb25240e6d", + "sig": "30440220655630c6bef940bc7360febfc8e7a09614e871b7ad8c500ad658a6ba7f1669d502202ad85b78a32a10c28b2d581d7e364f6c2b7caacb24a61e31130f2fae5a951de701", + "privkey": "23bf641b12ea841b7a8386a2ff4f378c8d33218fd147906db34c64363f59c1ae" + }, + { + "msg": "2a7f44ec15c00e5c457c545a7bd27dcf38ad636cd98d48f0964496d3a01f781f", + "sig": "3044022059bfd164d817b91b94dba6c3843cc85d08442662a9f3736b12f294630f75578b022017f6dffcc2039291bcf0719281b2e599044a63709e94ab0050ebe37a2394933c01", + "privkey": "86b53e69d27fa695bf8217b0a78d72651584e24f1d85e928647310ecc04d33da" + }, + { + "msg": "865c6d42b0ca9767593c8736c8b5151753f9c0068c9c52eaaf4305a19e2ea559", + "sig": "304402202b995842e430ed36900761f11440116c4a0ca5c4702aecf293625e608011b3df0220051b45eacacb9448cadd96cf4daef05db8f41dddfcb1943cb8ed67ded4a8e9e901", + "privkey": "8ca07dc245d61105afc9b40e69bbd1532b65e72094f929c117c5a72b4b6ddd25" + }, + { + "msg": "5170ee5b8311f24570aa8a639e33c22c8f883e8d947548d47e1e330b965cc57d", + "sig": "3045022100d523659075fe10d9f6cc3e75cc74bf94ee65f4a099eabf7fe6dbe24bbc17f65c02204423cb40c94d732a8a51487b9e398fdca78005bdf1571b7126d67d9f50b712c901", + "privkey": "44e488036d994a53d6d62bd6e3201b7d61aac740157bc25ea41c7da37b5d6149" + }, + { + "msg": "29b9327f728c7107537475f99ac50f28e33ec0f68f4db619ff0f8e5b314935f5", + "sig": "3044022035bc811ac5054c04febe41208c422922750ac045acc1cacf2529666a7fb7e40d022071837d85c64cf07a1d598de345125306053c3c9014b408898dc5edd04dd919e401", + "privkey": "1dc87fae4276cdae8ffd67563e0f8539231582818b2e2226dbbe159c021e61a0" + }, + { + "msg": "99c751a334d1a3687432e87a34301beae87ec78aed2d48ce066f118b476a85b0", + "sig": "3045022100efcfddecdfbd8157fbe996563256efdc6f29955fab32edb3efed9cab08ef1dcb022067b01f720312ae64475eccb6381e1d3fa342cbcf2852b1ca6a53f5b1a6e16ff901", + "privkey": "6e9f1467ebbfa71faa565e02a8663fd138487dc9526e5d096cfbb2ad38883d22" + }, + { + "msg": "76bdddc10926a641df369a6179ad622c6188d3081a3cc90d8dec398c68ab7af6", + "sig": "304402204d275af1bcd7ad578aff98d8a1551a83584b8ee9b57ef6d425fd191426f6f63a02206cb25c37fff11029f8fa5c2b99d0aa5bbc5a5fc484c863a49ab4ab4479892b3201", + "privkey": "f64b62c51f2de8f4643857ba12f81a433764a3e0cd9fa2316b8e202cad9778bd" + }, + { + "msg": "f87a7e12df4d4a0ed99ec33e3ce805151526bdbced2bbcb0a012019a5cec7f99", + "sig": "3044022029fa907c4e4ba985b362c2e291291271c6acbbecaf4c49b938261ea6f255ddde02206cfc13e0dbc8d5ec4c98684fb36087738f9b449cb0bd9d930cda0025083543d201", + "privkey": "c21f2a248126a5b5d964d404911682ae1cbe7b7741681226867337dab8974fcb" + }, + { + "msg": "493f0c699d505325bfd1dd86e28d7bf94d698120dc10d475aa2547bfdcf5d66e", + "sig": "3045022100c716b0c65339df2357089c202f4644603c21d7139f2cd77336f871834c27150d02206ef0c8cad1605b3957a15695db5fada122b9a8b9b4c49743088e88f93112320101", + "privkey": "5a4b74a8e52b8f2dfd45c2ff015641be2b1f66fc285661de8fc65badbd6707f5" + }, + { + "msg": "82c5878eb438661cf7c50655890ed64c374611f3cef2e309a76565f745fc2c96", + "sig": "3044022030db6955679658577e9a7cac8f7081105a173647362178efa7c74bc813396b8102206836332abe41ab0e23e6f62b0aa08666dbe8228c5138638ed0c2351c22e6c57301", + "privkey": "aa6db6512e8b33be3543a46a908f26720402e3c15bd70ba8ebdfe7ab80787afc" + }, + { + "msg": "652c4068be47d9437d49d36173e095118367e1d9d0e86295604c0eb94484d5ea", + "sig": "3044022065c05eecb47346d6b45b588a90eb0f5489a23f93170557eb969f258adffabde902202682a1ab6397c49892e349ba581fd623033a35910c97f4079e4c2e505dfdb21f01", + "privkey": "ef0d812b85eec684b3314de835f73fc06c3c90078d404862133643c3347ebe15" + }, + { + "msg": "a04a3ee113f5d3054fd1eaacf8f3b1db506122c413ab346250e08ef6b5be8236", + "sig": "3045022100ff6927f3d0c14cfff2ac2c8b47b20ac99baa48ac72726aca35e87af7965725730220654333918dc7615a2e1f5b59af74a1565c281db62201c54befc6158222f8284f01", + "privkey": "b85e9ba6297a46fa4f017742485616c61ce5dbf080782ba1dd961933b7390e18" + }, + { + "msg": "428f1dde2440673a19d0b97fe46ece447721e61a700376cc56263e63cac5a3da", + "sig": "3044022070ebbfb49ab2d2529546115e55f8aabb7784bd38fa16eb6a5cc6ac7ccce2fce202206d9afb41c0254c2aa1ba4fe3a05be5d5c1297803adb701197c918609184c2cda01", + "privkey": "c17b6ff03bc75792c3a3b4ed5612140e2f9d9e5d6b21650701523665b3819b05" + }, + { + "msg": "ca0d05a273ef3b2782059307d838599eb027b0962798d71efc00648a5b07b744", + "sig": "30450221009c88cd669ab7743fc2f3ccde723fa8ef653f951f67abad5afe8031c6fa3652c4022012cf4d5d66bc0e9d40322489ceedce43bcad5fb41cbf92a6ea0f387c4b3b214f01", + "privkey": "c658044aab784be15a5776d2c4346e1099368a45f06853277352d70823ea7572" + }, + { + "msg": "f6f4aa6943deafc1879c00589208656e927422b5f25cc9526a9fa6139c66613c", + "sig": "304402205325ccf115446eef902499ead3734d02065dfd337d924ca615f5d00b1580ef8b02205285496cb0cb63e8ccebf4ff999c922bc3bb5d4a4eb3267fa2c5608e6d0b5b1301", + "privkey": "480989d814f56895a0c5781497adb1ab82744c009815f00362321dcdb709f036" + }, + { + "msg": "f5747a05e3488bd03da4210f9233131e1983f9e969d23330b3858a6c71f5c484", + "sig": "30450221009e81de985b1bad7843c72cfb6ee2a30295f13ffb7e1c3b10ddd505cd5d6feb6d02203389442e24b7027466eeebf44a9390ff8f9832716544a4f508574fa919b4848701", + "privkey": "db1e27ec5686db0d8a2b7c609847652067534751944f610bc7ba9f3792e92fda" + }, + { + "msg": "ee0a83c20ff143b6629bd9599b5beb2e63384be72a53221c3263bb83efde8647", + "sig": "3044022063f2d7f32985641841f7c218e7a90add74b82e76004eb349d9e122162a574d7c022070e4793900af91b659030179ef46db54f478d74a31b31dd527af0952c49d461f01", + "privkey": "88624e28090c22fa80888c3f15000bd52da334c7b295587773a172aa95bffe2c" + }, + { + "msg": "80aaab2aba272c8ccb67022ae9a54bbfaf8443bb37d2f922021a681bc4252a90", + "sig": "304402204457849658bacecab40c4893021d2e567fc86f1c2ed2b20d9f1982138f7f00450220225b04c91531470606088263b28b3df2cccc5a9f1df36130d8960343ed89e13c01", + "privkey": "ac461d001fce26e7f75fd82fb910e839d6e92bca1db3969fd78e74674d3a6bff" + }, + { + "msg": "285b0f5cc3c35deb52d5e1f5fe6e7c5a82a0c3ae10249c39c4b81307bbc9a1df", + "sig": "304402205eed90c7c43c9dced57edcce95ae69e5babadaff58f033055d998e4df596121702201e47072efa39405f2920b240b56d3ee41c0b1c2adbef1f161c8da1e7eda6fbde01", + "privkey": "786f5c06867cc7e8a6b16c003ad6809da46851a8e3024527e93af60b1ff70a07" + }, + { + "msg": "d615006da4b6aeb980bc12f769e263821890003123b1d2439c69da2cecbe51bc", + "sig": "3045022100e13137464625b65c0403b71a3ff57b42da0f5d35be2384da2a4f52e93d8039b302207ae93812fb1aeffaf60c39b0096b39f2fd73bf2e695be8bddea458a2bd55b89101", + "privkey": "226140d24cc86b64a1c2aadc77bc8b05552386da2d707668b3c460f69d70108b" + }, + { + "msg": "0c26d76afb90e2fe6a8c4b2a9d2496e2a6e27f25380885f7985d8c1ab7d2dda6", + "sig": "304402207dfd5a172204356d4dbffe018b04cd6c123a48daf9b9fc201cf7e32088989b11022030217c1dce7e1d039ac011138569c4c897fd201694b10052a1f3ecb2aade3a7901", + "privkey": "1e807394e21a0412d2d48711c0be3685a49fa3810ff84517b5adb1189ebc452e" + }, + { + "msg": "ae93855f5897620269b0fbb6f2444fabf304c570c2bc3d1342aa3b0615ad5b70", + "sig": "3045022100bd83f85e36346c428909a60eddd7b1c52abfaf662cab6fc810e0fc398371f83d02207caafa58dceabf7176c2e3b8a8890e47b9c1cddd1cf000ba428a91c396932c7301", + "privkey": "c8d382437c63d3debc2844e00c7eea0e0f400b111e805ba32695de93fc150a65" + }, + { + "msg": "b9df3eba9ad579c1840fab29448186122ae27c9add5b5fd6c8a2c7556e0fda8c", + "sig": "30450221008bded4f87ee25852e45908397876b3601c6a0e177dc986bc43f52c5e25fe5d9a02205473929f0502abfc9ae0da25086b13d92e0ee4f1e1c9fcaf334fb4623048dbe101", + "privkey": "54a92b44ea83313d0779475a1e664ad132abc53dfd8e4742ef81d01b3ef657e5" + }, + { + "msg": "f304cff5f74fc72bddb353ecb5d1a250848ca764ace690cc308d00b247577226", + "sig": "3045022100c1f9fc9a63f0d26677bfd68687dd0e56a6342bc536a71c9b1f3a2bbd2a48360e022040a3f3179228bb89b82ebb648073e713cb759c1cb7d4e4f5486c29945d5c55e501", + "privkey": "b59821f0dba07cf87f0bcfb4310c6ab4e676ca319fc6c0d9d11ae80be8a0468b" + }, + { + "msg": "77ba3ec6b8fa5c2b8f6e4bfab18b2b51ecc94586a41a1dd80290665913412266", + "sig": "304402205d9fb1e3c6ea1b18849cbb2666ba5d5c67bffa78d6952e7b0f009226db6eac85022043cecaab697ed0684d53b497ac61ae614477ccc153c87f938e5a3302bb70d59f01", + "privkey": "a62d04ca999d3b5311f317edec9418fbb065805872b25dcf69c088ad7d3b9d11" + }, + { + "msg": "63c7a73d7d35dd73b94d23b446bde100dc15e3544222b9c7e6c9d0be84b1f5d6", + "sig": "30450221008043f2ee24182f28ecfc6c53cc3a51ae6da4ab902ca4dbcbcc629f3480b9a97c022052e44edd783f81cae9bcbf4e7185da17a82c09894bc44b0405392aa00000f85901", + "privkey": "57b66d323c278d6aa3799db509d1909da6d7f69385b2627f8785712777f8236d" + }, + { + "msg": "2ce5f3aff72b0867bc0b7c286dd49f011f65eb563a93cafef5d554ef3d9c1488", + "sig": "304402206b1cacf8fcc9e813f421f88ec8541c04de7f00430e1332829ded5ff73f218835022055b9da3bc1de4ed413f35765529c1df9d5b9b8e8ba1fbc7507c6e8fd747b191601", + "privkey": "81db6a86b8e6d840a97da1969d5ccb9b9eb4f9d36f6e59df65bcd42b9f3ef12b" + }, + { + "msg": "475ab4796a2038629a3b9f43a14d5a2c86467bc1e32ba654e87ba67ff99d2890", + "sig": "304402207d3375beafa30381e9ec3b32b0ab819d67c7f63c61df796993085ed9f61a1a100220050e89b744e94e4d7301701d602886a39e0529740c24f6a0f8bed0d91cc01ed501", + "privkey": "8b51025a732cd22a179591598414b66bc370295c1d35284f706d468de4684dda" + }, + { + "msg": "af1a72105095a243242132ad24085c444fc78bce26de4421467266d248536b87", + "sig": "3044022025accec34080896b7ef072474e0096fc58ae84bd73f045027007925dbb7fb5e002205602c0a5cce0b4d9e10a3009f9dca9d2599b694b6ef0e7c4360b08d35fbd607001", + "privkey": "5f0cc5d1b7996f0187a0e1c709981dc6dc944e92f908367eebd82f1babd2ea63" + }, + { + "msg": "029b0efbdf0374c6a23593cd7c6917a9404b9fa43ed32428a82be05bc7f2fc3a", + "sig": "304402205fee5f55838ab4f7f7551b64ed346565f64dd5b42e2694d7c372233db2fae37d0220026e8f5d54af25529d7ca1a4991a1385e7ea3ea9fb37db826d81aa32b0aeadbd01", + "privkey": "b7906b63b11eeeb3f69586b7a8323aab9f4dd51c157f813d24f8e34407eb5c18" + }, + { + "msg": "9db7ee956f52eba9fbfabcf840d9c107117a00f5e2874eeb54a91025951d2ea9", + "sig": "304402201fed017ec208e65cca442552269487cd15961c2603f6aa19fd035491cd4fa09602200d0c5c9ac89dd501c34f3b7403a82832f58153bb77d070c44fd8f9396dd0c2b401", + "privkey": "3e89238cb4a7de25f833f4b3cd3374cd5687d9cbb858de906a570818e14031db" + }, + { + "msg": "b502771c17443b8835fd6582fb2b44512b66f9bbe92dbed5e710b76fe35bcc56", + "sig": "3045022100a424be7d1cad14f52a4bc99736635e3130dceff4f9321dc3eec31915a99d365202202c573a3a8d2d24a79ae70ea15e32e0a79819406edcf54bcbae4d49ff87512c8001", + "privkey": "6a4aa42e630ede3342539fae35f43c6fa02c94c634753adcc2130de76e62dafe" + }, + { + "msg": "5c66cbe4059db5bc8046fc393266d2db410a81ec2a02ecae0368aa0eb35d68c6", + "sig": "304302204203bed95a0e92b6a4b6776551e01473b891487b051824cf707ca553b40972c7021f64f496fab45d743ffa95a520a7a6f5e98c49379e69f0b8a7dbeb98b576215001", + "privkey": "d7e3eb80f852de183837573ad3aef624e16e8302f7d0d4b4d5ff4abf9063e438" + }, + { + "msg": "12e16733960b2c7d5de1f06b824094bd116ee9ed83b680233298be7cead86741", + "sig": "304502210091d303cb2e80690531645c79743cdb29906fe6119023844b8c66c81d39c9e299022021e6614ab44c6da7bba1d7de4b37871cfaea7a76df43bb5b90ffc6f61fa7e86f01", + "privkey": "0686905b967248099704688e15d8e3eeeeb58ff24a06e8c7a0e17b534a4714f9" + }, + { + "msg": "2309bde84fa5fd4ed530fa7ba01af3dbb71e7967df1792a53b13bfa8225dca77", + "sig": "3045022100e8f17e0c541518d5eaa7ddfe24d7caec497783da37b7605522039024bcb835a2022075d5ef13cef091ebb861006299cac29fa762c2d635b3be798649633e4d8e0cf301", + "privkey": "4ded96d9315bf52be4ef30a2295d76a3c6a997a331555bebb5012491b6d315a5" + }, + { + "msg": "1453bb7e9be2757cfac795c751dcac6ea24a1a597d8ec4b5c0131142a985e17e", + "sig": "304402201a686a1eca60be4ec2d95f22765af2afe91a6493ae70dee9ec0ab8915792c02a022071aa6f6f48f2c04e1a56e116eca35cb36866595561cd10e75bfdaf7f08f2af2e01", + "privkey": "6d9ed1aae9dc352667d4feb5e3f41f51da9ef9eb56a58b2497d502779680ac4a" + }, + { + "msg": "863f7f5d7f0619816d65ef3eac2121c9d3b3a6980b044074652f99c70abf539d", + "sig": "304402200fcb08df78fd9aa098d627f6683faaf6535cb4452ac075a228ee72a3e5cdb16b02206936c264990abb530ab705249e564bb4bfa7227edbb71c5686387f7d82ec251501", + "privkey": "34f87676d627e5ce30cec37ca8b7add7b30e82f3e510b8ebac31fcedcabdb22a" + }, + { + "msg": "9d3469873f54a1c26498eaffa9fc7c49644664cc4b25297fefc1b1b8429f6674", + "sig": "304402206735289ce27cf7e55251526382a07eb9e4a132971834082002d4464faf012c1602204a6c9b451f9ad560bd5c10561a551f33b712d553dd209b5e9f12fec46c2ef9f201", + "privkey": "8b4bf88a79deedef116259d5dcc331e4e566c04f1581c2ce0d02e6e2f15b1ce0" + }, + { + "msg": "f479dd8ca6bef32889a4a0159462eb2b56e387b6ad15f8ae0b09e1f489d49cb3", + "sig": "3044022046df345f1bacaee73ab2157bcbe6e1b333d2abbe5cce53fb5a50f81c952caead022071ef3cab8a146da86366c1f79ccc7edc76bc630ab0e30956305ae041b908be7701", + "privkey": "d3259f9685535af057328f4b4aba66311fa654da96b01a4161749f12d27fdf60" + }, + { + "msg": "9b4ecdd6c6fd1a43ba3cdbf534a8eb0159d0216ccbff47c3e41665776f00aeba", + "sig": "3045022100e7f0b77b9f767b6cfcf33ecf00a5dde22fc7fb46f87a3289f09501dfd889a0360220645639cfb7bcf062d3bc62a81c27c79d6909758f2ee37b08032b2351988a7b5601", + "privkey": "3a6f3397de4bedee3cce0568298f039d97ef8f4ea1d3d136e6c857cc3cf477a4" + }, + { + "msg": "bc64a2216423e642a30a0f1d790f3cec68b71f06618494723541d3c778237c5e", + "sig": "3045022100f85ea06b50d834109e5a0cb1e4f506e86cddb875867a9c3b28b48b1ae086589c02206e875f5abce1a66c30cb082243dbd9ceca233ccfc758cf91bd16cbf08648f98501", + "privkey": "3783268c39a70a6ba824e2adbaa07cb11f94b39b63cc3e8d53cf3603042c5fd3" + }, + { + "msg": "3962c385ea39d4df584dc1d9b93c1424bce2bef2aebff1a26dc7ed181e57ca50", + "sig": "3044022043d17ebe7a376f79dd2ecd1b745548d9633e5c7871dd521f922af941c7ad47cb02203190a04501956eb66840ff7f7af13fb492e51b59ac981a6ae9e43fb06552365401", + "privkey": "c26e9a48223b3a3966495620a14db81803ffb6f3b3a69932b72b65f52b46ca80" + }, + { + "msg": "f87d0fe24e507120efd2d10aeed2905131d296d50e688684d1bb847e68c02bef", + "sig": "3045022100fe995bc6c1bc4e6f60fd8054baa3685cb09344fb83b18496f0a74da81a4ca46d02203ae1bed24bee86d68bad7501091593c5db3442b6f21fe02445ff14a0574d98af01", + "privkey": "53dc1c26dcbcd6220e7329e5d12fcf17d838b9f8936333b03d0abed3cfd3ac2d" + }, + { + "msg": "62d97d2a26ab35d9e2d18e4335f7e45665a712eb65a1b2da9c2824339c4f9780", + "sig": "3045022100e8542c42cb929f670c2c7e5faf2b46ff9a02852704e91e1a79097610476ed4f302206d9aa52a7b886fb4062a87ffb587e54c0c2a5a7ed1c12dcf112123e1b827b51401", + "privkey": "6742a01cbff6a2e83a4f68a338c6f0c0995f6cac6e842c6f06de8337fc679f19" + }, + { + "msg": "364f0f3c7f17aab5567cb6ab0d9a364a59ad8ff294a006eb89193396618ff58e", + "sig": "3045022100ec728047c10274e6c1f3ee2404a9bfb5d58beebed4ed7d0c80901926a2c5caa4022027f1905073e6730963b440c22e150504b47ae4b02b10dde1aa2177a169a80c9a01", + "privkey": "f2415dd427697296d40dfc72084df1249b04d33cedbc880df1d9a6c88917dd9d" + }, + { + "msg": "d0080a4d6d945980321e346feefa6d8056cde94b974210dc2064837d8f47ebaf", + "sig": "3045022100a81edb49b4d7544d27a5cd7e112b4caf58898cb83d76740934c151e79566f97802200156257235e64803ad6b15ee58d0eb7a103fbe1f6ea024fc25420db1d4b22b5b01", + "privkey": "a7ba1b4480cf766d833940311d8a8c59a22d761858443412a94aa3407e330c16" + }, + { + "msg": "f09feb58a0f48e1678434d3995d12185a9d340baf3d19902a4680a532456cd20", + "sig": "3045022100df54f5a3f4791b77107c11ac15b0ed7ac59cdc8a46234031f16317d1dfba946402203d768943db33aa775d86000428699ac45e683d9d0b4b5ecd47b99ec7c548709601", + "privkey": "ecc32707de9576a9e91fa013190253e12ef780a5d30a0b0806da2ac05678eb6e" + }, + { + "msg": "2e8e25a6cf4c689b3560007bbe26a3df37dbf0eb5562c68b8efcb42fd5760f1b", + "sig": "304402206d2f9b5b37afa234eabc8e9905f7094c56cb936b038abce5166a0e35b82ff9ad02206e0060d1b784e880f517a5d8607c77a82e93d6dab3c3b0ceffbd9e632ed3c78d01", + "privkey": "bd42ee836125cdb5cc41ef767933be53fd374924441c4ef829b18c88ae1340f8" + }, + { + "msg": "5d659bd8337e119afa182ead19ef91f5d2f4dc6f5849e8fc56b4e6045204679a", + "sig": "304402203ebb171ab9732a29344b2c5474f46068a7466c6db0694ce2935bb85f5a6cb57602201b80113965c0670f3b0065b0c3a527b89a4c328865362767d8fdd6d5c97258a201", + "privkey": "17324fd463b6990e89218846d24f13813e415ac8c29faa2c6e7b2a6169e32e8c" + }, + { + "msg": "1cb65e2253db80412c92e092db5864c2074fae2e0800ee213b4ee82d69d639d4", + "sig": "304402205c216ab6a7cb4bb9d33360999d2e00ac6b7c6e956150db10865ba8fcb87cda90022064fceefaee8c40a8f5ed8cee478d45d0e5da1aa15d29e103d1cfda7748f8160101", + "privkey": "5edd47eb6580ae11bf3a148e01ed28a94d6a7912621707408da31ce4c541f46c" + }, + { + "msg": "5ad8d22c2e648851a09d74f1f47d2f116b51e4cb662a7f6b217f609f6d578901", + "sig": "304402203c151a74e81770d564b18efbb895f0df2f4d225d8e215e671b5fa44b43b098f70220540f560d75456eef77ba2e52848326624ec76ae7edff7b2199b822d78e62a0b601", + "privkey": "0a2804f109b57c7768f1d034112ecf46c705c6bf01b68c24220ff80e332e1023" + }, + { + "msg": "53c82bb675afbb5f6ceea4f6b3bdb777cca87f9f27fca9c688432b69b80a8d9a", + "sig": "3045022100f49e0096e15d8d2183240fc3013fb71696aed95977d9788e1f6b99394006f0b502203d01efe4296b409db81a4e6cd601a7440859249339ca7c3a62188537802b488201", + "privkey": "9d0b7120991d0910765b1dd563a787ab9ed51afdab8fb6c214fa3c6d6e32a08f" + }, + { + "msg": "51ba637c78e753468782866a8eac39fed07f10e2e38946ae0ce7a9a087aeabc4", + "sig": "304402202067df8cec2b427a98fb7e0ec60715a4512102b74b651c9600a5b4883a0e5a2e02200daf8fb6d240f12f6a7afb2e9cb138160e16009498e49c8fc8f7f198dd1eda5001", + "privkey": "a73b76b643651ce1211f0f98ab19050a3aed4774f9ca2521249581c3b505817c" + }, + { + "msg": "5aa29ded6e2f76817a66fd97d28838a35b61bcb4f04bd7c9418f99786d9b67ff", + "sig": "304402205c5b3b02b9e0d50e2c5abe23cb046dcbb541b37f90c06bdad2d8a25bb91eaf050220346cf30343afa33695e160d2e8a66fa98fb2f8eaec1816178caadc223f93720701", + "privkey": "c9b796aa7aaebafcf3e7a2ab52b2dcc59acb926ded580c85ac95fb7333922c71" + }, + { + "msg": "e79b7d427349690bd001f4bf0a3fcb61a9a62f710dd7b84fa04a9ac8621dae22", + "sig": "304502210081a3126be36cef173363ac2b3d157e6b12ae905ebe0cc76bedece1f4451f2fed022046896d45d55e8698f6b628e930b09e230a778075e1c2ca5e1c61e75347eedc1e01", + "privkey": "a79e2a1d32fdec5d2425af329680cc7e466f37b559fe54a9414f383e0c02ce3e" + }, + { + "msg": "116eb6113b0e918e4590d9c0b6e335da67ca3c4e9ff65abf11655a8eea47e4f0", + "sig": "304502210094626b44fd9475c5f1300bdb3f66227371b42bf169ba0d75a9c5babd37ffc946022052b21f0bd6053814b76532320360c4ad93c0b856f4c80f43a4ff7757b3870a1f01", + "privkey": "326117f45d2e6e19c287813c7ad10e40be40d543951c9e81ce2547cb887e1308" + }, + { + "msg": "1c354d127988b843c7e73cc55767272a6ef7290b13ae90651202ce51653a9aa3", + "sig": "304402202fc5e5f3ad67a0b9515b0afe1f8e76b829ec604f112045cb34ccda7876f9f1110220090627218a60f449af87bc4703d8bdf226e502775d17fcc05ca86bbf125650c901", + "privkey": "7bb2bb79141834fc87df40d66db087c943613dba9ae64f44a7b6a78f4116df72" + }, + { + "msg": "f30ebdd3c9d82677fa3a1666c091d9edfb9a73bc44ad4e9addd8de7fe9216459", + "sig": "30450221009f649d2f5269d5bcc3636c5f7115952b93babbbcd679a746b7fc62d5b7645e9f02200e6fb9d63f00275f9fcfc91441e0110482a6931ae683d5b92cce9663a50b0d0801", + "privkey": "39884d1f793eb949ce5bb07dd1b045e5024904eca7845f2e2a682b3bd716f1a2" + }, + { + "msg": "a1c2b956c8d16378f8b37ba5a6507a39b2019f4920cea9e0fd8954535017d929", + "sig": "3045022100bd7cfc17f329f5248a3e90884ff27f6e43989b6955f0235027d633c80d414cba02205f465341ce8cdac4b3dbd3aed639816a883b3e10ec0c42dd00dc8151a8afe6b401", + "privkey": "7a214c6fe5a723dfa73db996d223a67e58f83f3b835bd054798f993146d962c1" + }, + { + "msg": "2a0425e8362bde896e2ea09a1228359e62911e8f9710e80918f26a74f0952cf0", + "sig": "3045022100c1f17cbe35264ec7643ecb9e9d9eb96251ff7fc627d288c5b9987a0907de33f1022005484896418729326860e8abeacfc7ac511f163e766510ae8f17df56f188558f01", + "privkey": "529e409a353f09bfec047cad40cc74c8990680498f30269b2869b1804b47410c" + }, + { + "msg": "dfe1ae0090ae3a721a001dbd9b3e33ceb4028c887b74b2b9557609229184a8c4", + "sig": "3044022002bebdab55b43bbeefc4c92fbcb0c8ec6462a63f80cf6b5b5876e2e8ece24a2f022006e667ab416bfa3c9052565a5199f16f4c68e9aaac3e5b20d52ae1286e8eaf9c01", + "privkey": "d2fc0076b87e6aee2852492a7092a49f80dd7a4fba43b1119ca23a0d5833f870" + }, + { + "msg": "a0fd53dafe53e8362b26116ec475e58da990cf7cf68c81c5bb643dd98e3952fb", + "sig": "304402205419be40e45705c8ede1de4aa194bea70c5aec160aa3ff0b7b897135097437da022076729f0571e5ab1c2a76d0f768103be8fe8170863f7501ead08d50fc5037b26b01", + "privkey": "68260c731196804f1f6a5325c0ea3fa6d8fb1b9964db1ea41f3add37dc65d31f" + }, + { + "msg": "4d23d02f8c91ec285631c4084bb6dfff6d8a96bfaf78ec3fe5f48ef25b4e911e", + "sig": "304402201ad146e7601eae64f06689dc5bebe1e5fa8f4dc0aaa1dda72659153b1db8ff4102204b5b3f639231a567c5c839f6c804febf9558403f553b6d1acdbb602aa790a0e701", + "privkey": "f48fca4688a9d6f522f345cfda72b847191b77ec891d39f54c422c0b0a4ad528" + }, + { + "msg": "88155ae33b918ecf6bafc7f24fe75b9de573e0f7217fda91fd2ca6b33c51ba0b", + "sig": "304402206af1fadaddf318e5cc6ea0d630c966a9aa6fdcfa1c51188dd18a30a5ce9292d702207b53272a1a29f92d9cc335005a9777a6352de56541694b42c3610f8287f3688e01", + "privkey": "31b614dbfa8820d15fa932946142ccf1e1f12c9dd57a6a7547e4fd80c5e418c5" + }, + { + "msg": "4dd10d1a99d91fa5677cff8285b8f1bc8c3e3addf2c45c4d7d5b3c7ed75f6970", + "sig": "30450221008f930b4e25f295f3c5a5e87fc0ec52bb915b96dacf2130be56540a6683d7a17802207b9f7eb912a8eca3990a6e192f01c072287f63202fbfcae20688117d30cc1a8f01", + "privkey": "db8b58e63fffcac3fc0b3d475059738d4c4f549ff3f0944bb9695353efb799a1" + }, + { + "msg": "925a060c837b7732e411d6dd6323c09f8cb8b2245b7855a51ec095f17828b953", + "sig": "3045022100e687b57e41c22c2f78aa75f000410bfddc852469e32352ce5e759a81c14ebe1702204ec924703af322348b6f06fd62567e689258988fe9928ab8987bbf25ca8a164301", + "privkey": "08c1df65ddd6405219f2f20c905693477db910566cbefc1fa3a53593c14d1157" + }, + { + "msg": "16ba4a02006bd0764558a71601542408b5dce7839ed91fdd3c229d37afd5cb66", + "sig": "3045022100eeec3696d777d1d4cc658ef6236356e32a92cee32670dc566e5ee28df32fe6f80220558c75df7de5286d89f7cdc7de3e1cb8d45aa73f34a05dad48e1079685813f2001", + "privkey": "c82829e681cc6cb6f124b4e1a0ea68d9aa063cf64be68fc95f6ccd095d97cf90" + }, + { + "msg": "977394a3cdb1151a226393902e9d4003b63678bbb4f67d784e45cbff6831a611", + "sig": "3045022100d3023f62a83b3d7a252fc7ddeb3072f1dd9c25b0c604f1c68959f22b9266186f02207e4d9f9ab40bd5fde9e55b42b05324d54bfd307a1b5c32a35ae2ce26ca8f1ce401", + "privkey": "1aabaf1d2953ff2b5f3f5ce80d5ab318bc31cad97eeb0fbf0f126b21b720c4ec" + }, + { + "msg": "0c9ebc4b38648729b33d86a001308c099b020e2cd2c989b82e9316b3687bc7fd", + "sig": "304402203aad8e8efb5721c59456d5121512db983672342dd2945f5666389f4fcef37d61022005b9a0d5ffd84e309ac186e91ceab6c5ffdb10afbde94f2c7fa904a1c241204901", + "privkey": "60f77c61b9fc3e3fdfbafb33a97d5da172c7223db73a22e8c19d8aee8e6bf8dd" + }, + { + "msg": "e672cf35e5b186843607321255beb9a626e9b16582ffe6cba68251cfa2d26edd", + "sig": "304402207a84304fa4d6521840d6e1b9582602a12574c1dba1f7088221748d08839e6101022076773ff0fb876865a3318f939e0f07721034e6886f6a9afe9546543df238e59401", + "privkey": "64e7e1a9a9e7b80cb5dae781b9d4060ac5129a2bb254076bc1bf1b3b5d0b6068" + }, + { + "msg": "7972a81012267be81555aac3644b4d6aac91061717ed33552b3cbbb5825151e4", + "sig": "3045022100f67a1f761743f7abf3ba3e0f0097e93579fc45cdba95476e5f5b9d8155ebc11402202984c12e518f5a6b3c59e248bf2660f9b4313f6030cf0b10a5bde3125aca1aad01", + "privkey": "af681d1431a137ca2ccfd9456123af2a50901826985d1b4d46ac33fe7439a0d6" + }, + { + "msg": "2884813390313e6832156ad2b86050d04dbfc3a810c1adb38a4ccfc3031db3e9", + "sig": "30450221009fc5d7058df747afb88e47dd18a9d8d73949b1af1ac4a7f4324b7e6d5ff499b602206e353305f58dfb727062bafd7dfe797c9f3071230f3780f5875d331bd99fbe5301", + "privkey": "c6904733a3f4a8786d04eb725ac9d7814ec66c667ee7f56d7e9c1d39c7a06d0a" + }, + { + "msg": "17dd2ab0e67376ec6dcfccaed832a5a154710034818a78498b2987a9453d61a5", + "sig": "3045022100d2c15d6611c1bde642076edf2b89fa2e1062c99c866935d4b7eca979a0ea63a10220624da519888c2316c265b554281b327d471eb98cf8c3fb72a7c7dbee22553edc01", + "privkey": "493a3a53de5389e4c75092732be209d2716b93795add2210f6a1460c92fe238f" + }, + { + "msg": "bf0bfaa0d35c77239d0c98b900c5dc4efdca9a83eaa0c1fc4c7a8d50c5136384", + "sig": "3044022032f05dc70f0b08a5b586732f377928ae5edaddf7d58d3cabf0e262d768db47cf02206faf588d1682554be1773f11fc52b0101aaad3acdedddce71ceb2cd4d0ed46f801", + "privkey": "649306bf872e1626d8531d655a38e4ed7c455af514dc9a90dd1bc434223a2e70" + }, + { + "msg": "eb73158bcf51a0d754baaf7e68c20c385185644acb701cf9d54fd41487f83709", + "sig": "3045022100beec086b0341c966e02014c7576b7d0d0ae007489bdece567fa64de4b810a09902203cbc3e4f414f766c4653c53f52272ab2b87c88d49d8be05bd2810bf67f4a9f0f01", + "privkey": "0548d0c8d32215ac696d32ae2f28c785d86d68433345fd83e6101b7bdbcd7199" + }, + { + "msg": "8558f4a0e8714bb6fe788d0a0c1e4bf5622eee75a163118dd312dd0bf12bc971", + "sig": "304502210093fb277d192b50368665826384f3f537917b4ab9122e3826c9039e45871fab380220745c193fa30a2a582be64072a71f8476e1ec8ee374424689f0656b24fb1c002d01", + "privkey": "303b41d5ba88eab108428fcdacb335ea96929989372069ae4cd27e692ffb3955" + }, + { + "msg": "727402055ed837f5eaf1329ac81082929aee22abe2246c6dcb483ee8c31b580a", + "sig": "30440220181a4a02b57b3223808dbde211d2cbb502f9d66c31975ae9f94cea26dddd5e0602204e6eaa65344ea524c207429647a27fefb4eb967c403c080e46877f61d22eb4fc01", + "privkey": "982e3cae8f991b965b44541243e2e9de3122c8faf05718ea7fa5ef00b4098220" + }, + { + "msg": "29a4c44b4d8a4d920fec9368f0dfbde2d245eeab89016af90e7019ef6e020f91", + "sig": "3044022038abb43bc0a1f4bda4d0dcd9e13d983a24e8c4b299dca06d61459fc56edb39fb02207fd3e3e37fa318907ee41222ec7cd4ce085b35c64dec1d8c6b61424306db50e601", + "privkey": "fc85d8dd8c854dbf7ec922c6124c654aebb61263b0572ff922beb523a743654f" + }, + { + "msg": "6f15ebe59374436bd4d6b1ddc7a2a016679ad682f077a8a096db0ac0f159229e", + "sig": "3045022100aa23abb03621b4834084e2372c8aa571b125a4e897d7a8b3690890e7cae22f08022021a5534de67162c0e02f946f49f72ea1cabc753395b80cbbfec117c2b253cc0f01", + "privkey": "c5fbec66e7c8b8d37e3dc65aec3ce66321983e87a7f48022e6d67f23f133fd2b" + }, + { + "msg": "08854040e59a06d8fa647274c751e69980a53045c7e10dac29e6c1f2293f8096", + "sig": "3045022100fafb9d2b34ae5a6efba997e865c34ac02402bdd1eacd4e51859e35ed16f73832022044bf0182a26d15905c672bae0dfb1ddd21264795947b591507f786541faba37301", + "privkey": "86410a06d6053dd75d05ab51e3a08608018bb7d70c14199ecbf0167cf459a3cc" + }, + { + "msg": "66d7220679b951b05ceee33cafa9490de8669514790200a5f86409722ffd5a23", + "sig": "3045022100cfad593cc4e424ccc6b7dcc8d576eb34d837ff3862ced984e61b3c0031ea11b4022034dc395f1c4cf1d84f074f45e4583ad15b94ebd74366f138d6b3228ac1cc1a2901", + "privkey": "148d9ae3cd5de9347b0ef76dd49022c416e05cab1d3e9f91de0bffabd9728aa3" + }, + { + "msg": "16d5f60b487f97c54ca4931e1804ff5e7f31b1a7546b90a515780b6aae66c67b", + "sig": "304402202eaa80e56f1fb665cb995bf12e4ad161e275c59a13930a78a1c8b990b2b40711022070603f86e4dbc0b89bfe02aa941bc901a2de2d880253f641c83c0fd6e59988ea01", + "privkey": "00b1ecd81941a3fbafe4420b9e96c36f40cb5067ccd0c128dcb40c4f9d508e68" + }, + { + "msg": "efe532630bef5f6404ab56e4329a08800c5f2ee06743b58c5c69bf47e78b27a5", + "sig": "30450221008807c44f387e9db50eea548928c1129308cf501f3bbe3fc1a4cabc400e57ab64022062d127baac5aa2d1fe08404b7ce8984a8fe1bdef50efd41eac5ee28b3d0e5ff301", + "privkey": "fb2ea5631dbc89764f2f592de36f1e087a313461f44c70fb231b0ef7928143c1" + }, + { + "msg": "02ceba7e7cfa451c9af56995c36f77252b3ec4a653bbc41ac94ea2751e8e7a07", + "sig": "304402200b028943013a0fdd47eba1117b89bc838a269ab923ffb3adfb125fdf971c7737022050f416497dc081b223c50349fea72a4cfec33c588474ea6dc9d7823076de856901", + "privkey": "35ce2144bc6e3fd449cc57516f2e0f63a9878a592ed1b6cce21c3de85d98d3af" + }, + { + "msg": "038decd7e8ecf898206c4af77fc8a6342d5b543a60f121685715319a6de3d947", + "sig": "304402201046959b39f101a68880dcd8958cd2908d228bc115988691d1cbc3f7bf5090a702202c2a82c6504ac301223d33608f7e9314825355b4e0907e6d7a965d8a90b14f5c01", + "privkey": "d71f018138fa752798132a8393f81f32c474bd60cecda2aa1baeb5a4b00e86e4" + }, + { + "msg": "517398a39596dea9899429688afe62c49ff2265f177b32ea452fab47ac57928e", + "sig": "3044022041c9adb3aa577da5f6a4ec2237bc7ade73b0f1db122a4ed3152fd53723067dd10220774bf2d35837da21ad6073330449ef969b3f28d1cf3ed8e35664e75d0257855b01", + "privkey": "533b93438ceccd4d12401e86b6810200211dcdeefec130410fd978814a8e76ac" + }, + { + "msg": "eb18410a53353de79a56a86f95ed94f7cc8efb20c7662f6acd1d0cb46dec6729", + "sig": "304402203beff0b6d06157a96bd48d84b70b2c8d5e4be1e60c358db05bab94c7b03685fb02205a3c07368ad539c0edff9ffc35f4d44cab663fbb3cb03f8e466929b5c9efd5c401", + "privkey": "5d006eeabbadd13ffcac0944381081f6f0dd7b3564fa5e9e0c0b2c8418d1ca52" + }, + { + "msg": "c886d6c0d4e62bd8c65c1d3319b32a82dcc4fb5780896c287f3bfac415a768ed", + "sig": "3044022068541ffbaab7dfdc9dd0d2a8e0d8d3a7e1acae685bceac3f1a0a19b61bdb9bf20220544d24dad0c195d0d57d2dbac2d22b328eb118da055f0e741b4346931a66de1c01", + "privkey": "c0d837694699e53ed82bf4fedfe7e8cf70dc02dbcad884c3b822b3ef6ddc5a19" + }, + { + "msg": "826f8c6ab61ed5928a1d6d9cd6d69082ec9f9e45c4e73f2121bf061ca1d88a87", + "sig": "3045022100e1d3b83cf96d324fb9bf2ac9096c70758799bf330104edcbf6c16ba672e8968d02206a9a826cf32840db5f2ddf887e819eb8f41d14e8be2e94aa0e7f064d96a4d21701", + "privkey": "3f523b03447d06bfa64fc78db115c7e5828739f38ba39663095309ae6051c092" + }, + { + "msg": "da71ad31c818c04ce018937d33a2428be6d4199af6e24f01b83f26212e3cb186", + "sig": "3044022000a0856075820b29361a83fb332c190048ad5f4a81f9b993765e5c76b6de462302200433ebf787caebb7d549fc93636e7e79b347a97fd56826f75adb69af01654efe01", + "privkey": "c235de75530efcf7c8bf08e3b3b69c13d5a306364172617f61c20d2d02d4b768" + }, + { + "msg": "de8f24d7924433bb1868e48a92aa49020c464140c1c69d36f8268b38798b1171", + "sig": "3045022100fbcc16baf92400595a5df863680c76388ff152e4e6ca3efb26d041f6126b51db022069c8c6ba124306ac55a3f5b5b95988fc45166aced7265d9fffdec77113cf572201", + "privkey": "231913cd2deed9aa0483d2a23719d9dc7a9354518ce5eea88f4d2de219891888" + }, + { + "msg": "3f87a3f5199d729f5683d90b1977e1403afab944a8a107abe8aeab1c2bbc4710", + "sig": "304402200e816369dc132b4331713cc481258cbe9a4526a767aeed50dd9c00d3cd5f321602200a592715b5538fe25713a179334dc0e275b710f74f16e11c599b79d397f1d01e01", + "privkey": "5b274ede3c80bcee4d5c1cf02f5b9f76adb95667a0369418370aa81530c28064" + }, + { + "msg": "12bb4666adc2cede1826b582085caed6fb64438a5462f74010eea04b4f2fb5fb", + "sig": "30450221008258561ae898aa8e689b6a8a878704020d1025d7ae835985eaac27a555996627022006bdaec9eaea8dc2eefcd197e1a10828e26f9114c394d1f2d161cfcc7e3d1cd401", + "privkey": "4fc83d5a7155af0810791a6db59e307295f0897682a1a6b958fd699f3ef9cb53" + }, + { + "msg": "1ac99db7e7ef6ee4af2016dd0c71b2a6d2995c1a2029c13959ddea0a4af1e839", + "sig": "30440220110722d507a7da0dc7a520ce7efe0e1fb42790c00ee8d565e0c7c8c4292cbcea0220267ae97ea9a2b1ef08239553cef818f625ed1e3e87ef766e8b6063f21a9daf9901", + "privkey": "f1fcd239bad3e3ef1483e10f3753283b88df5b8603f9bab20d66e00e81cef441" + }, + { + "msg": "b5d1b36d95311a86e450f507a0dea0805eaefb68c89f222d8a3d4761e5619b9d", + "sig": "3044022053a91f2c657aed63d265aa6249b3c0db90844210d828980b6ddf885b4e98b0840220325ba1809427c15527da92751f4fbe6e56230533ad7afccd91a244ff7c25ecb901", + "privkey": "ae74253a454718f1c08b4bc3b9673e2b084b1cd0b4c3bbc324da8329d5bced7c" + }, + { + "msg": "fb710ffc70334a93c4052be5e229875f55aa3f3067e6c493d53f115e39ba387a", + "sig": "304502210099b8afbdecefb8e2b5a3e2acdb7fb28da7d7f24c6ed6eb88e43c423b67954ebf022050050a3e69fbdfa91fa16d9ad669720c65b2fabe7e011ecab9336e92d18be19401", + "privkey": "40e53957385d806936ffba31637c7bcbc353616d896b6cda0e20d56e16baabaa" + }, + { + "msg": "b27b1bbaf48f7d3c38ce061542054b2fb19cce7a40a779253ece58169caa6efb", + "sig": "30450221009fccc94220c12ef508bfbe9a0d1a592875272e4213bdb78baa290d5a01054b1a02204101988977098b835b4b1ceff4e6af9925a92b7f879718a60340083679bbb63401", + "privkey": "67ff6b87850ab1fc1f8f7c0ddc606610fedd027e926fbed60f280abd2972a440" + }, + { + "msg": "433955be0f609ee6685e49229652c1311b6141f4b85a4f018e2f9b2ac49a4b54", + "sig": "304402202ccf1a22e503d11bad88fb90da3a5b3547397de3f125b86334ead3497fcd1ca302207065bdd03323de65b784384926fb26f637094774837b8368f59a191cf50b6f9101", + "privkey": "7befa50da27667bc46825f960dec45e461940da6a2267d8da6ce4b04bf4888c4" + }, + { + "msg": "577650e585efa3b2c2aa04f5c561306524178f0643c9208ec7034923a6949492", + "sig": "30450221008b75fcfac6277b160a555bbbb2dcb477c2509967946edfb0106f8d142fa1543c0220442de5a96c7e8f670398164a4380b97f8066304c62f5f7fef8b86e05941e94d301", + "privkey": "8cfe9d574c49070e41fc473352c4029547bba2299a2a61770fedb87d32de2edd" + }, + { + "msg": "a2fc75d302dadb11fc4bce7bafeb90406b9a367e368d0cb7a885e0b96d695fa6", + "sig": "30450221009ab4c7be6d7bebfbb9bdafa5abd628c8874b56872d77d04171209e692128b7ba022048f66d9206126e8a2a48a8cacb44dc7a6a660d04998b3f6d07d88481e4f230b301", + "privkey": "a1ab7d29541f45b96ccb881522f7dd45901765ac1160ebbabc50e2947b8853ef" + }, + { + "msg": "9acd7c5fedc120d69095eb7ce77684aae974cf7b48cfc806baece4dd812d560a", + "sig": "3045022100e8fb2e2817d7f481e059ccee51e8449f550f1488634ac012811aece52e5e23d502203d8d06125a037af6e32c0a0cd7032dbc12c7ca84f5d3952afb58857685c68fad01", + "privkey": "e2bccf63d91102cd90d519b18463ecdf41378c9f9b0e1d5a1ed58a837be11afa" + }, + { + "msg": "23ecbc3ed373e19e84d3d8e6420613d6e759b3e5d606e6ba9700234beaa7ae8d", + "sig": "3044022013b03a0a39a56f9241b21ee74acf83d93b5b6a81bcf254f7558648e686fc300e022065a5999b37b2fd7294f853b5c312cbf62c12a1db58f0d95041e7b7dd157cce7f01", + "privkey": "61dc64fb0590b9615bd5f381b0a301316857dd32f0b214c2e814f35e5fe956f2" + }, + { + "msg": "aea4c1124be7afa6c25af9f542b79997370ff6cd870e185a20c7be78c9c24b84", + "sig": "3045022100adac0cbb49e7d492b9f877a5f842860e0cbbce99fb4592558dee58f8e3cc44a4022074caa58d7edf18f2ed5c436930a5b8dd3a48a6024aa2c038b2f56c1187ab28b201", + "privkey": "0b31aea8e0af9a18f02e9cd4e06530e9ec9c4cab1e6a3bd52fdca5183617fc66" + }, + { + "msg": "f793e37b0dc14ffae24d6e5a3477aaf23cc3bba1ca939ccd0c4a4bc3f1943e68", + "sig": "304402200096eeb7256f916c256ae3884df5416bfac00143bcfb46a501cc0eee45ee432602200ba266f42639556de6a0f7c9f0bc2ee14d80cc035965c7fad9bd57c04826684601", + "privkey": "3fe28fcb15f00c93c5d628b4ae942beb2fb73e5f2c28f05dfd98998824c115c9" + }, + { + "msg": "85e774c6574ca6ae8f30af0ba108bbc487835a6ab9b9d7e00d17f1e710b3bde1", + "sig": "3045022100bb5a0cfb531d6bf5b817c1f6a17db02e7b592111a2a572a6ee4bf31e9de1ccd402202afab1acafd825fb8a51d801cb20564c67fa42a33afa5d7526f0d9f57535b5da01", + "privkey": "3902f9706403006e3fbc35d12b06fc78670509aa50b552544d708ab5dc5f5b79" + }, + { + "msg": "671db247e553158156e7c670136e9fd299a9d1fc33c394ee593752b0a1cc1f03", + "sig": "304402206d9f228584074ab3eafccffe240a1fbb448e8125836461da7423def37313aa1802205d076e6066caab751e95323be6761215e2fc5b69f2c9392b571e66a8f12ce2cb01", + "privkey": "2bc7499a1da26f836ed93be9834f9cfef1120e9512f3bc90c6d57c3ce366c58d" + }, + { + "msg": "d069674f48c2038bbb0dadcb18a9b18795eb71cc16cb34e91b4cbca86aec61d2", + "sig": "3045022100d1260fdebd27eed66d577b77a1f299cc42ac137227aa7730e2035077b71161da02204a8522a2f2eb8cc78e7ea11ad56f463f7d8f08c6e4e9a7db0cec3ad6779ff38d01", + "privkey": "0fc62bc36495f5f9b0d23145d0ee1983c29f822c7c60e22239959c13acec8da9" + }, + { + "msg": "e9a4c69779c44c72858e580297452f3ed488849a0cf204d75de42e591844f008", + "sig": "3045022100849c6e7b4d66ac63540a2784620c43ac1b558f7a1432237965949be3624af1d10220674f15f7779e4f0677f4c4cf66f85a5f7ca6a8b966f17c05ac1dd38e4664f0d801", + "privkey": "1229ade4f8919c0e61a5221c6cc37e7a2da7dcfc22eaf6d58b8e995d38a830c0" + }, + { + "msg": "183b7c41bb27526528ba72277a92ff7d39241539f6616f024e4389e76696db65", + "sig": "3045022100ba80e06c2a798b0dc206eb44b99703a31536ccc930eb0500a043f241aec21d1702200ce955a1627c9a073f8f49072afd5aa289e544bc90e5983b093c06c5c67e51a201", + "privkey": "08ece7a61cc766fee43dce42570d418d7509d63cc293a15e2292bef473e5c49a" + }, + { + "msg": "a119183cedb4d2385c204482f6f6aad863947f4dc336810a2cd494d73a7d63e6", + "sig": "3045022100bd8fe449160c9ec8029bb6f554f225fa985db131e2a7f56cda04d48d7133f8c10220060a2e95874ffddee22ce3e1a47bf15360922c73fb7c2a9ffe267447bbbd24d301", + "privkey": "70ea418b73f35a4d5fa241c97661be9e88d4e773478fc9ad59602e0d18d7499b" + }, + { + "msg": "e53804e86688bfb3e2d7a72d9a07d0b76c8d043472a70375f04bc26e5175d380", + "sig": "3044022076927896b56154a8eec11decbe729aa0a2543979cb388ceee3570b35e511e1ff0220730367ce5443b1522e61d990b5f0fe7c3e14d62fecf141d189da51285a65938e01", + "privkey": "4d2da431e0b77707cf388cc9d44f067d3fb82a3e544a436c2c94abfd0bd1a8eb" + }, + { + "msg": "c0a7969a9bd9689925f5b801e3937772fce4c20a238acf58e6baa4ddd68f958e", + "sig": "30440220700c5e64229194d774b222c34e436673c69aa8f1c9a18865895c05fccd02bf3a0220384b60122c477d03bc5ecfae58908dfc195dd94f09ae7e2eb18e14d54314982901", + "privkey": "7253a7b52381bce33b2502dd8026c6c242f66d75dbef89c6e47e8983a373941e" + }, + { + "msg": "d767a2f44d17543cb9833a4f5aa792f12064bcb1b7882feedd014cb9aeaba94c", + "sig": "3045022100d6cbcf05a476a5e05b92acf93c2ed41c97af666fc03f9a45e797af67f6f6eaf302202485861dd6538828e6ef0fe17f4e41c25053f4a2f28b017e181c0f364b44867f01", + "privkey": "90fb55d3cd1b87138b2983581f5f65efd7dc444c06438f492621e99311840805" + }, + { + "msg": "47d6db6d8e2a9aae31ade5ae2b1ae6ed17c25b7b74be25fbb6ea590046cf2d97", + "sig": "3044022054d1dd346604659a1ae9905a375f52124c066938bdd19200aa6598fe3cda676202202671b0da6d94702269909d2481347c328d789d052ff43b6821686fa65117627101", + "privkey": "cdcf9bb9730b0b88669876bc0692393a5dabaa75f78ca68372098a81374dee4e" + }, + { + "msg": "3e54cafef15a961d757071aee94b690280aad8201af7582aa81fafb64b748527", + "sig": "304402200e9cd509a33cc07318ac8e8c61c6e35a4825361bf255b47996ac6a6c45252a98022071092aee8df6e329303b5483c2e8fc6292b51df5e48ebef6548f043c11ad298201", + "privkey": "3b829c6c16002db5ba3323ac1ca6745cd1f6d1f67eb9c8f5f11b48df08d3fa75" + }, + { + "msg": "ff7482425542c945e2b83931583e2f516682dd24b2bac632ce00b0bf95f3764a", + "sig": "304402204ac0df04b0b83d87938c7d9591095acdcb6e0c6edaeb99a0ea40a1951f77470102201a40cd8a308c3a752cfb8c3741d6fec79b410a6bc4a3c64c4c377ea5b9bfddbe01", + "privkey": "1c1d11ed9739251c3e065db25ac10fd6413a54d8f9e553be3c67f4eb86bbdb08" + }, + { + "msg": "b5c1a15c2c219f845d5253f64947d49f94519a57aa484b6005517e0a8f933a58", + "sig": "3045022100c17a386ef1263ce5c1816e17504ccf8cbcdaf5f09ba00f141099c990ce2cc30002201d64bf0ad8da6d1b3fa02191145c19a94fb1011865933c2a8aaec4728fa5e06501", + "privkey": "df972b1d45f99fd4dbcb5e7354d6292b56b4a0f25f6432f9e1d7a318eecb2120" + }, + { + "msg": "bd15aac26ece339e81248e364dcc66dcbaadd6bac3f94047d161f0e71f44758c", + "sig": "30440220035a4c4bb28381cb4ed4f6f5714cb34bab019339299212fcc86ae90f83725ea502204f63ae13c03dc80e320b4274f9bd403f4966fde7c89c21328264a6305ee8c42701", + "privkey": "66eaec33187b285b3c604973aaacab3ae8d383a075dfd996c4cc3ac4cd16d0fd" + }, + { + "msg": "85fc198a649ee134d2116a2e0b189faf1a4d15c3afbb182033032f9ac322e1bd", + "sig": "3045022100aa128e5391a4bec3181d4a2127bd45fb38bc142993c967af8d7de33e90e3c03e022034eef4d80133c0002671027d55a1e10eaa12cd7e24f62d037077d1dd0e90775801", + "privkey": "5a6331ff79f2930f95df8a4747cdf56b0475eeae453af8da9257982f68fe66f4" + }, + { + "msg": "8b66547716aee0c7bcce9bc93051bd2babbcefaaed51a94605506f6ab6492744", + "sig": "3045022100bdadcc9d82b6bce0d4c453001e06481ba48b92ea2a8ed81b9186ceb247a6bb1e022005b30ff42cb05defa923dc09a9727eea67cbbaf1b5e5b561ea4d854b67e8208001", + "privkey": "994f92698ef865cc782429f13e47040ece8b95a2d6dc30fd8c6a9188db655668" + }, + { + "msg": "54fe0067ad6b4c7f4314802d40ab01896237015a466439d35ae986d81a6e5dbf", + "sig": "304402207b4f7d5bd15f520aabc9dabda7b8e73c660f10cca48c7e8ab5533a69137badc702204cd239932e7932d768bd65b55da2147ac527e61567f45bb14a953b0338211d3701", + "privkey": "21664545b76332766ec8959baedc77b7c842379d4400ce7f5f30417e5a1760e1" + }, + { + "msg": "438bafa3b8dbead8b2eeac1b9fd6527b9510d56d5bc09a2ae2a51b67e64ea8a9", + "sig": "30450221009d3fa71c0f2f7b015fff020316c81476930ed4d4f6fe3fdc348cae358d70206302202e2e69d6ca559ee5eea309b72c13bf22c643660e27cc7799d99bc807a28fbe3401", + "privkey": "dba5a15df6ef7b060b7e9a4ee819a431bd2c3146430e5d90b15c8c7f34fc5d9f" + }, + { + "msg": "2560b38e6a265f413fd762a88c4c492d46270b007e18cc844feb1dc06429a110", + "sig": "30440220361980512e7d7f6da1b37fb225c336801092d9ed05cf72b7723d7205de1b2baa02205cdf459c367d1f274b8067d008c533385c6c4330fd6376c4d330005312d4834b01", + "privkey": "d384f6a007cadf556e10c1bb59eb3e1e7dd940aae5ec6d305b64a6dbbe73ff64" + }, + { + "msg": "bf1d36ee509e65f04d78be03e0fa0d5ceae29397a33d9efad93332cb47ba0155", + "sig": "3045022100be83c754e4426893b698437baef7fe19329df4cd46f5cf05b33ed1090be2b4fa02202986f9ceb8ea9d2a30876b2a3e4c2e495d9716cc21c66018c91726955ea4b82201", + "privkey": "7f2776e0a044ff802d622f6ac37637ae83b4e2d83dbbf83c681f3606c46a7a8e" + }, + { + "msg": "fb75554ed0cc5485d2559c29f6510b6ef60dacb5f17d81564d25a87e79ac826e", + "sig": "304402207ab3815aae1a99a367489a31bf7a94661ee086e887641ebac2e455871994db3702204f6f8b7677bb30efb5c4602169f2541274b8f51e1938a2f84a828b9da0137ee201", + "privkey": "4c6f22a57c553e05a0a7a35adf46e1cb4c4d004a984e5af88bb2d2188ba7ab88" + }, + { + "msg": "6d18019673f7a984b0a222b7299b35e61622681cad5161748040c5375c951505", + "sig": "3044022034375c54a58c8562889c8e41f9c299f7f85704459f8d11f317dd52038ce7e29d02203e8a421f7f4d9d3dbad692dc81ce89ae060b734a01e9c048526ffb0eee908edb01", + "privkey": "0c0b3289b2c6fc93986902fab4457f42d22b0b461c5e5a53a5ec727051586fa7" + }, + { + "msg": "7e1e2a99702c16bed9055d399af557c2a63da0a5083292adeb3897af6b802564", + "sig": "3045022100c85073b669d65fa197cb73e4fc7a90c65b11cf195b8d718e998b22be071bd3c302207e7def3e6fe2e72aec48855ce06f9425c712fb874baa94484be96f9b9f472d3101", + "privkey": "4d1c0ae59c723633336f8dcc6bde9b358f9b75603e45168e406807212252b112" + }, + { + "msg": "a33b04ec26e5cbc6558c43abeed149ae35391bcccef36b684d345ff13496ca9b", + "sig": "3045022100f09854120ef83925f0a865aed3b256c5f0efef8f35f2bcf91384545d4ab6315e02205e9ff2aba9fe7270a73281f176d4675163a26b52e71819ac18f001cd5c93225401", + "privkey": "b2eef7149d49c01b51ee926e926e2e26f73c25bbf74371c990617eef8b50ecfe" + }, + { + "msg": "fa01a5e23fa06dd60c852d89edeb778f94ce904182a8b9d8d1ca9fa6634f9662", + "sig": "304402204cd469bb017d011fabb29cceb655148b0462c666dd940a2442176f4a02f5b02702207c64b92d62db3390facc8db753acbd05a9a1b63896ff4b27dbe47f256502bfad01", + "privkey": "7a572657b960cbeef0c13fd97855fd61147e896093d160fdb1191fe2849bf8e1" + }, + { + "msg": "14a93f4e03431f95877f6dc9f41f59bc967686bc8401ae10527483e1cdcfebf0", + "sig": "3045022100e502a90aa2908a903d45d5077d718812fd7341b551519f96fa7af94e66f39ef902201bef0e0b54a6fbc28e011d8ecefd0f33f6c7283cc2227ae7ae847b12b873e01001", + "privkey": "d661888426cf1c65cba5f96ec26314b55f421cd447ced732809e32220f28c246" + }, + { + "msg": "b6ec194ce825fc8ebee69325abfa2acb952d45495ab351455122d4901d4f64bb", + "sig": "304402205edce4c4ab58df2c58efeef2f12975a3a3ad38d6da9d4f18d76b086d5fc4d69d022074844f4cb83eae0aa01f409fbb27bccc32b44b0bca12b614831cfaea711edd9f01", + "privkey": "27cdce4f1e5ffa46fbbfe615bc1d1599db6869404714f0cc46300901b767383a" + }, + { + "msg": "9b86e708eb9574a8c3ded5d3932a6de43ae4982dcbdca3269af14e967c639b7f", + "sig": "30440220557f81e8f67ed361d2289aec02013731f75248350ecec55ac8dfb14418da68c202202598c35a9c0e062bc48d1ccb9494630a5daae324595be83c473fbaf2b3e7bdd201", + "privkey": "8d6fa8a66bc4684b35d9eb3226d352c7300452dd9b3d548d7a2d947459bc5a0f" + }, + { + "msg": "170a2926a37a37dbe2e406e2d5a3923973bae98e82ab55e26864a1dcf1785da1", + "sig": "3045022100fc7726b77976e58fd1f8a48c9232747edc40359eb1f6b393540608de72e2b4b5022005c22000c2c1c719c6f4f43ba81ba6ed4643a8645a34ec50619a4945849bd50a01", + "privkey": "339699b552be47df9e751d7bbd53fa052d953738d851741e656bba90de4a53b5" + }, + { + "msg": "90de053a840eb83db882433d067a2451bfc81f58db606d4e411a6b8fd82c953a", + "sig": "3045022100ae765968d1add07797a390b99ddb7faad3451e922a2e8f38adee56c654a3274902201f992b0f3605c54a6ae60d8604c7260b9a4db93be2512ad64937be4f0b3ad55501", + "privkey": "8b0377d0b6e665a0c6072009b50044c6891cec9316bfac8fc9b6a5a34e4eabb1" + }, + { + "msg": "38d14fe6dd85bdb8748f5cb23e1fb2e58df2e8bf841f1e1c68bd4d20dc94cfc5", + "sig": "30450221008e35cd8d034a2fc8234d9638f5baa6fe2bd96570df09b7b15ccd007f5c05a93e022041ae8101af3721d99668f87a743bad7bebfa3e0fbfb1a84d6e0f2e73e1d053a601", + "privkey": "6e99a1772417ee7deb91d0e3762d2642d7278f2f7431a4f659da50d43af879b8" + }, + { + "msg": "00ed851dc354b6df5a3e3bab543ee399b02f3600c595aa3e5ca6a1483465b155", + "sig": "3045022100deeb14e5b93035c0658f20aa05b87cb132609978bfa5ec008a3ca9502961244102205d0aef23a1f146edcda709137a5c5a376bb0f75abd031ba12128c4578ab93d8401", + "privkey": "56580e7ac5163e4e6579ab0e772f2a3848a80af534588e70f230a18158953803" + }, + { + "msg": "4d46ab40f75ab52c1fd8a7974e06ff684c01bf3e746977e811a1a442bf2912fd", + "sig": "3044022062aa9538861667b57609b750f7260df90373c01523b1341b7f841f3f53dafa0202200a3296141e23dec3292ae553a28c001efcdef18eca50ef09a0b4795b6d4b61b201", + "privkey": "3d38b60f2a844fb43dea0262aac32301ead58568074ca9915c6498155cb47f13" + }, + { + "msg": "9dd253813dd4ea8902617a09cfdcf060dd062849b76f3c1e556500d13d77170f", + "sig": "3045022100dccc41da7fdac14735bb98a2c59aae91d26284244f4cbc0beedb7851172a444a02206c5ac076f60a7f5243ef4e1630c51f411a03cdf57049d4b92a055ff90160ce8101", + "privkey": "80ac1ff9b4219c1aea37fa937299dfa946e48d23c858d463eafa1bd8d986d9e8" + }, + { + "msg": "c783fcc63873a8b39563fd0d39ded5453d9c7737e32a0946bc62ce4f6a4773bc", + "sig": "3045022100d782b60cca256c5b7918a62c3f6759588ed8bc3bad7b704dd8de3fe6e720a36802206d163563810897555f0a90c969d476f6c0452cc7a3027ab4ceaf8aafce1cb5a501", + "privkey": "527f7b367a63d977568bd25593860ae36bc3ba4b65f43b121f1af776c995d224" + }, + { + "msg": "4519ef8ca61e50159ee43d921a679ca78ab70784167ebe656112c2017f1e2a8e", + "sig": "3045022100dd23d3fee7e8fc4bac8c82378aee98fd7d3efa9140f18c1949b83f13654a7f8202201aabe8f08204e36e414d2a1cc42d76a7ba46bc3e4907dddae30944f14107b17a01", + "privkey": "e13d124062e954974d5e5918bf1409a7a5d1d20ad4f4217006e2d5612a255da3" + }, + { + "msg": "a3a2d23da4f1a6c4031879ba02e11952bd05209863f90907606615edc6dce871", + "sig": "3045022100983403797071adeae9cf36b3541580903d4fe20bbc29d7c85da3d5e86ebfbac202202b1cbdefdfa24e3c53b066b5bba6491f4117ab2b378c04552a4c1297d397670a01", + "privkey": "1f25a034e5df2a5ae72f91d63be72497c3a1df79300ce195ee73e4cfeeda37a6" + }, + { + "msg": "0b34440573c1ea6ea03e4b5500307948698f229b5a1315f81a5c622fdf660ddf", + "sig": "3045022100a5a3d9ffc866c3a747ad2a015f306d8a6c98540c7622f2bd0409e7a909924a7402201d0606df93f8f423fc5559623a829ae81632c6205af9a69e86965b1aafe9f7f101", + "privkey": "2dfc3b63b1c8f04643f550281371a846a1d31fa651fb861f7e6ae9db88122041" + }, + { + "msg": "88dde95676e529d3bd4422e8a50d106a4bbd465e8623b37d09228ff66c9dd275", + "sig": "30440220411a5d0613c89a246f08d1cf3db4b5d94b3c7de70a2464a0c6b930bd179db38702206253cc6df480e8fcc3716aa2e2c3cd10990fa73c6f2347e8aa7a499528ef2dec01", + "privkey": "d2f35b4f8e5f9db7e884ab4bcb64f84dc4d87a8d4b9055995df62b759e7ba4aa" + }, + { + "msg": "3617b55b4aed94d2fddf0f96f9c8c9f4359f948a2b902b76f0d9474a9e549710", + "sig": "3045022100ae0f294fbc13c28259019d000a9a9817173febfb37fb0a273511add46af4226102202d2a8b8b0e058179a0baf190dc76f649075a8d3ab3832d3be859159cbe1a9ae701", + "privkey": "66dc7feb6d7c733005c5d8716b22f38819738bd1538a40f46205f3f3be191efc" + } + ] +} \ No newline at end of file diff --git a/test/test_bip32.py b/test/test_bip32.py index 2cbecf6c..fff9a922 100644 --- a/test/test_bip32.py +++ b/test/test_bip32.py @@ -69,3 +69,33 @@ def test_bip32_vector(vector): print vector['keys'][i][1] assert pub == vector['keys'][i][ 1], 'failed: child pub key, should be: ' + vector['keys'][i][1] + +def test_invalid_bip32_key(): + #keys with invalid checksum + bad_keys = ( + 'xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8BrrngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7', + 'xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQQKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw' + ) + for x in bad_keys: + with pytest.raises(Exception) as e_info: + fake_tuple = btc.bip32_deserialize(x) + +def test_ckd_pubkeys(): + pub = 'xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw' + new_pub = btc.bip32_ckd(pub, 4) + #how to check it's right? + print new_pub + #try to do on hardened, should fail, that's the idea: + with pytest.raises(Exception) as e_info: + new_pub = btc.bip32_ckd(pub, 2**31+1) + +def test_bip32_descend(): + master = btc.bip32_master_key('\x07'*32) + end_key = btc.bip32_descend(master, [2, 3, 10000]) + assert end_key=="6856ef965940a1a7b1311dc041050ac0013e326c7ff4e2c677a7694b4f0405c901" + end_key = btc.bip32_descend(master, 2, 5, 4, 5) + assert end_key=="d2d816b6485103c0d7ff95482788f0e8e73fa11817079e006d47979d8196c4b101" + + + + \ No newline at end of file diff --git a/test/test_blockr.py b/test/test_blockr.py new file mode 100644 index 00000000..92a7939c --- /dev/null +++ b/test/test_blockr.py @@ -0,0 +1,113 @@ +#! /usr/bin/env python +from __future__ import absolute_import +'''Blockchain access via blockr tests.''' + +import sys +import os +import time +import binascii + +import bitcoin as btc +import pytest +from joinmarket import load_program_config, jm_single +from joinmarket.blockchaininterface import BlockrInterface +from joinmarket import get_p2pk_vbyte, get_log, Wallet + +log = get_log() + +#TODO: some kind of mainnet testing, harder. +blockr_root_url = "https://tbtc.blockr.io/api/v1/" + +def test_blockr_bad_request(): + with pytest.raises(Exception) as e_info: + btc.make_request(blockr_root_url+"address/txs/", "0000") + +def test_blockr_bad_pushtx(): + inps = [("00000000", "btc"), ("00000000", "testnet"), + ('\x00'*8, "testnet"), ('\x00'*8, "x")] + for i in inps: + with pytest.raises(Exception) as e_info: + btc.blockr_pushtx(i[0],i[1]) + +def test_bci_bad_pushtx(): + inps = [("00000000"), ('\x00'*8)] + for i in inps: + with pytest.raises(Exception) as e_info: + btc.bci_pushtx(i[0]) + +def test_blockr_estimate_fee(setup_blockr): + res = [] + for N in [1,3,6]: + res.append(jm_single().bc_interface.estimate_fee_per_kb(N)) + assert res[0] >= res[2] + #Note this can fail, it isn't very accurate. + #assert res[1] >= res[2] + #sanity checks: + assert res[0] < 200000 + assert res[2] < 150000 + +@pytest.mark.parametrize( + "net, seed, gaplimit, showprivkey, method", + [ + ("testnet", + #Dont take these testnet coins, itll botch up our tests!! + "I think i did pretty good with Christmas", + 6, + True, + #option "displayall" here will show all addresses from beginning + "display"), + ]) +def test_blockr_sync(setup_blockr, net, seed, gaplimit, showprivkey, method): + jm_single().config.set("BLOCKCHAIN", "network", net) + wallet = Wallet(seed, max_mix_depth = 5) + jm_single().bc_interface.sync_wallet(wallet) + + #copy pasted from wallet-tool; some boiled down form of + #this should really be in wallet.py in the joinmarket module. + def cus_print(s): + print s + + total_balance = 0 + for m in range(wallet.max_mix_depth): + cus_print('mixing depth %d m/0/%d/' % (m, m)) + balance_depth = 0 + for forchange in [0, 1]: + cus_print(' ' + ('external' if forchange == 0 else 'internal') + + ' addresses m/0/%d/%d/' % (m, forchange)) + + for k in range(wallet.index[m][forchange] + gaplimit): + addr = wallet.get_addr(m, forchange, k) + balance = 0.0 + for addrvalue in wallet.unspent.values(): + if addr == addrvalue['address']: + balance += addrvalue['value'] + balance_depth += balance + used = ('used' if k < wallet.index[m][forchange] else ' new') + if showprivkey: + if btc.secp_present: + privkey = btc.wif_compressed_privkey( + wallet.get_key(m, forchange, k), get_p2pk_vbyte()) + else: + privkey = btc.encode_privkey(wallet.get_key(m, + forchange, k), 'wif_compressed', get_p2pk_vbyte()) + else: + privkey = '' + if (method == 'displayall' or balance > 0 or + (used == ' new' and forchange == 0)): + cus_print(' m/0/%d/%d/%03d %-35s%s %.8f btc %s' % + (m, forchange, k, addr, used, balance / 1e8, + privkey)) + total_balance += balance_depth + print('for mixdepth=%d balance=%.8fbtc' % (m, balance_depth / 1e8)) + assert total_balance == 96143257 + + +@pytest.fixture(scope="module") +def setup_blockr(request): + def blockr_teardown(): + jm_single().config.set("BLOCKCHAIN", "blockchain_source", "regtest") + jm_single().config.set("BLOCKCHAIN", "network", "testnet") + request.addfinalizer(blockr_teardown) + load_program_config() + jm_single().config.set("BLOCKCHAIN", "blockchain_source", "blockr") + jm_single().bc_interface = BlockrInterface(True) diff --git a/test/test_btc_formatting.py b/test/test_btc_formatting.py new file mode 100644 index 00000000..67e2084f --- /dev/null +++ b/test/test_btc_formatting.py @@ -0,0 +1,47 @@ +#! /usr/bin/env python +from __future__ import absolute_import +'''Test bitcoin module data handling''' + +import bitcoin as btc +import pytest +import binascii +import hashlib + +#used in p2sh addresses +def test_hash160(): + assert '0e3397b4abc7a382b3ea2365883c3c7ca5f07600' == \ + btc.hash160('The quick brown fox jumps over the lazy dog') + +def test_bad_code_string(): + for i in [1,9,257,-3,"256"]: + with pytest.raises(ValueError) as e_info: + btc.get_code_string(i) + +@pytest.mark.parametrize( + "st, frm, to, minlen, res", + [ + ("0101aa", 16, 16, 12, "0000000101aa"), + ]) +def test_changebase(st, frm, to, minlen, res): + assert btc.changebase(st, frm, to, minlen) == res + + +#Tests of compactsize encoding, see: +#https://bitcoin.org/en/developer-reference#compactsize-unsigned-integers +#note that little endian is used. +@pytest.mark.parametrize( + "num, compactsize", + [ + (252, "fc"), + (253, "fdfd00"), + (254, "fdfe00"), + (515, "fd0302"), + (65535, "fdffff"), + (65536, "fe00000100"), + (65537, "fe01000100"), + (4294967295, "feffffffff"), + (4294967296, "ff0000000001000000"), + + ]) +def test_compact_size(num, compactsize): + assert btc.num_to_var_int(num) == binascii.unhexlify(compactsize) diff --git a/test/test_donations.py b/test/test_donations.py new file mode 100644 index 00000000..e0986c6d --- /dev/null +++ b/test/test_donations.py @@ -0,0 +1,109 @@ +import sys +import bitcoin as btc +import pytest +import json +from commontest import make_wallets +from joinmarket import load_program_config, get_p2pk_vbyte, get_log + +log = get_log() + +# This is a primitive version +# to test the basic concept is working (specifically the imports). +# It isn't required that the transaction is valid, only that a valid +# utxo from the wallet can extract a private key. +# A real test of donations fits into the tumbler test cases, although +# with effort an "intermediately realistic" version could be set up. + + +@pytest.mark.parametrize( + "tx_type, tx_id, tx_hex, address", + [("simple-tx", + "f31916a1d398a4ec18d56a311c942bb6db934cee6aa8ac30af0b30aad9efb841", + "0100000001c74265f31fc5e24895fdc83f7157cc40045235f3a71ae326a219de9de873" + + "0d8b010000006a473044022076055917470b7ec4f4bb008096266cf816ebb089ad983e" + + "6a0f63340ba0e6a6cb022059ec938b996a75db10504e46830e13d399f28191b9832bd5" + + "f61df097b9e0d47801210291941334a00959af4aa5757abf81d2a7d1aca8adb3431c67" + + "e89419271ba71cb4feffffff023cdeeb03000000001976a914a2426748f14eba44b3f6" + + "abba3e8bce216ea233f388acf4ebf303000000001976a914bfa366464a464005ba0df8" + + "6024a6c3ed859f03ac88ac33280600", + "msWrR3Gm2mBmdLZH8vGHbHifM53N2vuYBq"), + + ]) +def test_donation_address(setup_donations, tx_type, tx_id, tx_hex, address): + wallets = make_wallets(1, wallet_structures=[[1,1,1,0,0]], + mean_amt=0.5) + wallet = wallets[0]['wallet'] + priv, addr = donation_address(tx_hex, wallet) + print addr + #just a check that it doesn't throw + sign_donation_tx(tx_hex, 0, priv) + +if not btc.secp_present: + #See note above, this is NOT the real code, see taker.py + def donation_address(tx, wallet): + from bitcoin.main import multiply, G, deterministic_generate_k, add_pubkeys + reusable_donation_pubkey = ('02be838257fbfddabaea03afbb9f16e852' + '9dfe2de921260a5c46036d97b5eacf2a') + + privkey = wallet.get_key_from_addr(wallet.get_new_addr(0,0)) + msghash = btc.bin_txhash(tx, btc.SIGHASH_ALL) + # generate unpredictable k + global sign_k + sign_k = deterministic_generate_k(msghash, privkey) + c = btc.sha256(multiply(reusable_donation_pubkey, sign_k)) + sender_pubkey = add_pubkeys( + reusable_donation_pubkey, multiply( + G, c)) + sender_address = btc.pubtoaddr(sender_pubkey, get_p2pk_vbyte()) + log.debug('sending coins to ' + sender_address) + return privkey, sender_address + + #See note above, this is NOT the real code, see taker.py + def sign_donation_tx(tx, i, priv): + from bitcoin.main import fast_multiply, decode_privkey, G, inv, N + from bitcoin.transaction import der_encode_sig + k = sign_k + hashcode = btc.SIGHASH_ALL + i = int(i) + if len(priv) <= 33: + priv = btc.safe_hexlify(priv) + pub = btc.privkey_to_pubkey(priv) + address = btc.pubkey_to_address(pub) + signing_tx = btc.signature_form( + tx, i, btc.mk_pubkey_script(address), hashcode) + + msghash = btc.bin_txhash(signing_tx, hashcode) + z = btc.hash_to_int(msghash) + # k = deterministic_generate_k(msghash, priv) + r, y = fast_multiply(G, k) + s = inv(k, N) * (z + r * decode_privkey(priv)) % N + rawsig = 27 + (y % 2), r, s + + sig = der_encode_sig(*rawsig) + btc.encode(hashcode, 16, 2) + # sig = ecdsa_tx_sign(signing_tx, priv, hashcode) + txobj = btc.deserialize(tx) + txobj["ins"][i]["script"] = btc.serialize_script([sig, pub]) + return btc.serialize(txobj) +else: + def donation_address(cjtx, wallet): + privkey = wallet.get_key_from_addr(wallet.get_new_addr(0,0)) + reusable_donation_pubkey = '02be838257fbfddabaea03afbb9f16e8529dfe2de921260a5c46036d97b5eacf2a' + global sign_k + import os + import binascii + sign_k = os.urandom(32) + log.debug("Using the following nonce value: "+binascii.hexlify(sign_k)) + c = btc.sha256(btc.multiply(binascii.hexlify(sign_k), + reusable_donation_pubkey, True)) + sender_pubkey = btc.add_pubkeys([reusable_donation_pubkey, + btc.privtopub(c+'01', True)], True) + sender_address = btc.pubtoaddr(sender_pubkey, get_p2pk_vbyte()) + log.debug('sending coins to ' + sender_address) + return privkey, sender_address + + def sign_donation_tx(tx, i, priv): + return btc.sign(tx, i, priv, usenonce=sign_k) + +@pytest.fixture(scope="module") +def setup_donations(): + load_program_config() diff --git a/test/test_ecc_signing.py b/test/test_ecc_signing.py new file mode 100644 index 00000000..c063e083 --- /dev/null +++ b/test/test_ecc_signing.py @@ -0,0 +1,80 @@ +#! /usr/bin/env python +from __future__ import absolute_import +'''Test ECDSA signing and other key operations, including legacy message +signature conversion.''' + +import bitcoin as btc +import binascii +from joinmarket.configure import load_program_config, get_p2pk_vbyte +from joinmarket import jm_single +import json +import pytest + +vectors = None + +def test_valid_sigs(setup_ecc): + for v in vectors['vectors']: + msg = v['msg'] + sig = v['sig'] + priv = v['privkey'] + assert sig == btc.ecdsa_raw_sign(msg, priv, True, rawmsg=True)+'01' + #check that the signature verifies against the key(pair) + pubkey = btc.privtopub(priv) + assert btc.ecdsa_raw_verify(msg, pubkey, sig[:-2], True, rawmsg=True) + #check that it fails to verify against corrupted signatures + for i in [0,1,2,4,7,25,55]: + #corrupt one byte + binsig = binascii.unhexlify(sig) + checksig = binascii.hexlify(binsig[:i] + chr( + (ord(binsig[i])+1) %256) + binsig[i+1:-1]) + + #this kind of corruption will sometimes lead to an assert + #failure (if the DER format is corrupted) and sometimes lead + #to a signature verification failure. + try: + res = btc.ecdsa_raw_verify(msg, pubkey, checksig, True, rawmsg=True) + except: + continue + assert res==False + +def test_legacy_conversions(setup_ecc): + #run some checks of legacy conversion + for v in vectors['vectors']: + msg = v['msg'] + sig = binascii.unhexlify(v['sig'])[:-1] + priv = v['privkey'] + #check back-and-forth translation + assert btc.legacy_ecdsa_verify_convert( + btc.legacy_ecdsa_sign_convert(sig)) == sig + + #Correct cases passed, now try invalid signatures + + #screw up r-length + bad_sig = sig[:3] + '\x90' + sig[4:] + with pytest.raises(Exception) as e_info: + fake_sig = btc.legacy_ecdsa_sign_convert(bad_sig) + #screw up s-length + rlen = ord(sig[3]) + bad_sig = sig[:4+rlen+1] + '\x90' + sig[4+rlen+2:] + with pytest.raises(Exception) as e_info: + fake_sig = btc.legacy_ecdsa_sign_convert(bad_sig) + #valid length, but doesn't match s + bad_sig = sig[:4+rlen+1] + '\x06' + sig[4+rlen+2:] + with pytest.raises(Exception) as e_info: + fake_sig = btc.legacy_ecdsa_sign_convert(bad_sig) + #invalid inputs to legacy convert + #too short + bad_sig = '\x07'*32 + assert not btc.legacy_ecdsa_verify_convert(bad_sig) + #r OK, s too short + bad_sig = '\x07'*64 + assert not btc.legacy_ecdsa_verify_convert(bad_sig) + #note - no parity byte check, we don't bother (this is legacy) + + +@pytest.fixture(scope='module') +def setup_ecc(): + global vectors + with open("test/ecc_sigs_rfc6979_valid.json", "r") as f: + json_data = f.read() + vectors = json.loads(json_data) \ No newline at end of file diff --git a/test/test_irc_messaging.py b/test/test_irc_messaging.py new file mode 100644 index 00000000..ab8d604d --- /dev/null +++ b/test/test_irc_messaging.py @@ -0,0 +1,83 @@ +#! /usr/bin/env python +from __future__ import absolute_import +'''Tests of joinmarket bots end-to-end (including IRC and bitcoin) ''' + +import subprocess +import signal +import os +import pytest +import time +import threading +from commontest import local_command, make_wallets +from joinmarket.message_channel import CJPeerError +import joinmarket.irc +from joinmarket import load_program_config, IRCMessageChannel + +python_cmd = "python2" +yg_cmd = "yield-generator-basic.py" +yg_name = None + +class DummyMC(IRCMessageChannel): + def __init__(self, nick): + super(DummyMC, self).__init__(nick) + +def on_order_seen(counterparty, oid, ordertype, minsize, + maxsize, txfee, cjfee): + global yg_name + yg_name = counterparty + +def on_pubkey(pubkey): + print "received pubkey: " + pubkey + +class RawIRCThread(threading.Thread): + + def __init__(self, ircmsgchan): + threading.Thread.__init__(self, name='RawIRCThread') + self.daemon = True + self.ircmsgchan = ircmsgchan + + def run(self): + self.ircmsgchan.run() + +def test_junk_messages(setup_messaging): + #start a yg bot just to receive messages + wallets = make_wallets(1, + wallet_structures=[[1,0,0,0,0]], + mean_amt=1) + wallet = wallets[0]['wallet'] + ygp = local_command([python_cmd, yg_cmd,\ + str(wallets[0]['seed'])], bg=True) + + #start a raw IRCMessageChannel instance in a thread; + #then call send_* on it with various errant messages + mc = DummyMC("irc_ping_test") + mc.register_orderbookwatch_callbacks(on_order_seen=on_order_seen) + mc.register_taker_callbacks(on_pubkey=on_pubkey) + RawIRCThread(mc).start() + time.sleep(1) + mc._IRCMessageChannel__pubmsg("!orderbook") + time.sleep(1) + mc._IRCMessageChannel__pubmsg("!orderbook!orderbook") + time.sleep(1) + mc._IRCMessageChannel__pubmsg("junk and crap"*20) + time.sleep(5) + #try: + with pytest.raises(CJPeerError) as e_info: + mc.send_error(yg_name, "fly you fools!") + #except CJPeerError: + # print "CJPeerError raised" + # pass + time.sleep(5) + mc.shutdown() + ygp.send_signal(signal.SIGINT) + ygp.wait() + +@pytest.fixture(scope="module") +def setup_messaging(): + #Trigger PING LAG sending artificially + joinmarket.irc.PING_INTERVAL = 3 + load_program_config() + + + + diff --git a/test/test_keys.py b/test/test_keys.py index cec810bf..2dcb3f34 100644 --- a/test/test_keys.py +++ b/test/test_keys.py @@ -10,7 +10,39 @@ import pytest +def test_read_raw_privkeys(): + if not btc.secp_present: + #these are tests of format which the pybtc library didnt do + return + badkeys = ['', '\x07'*31,'\x07'*34, '\x07'*33] + for b in badkeys: + with pytest.raises(Exception) as e_info: + c, k = btc.read_privkey(b) + goodkeys = [('\x07'*32, False), ('\x07'*32 + '\x01', True)] + for g in goodkeys: + c, k = btc.read_privkey(g[0]) + assert c == g[1] + def test_wif_privkeys_invalid(setup_keys): + #first try to create wif privkey from key of wrong length + bad_privs = ['\x01\x02'*17] #some silly private key but > 33 bytes + + #next try to create wif with correct length but wrong compression byte + bad_privs.append('\x07'*32 + '\x02') + + for priv in bad_privs: + with pytest.raises(Exception) as e_info: + fake_wif = btc.wif_compressed_privkey(binascii.hexlify(priv)) + + #Create a wif with wrong length + bad_wif1 = btc.bin_to_b58check('\x01\x02'*34, 128) + #Create a wif with wrong compression byte + bad_wif2 = btc.bin_to_b58check('\x07'*33, 128) + for bw in [bad_wif1, bad_wif2]: + with pytest.raises(Exception) as e_info: + fake_priv = btc.from_wif_privkey(bw) + + #Some invalid b58 from bitcoin repo; #none of these are valid as any kind of key or address with open("test/base58_keys_invalid.json", "r") as f: json_data = f.read() diff --git a/test/test_regtest.py b/test/test_regtest.py index 7be5f0ed..ffb4b556 100644 --- a/test/test_regtest.py +++ b/test/test_regtest.py @@ -13,6 +13,7 @@ from joinmarket import random_nick, get_p2pk_vbyte from joinmarket import get_log, choose_sweep_orders, choose_orders, \ pick_order, cheapest_order_choose, weighted_order_choose, debug_dump_object +import joinmarket.irc import json import sendpayment import bitcoin as btc @@ -81,6 +82,10 @@ def test_sendpayment(setup_regtest, num_ygs, wallet_structures, mean_amt, log.debug('starting sendpayment') jm_single().bc_interface.sync_wallet(wallet) + + #Trigger PING LAG sending artificially + joinmarket.irc.PING_INTERVAL = 3 + irc = IRCMessageChannel(jm_single().nickname) taker = sendpayment.SendPayment(irc, wallet, destaddr, amount, makercount, txfee, waittime, mixdepth, answeryes, @@ -88,12 +93,6 @@ def test_sendpayment(setup_regtest, num_ygs, wallet_structures, mean_amt, try: log.debug('starting irc') irc.run() - except: - log.debug('CRASHING, DUMPING EVERYTHING') - debug_dump_object(wallet, ['addr_cache', 'keys', 'wallet_name', 'seed']) - debug_dump_object(taker) - import traceback - log.debug(traceback.format_exc()) finally: if any(yigen_procs): for ygp in yigen_procs: @@ -109,6 +108,8 @@ def test_sendpayment(setup_regtest, num_ygs, wallet_structures, mean_amt, assert received == amount, "sendpayment failed - coins not arrived, " +\ "received: " + str(received) #TODO: how to check success for sweep case? + else: + assert received != 0 @pytest.fixture(scope="module") diff --git a/test/test_tumbler.py b/test/test_tumbler.py new file mode 100644 index 00000000..43ddc68a --- /dev/null +++ b/test/test_tumbler.py @@ -0,0 +1,186 @@ +#! /usr/bin/env python +from __future__ import absolute_import +'''Tests of joinmarket bots end-to-end (including IRC and bitcoin) ''' + +import subprocess +import signal +from commontest import local_command, make_wallets +import os +import pytest +import time +from joinmarket import Taker, load_program_config, IRCMessageChannel +from joinmarket import validate_address, jm_single +from joinmarket import random_nick, get_p2pk_vbyte +from joinmarket import get_log, choose_sweep_orders, choose_orders, \ + pick_order, cheapest_order_choose, weighted_order_choose, debug_dump_object +import json +import tumbler +import bitcoin as btc +import copy +from pprint import pprint + +#for running bots as subprocesses +python_cmd = 'python2' +yg_cmd = 'yield-generator-basic.py' +#yg_cmd = 'yield-generator-mixdepth.py' +#yg_cmd = 'yield-generator-deluxe.py' + +class Options(object): + pass + +def get_options(): + options = Options() + options.mixdepthsrc = 0 + options.mixdepthcount = 4 + options.minmakercount = 2 + options.makercountrange = (6, 0) + options.maxcjfee = (0.01, 10000) + options.txfee = 5000 + options.addrcount = 3 + options.donateamount = 0.5 + options.txcountparams = (4, 1) + options.mintxcount = 1 + options.amountpower = 100 + options.timelambda = 0.2 + options.waittime = 10 + options.mincjamount = 1000000 + options.liquiditywait = 5 + return options + +def test_generate_tumbler_tx(): + options = get_options() + destaddrs = ["A","B","C"] + tx_list = tumbler.generate_tumbler_tx(destaddrs, options) + from pprint import pformat + print pformat(tx_list) + +@pytest.mark.parametrize( + "num_ygs, wallet_structures, mean_amt, sdev_amt, yg_excess", + [ + # basic 1sp 2yg + (6, [[4, 4, 4, 4, 4]] * 7, 0.5, 0.3, 10), + ]) +def test_tumbler(setup_tumbler, num_ygs, wallet_structures, mean_amt, sdev_amt, + yg_excess): + """Test of tumbler code, with yield generators in background. + """ + log = get_log() + options = Options() + options.mixdepthsrc = 0 + options.mixdepthcount = 4 + options.minmakercount = 2 + options.makercountrange = (num_ygs, 0) + options.maxcjfee = (0.01, 10000) + options.txfee = 5000 + options.addrcount = 3 + options.donateamount = 0.5 + options.txcountparams = (4, 1) + options.mintxcount = 1 + options.amountpower = 100 + options.timelambda = 0.2 + options.waittime = 10 + options.mincjamount = 1000000 + options.liquiditywait = 5 + + wallets = make_wallets(num_ygs + 1, + wallet_structures=wallet_structures, + mean_amt=mean_amt, sdev_amt=sdev_amt) + #need to make sure that at least some ygs have substantially + #more coins for last stages of sweep/spend in tumble: + for i in range(num_ygs): + jm_single().bc_interface.grab_coins( + wallets[i]['wallet'].get_external_addr(0), yg_excess) + #the tumbler bot uses the last wallet in the list + wallet = wallets[num_ygs]['wallet'] + + yigen_procs = [] + for i in range(num_ygs): + ygp = local_command([python_cmd, yg_cmd,\ + str(wallets[i]['seed'])], bg=True) + time.sleep(2) #give it a chance + yigen_procs.append(ygp) + + #A significant delay is needed to wait for the yield generators to sync + time.sleep(20) + destaddrs = [] + for i in range(3): + if btc.secp_present: + destaddr = btc.privkey_to_address( + os.urandom(32), + from_hex=False, + magicbyte=get_p2pk_vbyte()) + else: + destaddr = btc.privkey_to_address( + os.urandom(32), + magicbyte=get_p2pk_vbyte()) + addr_valid, errormsg = validate_address(destaddr) + assert addr_valid, "Invalid destination address: " + destaddr + \ + ", error message: " + errormsg + destaddrs.append(destaddr) + tx_list = tumbler.generate_tumbler_tx(destaddrs, options) + pprint(tx_list) + if options.addrcount + 1 > options.mixdepthcount: + print('not enough mixing depths to pay to all destination addresses, ' + 'increasing mixdepthcount') + options.mixdepthcount = options.addrcount + 1 + + tx_list2 = copy.deepcopy(tx_list) + tx_dict = {} + for tx in tx_list2: + srcmixdepth = tx['srcmixdepth'] + tx.pop('srcmixdepth') + if srcmixdepth not in tx_dict: + tx_dict[srcmixdepth] = [] + tx_dict[srcmixdepth].append(tx) + dbg_tx_list = [] + for srcmixdepth, txlist in tx_dict.iteritems(): + dbg_tx_list.append({'srcmixdepth': srcmixdepth, 'tx': txlist}) + log.debug('tumbler transaction list') + pprint(dbg_tx_list) + + total_wait = sum([tx['wait'] for tx in tx_list]) + print('creates ' + str(len(tx_list)) + ' transactions in total') + print('waits in total for ' + str(len(tx_list)) + ' blocks and ' + str( + total_wait) + ' minutes') + total_block_and_wait = len(tx_list) * 10 + total_wait + print('estimated time taken ' + str(total_block_and_wait) + ' minutes or ' + + str(round(total_block_and_wait / 60.0, 2)) + ' hours') + + jm_single().nickname = random_nick() + + log.debug('starting tumbler') + + jm_single().bc_interface.sync_wallet(wallet) + irc = IRCMessageChannel(jm_single().nickname) + tumbler_bot = tumbler.Tumbler(irc, wallet, tx_list, options) + try: + log.debug('starting irc') + irc.run() + except: + log.debug('CRASHING, DUMPING EVERYTHING') + debug_dump_object(wallet, ['addr_cache', 'keys', 'wallet_name', 'seed']) + debug_dump_object(tumbler_bot) + import traceback + log.debug(traceback.format_exc()) + finally: + if any(yigen_procs): + for ygp in yigen_procs: + #NB *GENTLE* shutdown is essential for + #test coverage reporting! + ygp.send_signal(signal.SIGINT) + ygp.wait() + #wait for block generation + time.sleep(5) + received = jm_single().bc_interface.get_received_by_addr( + [destaddr], None)['data'][0]['balance'] + assert received != 0 + """TODO: figure out a sensible assertion check for the destination + if amount != 0: + assert received == amount, "sendpayment failed - coins not arrived, " +\ + "received: " + str(received) + """ + + +@pytest.fixture(scope="module") +def setup_tumbler(): + load_program_config() diff --git a/test/test_tx_creation.py b/test/test_tx_creation.py new file mode 100644 index 00000000..4ac30a99 --- /dev/null +++ b/test/test_tx_creation.py @@ -0,0 +1,148 @@ +#! /usr/bin/env python +from __future__ import absolute_import +'''Test of unusual transaction types creation and push to +network to check validity.''' + +import sys +import os +import time +import binascii +import pexpect +import random +import subprocess +import unittest +from commontest import local_command, interact, make_wallets + +import bitcoin as btc +import pytest +from joinmarket import load_program_config, jm_single +from joinmarket import get_p2pk_vbyte, get_log, Wallet +from joinmarket.support import chunks, select_gradual, \ + select_greedy, select_greediest + +log = get_log() +#just a random selection of pubkeys for receiving multisigs; +#if we ever need the privkeys, they are in a json file somewhere +vpubs = ["03e9a06e539d6bf5cf1ca5c41b59121fa3df07a338322405a312c67b6349a707e9", + "0280125e42c1984923106e281615dfada44d38c4125c005963b322427110d709d6", + "02726fa5b19e9406aaa46ee22fd9e81a09dd5eb7c87505b93a11efcf4b945e778c", + "03600a739be32a14938680b3b3d61b51f217a60df118160d0decab22c9e1329862", + "028a2f126e3999ff66d01dcb101ab526d3aa1bf5cbdc4bde14950a4cead95f6fcb", + "02bea84d70e74f7603746b62d79bf035e16d982b56e6a1ee07dfd3b9130e8a2ad9"] + + +@pytest.mark.parametrize( + "nw, wallet_structures, mean_amt, sdev_amt, amount, pubs, k", [ + (1, [[2, 1, 4, 0, 0]], 4, 1.4, 600000000, vpubs[1:4], 2), + (1, [[3, 3, 0, 0, 3]], 4, 1.4, 100000000, vpubs[:4], 3), + ]) +def test_create_p2sh_output_tx(setup_tx_creation, nw, wallet_structures, + mean_amt, sdev_amt, amount, pubs, k): + wallets = make_wallets(nw, wallet_structures, mean_amt, sdev_amt) + for w in wallets.values(): + jm_single().bc_interface.sync_wallet(w['wallet']) + for k, w in enumerate(wallets.values()): + wallet = w['wallet'] + ins_full = wallet.select_utxos(0, amount) + script = btc.mk_multisig_script(pubs, k) + #try the alternative argument passing + pubs.append(k) + script2 = btc.mk_multisig_script(*pubs) + assert script2 == script + output_addr = btc.scriptaddr(script, magicbyte=196) + txid = make_sign_and_push(ins_full, + wallet, + amount, + output_addr=output_addr) + assert txid + + +def make_sign_and_push(ins_full, + wallet, + amount, + output_addr=None, + change_addr=None, + hashcode=btc.SIGHASH_ALL): + total = sum(x['value'] for x in ins_full.values()) + ins = ins_full.keys() + #random output address and change addr + output_addr = wallet.get_new_addr(1, 1) if not output_addr else output_addr + change_addr = wallet.get_new_addr(1, 0) if not change_addr else change_addr + outs = [{'value': amount, + 'address': output_addr}, {'value': total - amount - 100000, + 'address': change_addr}] + + tx = btc.mktx(ins, outs) + de_tx = btc.deserialize(tx) + for index, ins in enumerate(de_tx['ins']): + utxo = ins['outpoint']['hash'] + ':' + str(ins['outpoint']['index']) + addr = ins_full[utxo]['address'] + priv = wallet.get_key_from_addr(addr) + if index % 2: + priv = binascii.unhexlify(priv) + tx = btc.sign(tx, index, priv, hashcode=hashcode) + #pushtx returns False on any error + print btc.deserialize(tx) + return jm_single().bc_interface.pushtx(tx) + + +def test_create_sighash_txs(setup_tx_creation): + #non-standard hash codes: + for sighash in [btc.SIGHASH_ANYONECANPAY + btc.SIGHASH_SINGLE, + btc.SIGHASH_NONE, btc.SIGHASH_SINGLE]: + wallet = make_wallets(1, [[2, 0, 0, 0, 1]], 3)[0]['wallet'] + jm_single().bc_interface.sync_wallet(wallet) + amount = 350000000 + ins_full = wallet.select_utxos(0, amount) + print "using hashcode: " + str(sighash) + txid = make_sign_and_push(ins_full, wallet, amount, hashcode=sighash) + assert txid + + #Create an invalid sighash single (too many inputs) + extra = wallet.select_utxos(4, 100000000) #just a few more inputs + ins_full.update(extra) + with pytest.raises(Exception) as e_info: + txid = make_sign_and_push(ins_full, + wallet, + amount, + hashcode=btc.SIGHASH_SINGLE) + + #trigger insufficient funds + with pytest.raises(Exception) as e_info: + fake_utxos = wallet.select_utxos(4, 1000000000) + + +def test_spend_p2sh_utxos(setup_tx_creation): + #make a multisig address from 3 privs + privs = [chr(x) * 32 + '\x01' for x in range(1, 4)] + pubs = [btc.privkey_to_pubkey(binascii.hexlify(priv)) for priv in privs] + script = btc.mk_multisig_script(pubs, 2) + msig_addr = btc.scriptaddr(script, magicbyte=196) + #pay into it + wallet = make_wallets(1, [[2, 0, 0, 0, 1]], 3)[0]['wallet'] + jm_single().bc_interface.sync_wallet(wallet) + amount = 350000000 + ins_full = wallet.select_utxos(0, amount) + txid = make_sign_and_push(ins_full, wallet, amount, output_addr=msig_addr) + assert txid + #wait for mining + time.sleep(4) + #spend out; the input can be constructed from the txid of previous + msig_in = txid + ":0" + ins = [msig_in] + #random output address and change addr + output_addr = wallet.get_new_addr(1, 1) + amount2 = amount - 50000 + outs = [{'value': amount2, 'address': output_addr}] + tx = btc.mktx(ins, outs) + sigs = [] + for priv in privs[:2]: + sigs.append(btc.multisign(tx, 0, script, binascii.hexlify(priv))) + tx = btc.apply_multisignatures(tx, 0, script, sigs) + txid = jm_single().bc_interface.pushtx(tx) + assert txid + + +@pytest.fixture(scope="module") +def setup_tx_creation(): + load_program_config() diff --git a/test/test_tx_serialize.py b/test/test_tx_serialize.py index b841db14..a605c1e3 100644 --- a/test/test_tx_serialize.py +++ b/test/test_tx_serialize.py @@ -199,7 +199,21 @@ def test_serialization_roundtrip(tx_type, tx_id, tx_hex): assert tx_hex == btc.serialize(btc.deserialize(tx_hex)) +@pytest.mark.parametrize( + "ins, outs, txtype, valid", + [ + (4, 3, "p2pkh", True), + (4, 3, "p2sh", False), + ]) +def test_estimate_tx_size(ins, outs, txtype, valid): + #TODO: this function should throw on invalid number of ins or outs + if valid: + assert btc.estimate_tx_size(ins, outs, txtype)== 10 + 147*ins + 34*outs + else: + with pytest.raises(NotImplementedError) as e_info: + btc.estimate_tx_size(ins, outs, txtype) + def test_serialization_roundtrip2(): #Data extracted from: #https://github.com/bitcoin/bitcoin/blob/master/src/test/data/tx_valid.json @@ -209,7 +223,6 @@ def test_serialization_roundtrip2(): #only currently of very limited significance with open("test/tx_valid.json", "r") as f: json_data = f.read() - print 'read the tx data' valid_txs = json.loads(json_data) for j in valid_txs: #ignore comment entries diff --git a/test/test_wallets.py b/test/test_wallets.py index 9b313ba2..74f5313e 100644 --- a/test/test_wallets.py +++ b/test/test_wallets.py @@ -197,6 +197,34 @@ def run_recover(self, seed): return False return True +def test_pkcs7_bad_padding(): + #used in seed decryption; check that it throws + #if wrongly padded (this caused a REAL bug before!) + import joinmarket.slowaes + bad_padded = ['\x07'*14, '\x07'*31, '\x07'*31+'\x11', '\x07'*31+'\x00', + '\x07'*14+'\x01\x02'] + for b in bad_padded: + with pytest.raises(Exception) as e_info: + fake_unpadded = joinmarket.slowaes.strip_PKCS7_padding(b) + +def test_aes(): + #test general AES operation; probably not needed + import joinmarket.slowaes as sa + cleartext = "This is a test!" + iv = [103, 35, 148, 239, 76, 213, 47, 118, 255, 222, 123, 176, 106, 134, 98, + 92] + for ks in [16,24,32]: + for mode in ["CFB", "CBC", "OFB"]: + cypherkey = map(ord, os.urandom(ks)) + moo = sa.AESModeOfOperation() + mode, orig_len, ciph = moo.encrypt(cleartext, moo.modeOfOperation[mode], + cypherkey, ks, + iv) + decr = moo.decrypt(ciph, orig_len, mode, cypherkey, + ks, iv) + assert decr==cleartext + + @pytest.fixture(scope="module") def setup_wallets(): load_program_config()