2016-05-24 11:47:57 -07:00
|
|
|
#!/usr/bin/env python
|
2016-05-20 13:27:20 -07:00
|
|
|
from __future__ import print_function
|
2016-05-02 12:03:01 -07:00
|
|
|
import binascii
|
|
|
|
import os
|
|
|
|
import random
|
|
|
|
import trezorlib.messages_pb2 as proto
|
|
|
|
import trezorlib.types_pb2 as proto_types
|
|
|
|
import trezorlib.tools as tools
|
|
|
|
import trezorlib.ckd_public as bip32
|
|
|
|
|
|
|
|
import hashlib
|
|
|
|
from trezorlib.client import TrezorClient
|
|
|
|
from trezorlib.client import TrezorClientDebug
|
|
|
|
from trezorlib.tx_api import TXAPITestnet
|
|
|
|
from trezorlib.tx_api import TXAPIBitcoin
|
|
|
|
from trezorlib.transport_hid import HidTransport
|
|
|
|
from trezorlib.transport_bridge import BridgeTransport
|
|
|
|
|
|
|
|
def pack_varint(x):
|
|
|
|
if (x < 0xfd):
|
|
|
|
return chr(x)
|
|
|
|
else:
|
|
|
|
return '\xfd'+chr(x & 0xff) + chr((x >> 8) & 0xff)
|
2016-05-24 11:47:57 -07:00
|
|
|
|
2016-05-02 12:03:01 -07:00
|
|
|
def int_to_string(x, pad):
|
|
|
|
result = ['\x00'] * pad
|
|
|
|
while x > 0:
|
|
|
|
pad -= 1
|
|
|
|
ordinal = x & 0xFF
|
|
|
|
result[pad] = (chr(ordinal))
|
|
|
|
x >>= 8
|
|
|
|
return ''.join(result)
|
|
|
|
|
|
|
|
def string_to_int(s):
|
|
|
|
result = 0
|
|
|
|
for c in s:
|
|
|
|
if not isinstance(c, int):
|
|
|
|
c = ord(c)
|
|
|
|
result = (result << 8) + c
|
|
|
|
return result
|
|
|
|
|
|
|
|
class MyTXAPIBitcoin(object):
|
|
|
|
|
|
|
|
def set_publickey(self, node):
|
|
|
|
self.node = node.node
|
|
|
|
|
|
|
|
def set_client(self, client):
|
|
|
|
self.client = client
|
|
|
|
|
|
|
|
def serialize_tx(self, tx):
|
|
|
|
ser = ''
|
|
|
|
ser = ser + int_to_string(tx.version, 4)[::-1]
|
|
|
|
ser = ser + pack_varint(len(tx.inputs))
|
|
|
|
for i in tx.inputs:
|
|
|
|
ser = ser + i.prev_hash[::-1]
|
|
|
|
ser = ser + int_to_string(i.prev_index, 4)[::-1]
|
|
|
|
ser = ser + pack_varint(len(i.script_sig)) + i.script_sig
|
|
|
|
ser = ser + int_to_string(i.sequence, 4)[::-1]
|
|
|
|
ser = ser + pack_varint(len(tx.bin_outputs))
|
|
|
|
for o in tx.bin_outputs:
|
|
|
|
ser = ser + int_to_string(o.amount, 8)[::-1]
|
|
|
|
ser = ser + pack_varint(len(o.script_pubkey)) + o.script_pubkey
|
|
|
|
ser = ser + int_to_string(tx.lock_time, 4)[::-1]
|
2016-05-24 11:47:57 -07:00
|
|
|
return ser
|
|
|
|
|
2016-05-02 12:03:01 -07:00
|
|
|
|
|
|
|
def create_inputs(self, numinputs, txsize):
|
|
|
|
idx = 0
|
|
|
|
sum = 0
|
|
|
|
self.inputs = []
|
|
|
|
self.txs = {}
|
|
|
|
for nr in range(numinputs):
|
|
|
|
t = proto_types.TransactionType()
|
|
|
|
t.version = 1
|
|
|
|
t.lock_time = 0
|
|
|
|
i = t.inputs.add()
|
|
|
|
i.prev_hash = os.urandom(32)
|
|
|
|
i.prev_index = random.randint(0,4)
|
|
|
|
i.script_sig = os.urandom(100)
|
|
|
|
i.sequence = 0xffffffff
|
|
|
|
if (nr % 50 == 0):
|
2016-05-20 13:27:20 -07:00
|
|
|
print(nr)
|
2016-05-02 12:03:01 -07:00
|
|
|
myout = random.randint(0, txsize-1)
|
|
|
|
segwit = 1 #random.randint(0,1)
|
|
|
|
for vout in range(txsize):
|
|
|
|
o = t.bin_outputs.add()
|
|
|
|
o.amount = random.randint(10000,1000000)
|
|
|
|
if vout == myout:
|
|
|
|
amount = o.amount
|
|
|
|
sum = sum + o.amount
|
|
|
|
node = self.node
|
|
|
|
path = [0, idx]
|
|
|
|
node = bip32.public_ckd(node, path)
|
|
|
|
idx = idx + 1
|
|
|
|
pubkey = tools.hash_160(node.public_key)
|
|
|
|
else:
|
|
|
|
pubkey = os.urandom(20)
|
|
|
|
if (segwit):
|
|
|
|
o.script_pubkey = binascii.unhexlify('0014') + pubkey
|
|
|
|
else:
|
|
|
|
o.script_pubkey = binascii.unhexlify('76a914') + pubkey + binascii.unhexlify('88ac')
|
|
|
|
|
|
|
|
txser = self.serialize_tx(t)
|
|
|
|
txhash = tools.Hash(txser)[::-1]
|
|
|
|
if (segwit):
|
|
|
|
outi = self.inputs.append(
|
|
|
|
proto_types.TxInputType(
|
|
|
|
address_n=self.client.expand_path("44'/0'/0'/0/"+str(idx)),
|
|
|
|
script_type = proto_types.SPENDWADDRESS,
|
|
|
|
prev_hash=txhash,
|
|
|
|
prev_index = myout,
|
|
|
|
amount = amount
|
|
|
|
))
|
|
|
|
else:
|
|
|
|
outi = self.inputs.append(
|
|
|
|
proto_types.TxInputType(
|
|
|
|
address_n=self.client.expand_path("44'/0'/0'/0/"+str(idx)),
|
|
|
|
script_type = proto_types.SPENDADDRESS,
|
|
|
|
prev_hash=txhash,
|
|
|
|
prev_index = myout
|
|
|
|
))
|
2016-05-20 13:27:20 -07:00
|
|
|
#print(binascii.hexlify(txser))
|
|
|
|
#print(binascii.hexlify(txhash))
|
2016-05-02 12:03:01 -07:00
|
|
|
self.txs[binascii.hexlify(txhash)] = t
|
|
|
|
|
|
|
|
self.outputs = [
|
|
|
|
proto_types.TxOutputType(
|
|
|
|
amount=sum,
|
|
|
|
script_type=proto_types.PAYTOADDRESS,
|
|
|
|
address_n=self.client.expand_path("44'/0'/0'/1/0")
|
|
|
|
)]
|
|
|
|
|
|
|
|
def get_inputs(self):
|
|
|
|
return self.inputs
|
|
|
|
|
|
|
|
def get_outputs(self):
|
|
|
|
return self.outputs
|
2016-05-24 11:47:57 -07:00
|
|
|
|
2016-05-02 12:03:01 -07:00
|
|
|
def get_tx(self, txhash):
|
|
|
|
t = self.txs[txhash]
|
2016-05-20 13:27:20 -07:00
|
|
|
#print(t)
|
2016-05-02 12:03:01 -07:00
|
|
|
return t
|
|
|
|
|
|
|
|
def main():
|
|
|
|
numinputs = 600
|
|
|
|
sizeinputtx = 10
|
2016-05-24 11:47:57 -07:00
|
|
|
|
2016-05-02 12:03:01 -07:00
|
|
|
# List all connected TREZORs on USB
|
|
|
|
devices = HidTransport.enumerate()
|
|
|
|
|
|
|
|
# Check whether we found any
|
|
|
|
if len(devices) == 0:
|
2016-05-20 13:27:20 -07:00
|
|
|
print('No TREZOR found')
|
2016-05-02 12:03:01 -07:00
|
|
|
return
|
|
|
|
|
|
|
|
# Use first connected device
|
2016-05-20 13:27:20 -07:00
|
|
|
print(devices[0][0])
|
2016-05-02 12:03:01 -07:00
|
|
|
# transport = BridgeTransport(devices[0][0])
|
|
|
|
transport = HidTransport(devices[0])
|
2016-05-24 11:47:57 -07:00
|
|
|
|
2016-05-02 12:03:01 -07:00
|
|
|
txstore = MyTXAPIBitcoin()
|
2016-05-24 11:47:57 -07:00
|
|
|
|
2016-05-02 12:03:01 -07:00
|
|
|
# Creates object for manipulating TREZOR
|
|
|
|
client = TrezorClient(transport)
|
|
|
|
# client.set_tx_api(TXAPITestnet())
|
|
|
|
txstore.set_client(client)
|
|
|
|
txstore.set_publickey(client.get_public_node(client.expand_path("44'/0'/0'")))
|
2016-05-20 13:27:20 -07:00
|
|
|
print("creating input txs")
|
2016-05-02 12:03:01 -07:00
|
|
|
txstore.create_inputs(numinputs, sizeinputtx)
|
2016-05-20 13:27:20 -07:00
|
|
|
print("go")
|
2016-05-02 12:03:01 -07:00
|
|
|
client.set_tx_api(txstore)
|
|
|
|
# client.set_tx_api(MyTXAPIBitcoin())
|
|
|
|
|
|
|
|
# Print out TREZOR's features and settings
|
2016-05-20 13:27:20 -07:00
|
|
|
print(client.features)
|
2016-05-02 12:03:01 -07:00
|
|
|
|
|
|
|
# Get the first address of first BIP44 account
|
|
|
|
# (should be the same address as shown in mytrezor.com)
|
|
|
|
|
|
|
|
outputs = [
|
|
|
|
proto_types.TxOutputType(
|
|
|
|
amount=0,
|
|
|
|
script_type=proto_types.PAYTOADDRESS,
|
|
|
|
address='p2xtZoXeX5X8BP8JfFhQK2nD3emtjch7UeFm'
|
|
|
|
# op_return_data=binascii.unhexlify('2890770995194662774cd192ee383b805e9a066e6a456be037727649228fb7f6')
|
|
|
|
# address_n=client.expand_path("44'/0'/0'/0/35"),
|
|
|
|
# address='3PUxV6Cc4udQZQsJhArVUzvvVoKC8ohkAj',
|
|
|
|
),
|
|
|
|
# proto_types.TxOutputType(
|
|
|
|
# amount=0,
|
|
|
|
# script_type=proto_types.PAYTOOPRETURN,
|
|
|
|
# op_return_data=binascii.unhexlify('2890770995194662774cd192ee383b805e9a066e6a456be037727649228fb7f6')
|
|
|
|
# ),
|
|
|
|
# proto_types.TxOutputType(
|
|
|
|
# amount= 8120,
|
|
|
|
# script_type=proto_types.PAYTOADDRESS,
|
|
|
|
# address_n=client.expand_path("44'/1'/0'/1/0"),
|
|
|
|
# address='1PtCkQgyN6xHmXWzLmFFrDNA5vYhYLeNFZ',
|
|
|
|
# address='14KRxYgFc7Se8j7MDdrK5PTNv8meq4GivK',
|
|
|
|
# ),
|
|
|
|
# proto_types.TxOutputType(
|
|
|
|
# amount= 18684 - 2000,
|
|
|
|
# script_type=proto_types.PAYTOADDRESS,
|
|
|
|
# address_n=client.expand_path("44'/0'/0'/0/7"),
|
|
|
|
# # address='1PtCkQgyN6xHmXWzLmFFrDNA5vYhYLeNFZ',
|
|
|
|
# # address='1s9TSqr3PHZdXGrYws59Uaf5SPqavH43z',
|
|
|
|
# ),
|
|
|
|
# proto_types.TxOutputType(
|
|
|
|
# amount= 1000,
|
|
|
|
# script_type=proto_types.PAYTOADDRESS,
|
|
|
|
# # address_n=client.expand_path("44'/0'/0'/0/18"),
|
|
|
|
# # address='1PtCkQgyN6xHmXWzLmFFrDNA5vYhYLeNFZ',
|
|
|
|
# address='1NcMqUvyWv1K3Zxwmx5sqfj7ZEmPCSdJFM',
|
|
|
|
# ),
|
|
|
|
]
|
2016-05-24 11:47:57 -07:00
|
|
|
|
2016-05-02 12:03:01 -07:00
|
|
|
# (signatures, serialized_tx) = client.sign_tx('Testnet', inputs, outputs)
|
|
|
|
(signatures, serialized_tx) = client.sign_tx('Bitcoin', txstore.get_inputs(), txstore.get_outputs())
|
2016-05-20 13:27:20 -07:00
|
|
|
print('Transaction:', binascii.hexlify(serialized_tx))
|
2016-05-02 12:03:01 -07:00
|
|
|
|
|
|
|
client.close()
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
main()
|