Version 0.3.1, rev238, Connection encryption using TLS, One click site clone feature, Encryption stats, Disable encryption startup parameter, Disable ssl compression startup parameter, Exchange supported encryption methods at handshake, Alternative open port checker, Option to store site privatekey in users.json, Torrent tracker swap, Test for bip32 based site creation, cloning and sslcert creation, Fix for Chrome plugin on OSX, Separate siteSign websocket command, Update pybitcointools to major speedup, Re-add sslwrap for python 0.2.9+, Disable SSL compression to save memory and better performance
This commit is contained in:
parent
f0597afe1f
commit
a78907cc9d
64 changed files with 4141 additions and 213 deletions
10
src/lib/opensslVerify/gencert.cmd
Normal file
10
src/lib/opensslVerify/gencert.cmd
Normal file
|
@ -0,0 +1,10 @@
|
|||
openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -nodes -config openssl.cnf
|
||||
REM openssl ecparam -name secp521r1 -genkey -param_enc explicit -out key-ecc.pem -config openssl.cnf
|
||||
|
||||
openssl ecparam -name secp256r1 -genkey -out key-ecc.pem
|
||||
openssl req -new -key key-ecc.pem -x509 -nodes -out cert-ecc.pem -config openssl.cnf
|
||||
|
||||
@echo off
|
||||
REM openssl ecparam -genkey -name prime256v1 -out key.pem
|
||||
REM openssl req -new -key key.pem -out csr.pem
|
||||
REM openssl req -x509 -days 365 -key key.pem -in csr.pem -out certificate.pem
|
70
src/lib/opensslVerify/openssl.cnf
Normal file
70
src/lib/opensslVerify/openssl.cnf
Normal file
|
@ -0,0 +1,70 @@
|
|||
[ req ]
|
||||
prompt = no
|
||||
default_bits = 2048
|
||||
default_keyfile = server-key.pem
|
||||
distinguished_name = subject
|
||||
req_extensions = req_ext
|
||||
x509_extensions = x509_ext
|
||||
string_mask = utf8only
|
||||
|
||||
# The Subject DN can be formed using X501 or RFC 4514 (see RFC 4519 for a description).
|
||||
# Its sort of a mashup. For example, RFC 4514 does not provide emailAddress.
|
||||
[ subject ]
|
||||
countryName = US
|
||||
stateOrProvinceName = NY
|
||||
localityName = New York
|
||||
organizationName = Example, LLC
|
||||
|
||||
# Use a friendly name here because its presented to the user. The server's DNS
|
||||
# names are placed in Subject Alternate Names. Plus, DNS names here is deprecated
|
||||
# by both IETF and CA/Browser Forums. If you place a DNS name here, then you
|
||||
# must include the DNS name in the SAN too (otherwise, Chrome and others that
|
||||
# strictly follow the CA/Browser Baseline Requirements will fail).
|
||||
commonName = Example Company
|
||||
|
||||
emailAddress = test@example.com
|
||||
|
||||
# Section x509_ext is used when generating a self-signed certificate. I.e., openssl req -x509 ...
|
||||
[ x509_ext ]
|
||||
|
||||
subjectKeyIdentifier = hash
|
||||
authorityKeyIdentifier = keyid,issuer
|
||||
|
||||
basicConstraints = CA:FALSE
|
||||
keyUsage = digitalSignature, keyEncipherment
|
||||
subjectAltName = @alternate_names
|
||||
nsComment = "OpenSSL Generated Certificate"
|
||||
|
||||
# RFC 5280, Section 4.2.1.12 makes EKU optional
|
||||
# CA/Browser Baseline Requirements, Appendix (B)(3)(G) makes me confused
|
||||
# extendedKeyUsage = serverAuth, clientAuth
|
||||
|
||||
# Section req_ext is used when generating a certificate signing request. I.e., openssl req ...
|
||||
[ req_ext ]
|
||||
|
||||
subjectKeyIdentifier = hash
|
||||
|
||||
basicConstraints = CA:FALSE
|
||||
keyUsage = digitalSignature, keyEncipherment
|
||||
subjectAltName = @alternate_names
|
||||
nsComment = "OpenSSL Generated Certificate"
|
||||
|
||||
# RFC 5280, Section 4.2.1.12 makes EKU optional
|
||||
# CA/Browser Baseline Requirements, Appendix (B)(3)(G) makes me confused
|
||||
# extendedKeyUsage = serverAuth, clientAuth
|
||||
|
||||
[ alternate_names ]
|
||||
|
||||
DNS.1 = example.com
|
||||
DNS.2 = www.example.com
|
||||
DNS.3 = mail.example.com
|
||||
DNS.4 = ftp.example.com
|
||||
|
||||
# Add these if you need them. But usually you don't want them or
|
||||
# need them in production. You may need them for development.
|
||||
# DNS.5 = localhost
|
||||
# DNS.6 = localhost.localdomain
|
||||
# DNS.7 = 127.0.0.1
|
||||
|
||||
# IPv6 localhost
|
||||
# DNS.8 = ::1
|
BIN
src/lib/opensslVerify/openssl.exe
Normal file
BIN
src/lib/opensslVerify/openssl.exe
Normal file
Binary file not shown.
BIN
src/lib/opensslVerify/ssleay32.dll
Normal file
BIN
src/lib/opensslVerify/ssleay32.dll
Normal file
Binary file not shown.
|
@ -23,16 +23,26 @@ def make_request(*args):
|
|||
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 unspent(*args):
|
||||
# Valid input formats: unspent([addr1, addr2,addr3])
|
||||
# unspent(addr1, addr2, addr3)
|
||||
if len(args) == 0:
|
||||
return []
|
||||
elif isinstance(args[0], list):
|
||||
addrs = args[0]
|
||||
else:
|
||||
addrs = args
|
||||
def bci_unspent(*args):
|
||||
network, addrs = parse_addr_args(*args)
|
||||
u = []
|
||||
for a in addrs:
|
||||
try:
|
||||
|
@ -61,11 +71,7 @@ def blockr_unspent(*args):
|
|||
# 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]
|
||||
network, addr_args = parse_addr_args(*args)
|
||||
|
||||
if network == 'testnet':
|
||||
blockr_url = 'https://tbtc.blockr.io/api/v1/address/unspent/'
|
||||
|
@ -95,6 +101,41 @@ def blockr_unspent(*args):
|
|||
return o
|
||||
|
||||
|
||||
def helloblock_unspent(*args):
|
||||
network, addrs = parse_addr_args(*args)
|
||||
if network == 'testnet':
|
||||
url = 'https://testnet.helloblock.io/v1/addresses/%s/unspents?limit=500&offset=%s'
|
||||
elif network == 'btc':
|
||||
url = 'https://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):
|
||||
|
@ -145,7 +186,7 @@ def history(*args):
|
|||
|
||||
|
||||
# Pushes a transaction to the network using https://blockchain.info/pushtx
|
||||
def pushtx(tx):
|
||||
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)
|
||||
|
@ -184,6 +225,17 @@ def helloblock_pushtx(tx):
|
|||
return make_request('https://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')
|
||||
|
@ -213,11 +265,54 @@ def blockr_fetchtx(txhash, network='btc'):
|
|||
return jsondata['data']['tx']['hex']
|
||||
|
||||
|
||||
def fetchtx(txhash):
|
||||
try:
|
||||
return bci_fetchtx(txhash)
|
||||
except:
|
||||
return blockr_fetchtx(txhash)
|
||||
def helloblock_fetchtx(txhash, network='btc'):
|
||||
if not re.match('^[0-9a-fA-F]*$', txhash):
|
||||
txhash = txhash.encode('hex')
|
||||
if network == 'testnet':
|
||||
url = 'https://testnet.helloblock.io/v1/transactions/'
|
||||
elif network == 'btc':
|
||||
url = 'https://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):
|
||||
|
@ -257,6 +352,26 @@ def get_block_header_data(inp):
|
|||
'nonce': j['nonce'],
|
||||
}
|
||||
|
||||
def blockr_get_block_header_data(height, network='btc'):
|
||||
if network == 'testnet':
|
||||
blockr_url = "https://tbtc.blockr.io/api/v1/block/raw/"
|
||||
elif network == 'btc':
|
||||
blockr_url = "https://btc.blockr.io/api/v1/block/raw/"
|
||||
else:
|
||||
raise Exception(
|
||||
'Unsupported network {0} for blockr_get_block_header_data'.format(network))
|
||||
|
||||
k = json.loads(make_request(blockr_url + str(height)))
|
||||
j = k['data']
|
||||
return {
|
||||
'version': j['version'],
|
||||
'hash': j['hash'],
|
||||
'prevhash': j['previousblockhash'],
|
||||
'timestamp': j['time'],
|
||||
'merkle_root': j['merkleroot'],
|
||||
'bits': int(j['bits'], 16),
|
||||
'nonce': j['nonce'],
|
||||
}
|
||||
|
||||
def get_txs_in_block(inp):
|
||||
j = _get_block(inp)
|
||||
|
|
|
@ -28,13 +28,15 @@ def deserialize_header(inp):
|
|||
|
||||
def mk_merkle_proof(header, hashes, index):
|
||||
nodes = [h.decode('hex')[::-1] for h in hashes]
|
||||
if len(nodes) % 2 and len(nodes) > 2:
|
||||
nodes.append(nodes[-1])
|
||||
layers = [nodes]
|
||||
while len(nodes) > 1:
|
||||
newnodes = []
|
||||
for i in range(0, len(nodes) - 1, 2):
|
||||
newnodes.append(bin_sha256(bin_sha256(nodes[i] + nodes[i+1])))
|
||||
if len(nodes) % 2:
|
||||
newnodes.append(bin_sha256(bin_sha256(nodes[-1] + nodes[-1])))
|
||||
if len(newnodes) % 2 and len(newnodes) > 2:
|
||||
newnodes.append(newnodes[-1])
|
||||
nodes = newnodes
|
||||
layers.append(nodes)
|
||||
# Sanity check, make sure merkle root is valid
|
||||
|
|
|
@ -11,30 +11,7 @@ def send(frm, to, value, fee=10000):
|
|||
|
||||
|
||||
# Takes privkey, "address1:value1,address2:value2" (satoshis), fee (satoshis)
|
||||
def sendmultitx(frm, tovalues, fee=10000):
|
||||
outs = []
|
||||
outvalue = 0
|
||||
tv = tovalues.split(",")
|
||||
for a in tv:
|
||||
outs.append(a)
|
||||
outvalue += int(a.split(":")[1])
|
||||
|
||||
u = unspent(privtoaddr(frm))
|
||||
u2 = select(u, int(outvalue)+int(fee))
|
||||
argz = u2 + outs + [frm, fee]
|
||||
tx = mksend(*argz)
|
||||
tx2 = signall(tx, frm)
|
||||
return pushtx(tx2)
|
||||
|
||||
|
||||
# Takes address, address, value (satoshis), fee(satoshis)
|
||||
def preparetx(frm, to, value, fee=10000):
|
||||
tovalues = to + ":" + str(value)
|
||||
return preparemultitx(frm, tovalues, fee)
|
||||
|
||||
|
||||
# Takes address, address:value, address:value ... (satoshis), fee(satoshis)
|
||||
def preparemultitx(frm, *args):
|
||||
def sendmultitx(frm, tovalues, fee=10000, **kwargs):
|
||||
tv, fee = args[:-1], int(args[-1])
|
||||
outs = []
|
||||
outvalue = 0
|
||||
|
@ -42,7 +19,30 @@ def preparemultitx(frm, *args):
|
|||
outs.append(a)
|
||||
outvalue += int(a.split(":")[1])
|
||||
|
||||
u = unspent(frm)
|
||||
u = unspent(privtoaddr(frm), **kwargs)
|
||||
u2 = select(u, int(outvalue)+int(fee))
|
||||
argz = u2 + outs + [frm, fee]
|
||||
tx = mksend(*argz)
|
||||
tx2 = signall(tx, frm)
|
||||
return pushtx(tx2, **kwargs)
|
||||
|
||||
|
||||
# Takes address, address, value (satoshis), fee(satoshis)
|
||||
def preparetx(frm, to, value, fee=10000, **kwargs):
|
||||
tovalues = to + ":" + str(value)
|
||||
return preparemultitx(frm, tovalues, fee, **kwargs)
|
||||
|
||||
|
||||
# Takes address, address:value, address:value ... (satoshis), fee(satoshis)
|
||||
def preparemultitx(frm, *args, **kwargs):
|
||||
tv, fee = args[:-1], int(args[-1])
|
||||
outs = []
|
||||
outvalue = 0
|
||||
for a in tv:
|
||||
outs.append(a)
|
||||
outvalue += int(a.split(":")[1])
|
||||
|
||||
u = unspent(frm, **kwargs)
|
||||
u2 = select(u, int(outvalue)+int(fee))
|
||||
argz = u2 + outs + [frm, fee]
|
||||
return mksend(*argz)
|
||||
|
@ -96,14 +96,14 @@ def sign_coinvault_tx(tx, priv):
|
|||
|
||||
|
||||
# Inspects a transaction
|
||||
def inspect(tx):
|
||||
def inspect(tx, **kwargs):
|
||||
d = deserialize(tx)
|
||||
isum = 0
|
||||
ins = {}
|
||||
for _in in d['ins']:
|
||||
h = _in['outpoint']['hash']
|
||||
i = _in['outpoint']['index']
|
||||
prevout = deserialize(fetchtx(h))['outs'][i]
|
||||
prevout = deserialize(fetchtx(h, **kwargs))['outs'][i]
|
||||
isum += prevout['value']
|
||||
a = script_to_address(prevout['script'])
|
||||
ins[a] = ins.get(a, 0) + prevout['value']
|
||||
|
|
|
@ -59,8 +59,12 @@ def crack_electrum_wallet(mpk, pk, n, for_change=0):
|
|||
return subtract_privkeys(pk, offset)
|
||||
|
||||
# Below code ASSUMES binary inputs and compressed pubkeys
|
||||
PRIVATE = b'\x04\x88\xAD\xE4'
|
||||
PUBLIC = b'\x04\x88\xB2\x1E'
|
||||
MAINNET_PRIVATE = b'\x04\x88\xAD\xE4'
|
||||
MAINNET_PUBLIC = b'\x04\x88\xB2\x1E'
|
||||
TESTNET_PRIVATE = b'\x04\x35\x83\x94'
|
||||
TESTNET_PUBLIC = b'\x04\x35\x87\xCF'
|
||||
PRIVATE = [MAINNET_PRIVATE, TESTNET_PRIVATE]
|
||||
PUBLIC = [MAINNET_PUBLIC, TESTNET_PUBLIC]
|
||||
|
||||
# BIP32 child key derivation
|
||||
|
||||
|
@ -69,23 +73,23 @@ def raw_bip32_ckd(rawtuple, i):
|
|||
vbytes, depth, fingerprint, oldi, chaincode, key = rawtuple
|
||||
i = int(i)
|
||||
|
||||
if vbytes == PRIVATE:
|
||||
if vbytes in PRIVATE:
|
||||
priv = key
|
||||
pub = privtopub(key)
|
||||
else:
|
||||
pub = key
|
||||
|
||||
if i >= 2**31:
|
||||
if vbytes == PUBLIC:
|
||||
if vbytes in PUBLIC:
|
||||
raise Exception("Can't do private derivation on public key!")
|
||||
I = hmac.new(chaincode, b'\x00'+priv[:32]+encode(i, 256, 4), hashlib.sha512).digest()
|
||||
else:
|
||||
I = hmac.new(chaincode, pub+encode(i, 256, 4), hashlib.sha512).digest()
|
||||
|
||||
if vbytes == PRIVATE:
|
||||
newkey = add_privkeys(I[:32]+b'\x01', priv)
|
||||
if vbytes in PRIVATE:
|
||||
newkey = add_privkeys(I[:32]+B'\x01', priv)
|
||||
fingerprint = bin_hash160(privtopub(key))[:4]
|
||||
if vbytes == PUBLIC:
|
||||
if vbytes in PUBLIC:
|
||||
newkey = add_pubkeys(compress(privtopub(I[:32])), key)
|
||||
fingerprint = bin_hash160(key)[:4]
|
||||
|
||||
|
@ -96,7 +100,7 @@ def bip32_serialize(rawtuple):
|
|||
vbytes, depth, fingerprint, i, chaincode, key = rawtuple
|
||||
i = encode(i, 256, 4)
|
||||
chaincode = encode(hash_to_int(chaincode), 256, 32)
|
||||
keydata = b'\x00'+key[:-1] if vbytes == PRIVATE else key
|
||||
keydata = b'\x00'+key[:-1] if vbytes in PRIVATE else key
|
||||
bindata = vbytes + from_int_to_byte(depth % 256) + fingerprint + i + chaincode + keydata
|
||||
return changebase(bindata+bin_dbl_sha256(bindata)[:4], 256, 58)
|
||||
|
||||
|
@ -110,13 +114,14 @@ def bip32_deserialize(data):
|
|||
fingerprint = dbin[5:9]
|
||||
i = decode(dbin[9:13], 256)
|
||||
chaincode = dbin[13:45]
|
||||
key = dbin[46:78]+b'\x01' if vbytes == PRIVATE else dbin[45:78]
|
||||
key = dbin[46:78]+b'\x01' if vbytes in PRIVATE else dbin[45:78]
|
||||
return (vbytes, depth, fingerprint, i, chaincode, key)
|
||||
|
||||
|
||||
def raw_bip32_privtopub(rawtuple):
|
||||
vbytes, depth, fingerprint, i, chaincode, key = rawtuple
|
||||
return (PUBLIC, depth, fingerprint, i, chaincode, privtopub(key))
|
||||
newvbytes = MAINNET_PUBLIC if vbytes == MAINNET_PRIVATE else TESTNET_PUBLIC
|
||||
return (newvbytes, depth, fingerprint, i, chaincode, privtopub(key))
|
||||
|
||||
|
||||
def bip32_privtopub(data):
|
||||
|
@ -127,9 +132,9 @@ def bip32_ckd(data, i):
|
|||
return bip32_serialize(raw_bip32_ckd(bip32_deserialize(data), i))
|
||||
|
||||
|
||||
def bip32_master_key(seed):
|
||||
def bip32_master_key(seed, vbytes=MAINNET_PRIVATE):
|
||||
I = hmac.new(from_string_to_bytes("Bitcoin seed"), seed, hashlib.sha512).digest()
|
||||
return bip32_serialize((PRIVATE, 0, b'\x00'*4, 0, I[32:], I[:32]+b'\x01'))
|
||||
return bip32_serialize((vbytes, 0, b'\x00'*4, 0, I[32:], I[:32]+b'\x01'))
|
||||
|
||||
|
||||
def bip32_bin_extract_key(data):
|
||||
|
@ -156,7 +161,8 @@ def raw_crack_bip32_privkey(parent_pub, priv):
|
|||
|
||||
pprivkey = subtract_privkeys(key, I[:32]+b'\x01')
|
||||
|
||||
return (PRIVATE, pdepth, pfingerprint, pi, pchaincode, pprivkey)
|
||||
newvbytes = MAINNET_PRIVATE if vbytes == MAINNET_PUBLIC else TESTNET_PRIVATE
|
||||
return (newvbytes, pdepth, pfingerprint, pi, pchaincode, pprivkey)
|
||||
|
||||
|
||||
def crack_bip32_privkey(parent_pub, priv):
|
||||
|
@ -171,7 +177,7 @@ def coinvault_pub_to_bip32(*args):
|
|||
vals = map(int, args[34:])
|
||||
I1 = ''.join(map(chr, vals[:33]))
|
||||
I2 = ''.join(map(chr, vals[35:67]))
|
||||
return bip32_serialize((PUBLIC, 0, b'\x00'*4, 0, I2, I1))
|
||||
return bip32_serialize((MAINNET_PUBLIC, 0, b'\x00'*4, 0, I2, I1))
|
||||
|
||||
|
||||
def coinvault_priv_to_bip32(*args):
|
||||
|
@ -180,11 +186,11 @@ def coinvault_priv_to_bip32(*args):
|
|||
vals = map(int, args[34:])
|
||||
I2 = ''.join(map(chr, vals[35:67]))
|
||||
I3 = ''.join(map(chr, vals[72:104]))
|
||||
return bip32_serialize((PRIVATE, 0, b'\x00'*4, 0, I2, I3+b'\x01'))
|
||||
return bip32_serialize((MAINNET_PRIVATE, 0, b'\x00'*4, 0, I2, I3+b'\x01'))
|
||||
|
||||
|
||||
def bip32_descend(*args):
|
||||
if len(args) == 2:
|
||||
if len(args) == 2 and isinstance(args[1], list):
|
||||
key, path = args
|
||||
else:
|
||||
key, path = args[0], map(int, args[1:])
|
||||
|
|
|
@ -36,6 +36,8 @@ def getG():
|
|||
|
||||
|
||||
def inv(a, n):
|
||||
if a == 0:
|
||||
return 0
|
||||
lm, hm = 1, 0
|
||||
low, high = a % n, n
|
||||
while low > 1:
|
||||
|
@ -79,95 +81,75 @@ 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
|
||||
|
||||
|
||||
def jordan_isinf(p):
|
||||
return p[0][0] == 0 and p[1][0] == 0
|
||||
def to_jacobian(p):
|
||||
o = (p[0], p[1], 1)
|
||||
return o
|
||||
|
||||
|
||||
def mulcoords(c1, c2):
|
||||
return (c1[0] * c2[0] % P, c1[1] * c2[1] % P)
|
||||
def jacobian_double(p):
|
||||
if not p[1]:
|
||||
return (0, 0, 0)
|
||||
ysq = (p[1] ** 2) % P
|
||||
S = (4 * p[0] * ysq) % P
|
||||
M = (3 * p[0] ** 2 + A * p[2] ** 4) % P
|
||||
nx = (M**2 - 2 * S) % P
|
||||
ny = (M * (S - nx) - 8 * ysq ** 2) % P
|
||||
nz = (2 * p[1] * p[2]) % P
|
||||
return (nx, ny, nz)
|
||||
|
||||
|
||||
def mul_by_const(c, v):
|
||||
return (c[0] * v % P, c[1])
|
||||
def jacobian_add(p, q):
|
||||
if not p[1]:
|
||||
return q
|
||||
if not q[1]:
|
||||
return p
|
||||
U1 = (p[0] * q[2] ** 2) % P
|
||||
U2 = (q[0] * p[2] ** 2) % P
|
||||
S1 = (p[1] * q[2] ** 3) % P
|
||||
S2 = (q[1] * p[2] ** 3) % P
|
||||
if U1 == U2:
|
||||
if S1 != S2:
|
||||
return (0, 0, 1)
|
||||
return jacobian_double(p)
|
||||
H = U2 - U1
|
||||
R = S2 - S1
|
||||
H2 = (H * H) % P
|
||||
H3 = (H * H2) % P
|
||||
U1H2 = (U1 * H2) % P
|
||||
nx = (R ** 2 - H3 - 2 * U1H2) % P
|
||||
ny = (R * (U1H2 - nx) - S1 * H3) % P
|
||||
nz = H * p[2] * q[2]
|
||||
return (nx, ny, nz)
|
||||
|
||||
|
||||
def addcoords(c1, c2):
|
||||
return ((c1[0] * c2[1] + c2[0] * c1[1]) % P, c1[1] * c2[1] % P)
|
||||
def from_jacobian(p):
|
||||
z = inv(p[2], P)
|
||||
return ((p[0] * z**2) % P, (p[1] * z**3) % P)
|
||||
|
||||
|
||||
def subcoords(c1, c2):
|
||||
return ((c1[0] * c2[1] - c2[0] * c1[1]) % P, c1[1] * c2[1] % P)
|
||||
|
||||
|
||||
def invcoords(c):
|
||||
return (c[1], c[0])
|
||||
|
||||
|
||||
def jordan_add(a, b):
|
||||
if jordan_isinf(a):
|
||||
return b
|
||||
if jordan_isinf(b):
|
||||
return a
|
||||
|
||||
if (a[0][0] * b[0][1] - b[0][0] * a[0][1]) % P == 0:
|
||||
if (a[1][0] * b[1][1] - b[1][0] * a[1][1]) % P == 0:
|
||||
return jordan_double(a)
|
||||
else:
|
||||
return ((0, 1), (0, 1))
|
||||
xdiff = subcoords(b[0], a[0])
|
||||
ydiff = subcoords(b[1], a[1])
|
||||
m = mulcoords(ydiff, invcoords(xdiff))
|
||||
x = subcoords(subcoords(mulcoords(m, m), a[0]), b[0])
|
||||
y = subcoords(mulcoords(m, subcoords(a[0], x)), a[1])
|
||||
return (x, y)
|
||||
|
||||
|
||||
def jordan_double(a):
|
||||
if jordan_isinf(a):
|
||||
return ((0, 1), (0, 1))
|
||||
num = addcoords(mul_by_const(mulcoords(a[0], a[0]), 3), (A, 1))
|
||||
den = mul_by_const(a[1], 2)
|
||||
m = mulcoords(num, invcoords(den))
|
||||
x = subcoords(mulcoords(m, m), mul_by_const(a[0], 2))
|
||||
y = subcoords(mulcoords(m, subcoords(a[0], x)), a[1])
|
||||
return (x, y)
|
||||
|
||||
|
||||
def jordan_multiply(a, n):
|
||||
if jordan_isinf(a) or n == 0:
|
||||
return ((0, 0), (0, 0))
|
||||
def jacobian_multiply(a, n):
|
||||
if a[1] == 0 or n == 0:
|
||||
return (0, 0, 1)
|
||||
if n == 1:
|
||||
return a
|
||||
if n < 0 or n >= N:
|
||||
return jordan_multiply(a, n % N)
|
||||
return jacobian_multiply(a, n % N)
|
||||
if (n % 2) == 0:
|
||||
return jordan_double(jordan_multiply(a, n//2))
|
||||
return jacobian_double(jacobian_multiply(a, n//2))
|
||||
if (n % 2) == 1:
|
||||
return jordan_add(jordan_double(jordan_multiply(a, n//2)), a)
|
||||
|
||||
|
||||
def to_jordan(p):
|
||||
return ((p[0], 1), (p[1], 1))
|
||||
|
||||
|
||||
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)
|
||||
return jacobian_add(jacobian_double(jacobian_multiply(a, n//2)), a)
|
||||
|
||||
|
||||
def fast_multiply(a, n):
|
||||
return from_jordan(jordan_multiply(to_jordan(a), n))
|
||||
return from_jacobian(jacobian_multiply(to_jacobian(a), n))
|
||||
|
||||
|
||||
def fast_add(a, b):
|
||||
return from_jordan(jordan_add(to_jordan(a), to_jordan(b)))
|
||||
return from_jacobian(jacobian_add(to_jacobian(a), to_jacobian(b)))
|
||||
|
||||
# Functions for handling pubkey and privkey formats
|
||||
|
||||
|
@ -181,7 +163,7 @@ def get_pubkey_format(pub):
|
|||
two = 2
|
||||
three = 3
|
||||
four = 4
|
||||
|
||||
|
||||
if isinstance(pub, (tuple, list)): return 'decimal'
|
||||
elif len(pub) == 65 and pub[0] == four: return 'bin'
|
||||
elif len(pub) == 130 and pub[0:2] == '04': return 'hex'
|
||||
|
@ -535,11 +517,11 @@ def ecdsa_raw_recover(msghash, vrs):
|
|||
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)
|
||||
Gz = jacobian_multiply((Gx, Gy, 1), (N - z) % N)
|
||||
XY = jacobian_multiply((x, y, 1), s)
|
||||
Qr = jacobian_add(Gz, XY)
|
||||
Q = jacobian_multiply(Qr, inv(r, N))
|
||||
Q = from_jacobian(Q)
|
||||
|
||||
if ecdsa_raw_verify(msghash, vrs, Q):
|
||||
return Q
|
||||
|
|
|
@ -60,7 +60,7 @@ if sys.version_info.major == 2:
|
|||
def from_byte_to_int(a):
|
||||
return ord(a)
|
||||
|
||||
def from_byes_to_string(s):
|
||||
def from_bytes_to_string(s):
|
||||
return s
|
||||
|
||||
def from_string_to_bytes(a):
|
||||
|
|
|
@ -38,7 +38,7 @@ if sys.version_info.major == 3:
|
|||
return encode(decode(string, frm), to, minlen)
|
||||
|
||||
def bin_to_b58check(inp, magicbyte=0):
|
||||
inp_fmtd = from_int_to_byte(magicbyte)+inp
|
||||
inp_fmtd = from_int_to_byte(int(magicbyte))+inp
|
||||
|
||||
leadingzbytes = 0
|
||||
for x in inp_fmtd:
|
||||
|
@ -84,7 +84,8 @@ if sys.version_info.major == 3:
|
|||
|
||||
pad_size = minlen - len(result_bytes)
|
||||
|
||||
padding_element = b'\x00' if base == 256 else b'0'
|
||||
padding_element = b'\x00' if base == 256 else b'1' \
|
||||
if base == 58 else b'0'
|
||||
if (pad_size > 0):
|
||||
result_bytes = padding_element*pad_size + result_bytes
|
||||
|
||||
|
|
|
@ -227,7 +227,7 @@ def script_to_address(script, vbyte=0):
|
|||
if script[:3] == b'\x76\xa9\x14' and script[-2:] == b'\x88\xac' and len(script) == 25:
|
||||
return bin_to_b58check(script[3:-2], vbyte) # pubkey hash addresses
|
||||
else:
|
||||
if vbyte == 111:
|
||||
if vbyte in [111, 196]:
|
||||
# Testnet
|
||||
scripthash_byte = 196
|
||||
else:
|
||||
|
@ -313,7 +313,7 @@ def mk_multisig_script(*args): # [pubs],k or pub1,pub2...pub[n],k
|
|||
else:
|
||||
pubs = list(filter(lambda x: len(str(x)) >= 32, args))
|
||||
k = int(args[len(pubs)])
|
||||
return serialize_script([k]+pubs+[len(pubs), 174])
|
||||
return serialize_script([k]+pubs+[len(pubs)]) + 'ae'
|
||||
|
||||
# Signing and verifying
|
||||
|
||||
|
|
|
@ -5,20 +5,32 @@ from bitcoin import *
|
|||
if len(sys.argv) == 1:
|
||||
print "pybtctool <command> <arg1> <arg2> ..."
|
||||
else:
|
||||
cmd = sys.argv[2] if sys.argv[1][0] == '-' else sys.argv[1]
|
||||
cmdargs, preargs, kwargs = [], [], {}
|
||||
i = 2
|
||||
# Process first arg tag
|
||||
if sys.argv[1] == '-s':
|
||||
args = re.findall(r'\S\S*',sys.stdin.read())+sys.argv[3:]
|
||||
preargs.extend(re.findall(r'\S\S*', sys.stdin.read()))
|
||||
elif sys.argv[1] == '-B':
|
||||
args = [sys.stdin.read()]+sys.argv[3:]
|
||||
preargs.extend([sys.stdin.read()])
|
||||
elif sys.argv[1] == '-b':
|
||||
args = [sys.stdin.read()[:-1]]+sys.argv[3:] # remove trailing \n
|
||||
preargs.extend([sys.stdin.read()[:-1]])
|
||||
elif sys.argv[1] == '-j':
|
||||
args = [json.loads(sys.stdin.read())]+sys.argv[3:]
|
||||
preargs.extend([json.loads(sys.stdin.read())])
|
||||
elif sys.argv[1] == '-J':
|
||||
args = json.loads(sys.stdin.read())+sys.argv[3:]
|
||||
preargs.extend(json.loads(sys.stdin.read()))
|
||||
else:
|
||||
cmd = sys.argv[1]
|
||||
args = sys.argv[2:]
|
||||
o = vars()[cmd](*args)
|
||||
if isinstance(o,(list,dict)): print json.dumps(o)
|
||||
else: print o
|
||||
i = 1
|
||||
while i < len(sys.argv):
|
||||
if sys.argv[i][:2] == '--':
|
||||
kwargs[sys.argv[i][2:]] = sys.argv[i+1]
|
||||
i += 2
|
||||
else:
|
||||
cmdargs.append(sys.argv[i])
|
||||
i += 1
|
||||
cmd = cmdargs[0]
|
||||
args = preargs + cmdargs[1:]
|
||||
o = vars()[cmd](*args, **kwargs)
|
||||
if isinstance(o, (list, dict)):
|
||||
print json.dumps(o)
|
||||
else:
|
||||
print o
|
||||
|
|
|
@ -5,12 +5,11 @@ except ImportError:
|
|||
from distutils.core import setup
|
||||
|
||||
setup(name='bitcoin',
|
||||
version='1.1.25',
|
||||
version='1.1.28',
|
||||
description='Python Bitcoin Tools',
|
||||
author='Vitalik Buterin',
|
||||
author_email='vbuterin@gmail.com',
|
||||
url='http://github.com/vbuterin/pybitcointools',
|
||||
install_requires='six==1.8.0',
|
||||
packages=['bitcoin'],
|
||||
scripts=['pybtctool'],
|
||||
include_package_data=True,
|
||||
|
|
|
@ -222,6 +222,20 @@ class TestTransaction(unittest.TestCase):
|
|||
tx2 = apply_multisignatures(tx1, 0, mscript, [sig1, sig3])
|
||||
print("Outputting transaction: ", tx2)
|
||||
|
||||
# https://github.com/vbuterin/pybitcointools/issues/71
|
||||
def test_multisig(self):
|
||||
script = mk_multisig_script(["0254236f7d1124fc07600ad3eec5ac47393bf963fbf0608bcce255e685580d16d9",
|
||||
"03560cad89031c412ad8619398bd43b3d673cb5bdcdac1afc46449382c6a8e0b2b"],
|
||||
2)
|
||||
|
||||
self.assertEqual(p2sh_scriptaddr(script), "33byJBaS5N45RHFcatTSt9ZjiGb6nK4iV3")
|
||||
|
||||
self.assertEqual(p2sh_scriptaddr(script, 0x05), "33byJBaS5N45RHFcatTSt9ZjiGb6nK4iV3")
|
||||
self.assertEqual(p2sh_scriptaddr(script, 5), "33byJBaS5N45RHFcatTSt9ZjiGb6nK4iV3")
|
||||
|
||||
self.assertEqual(p2sh_scriptaddr(script, 0xc4), "2MuABMvWTgpZRd4tAG25KW6YzvcoGVZDZYP")
|
||||
self.assertEqual(p2sh_scriptaddr(script, 196), "2MuABMvWTgpZRd4tAG25KW6YzvcoGVZDZYP")
|
||||
|
||||
|
||||
class TestDeterministicGenerate(unittest.TestCase):
|
||||
@classmethod
|
||||
|
@ -298,6 +312,70 @@ class TestBIP0032(unittest.TestCase):
|
|||
)
|
||||
)
|
||||
|
||||
def test_all_testnet(self):
|
||||
test_vectors = [
|
||||
[[], 'tprv8ZgxMBicQKsPeDgjzdC36fs6bMjGApWDNLR9erAXMs5skhMv36j9MV5ecvfavji5khqjWaWSFhN3YcCUUdiKH6isR4Pwy3U5y5egddBr16m'],
|
||||
[['pub'], 'tpubD6NzVbkrYhZ4XgiXtGrdW5XDAPFCL9h7we1vwNCpn8tGbBcgfVYjXyhWo4E1xkh56hjod1RhGjxbaTLV3X4FyWuejifB9jusQ46QzG87VKp'],
|
||||
[[2**31], 'tprv8bxNLu25VazNnppTCP4fyhyCvBHcYtzE3wr3cwYeL4HA7yf6TLGEUdS4QC1vLT63TkjRssqJe4CvGNEC8DzW5AoPUw56D1Ayg6HY4oy8QZ9'],
|
||||
[[2**31, 1], 'tprv8e8VYgZxtHsSdGrtvdxYaSrryZGiYviWzGWtDDKTGh5NMXAEB8gYSCLHpFCywNs5uqV7ghRjimALQJkRFZnUrLHpzi2pGkwqLtbubgWuQ8q'],
|
||||
[[2**31, 1, 2**31 + 2], 'tprv8gjmbDPpbAirVSezBEMuwSu1Ci9EpUJWKokZTYccSZSomNMLytWyLdtDNHRbucNaRJWWHANf9AzEdWVAqahfyRjVMKbNRhBmxAM8EJr7R15'],
|
||||
[[2**31, 1, 2**31 + 2, 'pub', 2, 1000000000], 'tpubDHNy3kAG39ThyiwwsgoKY4iRenXDRtce8qdCFJZXPMCJg5dsCUHayp84raLTpvyiNA9sXPob5rgqkKvkN8S7MMyXbnEhGJMW64Cf4vFAoaF']
|
||||
]
|
||||
|
||||
mk = bip32_master_key(safe_from_hex('000102030405060708090a0b0c0d0e0f'), TESTNET_PRIVATE)
|
||||
|
||||
for tv in test_vectors:
|
||||
left, right = self._full_derive(mk, tv[0]), tv[1]
|
||||
self.assertEqual(
|
||||
left,
|
||||
right,
|
||||
"Test vector does not match. Details:\n%s\n%s\n%s\n\%s" % (
|
||||
left,
|
||||
tv[0],
|
||||
[x.encode('hex') if isinstance(x, str) else x for x in bip32_deserialize(left)],
|
||||
[x.encode('hex') if isinstance(x, str) else x for x in bip32_deserialize(right)],
|
||||
)
|
||||
)
|
||||
|
||||
def test_extra(self):
|
||||
master = bip32_master_key(safe_from_hex("000102030405060708090a0b0c0d0e0f"))
|
||||
|
||||
# m/0
|
||||
assert bip32_ckd(master, "0") == "xprv9uHRZZhbkedL37eZEnyrNsQPFZYRAvjy5rt6M1nbEkLSo378x1CQQLo2xxBvREwiK6kqf7GRNvsNEchwibzXaV6i5GcsgyjBeRguXhKsi4R"
|
||||
assert bip32_privtopub(bip32_ckd(master, "0")) == "xpub68Gmy5EVb2BdFbj2LpWrk1M7obNuaPTpT5oh9QCCo5sRfqSHVYWex97WpDZzszdzHzxXDAzPLVSwybe4uPYkSk4G3gnrPqqkV9RyNzAcNJ1"
|
||||
|
||||
# m/1
|
||||
assert bip32_ckd(master, "1") == "xprv9uHRZZhbkedL4yTpidDvuVfrdUkTbhDHviERRBkbzbNDZeMjWzqzKAdxWhzftGDSxDmBdakjqHiZJbkwiaTEXJdjZAaAjMZEE3PMbMrPJih"
|
||||
assert bip32_privtopub(bip32_ckd(master, "1")) == "xpub68Gmy5EVb2BdHTYHpekwGdcbBWax19w9HwA2DaADYvuCSSgt4YAErxxSN1KWSnmyqkwRNbnTj3XiUBKmHeC8rTjLRPjSULcDKQQgfgJDppq"
|
||||
|
||||
# m/0/0
|
||||
assert bip32_ckd(bip32_ckd(master, "0"), "0") == "xprv9ww7sMFLzJMzur2oEQDB642fbsMS4q6JRraMVTrM9bTWBq7NDS8ZpmsKVB4YF3mZecqax1fjnsPF19xnsJNfRp4RSyexacULXMKowSACTRc"
|
||||
assert bip32_privtopub(bip32_ckd(bip32_ckd(master, "0"), "0")) == "xpub6AvUGrnEpfvJ8L7GLRkBTByQ9uBvUHp9o5VxHrFxhvzV4dSWkySpNaBoLR9FpbnwRmTa69yLHF3QfcaxbWT7gWdwws5k4dpmJvqpEuMWwnj"
|
||||
|
||||
# m/0'
|
||||
assert bip32_ckd(master, 2**31) == "xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7"
|
||||
assert bip32_privtopub(bip32_ckd(master, 2**31)) == "xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw"
|
||||
|
||||
# m/1'
|
||||
assert bip32_ckd(master, 2**31 + 1) == "xprv9uHRZZhk6KAJFszJGW6LoUFq92uL7FvkBhmYiMurCWPHLJZkX2aGvNdRUBNnJu7nv36WnwCN59uNy6sxLDZvvNSgFz3TCCcKo7iutQzpg78"
|
||||
assert bip32_privtopub(bip32_ckd(master, 2**31 + 1)) == "xpub68Gmy5EdvgibUN4mNXdMAcCZh4jpWiebYvh9WkKTkqvGD6tu4ZtXUAwuKSyF5DFZVmotf9UHFTGqSXo9qyDBSn47RkaN6Aedt9JbL7zcgSL"
|
||||
|
||||
# m/1'
|
||||
assert bip32_ckd(master, 1 + 2**31) == "xprv9uHRZZhk6KAJFszJGW6LoUFq92uL7FvkBhmYiMurCWPHLJZkX2aGvNdRUBNnJu7nv36WnwCN59uNy6sxLDZvvNSgFz3TCCcKo7iutQzpg78"
|
||||
assert bip32_privtopub(bip32_ckd(master, 1 + 2**31)) == "xpub68Gmy5EdvgibUN4mNXdMAcCZh4jpWiebYvh9WkKTkqvGD6tu4ZtXUAwuKSyF5DFZVmotf9UHFTGqSXo9qyDBSn47RkaN6Aedt9JbL7zcgSL"
|
||||
|
||||
# m/0'/0
|
||||
assert bip32_ckd(bip32_ckd(master, 2**31), "0") == "xprv9wTYmMFdV23N21MM6dLNavSQV7Sj7meSPXx6AV5eTdqqGLjycVjb115Ec5LgRAXscPZgy5G4jQ9csyyZLN3PZLxoM1h3BoPuEJzsgeypdKj"
|
||||
assert bip32_privtopub(bip32_ckd(bip32_ckd(master, 2**31), "0")) == "xpub6ASuArnXKPbfEVRpCesNx4P939HDXENHkksgxsVG1yNp9958A33qYoPiTN9QrJmWFa2jNLdK84bWmyqTSPGtApP8P7nHUYwxHPhqmzUyeFG"
|
||||
|
||||
# m/0'/0'
|
||||
assert bip32_ckd(bip32_ckd(master, 2**31), 2**31) == "xprv9wTYmMFmpgaLB5Hge4YtaGqCKpsYPTD9vXWSsmdZrNU3Y2i4WoBykm6ZteeCLCCZpGxdHQuqEhM6Gdo2X6CVrQiTw6AAneF9WSkA9ewaxtS"
|
||||
assert bip32_privtopub(bip32_ckd(bip32_ckd(master, 2**31), 2**31)) == "xpub6ASuArnff48dPZN9k65twQmvsri2nuw1HkS3gA3BQi12Qq3D4LWEJZR3jwCAr1NhsFMcQcBkmevmub6SLP37bNq91SEShXtEGUbX3GhNaGk"
|
||||
|
||||
# m/44'/0'/0'/0/0
|
||||
assert bip32_ckd(bip32_ckd(bip32_ckd(bip32_ckd(bip32_ckd(master, 44 + 2**31), 2**31), 2**31), 0), 0) == "xprvA4A9CuBXhdBtCaLxwrw64Jaran4n1rgzeS5mjH47Ds8V67uZS8tTkG8jV3BZi83QqYXPcN4v8EjK2Aof4YcEeqLt688mV57gF4j6QZWdP9U"
|
||||
assert bip32_privtopub(bip32_ckd(bip32_ckd(bip32_ckd(bip32_ckd(bip32_ckd(master, 44 + 2**31), 2**31), 2**31), 0), 0)) == "xpub6H9VcQiRXzkBR4RS3tU6RSXb8ouGRKQr1f1NXfTinCfTxvEhygCiJ4TDLHz1dyQ6d2Vz8Ne7eezkrViwaPo2ZMsNjVtFwvzsQXCDV6HJ3cV"
|
||||
|
||||
|
||||
class TestStartingAddressAndScriptGenerationConsistency(unittest.TestCase):
|
||||
@classmethod
|
||||
|
@ -308,8 +386,27 @@ class TestStartingAddressAndScriptGenerationConsistency(unittest.TestCase):
|
|||
for i in range(5):
|
||||
a = privtoaddr(random_key())
|
||||
self.assertEqual(a, script_to_address(address_to_script(a)))
|
||||
self.assertEqual(a, script_to_address(address_to_script(a), 0))
|
||||
self.assertEqual(a, script_to_address(address_to_script(a), 0x00))
|
||||
|
||||
b = privtoaddr(random_key(), 5)
|
||||
self.assertEqual(b, script_to_address(address_to_script(b)))
|
||||
self.assertEqual(b, script_to_address(address_to_script(b), 0))
|
||||
self.assertEqual(b, script_to_address(address_to_script(b), 0x00))
|
||||
self.assertEqual(b, script_to_address(address_to_script(b), 5))
|
||||
self.assertEqual(b, script_to_address(address_to_script(b), 0x05))
|
||||
|
||||
|
||||
for i in range(5):
|
||||
a = privtoaddr(random_key(), 0x6f)
|
||||
self.assertEqual(a, script_to_address(address_to_script(a), 111))
|
||||
self.assertEqual(a, script_to_address(address_to_script(a), 0x6f))
|
||||
|
||||
b = privtoaddr(random_key(), 0xc4)
|
||||
self.assertEqual(b, script_to_address(address_to_script(b), 111))
|
||||
self.assertEqual(b, script_to_address(address_to_script(b), 0x6f))
|
||||
self.assertEqual(b, script_to_address(address_to_script(b), 196))
|
||||
self.assertEqual(b, script_to_address(address_to_script(b), 0xc4))
|
||||
|
||||
|
||||
class TestRipeMD160PythonBackup(unittest.TestCase):
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue