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:
HelloZeroNet 2015-06-10 00:29:30 +02:00
parent f0597afe1f
commit a78907cc9d
64 changed files with 4141 additions and 213 deletions

View 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

View 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

Binary file not shown.

Binary file not shown.

View file

@ -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)

View file

@ -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

View file

@ -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']

View file

@ -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:])

View file

@ -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

View file

@ -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):

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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,

View file

@ -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):