commit
4e8e7425a2
|
@ -0,0 +1,192 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
import struct
|
||||||
|
|
||||||
|
from zc_utils import write_compact_size
|
||||||
|
|
||||||
|
MAX_MONEY = 21000000 * 100000000
|
||||||
|
TX_EXPIRY_HEIGHT_THRESHOLD = 500000000
|
||||||
|
|
||||||
|
OVERWINTER_VERSION_GROUP_ID = 0x03C48270
|
||||||
|
OVERWINTER_TX_VERSION = 3
|
||||||
|
|
||||||
|
|
||||||
|
# BN254 encoding of G1 elements. p[1] is big-endian.
|
||||||
|
def pack_g1(p):
|
||||||
|
return struct.pack('B', 0x02 | (1 if p[0] else 0)) + p[1]
|
||||||
|
|
||||||
|
# BN254 encoding of G2 elements. p[1] is big-endian.
|
||||||
|
def pack_g2(p):
|
||||||
|
return struct.pack('B', 0x0a | (1 if p[0] else 0)) + p[1]
|
||||||
|
|
||||||
|
class PHGRProof(object):
|
||||||
|
def __init__(self, rand):
|
||||||
|
self.g_A = (rand.bool(), rand.b(32))
|
||||||
|
self.g_A_prime = (rand.bool(), rand.b(32))
|
||||||
|
self.g_B = (rand.bool(), rand.b(64))
|
||||||
|
self.g_B_prime = (rand.bool(), rand.b(32))
|
||||||
|
self.g_C = (rand.bool(), rand.b(32))
|
||||||
|
self.g_C_prime = (rand.bool(), rand.b(32))
|
||||||
|
self.g_K = (rand.bool(), rand.b(32))
|
||||||
|
self.g_H = (rand.bool(), rand.b(32))
|
||||||
|
|
||||||
|
def __bytes__(self):
|
||||||
|
return (
|
||||||
|
pack_g1(self.g_A) +
|
||||||
|
pack_g1(self.g_A_prime) +
|
||||||
|
pack_g2(self.g_B) +
|
||||||
|
pack_g1(self.g_B_prime) +
|
||||||
|
pack_g1(self.g_C) +
|
||||||
|
pack_g1(self.g_C_prime) +
|
||||||
|
pack_g1(self.g_K) +
|
||||||
|
pack_g1(self.g_H)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class JoinSplit(object):
|
||||||
|
def __init__(self, rand):
|
||||||
|
self.vpub_old = 0
|
||||||
|
self.vpub_new = 0
|
||||||
|
self.anchor = rand.b(32)
|
||||||
|
self.nullifiers = (rand.b(32), rand.b(32))
|
||||||
|
self.commitments = (rand.b(32), rand.b(32))
|
||||||
|
self.ephemeralKey = rand.b(32)
|
||||||
|
self.randomSeed = rand.b(32)
|
||||||
|
self.macs = (rand.b(32), rand.b(32))
|
||||||
|
self.proof = PHGRProof(rand)
|
||||||
|
self.ciphertexts = (rand.b(601), rand.b(601))
|
||||||
|
|
||||||
|
def __bytes__(self):
|
||||||
|
return (
|
||||||
|
struct.pack('<Q', self.vpub_old) +
|
||||||
|
struct.pack('<Q', self.vpub_new) +
|
||||||
|
self.anchor +
|
||||||
|
b''.join(self.nullifiers) +
|
||||||
|
b''.join(self.commitments) +
|
||||||
|
self.ephemeralKey +
|
||||||
|
self.randomSeed +
|
||||||
|
b''.join(self.macs) +
|
||||||
|
bytes(self.proof) +
|
||||||
|
b''.join(self.ciphertexts)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
RAND_OPCODES = [
|
||||||
|
0x00, # OP_FALSE,
|
||||||
|
0x51, # OP_1,
|
||||||
|
0x52, # OP_2,
|
||||||
|
0x53, # OP_3,
|
||||||
|
0xac, # OP_CHECKSIG,
|
||||||
|
0x63, # OP_IF,
|
||||||
|
0x65, # OP_VERIF,
|
||||||
|
0x6a, # OP_RETURN,
|
||||||
|
]
|
||||||
|
|
||||||
|
class Script(object):
|
||||||
|
def __init__(self, rand):
|
||||||
|
self._script = bytes([
|
||||||
|
rand.a(RAND_OPCODES) for i in range(rand.u8() % 10)
|
||||||
|
])
|
||||||
|
|
||||||
|
def raw(self):
|
||||||
|
return self._script
|
||||||
|
|
||||||
|
def __bytes__(self):
|
||||||
|
return write_compact_size(len(self._script)) + self._script
|
||||||
|
|
||||||
|
|
||||||
|
class OutPoint(object):
|
||||||
|
def __init__(self, rand):
|
||||||
|
self.txid = rand.b(32)
|
||||||
|
self.n = rand.u32()
|
||||||
|
|
||||||
|
def __bytes__(self):
|
||||||
|
return self.txid + struct.pack('<I', self.n)
|
||||||
|
|
||||||
|
|
||||||
|
class TxIn(object):
|
||||||
|
def __init__(self, rand):
|
||||||
|
self.prevout = OutPoint(rand)
|
||||||
|
self.scriptSig = Script(rand)
|
||||||
|
self.nSequence = rand.u32()
|
||||||
|
|
||||||
|
def __bytes__(self):
|
||||||
|
return (
|
||||||
|
bytes(self.prevout) +
|
||||||
|
bytes(self.scriptSig) +
|
||||||
|
struct.pack('<I', self.nSequence)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class TxOut(object):
|
||||||
|
def __init__(self, rand):
|
||||||
|
self.nValue = rand.u64() % (MAX_MONEY + 1)
|
||||||
|
self.scriptPubKey = Script(rand)
|
||||||
|
|
||||||
|
def __bytes__(self):
|
||||||
|
return struct.pack('<Q', self.nValue) + bytes(self.scriptPubKey)
|
||||||
|
|
||||||
|
|
||||||
|
class Transaction(object):
|
||||||
|
def __init__(self, rand, version):
|
||||||
|
if version == OVERWINTER_TX_VERSION:
|
||||||
|
self.fOverwintered = True
|
||||||
|
self.nVersionGroupId = OVERWINTER_VERSION_GROUP_ID
|
||||||
|
self.nVersion = OVERWINTER_TX_VERSION
|
||||||
|
else:
|
||||||
|
self.fOverwintered = False
|
||||||
|
self.nVersion = rand.u32() & ((1 << 31) - 1)
|
||||||
|
|
||||||
|
self.vin = []
|
||||||
|
for i in range(rand.u8() % 3):
|
||||||
|
self.vin.append(TxIn(rand))
|
||||||
|
|
||||||
|
self.vout = []
|
||||||
|
for i in range(rand.u8() % 3):
|
||||||
|
self.vout.append(TxOut(rand))
|
||||||
|
|
||||||
|
self.nLockTime = rand.u32()
|
||||||
|
self.nExpiryHeight = rand.u32() % TX_EXPIRY_HEIGHT_THRESHOLD
|
||||||
|
|
||||||
|
self.vJoinSplit = []
|
||||||
|
if self.nVersion >= 2:
|
||||||
|
for i in range(rand.u8() % 3):
|
||||||
|
self.vJoinSplit.append(JoinSplit(rand))
|
||||||
|
if len(self.vJoinSplit) > 0:
|
||||||
|
self.joinSplitPubKey = rand.b(32) # Potentially invalid
|
||||||
|
self.joinSplitSig = rand.b(64) # Invalid
|
||||||
|
|
||||||
|
def header(self):
|
||||||
|
return self.nVersion | (1 << 31 if self.fOverwintered else 0)
|
||||||
|
|
||||||
|
def __bytes__(self):
|
||||||
|
ret = b''
|
||||||
|
ret += struct.pack('<I', self.header())
|
||||||
|
if self.fOverwintered:
|
||||||
|
ret += struct.pack('<I', self.nVersionGroupId)
|
||||||
|
|
||||||
|
isOverwinterV3 = \
|
||||||
|
self.fOverwintered and \
|
||||||
|
self.nVersionGroupId == OVERWINTER_VERSION_GROUP_ID and \
|
||||||
|
self.nVersion == OVERWINTER_TX_VERSION
|
||||||
|
|
||||||
|
ret += write_compact_size(len(self.vin))
|
||||||
|
for x in self.vin:
|
||||||
|
ret += bytes(x)
|
||||||
|
|
||||||
|
ret += write_compact_size(len(self.vout))
|
||||||
|
for x in self.vout:
|
||||||
|
ret += bytes(x)
|
||||||
|
|
||||||
|
ret += struct.pack('<I', self.nLockTime)
|
||||||
|
if isOverwinterV3:
|
||||||
|
ret += struct.pack('<I', self.nExpiryHeight)
|
||||||
|
|
||||||
|
if self.nVersion >= 2:
|
||||||
|
ret += write_compact_size(len(self.vJoinSplit))
|
||||||
|
for jsdesc in self.vJoinSplit:
|
||||||
|
ret += bytes(jsdesc)
|
||||||
|
if len(self.vJoinSplit) > 0:
|
||||||
|
ret += self.joinSplitPubKey
|
||||||
|
ret += self.joinSplitSig
|
||||||
|
|
||||||
|
return ret
|
59
tv_output.py
59
tv_output.py
|
@ -43,7 +43,7 @@ def tv_json(filename, parts, vectors, bitcoin_flavoured):
|
||||||
', '.join([p[0] for p in parts])
|
', '.join([p[0] for p in parts])
|
||||||
))
|
))
|
||||||
print(' ' + ',\n '.join([
|
print(' ' + ',\n '.join([
|
||||||
json.dumps([tv_value_json(v[p[0]], bitcoin_flavoured) for p in parts]) for v in vectors
|
json.dumps([tv_value_json(v[p[0]], p[1].get('bitcoin_flavoured', bitcoin_flavoured)) for p in parts]) for v in vectors
|
||||||
]))
|
]))
|
||||||
print(']')
|
print(']')
|
||||||
|
|
||||||
|
@ -63,6 +63,17 @@ def tv_bytes_rust(name, value, pad):
|
||||||
pad,
|
pad,
|
||||||
))
|
))
|
||||||
|
|
||||||
|
def tv_vec_bytes_rust(name, value, pad):
|
||||||
|
print('''%s%s: vec![
|
||||||
|
%s%s
|
||||||
|
%s],''' % (
|
||||||
|
pad,
|
||||||
|
name,
|
||||||
|
pad,
|
||||||
|
chunk(hexlify(value)),
|
||||||
|
pad,
|
||||||
|
))
|
||||||
|
|
||||||
def tv_option_bytes_rust(name, value, pad):
|
def tv_option_bytes_rust(name, value, pad):
|
||||||
if value:
|
if value:
|
||||||
print('''%s%s: Some([
|
print('''%s%s: Some([
|
||||||
|
@ -77,15 +88,44 @@ def tv_option_bytes_rust(name, value, pad):
|
||||||
else:
|
else:
|
||||||
print('%s%s: None,' % (pad, name))
|
print('%s%s: None,' % (pad, name))
|
||||||
|
|
||||||
|
def tv_option_vec_bytes_rust(name, value, pad):
|
||||||
|
if value:
|
||||||
|
print('''%s%s: Some(vec![
|
||||||
|
%s%s
|
||||||
|
%s]),''' % (
|
||||||
|
pad,
|
||||||
|
name,
|
||||||
|
pad,
|
||||||
|
chunk(hexlify(value.thing)),
|
||||||
|
pad,
|
||||||
|
))
|
||||||
|
else:
|
||||||
|
print('%s%s: None,' % (pad, name))
|
||||||
|
|
||||||
def tv_int_rust(name, value, pad):
|
def tv_int_rust(name, value, pad):
|
||||||
print('%s%s: %d,' % (pad, name, value))
|
print('%s%s: %d,' % (pad, name, value))
|
||||||
|
|
||||||
def tv_part_rust(name, value, indent=3):
|
def tv_option_int_rust(name, value, pad):
|
||||||
|
if value:
|
||||||
|
print('%s%s: Some(%d),' % (pad, name, value.thing))
|
||||||
|
else:
|
||||||
|
print('%s%s: None,' % (pad, name))
|
||||||
|
|
||||||
|
def tv_part_rust(name, value, config, indent=3):
|
||||||
|
if 'rust_fmt' in config:
|
||||||
|
value = config['rust_fmt'](value)
|
||||||
|
|
||||||
pad = ' ' * indent
|
pad = ' ' * indent
|
||||||
if type(value) == bytes:
|
if config['rust_type'] == 'Option<Vec<u8>>':
|
||||||
tv_bytes_rust(name, value, pad)
|
tv_option_vec_bytes_rust(name, value, pad)
|
||||||
elif isinstance(value, Some) or value is None:
|
elif config['rust_type'] == 'Vec<u8>':
|
||||||
|
tv_vec_bytes_rust(name, value, pad)
|
||||||
|
elif config['rust_type'].startswith('Option<['):
|
||||||
tv_option_bytes_rust(name, value, pad)
|
tv_option_bytes_rust(name, value, pad)
|
||||||
|
elif type(value) == bytes:
|
||||||
|
tv_bytes_rust(name, value, pad)
|
||||||
|
elif config['rust_type'].startswith('Option<'):
|
||||||
|
tv_option_int_rust(name, value, pad)
|
||||||
elif type(value) == int:
|
elif type(value) == int:
|
||||||
tv_int_rust(name, value, pad)
|
tv_int_rust(name, value, pad)
|
||||||
else:
|
else:
|
||||||
|
@ -93,7 +133,7 @@ def tv_part_rust(name, value, indent=3):
|
||||||
|
|
||||||
def tv_rust(filename, parts, vectors):
|
def tv_rust(filename, parts, vectors):
|
||||||
print(' struct TestVector {')
|
print(' struct TestVector {')
|
||||||
for p in parts: print(' %s: %s,' % p)
|
for p in parts: print(' %s: %s,' % (p[0], p[1]['rust_type']))
|
||||||
print(''' };
|
print(''' };
|
||||||
|
|
||||||
// From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/%s.py''' % (
|
// From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/%s.py''' % (
|
||||||
|
@ -101,13 +141,13 @@ def tv_rust(filename, parts, vectors):
|
||||||
))
|
))
|
||||||
if type(vectors) == type({}):
|
if type(vectors) == type({}):
|
||||||
print(' let test_vector = TestVector {')
|
print(' let test_vector = TestVector {')
|
||||||
for p in parts: tv_part_rust(p[0], vectors[p[0]])
|
for p in parts: tv_part_rust(p[0], vectors[p[0]], p[1])
|
||||||
print(' };')
|
print(' };')
|
||||||
elif type(vectors) == type([]):
|
elif type(vectors) == type([]):
|
||||||
print(' let test_vectors = vec![')
|
print(' let test_vectors = vec![')
|
||||||
for vector in vectors:
|
for vector in vectors:
|
||||||
print(' TestVector {')
|
print(' TestVector {')
|
||||||
for p in parts: tv_part_rust(p[0], vector[p[0]], 4)
|
for p in parts: tv_part_rust(p[0], vector[p[0]], p[1], 4)
|
||||||
print(' },')
|
print(' },')
|
||||||
print(' ];')
|
print(' ];')
|
||||||
else:
|
else:
|
||||||
|
@ -124,6 +164,9 @@ def render_args():
|
||||||
return parser.parse_args()
|
return parser.parse_args()
|
||||||
|
|
||||||
def render_tv(args, filename, parts, vectors):
|
def render_tv(args, filename, parts, vectors):
|
||||||
|
# Convert older format
|
||||||
|
parts = [(p[0], p[1] if type(p[1]) == type({}) else {'rust_type': p[1]}) for p in parts]
|
||||||
|
|
||||||
if args.target == 'rust':
|
if args.target == 'rust':
|
||||||
tv_rust(filename, parts, vectors)
|
tv_rust(filename, parts, vectors)
|
||||||
elif args.target == 'zcash':
|
elif args.target == 'zcash':
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
import os
|
||||||
|
import struct
|
||||||
|
|
||||||
|
|
||||||
|
class Rand(object):
|
||||||
|
def __init__(self, random=os.urandom):
|
||||||
|
self._random = random
|
||||||
|
|
||||||
|
def b(self, l):
|
||||||
|
return self._random(l)
|
||||||
|
|
||||||
|
def v(self, l, f):
|
||||||
|
return struct.unpack(f, self.b(l))[0]
|
||||||
|
|
||||||
|
def u8(self):
|
||||||
|
return self.v(1, 'b')
|
||||||
|
|
||||||
|
def u32(self):
|
||||||
|
return self.v(4, '<I')
|
||||||
|
|
||||||
|
def u64(self):
|
||||||
|
return self.v(8, '<Q')
|
||||||
|
|
||||||
|
def bool(self):
|
||||||
|
return self.u8() % 2 > 0
|
||||||
|
|
||||||
|
def a(self, vals):
|
||||||
|
return vals[self.u8() % len(vals)]
|
|
@ -0,0 +1,27 @@
|
||||||
|
import struct
|
||||||
|
|
||||||
|
def write_compact_size(n):
|
||||||
|
if n < 253:
|
||||||
|
return struct.pack('B', n)
|
||||||
|
elif n <= 0xFFFF:
|
||||||
|
return struct.pack('B', 253) + struct.pack('<H', n)
|
||||||
|
elif n <= 0xFFFFFFFF:
|
||||||
|
return struct.pack('B', 254) + struct.pack('<I', n)
|
||||||
|
else:
|
||||||
|
return struct.pack('B', 255) + struct.pack('<Q', n)
|
||||||
|
|
||||||
|
assert write_compact_size(0) == b'\x00'
|
||||||
|
assert write_compact_size(1) == b'\x01'
|
||||||
|
assert write_compact_size(252) == b'\xFC'
|
||||||
|
assert write_compact_size(253) == b'\xFD\xFD\x00'
|
||||||
|
assert write_compact_size(254) == b'\xFD\xFE\x00'
|
||||||
|
assert write_compact_size(255) == b'\xFD\xFF\x00'
|
||||||
|
assert write_compact_size(256) == b'\xFD\x00\x01'
|
||||||
|
assert write_compact_size(0xFFFE) == b'\xFD\xFE\xFF'
|
||||||
|
assert write_compact_size(0xFFFF) == b'\xFD\xFF\xFF'
|
||||||
|
assert write_compact_size(0x010000) == b'\xFE\x00\x00\x01\x00'
|
||||||
|
assert write_compact_size(0x010001) == b'\xFE\x01\x00\x01\x00'
|
||||||
|
assert write_compact_size(0xFFFFFFFE) == b'\xFE\xFE\xFF\xFF\xFF'
|
||||||
|
assert write_compact_size(0xFFFFFFFF) == b'\xFE\xFF\xFF\xFF\xFF'
|
||||||
|
assert write_compact_size(0x0100000000) == b'\xFF\x00\x00\x00\x00\x01\x00\x00\x00'
|
||||||
|
assert write_compact_size(0xFFFFFFFFFFFFFFFF) == b'\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF'
|
|
@ -0,0 +1,168 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
from pyblake2 import blake2b
|
||||||
|
import struct
|
||||||
|
|
||||||
|
from transaction import (
|
||||||
|
MAX_MONEY,
|
||||||
|
OVERWINTER_TX_VERSION,
|
||||||
|
Script,
|
||||||
|
Transaction,
|
||||||
|
)
|
||||||
|
from tv_output import render_args, render_tv, Some
|
||||||
|
from tv_rand import Rand
|
||||||
|
|
||||||
|
|
||||||
|
SIGHASH_ALL = 1
|
||||||
|
SIGHASH_NONE = 2
|
||||||
|
SIGHASH_SINGLE = 3
|
||||||
|
SIGHASH_ANYONECANPAY = 0x80
|
||||||
|
|
||||||
|
NOT_AN_INPUT = -1 # For portability of the test vectors; replaced with None for Rust
|
||||||
|
|
||||||
|
def getHashPrevouts(tx):
|
||||||
|
digest = blake2b(digest_size=32, person=b'ZcashPrevoutHash')
|
||||||
|
for x in tx.vin:
|
||||||
|
digest.update(bytes(x.prevout))
|
||||||
|
return digest.digest()
|
||||||
|
|
||||||
|
def getHashSequence(tx):
|
||||||
|
digest = blake2b(digest_size=32, person=b'ZcashSequencHash')
|
||||||
|
for x in tx.vin:
|
||||||
|
digest.update(struct.pack('<I', x.nSequence))
|
||||||
|
return digest.digest()
|
||||||
|
|
||||||
|
def getHashOutputs(tx):
|
||||||
|
digest = blake2b(digest_size=32, person=b'ZcashOutputsHash')
|
||||||
|
for x in tx.vout:
|
||||||
|
digest.update(bytes(x))
|
||||||
|
return digest.digest()
|
||||||
|
|
||||||
|
def getHashJoinSplits(tx):
|
||||||
|
digest = blake2b(digest_size=32, person=b'ZcashJSplitsHash')
|
||||||
|
for jsdesc in tx.vJoinSplit:
|
||||||
|
digest.update(bytes(jsdesc))
|
||||||
|
digest.update(tx.joinSplitPubKey)
|
||||||
|
return digest.digest()
|
||||||
|
|
||||||
|
|
||||||
|
def signature_hash(scriptCode, tx, nIn, nHashType, amount, consensusBranchId):
|
||||||
|
hashPrevouts = b'\x00'*32
|
||||||
|
hashSequence = b'\x00'*32
|
||||||
|
hashOutputs = b'\x00'*32
|
||||||
|
hashJoinSplits = b'\x00'*32
|
||||||
|
|
||||||
|
if not (nHashType & SIGHASH_ANYONECANPAY):
|
||||||
|
hashPrevouts = getHashPrevouts(tx)
|
||||||
|
|
||||||
|
if (not (nHashType & SIGHASH_ANYONECANPAY)) and \
|
||||||
|
(nHashType & 0x1f) != SIGHASH_SINGLE and \
|
||||||
|
(nHashType & 0x1f) != SIGHASH_NONE:
|
||||||
|
hashSequence = getHashSequence(tx)
|
||||||
|
|
||||||
|
if (nHashType & 0x1f) != SIGHASH_SINGLE and \
|
||||||
|
(nHashType & 0x1f) != SIGHASH_NONE:
|
||||||
|
hashOutputs = getHashOutputs(tx)
|
||||||
|
elif (nHashType & 0x1f) == SIGHASH_SINGLE and \
|
||||||
|
0 <= nIn and nIn < len(tx.vout):
|
||||||
|
digest = blake2b(digest_size=32, person=b'ZcashOutputsHash')
|
||||||
|
digest.update(bytes(tx.vout[nIn]))
|
||||||
|
hashOutputs = digest.digest()
|
||||||
|
|
||||||
|
if len(tx.vJoinSplit) > 0:
|
||||||
|
hashJoinSplits = getHashJoinSplits(tx)
|
||||||
|
|
||||||
|
digest = blake2b(
|
||||||
|
digest_size=32,
|
||||||
|
person=b'ZcashSigHash' + struct.pack('<I', consensusBranchId),
|
||||||
|
)
|
||||||
|
|
||||||
|
digest.update(struct.pack('<I', tx.header()))
|
||||||
|
digest.update(struct.pack('<I', tx.nVersionGroupId))
|
||||||
|
digest.update(hashPrevouts)
|
||||||
|
digest.update(hashSequence)
|
||||||
|
digest.update(hashOutputs)
|
||||||
|
digest.update(hashJoinSplits)
|
||||||
|
digest.update(struct.pack('<I', tx.nLockTime))
|
||||||
|
digest.update(struct.pack('<I', tx.nExpiryHeight))
|
||||||
|
digest.update(struct.pack('<I', nHashType))
|
||||||
|
|
||||||
|
if nIn != NOT_AN_INPUT:
|
||||||
|
digest.update(bytes(tx.vin[nIn].prevout))
|
||||||
|
digest.update(bytes(scriptCode))
|
||||||
|
digest.update(struct.pack('<Q', amount))
|
||||||
|
digest.update(struct.pack('<I', tx.vin[nIn].nSequence))
|
||||||
|
|
||||||
|
return digest.digest()
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
args = render_args()
|
||||||
|
|
||||||
|
from random import Random
|
||||||
|
rng = Random(0xabad533d)
|
||||||
|
def randbytes(l):
|
||||||
|
ret = []
|
||||||
|
while len(ret) < l:
|
||||||
|
ret.append(rng.randrange(0, 256))
|
||||||
|
return bytes(ret)
|
||||||
|
rand = Rand(randbytes)
|
||||||
|
|
||||||
|
consensusBranchId = 0x5ba81b19 # Overwinter
|
||||||
|
|
||||||
|
test_vectors = []
|
||||||
|
for i in range(10):
|
||||||
|
tx = Transaction(rand, OVERWINTER_TX_VERSION)
|
||||||
|
scriptCode = Script(rand)
|
||||||
|
nIn = rand.u8() % (len(tx.vin) + 1)
|
||||||
|
if nIn == len(tx.vin):
|
||||||
|
nIn = NOT_AN_INPUT
|
||||||
|
nHashType = SIGHASH_ALL if nIn == NOT_AN_INPUT else rand.a([
|
||||||
|
SIGHASH_ALL,
|
||||||
|
SIGHASH_NONE,
|
||||||
|
SIGHASH_SINGLE,
|
||||||
|
SIGHASH_ALL | SIGHASH_ANYONECANPAY,
|
||||||
|
SIGHASH_NONE | SIGHASH_ANYONECANPAY,
|
||||||
|
SIGHASH_SINGLE | SIGHASH_ANYONECANPAY,
|
||||||
|
])
|
||||||
|
amount = rand.u64() % (MAX_MONEY + 1)
|
||||||
|
|
||||||
|
sighash = signature_hash(
|
||||||
|
scriptCode,
|
||||||
|
tx,
|
||||||
|
nIn,
|
||||||
|
nHashType,
|
||||||
|
amount,
|
||||||
|
consensusBranchId,
|
||||||
|
)
|
||||||
|
|
||||||
|
test_vectors.append({
|
||||||
|
'tx': bytes(tx),
|
||||||
|
'script_code': scriptCode.raw(),
|
||||||
|
'transparent_input': nIn,
|
||||||
|
'hash_type': nHashType,
|
||||||
|
'amount': amount,
|
||||||
|
'consensus_branch_id': consensusBranchId,
|
||||||
|
'sighash': sighash,
|
||||||
|
})
|
||||||
|
|
||||||
|
render_tv(
|
||||||
|
args,
|
||||||
|
'zip_0143',
|
||||||
|
(
|
||||||
|
('tx', {'rust_type': 'Vec<u8>', 'bitcoin_flavoured': False}),
|
||||||
|
('script_code', 'Vec<u8>'),
|
||||||
|
('transparent_input', {
|
||||||
|
'rust_type': 'Option<u32>',
|
||||||
|
'rust_fmt': lambda x: None if x == -1 else Some(x),
|
||||||
|
}),
|
||||||
|
('hash_type', 'u32'),
|
||||||
|
('amount', 'u64'),
|
||||||
|
('consensus_branch_id', 'u32'),
|
||||||
|
('sighash', '[u8; 32]'),
|
||||||
|
),
|
||||||
|
test_vectors,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
Loading…
Reference in New Issue