Skip to content

Instantly share code, notes, and snippets.

@andelf
Created February 24, 2020 11:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save andelf/d5f8fb18295836e9e264cd41c1575a0c to your computer and use it in GitHub Desktop.
Save andelf/d5f8fb18295836e9e264cd41c1575a0c to your computer and use it in GitHub Desktop.
Split Raw transaction
# define P1_FIRST 0x00
# define P1_MORE 0x80
# define P1_LAST 0x90
from google.protobuf.internal.decoder import _DecodeVarint32
from base import parse_bip32_path
def decode_varint32(raw, offset):
key, pos = _DecodeVarint32(raw, offset)
# print(f"! Remain: {len(raw[offset:])}")
# print(f"! Varint: fieldNo={key >> 3} type={key & 0x7}, pos={pos}")
return key, pos
def get_next_length(tx):
field, pos = decode_varint32(tx, 0)
size, newpos = decode_varint32(tx, pos)
if field & 0x07 == 0:
return newpos
return size + newpos
transactionRaw = bytes.fromhex(
"0a027d52220889fd90c45b71f24740e0bcb0f2be2c5a67080112630a2d747970"
"652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e7366"
"6572436f6e747261637412320a1541c8599111f29c1e1e061265b4af93ea1f27"
"4ad78a1215414f560eb4182ca53757f905609e226e96e8e1a80c18c0843d70d0"
"f5acf2be2c"
)
# set_permission
transactionRaw = bytes.fromhex(
"0a02785e220829557712af17b02140e2ebe3b2872e5ab802082e12b3020a3c747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e4163636f756e745065726d697373696f6e557064617465436f6e747261637412f2010a15411563915e194d8cfba1943570603f7606a3115508123f1a056f776e657220013a190a154119e7e376e7c213b7e7e7e46cc70a5dd086daff2a10013a190a15411563915e194d8cfba1943570603f7606a31155081001224b080210021a06616374697665200132207fff1fc0033e0b000000000000000000000000000000000000000000000000003a190a154119e7e376e7c213b7e7e7e46cc70a5dd086daff2a1001224b080210021a06616374697665200132207fff1fc0033e0b000000000000000000000000000000000000000000000000003a190a15411563915e194d8cfba1943570603f7606a3115508100170a49ce0b2872e"
)
transactionRaw = bytes.fromhex(
"0a024f952208e6530b36b320608940f8ddc8b6872e5aeb01082e12e6010a3c747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e4163636f756e745065726d697373696f6e557064617465436f6e747261637412a5010a1541340967e825557559dc46bbf0eabe5ccf99fd134e123f1a056f776e657220013a190a1541340967e825557559dc46bbf0eabe5ccf99fd134e10013a190a15415cbdd86a2fa8dc4bddd8a8f69dba48572eec07fb1001224b080210021a06616374697665200132207fff1fc0033e01000000000000000000000000000000000000000000000000003a190a1541340967e825557559dc46bbf0eabe5ccf99fd134e100170c292c5b6872e"
)
path = "44'/195'/0'/0/0"
donglePath = parse_bip32_path(path)
def apduMessage(INS, P1, P2, MESSAGE):
hexString = "E0{:02x}{:02x}{:02x}{:02x}{}".format(INS, P1, P2, len(MESSAGE) // 2, MESSAGE)
print('send hex:', hexString)
def sign(path, tx, signatures=[], verbose=False):
max_length = 255
to_send = []
start_bytes = []
data = bytearray.fromhex(f"05{path}")
while len(tx) > 0:
# get next message field
newpos = get_next_length(tx)
assert newpos < max_length
if (len(data) + newpos) > max_length:
# add chunk
to_send.append(data.hex())
data = bytearray()
continue
# append to data
data.extend(tx[:newpos])
tx = tx[newpos:]
# append last
to_send.append(data.hex())
token_pos = len(to_send)
to_send.extend(signatures)
if len(to_send) == 1:
start_bytes.append(0x10)
else:
start_bytes.append(0x00)
for i in range(1, len(to_send) - 1):
if i >= token_pos:
start_bytes.append(0xA0 | 0x00 | i - token_pos)
else:
start_bytes.append(0x80)
if not (signatures is None) and len(signatures) > 0:
start_bytes.append(0xA0 | 0x08 | len(signatures) - 1)
else:
start_bytes.append(0x90)
result = None
for i in range(len(to_send)):
pack = apduMessage(0x04, start_bytes[i], 0x00, to_send[i])
# result, status = self.exchange(pack, True)
# if not (status == 0x9000):
# return None, status
return result, 0x9000
# send signature if any
sign(donglePath, transactionRaw)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment