From 673deccf03b0c4f5870f9b2ff5391accf6810a88 Mon Sep 17 00:00:00 2001 From: barbatos2011 Date: Mon, 29 Apr 2024 21:18:55 +0800 Subject: [PATCH 1/2] [add] support tip712 transactions --- examples/base.py | 51 ++- examples/ecdh_eke.py.py | 44 +- examples/getPublicKey.py | 29 +- examples/getVersion.py | 2 +- examples/multisignTransfer.py | 81 ++-- examples/runTest.py | 431 ++++++++++-------- examples/signExchangeTransaction.py | 19 +- examples/signMessage.py | 26 +- examples/signPermissionedTransaction.py | 79 ++-- examples/signStakeV2.py | 71 ++- examples/signTRC10WithName.py | 19 +- examples/signTip712Message.py | 71 +++ examples/signTransaction.py | 17 +- examples/signTransactionExtension.py | 42 +- examples/testCustomContracts.py | 153 ++++--- examples/validateSignature.py | 16 +- src/handlers/dispatcher.c | 3 + src/handlers/handlers.h | 2 + src/handlers/sign_tip712_message.c | 69 +++ src/parse.c | 19 +- src/parse.h | 35 ++ src/ui/ui_globals.c | 137 ++++++ src/ui/ui_globals.h | 4 + src/ui/ui_review_menu.h | 1 + src/ui/ui_review_menu_bagl.c | 74 +++ src/ui/ui_review_menu_nbgl.c | 28 +- .../nanos/test_trx_sign_tip712/00000.png | Bin 0 -> 414 bytes .../nanos/test_trx_sign_tip712/00001.png | Bin 0 -> 490 bytes .../nanos/test_trx_sign_tip712/00002.png | Bin 0 -> 482 bytes .../nanos/test_trx_sign_tip712/00003.png | Bin 0 -> 494 bytes .../nanos/test_trx_sign_tip712/00004.png | Bin 0 -> 457 bytes .../nanos/test_trx_sign_tip712/00005.png | Bin 0 -> 528 bytes .../nanos/test_trx_sign_tip712/00006.png | Bin 0 -> 539 bytes .../nanos/test_trx_sign_tip712/00007.png | Bin 0 -> 545 bytes .../nanos/test_trx_sign_tip712/00008.png | Bin 0 -> 500 bytes .../nanos/test_trx_sign_tip712/00009.png | Bin 0 -> 407 bytes .../nanos/test_trx_sign_tip712/00010.png | Bin 0 -> 397 bytes .../nanosp/test_trx_sign_tip712/00000.png | Bin 0 -> 473 bytes .../nanosp/test_trx_sign_tip712/00001.png | Bin 0 -> 894 bytes .../nanosp/test_trx_sign_tip712/00002.png | Bin 0 -> 522 bytes .../nanosp/test_trx_sign_tip712/00003.png | Bin 0 -> 944 bytes .../nanosp/test_trx_sign_tip712/00004.png | Bin 0 -> 568 bytes .../nanosp/test_trx_sign_tip712/00005.png | Bin 0 -> 457 bytes .../nanosp/test_trx_sign_tip712/00006.png | Bin 0 -> 455 bytes .../nanox/test_trx_sign_tip712/00000.png | Bin 0 -> 473 bytes .../nanox/test_trx_sign_tip712/00001.png | Bin 0 -> 894 bytes .../nanox/test_trx_sign_tip712/00002.png | Bin 0 -> 522 bytes .../nanox/test_trx_sign_tip712/00003.png | Bin 0 -> 944 bytes .../nanox/test_trx_sign_tip712/00004.png | Bin 0 -> 568 bytes .../nanox/test_trx_sign_tip712/00005.png | Bin 0 -> 457 bytes .../nanox/test_trx_sign_tip712/00006.png | Bin 0 -> 455 bytes .../stax/test_trx_sign_tip712/00000.png | Bin 0 -> 8035 bytes .../stax/test_trx_sign_tip712/00001.png | Bin 0 -> 15596 bytes .../stax/test_trx_sign_tip712/00002.png | Bin 0 -> 15835 bytes .../stax/test_trx_sign_tip712/00003.png | Bin 0 -> 8756 bytes .../stax/test_trx_sign_tip712/00004.png | Bin 0 -> 6108 bytes .../stax/test_trx_sign_tip712/00005.png | Bin 0 -> 9811 bytes tests/test_trx.py | 32 +- tests/tron.py | 1 + 59 files changed, 1107 insertions(+), 449 deletions(-) create mode 100644 examples/signTip712Message.py create mode 100644 src/handlers/sign_tip712_message.c create mode 100644 tests/snapshots/nanos/test_trx_sign_tip712/00000.png create mode 100644 tests/snapshots/nanos/test_trx_sign_tip712/00001.png create mode 100644 tests/snapshots/nanos/test_trx_sign_tip712/00002.png create mode 100644 tests/snapshots/nanos/test_trx_sign_tip712/00003.png create mode 100644 tests/snapshots/nanos/test_trx_sign_tip712/00004.png create mode 100644 tests/snapshots/nanos/test_trx_sign_tip712/00005.png create mode 100644 tests/snapshots/nanos/test_trx_sign_tip712/00006.png create mode 100644 tests/snapshots/nanos/test_trx_sign_tip712/00007.png create mode 100644 tests/snapshots/nanos/test_trx_sign_tip712/00008.png create mode 100644 tests/snapshots/nanos/test_trx_sign_tip712/00009.png create mode 100644 tests/snapshots/nanos/test_trx_sign_tip712/00010.png create mode 100644 tests/snapshots/nanosp/test_trx_sign_tip712/00000.png create mode 100644 tests/snapshots/nanosp/test_trx_sign_tip712/00001.png create mode 100644 tests/snapshots/nanosp/test_trx_sign_tip712/00002.png create mode 100644 tests/snapshots/nanosp/test_trx_sign_tip712/00003.png create mode 100644 tests/snapshots/nanosp/test_trx_sign_tip712/00004.png create mode 100644 tests/snapshots/nanosp/test_trx_sign_tip712/00005.png create mode 100644 tests/snapshots/nanosp/test_trx_sign_tip712/00006.png create mode 100644 tests/snapshots/nanox/test_trx_sign_tip712/00000.png create mode 100644 tests/snapshots/nanox/test_trx_sign_tip712/00001.png create mode 100644 tests/snapshots/nanox/test_trx_sign_tip712/00002.png create mode 100644 tests/snapshots/nanox/test_trx_sign_tip712/00003.png create mode 100644 tests/snapshots/nanox/test_trx_sign_tip712/00004.png create mode 100644 tests/snapshots/nanox/test_trx_sign_tip712/00005.png create mode 100644 tests/snapshots/nanox/test_trx_sign_tip712/00006.png create mode 100644 tests/snapshots/stax/test_trx_sign_tip712/00000.png create mode 100644 tests/snapshots/stax/test_trx_sign_tip712/00001.png create mode 100644 tests/snapshots/stax/test_trx_sign_tip712/00002.png create mode 100644 tests/snapshots/stax/test_trx_sign_tip712/00003.png create mode 100644 tests/snapshots/stax/test_trx_sign_tip712/00004.png create mode 100644 tests/snapshots/stax/test_trx_sign_tip712/00005.png diff --git a/examples/base.py b/examples/base.py index 477d5a46..d193dd4b 100755 --- a/examples/base.py +++ b/examples/base.py @@ -1,14 +1,43 @@ import struct + def parse_bip32_path(path): - if len(path) == 0: - return "" - result = "" - elements = path.split('/') - for pathElement in elements: - element = pathElement.split('\'') - if len(element) == 1: - result = result + struct.pack(">I", int(element[0])).hex() - else: - result = result + struct.pack(">I", 0x80000000 | int(element[0])).hex() - return result \ No newline at end of file + if len(path) == 0: + return "" + result = "" + elements = path.split('/') + for pathElement in elements: + element = pathElement.split('\'') + if len(element) == 1: + result = result + struct.pack(">I", int(element[0])).hex() + else: + result = result + struct.pack(">I", + 0x80000000 | int(element[0])).hex() + return result + + +def parse_bip32_path_to_bytes(path): + if len(path) == 0: + return b"" + result = b"" + elements = path.split('/') + for pathElement in elements: + element = pathElement.split('\'') + if len(element) == 1: + result = result + struct.pack(">I", int(element[0])) + else: + result = result + struct.pack(">I", 0x80000000 | int(element[0])) + return result + + +def apduMessage(INS, P1, P2, PATH, MESSAGE): + hexString = "" + if PATH: + hexString = "E0{:02x}{:02x}{:02x}{:02x}{:02x}{}".format( + INS, P1, P2, (len(PATH) + len(MESSAGE)) // 2 + 1, + len(PATH) // 4 // 2, PATH + MESSAGE) + else: + hexString = "E0{:02x}{:02x}{:02x}{:02x}{}".format( + INS, P1, P2, + len(MESSAGE) // 2, MESSAGE) + return bytearray.fromhex(hexString) diff --git a/examples/ecdh_eke.py.py b/examples/ecdh_eke.py.py index 8d88d725..764b7edd 100755 --- a/examples/ecdh_eke.py.py +++ b/examples/ecdh_eke.py.py @@ -7,9 +7,13 @@ from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes from secrets import token_bytes + class DiffieHellman: + def __init__(self): - self.diffieHellman = ec.derive_private_key(0xb5a4cea271ff424d7c31dc12a3e43e401df7a40d7412a15750f3f0b6b5449a28,ec.SECP256K1(), default_backend()) + self.diffieHellman = ec.derive_private_key( + 0xb5a4cea271ff424d7c31dc12a3e43e401df7a40d7412a15750f3f0b6b5449a28, + ec.SECP256K1(), default_backend()) self.public_key = self.diffieHellman.public_key() self.IV = token_bytes(16) @@ -17,15 +21,15 @@ def encrypt(self, public_key, secret): shared_key = self.diffieHellman.exchange(ec.ECDH(), public_key) print("Shared") print(shared_key.hex()) - derived_key = HKDF( - algorithm=hashes.SHA256(), - length=32, - salt=None, - info=None, - backend=default_backend() - ).derive(shared_key) - - aes = Cipher(algorithms.AES(derived_key), modes.CBC(self.IV), backend=default_backend()) + derived_key = HKDF(algorithm=hashes.SHA256(), + length=32, + salt=None, + info=None, + backend=default_backend()).derive(shared_key) + + aes = Cipher(algorithms.AES(derived_key), + modes.CBC(self.IV), + backend=default_backend()) encryptor = aes.encryptor() padder = padding.PKCS7(128).padder() @@ -34,15 +38,15 @@ def encrypt(self, public_key, secret): def decrypt(self, public_key, secret, iv): shared_key = self.diffieHellman.exchange(ec.ECDH(), public_key) - derived_key = HKDF( - algorithm=hashes.SHA256(), - length=32, - salt=None, - info=None, - backend=default_backend() - ).derive(shared_key) - - aes = Cipher(algorithms.AES(derived_key), modes.CBC(iv), backend=default_backend()) + derived_key = HKDF(algorithm=hashes.SHA256(), + length=32, + salt=None, + info=None, + backend=default_backend()).derive(shared_key) + + aes = Cipher(algorithms.AES(derived_key), + modes.CBC(iv), + backend=default_backend()) decryptor = aes.decryptor() decrypted_data = decryptor.update(secret) + decryptor.finalize() @@ -59,4 +63,4 @@ def decrypt(self, public_key, secret, iv): print(encrypted_message) decrypted_message = alice.decrypt(bob.public_key, encrypted_message, bob.IV) -print(decrypted_message) \ No newline at end of file +print(decrypted_message) diff --git a/examples/getPublicKey.py b/examples/getPublicKey.py index 02a62df5..caf9c005 100755 --- a/examples/getPublicKey.py +++ b/examples/getPublicKey.py @@ -5,11 +5,12 @@ from base import parse_bip32_path parser = argparse.ArgumentParser() -parser.add_argument('--path', help="BIP32 path to retrieve. e.g. \"44'/195'/0'/0/0\".") +parser.add_argument('--path', + help="BIP32 path to retrieve. e.g. \"44'/195'/0'/0/0\".") args = parser.parse_args() if args.path == None: - args.path = "44'/195'/0'/0/0" + args.path = "44'/195'/0'/0/0" donglePath = parse_bip32_path(args.path) @@ -21,7 +22,9 @@ # Ask for confirmation # txt = "E0020100" + '{:02x}'.format(len(donglePath) + 1) + '{:02x}'.format( int(len(donglePath) / 4 / 2)) + donglePath # No confirmation -apduMessage = "E0020000" + '{:02x}'.format(int(len(donglePath)/2) ) + '{:02x}'.format(int(len(donglePath) / 4 / 2)) + donglePath +apduMessage = "E0020000" + '{:02x}'.format(int( + len(donglePath) / 2)) + '{:02x}'.format(int( + len(donglePath) / 4 / 2)) + donglePath apdu = bytearray.fromhex(apduMessage) print("-= Tron Ledger =-") @@ -29,16 +32,16 @@ dongle = getDongle(True) result = dongle.exchange(apdu) -size=result[0] -if size == 65 : - print("Public Key: " + result[1:1+size].hex()) +size = result[0] +if size == 65: + print("Public Key: " + result[1:1 + size].hex()) else: - print("Error... Public Key Size: {:d}".format(size)) + print("Error... Public Key Size: {:d}".format(size)) -size=result[size+1] -if size == 34 : - print("Address: " + result[67:67+size].decode()) - if (result[67:67+size].decode()=="TUEZSdKsoDHQMeZwihtdoBiN46zxhGWYdH"): - print("Address match with test case!") +size = result[size + 1] +if size == 34: + print("Address: " + result[67:67 + size].decode()) + if (result[67:67 + size].decode() == "TUEZSdKsoDHQMeZwihtdoBiN46zxhGWYdH"): + print("Address match with test case!") else: - print("Error... Address Size: {:d}".format(size)) + print("Error... Address Size: {:d}".format(size)) diff --git a/examples/getVersion.py b/examples/getVersion.py index 841d8266..fc589e21 100755 --- a/examples/getVersion.py +++ b/examples/getVersion.py @@ -15,4 +15,4 @@ dongle = getDongle(True) result = dongle.exchange(bytearray.fromhex(apduMessage)) -print('Version={:d}.{:d}.{:d}'.format(result[1],result[2],result[3])) +print('Version={:d}.{:d}.{:d}'.format(result[1], result[2], result[3])) diff --git a/examples/multisignTransfer.py b/examples/multisignTransfer.py index 24e89bae..80aad767 100644 --- a/examples/multisignTransfer.py +++ b/examples/multisignTransfer.py @@ -1,6 +1,7 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- import sys + sys.path.append("./examples/proto") from pprint import pprint @@ -15,7 +16,8 @@ import binascii import base58 -logging.basicConfig(level=logging.DEBUG, format="%(asctime)s - %(levelname)s - %(message)s") +logging.basicConfig(level=logging.DEBUG, + format="%(asctime)s - %(levelname)s - %(message)s") logger = logging.getLogger() # Start Ledger @@ -27,50 +29,67 @@ def chunks(l, n): for i in range(0, len(l), n): yield l[i:i + n] + def apduMessage(INS, P1, P2, PATH, MESSAGE): hexString = "" if PATH: - hexString = "E0{:02x}{:02x}{:02x}{:02x}{:02x}{}".format(INS,P1,P2,(len(PATH)+len(MESSAGE))//2+1,len(PATH)//4//2,PATH+MESSAGE) + hexString = "E0{:02x}{:02x}{:02x}{:02x}{:02x}{}".format( + INS, P1, P2, (len(PATH) + len(MESSAGE)) // 2 + 1, + len(PATH) // 4 // 2, PATH + MESSAGE) else: - hexString = "E0{:02x}{:02x}{:02x}{:02x}{}".format(INS,P1,P2,len(MESSAGE)//2,MESSAGE) + hexString = "E0{:02x}{:02x}{:02x}{:02x}{}".format( + INS, P1, P2, + len(MESSAGE) // 2, MESSAGE) print(hexString) return bytearray.fromhex(hexString) + def ledgerSign(PATH, tx, tokenSignature=[]): raw_tx = tx.raw_data.SerializeToString().hex() # Sign in chunks - chunkList = list(chunks(raw_tx,420)) - if len(tokenSignature)>0: + chunkList = list(chunks(raw_tx, 420)) + if len(tokenSignature) > 0: chunkList.extend(tokenSignature) # P1 = P1_FIRST = 0x00 - if len(chunkList)>1: - result = dongle.exchange(apduMessage(0x04,0x00,0x00, PATH, chunkList[0])) + if len(chunkList) > 1: + result = dongle.exchange( + apduMessage(0x04, 0x00, 0x00, PATH, chunkList[0])) else: - result = dongle.exchange(apduMessage(0x04,0x10,0x00, PATH, chunkList[0])) + result = dongle.exchange( + apduMessage(0x04, 0x10, 0x00, PATH, chunkList[0])) - for i in range(1,len(chunkList)-1-len(tokenSignature)): + for i in range(1, len(chunkList) - 1 - len(tokenSignature)): # P1 = P1_MODE = 0x80 - result = dongle.exchange(apduMessage(0x04,0x80,0x00, None, chunkList[i])) - - for i in range(0,len(tokenSignature)-1): - result = dongle.exchange(apduMessage(0x04,0xA0 | (0x00+i), 0x00, None, tokenSignature[i])) - + result = dongle.exchange( + apduMessage(0x04, 0x80, 0x00, None, chunkList[i])) + + for i in range(0, len(tokenSignature) - 1): + result = dongle.exchange( + apduMessage(0x04, 0xA0 | (0x00 + i), 0x00, None, + tokenSignature[i])) + # P1 = P1_LAST = 0x90 - if len(chunkList)>1: - if len(tokenSignature)>0: - result = dongle.exchange(apduMessage(0x04,0xA0 | 0x08 | (0x00+len(tokenSignature)-1),0x00, None, chunkList[len(chunkList)-1])) + if len(chunkList) > 1: + if len(tokenSignature) > 0: + result = dongle.exchange( + apduMessage(0x04, + 0xA0 | 0x08 | (0x00 + len(tokenSignature) - 1), + 0x00, None, chunkList[len(chunkList) - 1])) else: - result = dongle.exchange(apduMessage(0x04,0x90,0x00, None, chunkList[len(chunkList)-1])) + result = dongle.exchange( + apduMessage(0x04, 0x90, 0x00, None, + chunkList[len(chunkList) - 1])) return raw_tx, result + def address_hex(address): return base58.b58decode_check(address).hex().upper() + # Get Addresses logger.debug('-= Tron Ledger =-') - ''' Tron Protobuf ''' @@ -90,19 +109,17 @@ def address_hex(address): ''') tx = stub.CreateTransaction2( - contract.TransferContract( - owner_address=bytes.fromhex(address_hex("TUEZSdKsoDHQMeZwihtdoBiN46zxhGWYdH")), - to_address=bytes.fromhex(address_hex("TPnYqC2ukKyhEDAjqRRobSVygMAb8nAcXM")), - amount=100000 - ) - ) + contract.TransferContract( + owner_address=bytes.fromhex( + address_hex("TUEZSdKsoDHQMeZwihtdoBiN46zxhGWYdH")), + to_address=bytes.fromhex( + address_hex("TPnYqC2ukKyhEDAjqRRobSVygMAb8nAcXM")), + amount=100000)) # use permission 2 -tx.transaction.raw_data.contract[0].Permission_id=2 - - +tx.transaction.raw_data.contract[0].Permission_id = 2 -raw_tx, sign1 = ledgerSign(parse_bip32_path("44'/195'/0'/0/0"),tx.transaction) -raw_tx, sign2 = ledgerSign(parse_bip32_path("44'/195'/1'/0/0"),tx.transaction) +raw_tx, sign1 = ledgerSign(parse_bip32_path("44'/195'/0'/0/0"), tx.transaction) +raw_tx, sign2 = ledgerSign(parse_bip32_path("44'/195'/1'/0/0"), tx.transaction) tx.transaction.signature.extend([bytes(sign1[0:65])]) tx.transaction.signature.extend([bytes(sign2[0:65])]) @@ -110,6 +127,6 @@ def address_hex(address): r = stub.BroadcastTransaction(tx.transaction) if r.result == True: - print("Success") + print("Success") else: - print("Fail") + print("Fail") diff --git a/examples/runTest.py b/examples/runTest.py index c6f28eec..b14e3c90 100755 --- a/examples/runTest.py +++ b/examples/runTest.py @@ -1,6 +1,7 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- import sys + sys.path.append("./examples/proto") from pprint import pprint @@ -15,7 +16,8 @@ import binascii import base58 -logging.basicConfig(level=logging.DEBUG, format="%(asctime)s - %(levelname)s - %(message)s") +logging.basicConfig(level=logging.DEBUG, + format="%(asctime)s - %(levelname)s - %(message)s") logger = logging.getLogger() @@ -24,79 +26,94 @@ def chunks(l, n): for i in range(0, len(l), n): yield l[i:i + n] + def apduMessage(INS, P1, P2, PATH, MESSAGE): hexString = "" if PATH: - hexString = "E0{:02x}{:02x}{:02x}{:02x}{:02x}{}".format(INS,P1,P2,(len(PATH)+len(MESSAGE))//2+1,len(PATH)//4//2,PATH+MESSAGE) + hexString = "E0{:02x}{:02x}{:02x}{:02x}{:02x}{}".format( + INS, P1, P2, (len(PATH) + len(MESSAGE)) // 2 + 1, + len(PATH) // 4 // 2, PATH + MESSAGE) else: - hexString = "E0{:02x}{:02x}{:02x}{:02x}{}".format(INS,P1,P2,len(MESSAGE)//2,MESSAGE) + hexString = "E0{:02x}{:02x}{:02x}{:02x}{}".format( + INS, P1, P2, + len(MESSAGE) // 2, MESSAGE) print(hexString) return bytearray.fromhex(hexString) + def ledgerSign(PATH, tx, tokenSignature=[]): raw_tx = tx.raw_data.SerializeToString().hex() # Sign in chunks - chunkList = list(chunks(raw_tx,410)) - if len(tokenSignature)>0: + chunkList = list(chunks(raw_tx, 410)) + if len(tokenSignature) > 0: chunkList.extend(tokenSignature) # P1 = P1_FIRST = 0x00 - if len(chunkList)>1: - result = dongle.exchange(apduMessage(0x04,0x00,0x00, PATH, chunkList[0])) + if len(chunkList) > 1: + result = dongle.exchange( + apduMessage(0x04, 0x00, 0x00, PATH, chunkList[0])) else: - result = dongle.exchange(apduMessage(0x04,0x10,0x00, PATH, chunkList[0])) + result = dongle.exchange( + apduMessage(0x04, 0x10, 0x00, PATH, chunkList[0])) - for i in range(1,len(chunkList)-1-len(tokenSignature)): + for i in range(1, len(chunkList) - 1 - len(tokenSignature)): # P1 = P1_MODE = 0x80 - result = dongle.exchange(apduMessage(0x04,0x80,0x00, None, chunkList[i])) - - for i in range(0,len(tokenSignature)-1): - result = dongle.exchange(apduMessage(0x04,0xA0 | (0x00+i), 0x00, None, tokenSignature[i])) - + result = dongle.exchange( + apduMessage(0x04, 0x80, 0x00, None, chunkList[i])) + + for i in range(0, len(tokenSignature) - 1): + result = dongle.exchange( + apduMessage(0x04, 0xA0 | (0x00 + i), 0x00, None, + tokenSignature[i])) + # P1 = P1_LAST = 0x90 - if len(chunkList)>1: - if len(tokenSignature)>0: - result = dongle.exchange(apduMessage(0x04,0xA0 | 0x08 | (0x00+len(tokenSignature)-1),0x00, None, chunkList[len(chunkList)-1])) + if len(chunkList) > 1: + if len(tokenSignature) > 0: + result = dongle.exchange( + apduMessage(0x04, + 0xA0 | 0x08 | (0x00 + len(tokenSignature) - 1), + 0x00, None, chunkList[len(chunkList) - 1])) else: - result = dongle.exchange(apduMessage(0x04,0x90,0x00, None, chunkList[len(chunkList)-1])) + result = dongle.exchange( + apduMessage(0x04, 0x90, 0x00, None, + chunkList[len(chunkList) - 1])) return raw_tx, result + def address_hex(address): return base58.b58decode_check(address).hex().upper() + accounts = [{ - "path": parse_bip32_path("44'/195'/0'/0/0"), - }, - { - "path": parse_bip32_path("44'/195'/1'/0/0"), - }] + "path": parse_bip32_path("44'/195'/0'/0/0"), +}, { + "path": parse_bip32_path("44'/195'/1'/0/0"), +}] # Get Addresses logger.debug('-= Tron Ledger =-') logger.debug('Requesting Public Keys...') dongle = getDongle(True) for i in range(2): - result = dongle.exchange(apduMessage(0x02,0x00,0x00,accounts[i]['path'], "")) - size=result[0] - if size == 65 : - accounts[i]['publicKey'] = result[1:1+size].hex() - size=result[size+1] - if size == 34 : - accounts[i]['address'] = result[67:67+size].decode() + result = dongle.exchange( + apduMessage(0x02, 0x00, 0x00, accounts[i]['path'], "")) + size = result[0] + if size == 65: + accounts[i]['publicKey'] = result[1:1 + size].hex() + size = result[size + 1] + if size == 34: + accounts[i]['address'] = result[67:67 + size].decode() accounts[i]['addressHex'] = address_hex(accounts[i]['address']) else: logger.error('Error... Address Size: {:d}'.format(size)) else: logger.error('Error... Public Key Size: {:d}'.format(size)) - logger.debug('Test Accounts:') for i in range(2): logger.debug('- Public Key {}: {}'.format(i, accounts[i]['publicKey'])) - logger.debug('- Address {}: {}'.format(i,accounts[i]['address'])) - - + logger.debug('- Address {}: {}'.format(i, accounts[i]['address'])) ''' Tron Protobuf ''' @@ -120,14 +137,15 @@ def address_hex(address): ############ logger.debug('\n\nTransfer Contract:') -tx = stub.CreateTransaction2(contract.TransferContract( +tx = stub.CreateTransaction2( + contract.TransferContract( owner_address=bytes.fromhex(accounts[1]['addressHex']), to_address=bytes.fromhex(accounts[0]['addressHex']), - amount=1 - )) + amount=1)) -raw_tx, result = ledgerSign(accounts[1]['path'],tx.transaction) -validSignature, txID = validateSignature.validate(raw_tx,result[0:65],accounts[1]['publicKey'][2:]) +raw_tx, result = ledgerSign(accounts[1]['path'], tx.transaction) +validSignature, txID = validateSignature.validate(raw_tx, result[0:65], + accounts[1]['publicKey'][2:]) logger.debug('- RAW: {}'.format(raw_tx)) logger.debug('- txID: {}'.format(txID)) logger.debug('- Signature: {}'.format(binascii.hexlify(result[0:65]))) @@ -141,7 +159,6 @@ def address_hex(address): #tx.transaction.signature.extend([bytes(result[0:65])]) #r = stub.BroadcastTransaction(tx.transaction) - ###################### # Send TRX with DATA # ###################### @@ -150,20 +167,21 @@ def address_hex(address): # check if device have data enable result = dongle.exchange(bytearray.fromhex("E0060000FF")) dataAllowed = result[0] & 0x01 -if dataAllowed==0: +if dataAllowed == 0: print("Data field not allowed, test should fail...") sys.exit(0) -tx = stub.CreateTransaction2(contract.TransferContract( +tx = stub.CreateTransaction2( + contract.TransferContract( owner_address=bytes.fromhex(accounts[1]['addressHex']), to_address=bytes.fromhex(accounts[0]['addressHex']), - amount=1 - )) + amount=1)) tx.transaction.raw_data.data = b'CryptoChain-TronSR Ledger Transactions Tests' -raw_tx, result = ledgerSign(accounts[1]['path'],tx.transaction) -validSignature, txID = validateSignature.validate(raw_tx,result[0:65],accounts[1]['publicKey'][2:]) +raw_tx, result = ledgerSign(accounts[1]['path'], tx.transaction) +validSignature, txID = validateSignature.validate(raw_tx, result[0:65], + accounts[1]['publicKey'][2:]) logger.debug('- RAW: {}'.format(raw_tx)) logger.debug('- txID: {}'.format(txID)) logger.debug('- Signature: {}'.format(binascii.hexlify(result[0:65]))) @@ -178,15 +196,16 @@ def address_hex(address): #################### logger.debug('\n\nTransfer Asset Contract:') -tx = stub.TransferAsset2(contract.TransferAssetContract( +tx = stub.TransferAsset2( + contract.TransferAssetContract( asset_name="1000166".encode(), owner_address=bytes.fromhex(accounts[1]['addressHex']), to_address=bytes.fromhex(accounts[0]['addressHex']), - amount=1 - )) + amount=1)) -raw_tx, result = ledgerSign(accounts[1]['path'],tx.transaction) -validSignature, txID = validateSignature.validate(raw_tx,result[0:65],accounts[1]['publicKey'][2:]) +raw_tx, result = ledgerSign(accounts[1]['path'], tx.transaction) +validSignature, txID = validateSignature.validate(raw_tx, result[0:65], + accounts[1]['publicKey'][2:]) logger.debug('- RAW: {}'.format(raw_tx)) logger.debug('- txID: {}'.format(txID)) logger.debug('- Signature: {}'.format(binascii.hexlify(result[0:65]))) @@ -201,16 +220,20 @@ def address_hex(address): ####################################### logger.debug('\n\nTransfer Asset Contract with Name/Decimals:') -tx = stub.TransferAsset2(contract.TransferAssetContract( +tx = stub.TransferAsset2( + contract.TransferAssetContract( asset_name="1002000".encode(), owner_address=bytes.fromhex(accounts[1]['addressHex']), to_address=bytes.fromhex(accounts[0]['addressHex']), - amount=1 - )) + amount=1)) # BitTorrent 1002000 -> Decimals: 6 -tokenSignature = ["0a0a426974546f7272656e7410061a46304402202e2502f36b00e57be785fc79ec4043abcdd4fdd1b58d737ce123599dffad2cb602201702c307f009d014a553503b499591558b3634ceee4c054c61cedd8aca94c02b"] -raw_tx, result = ledgerSign(accounts[1]['path'],tx.transaction, tokenSignature) -validSignature, txID = validateSignature.validate(raw_tx,result[0:65],accounts[1]['publicKey'][2:]) +tokenSignature = [ + "0a0a426974546f7272656e7410061a46304402202e2502f36b00e57be785fc79ec4043abcdd4fdd1b58d737ce123599dffad2cb602201702c307f009d014a553503b499591558b3634ceee4c054c61cedd8aca94c02b" +] +raw_tx, result = ledgerSign(accounts[1]['path'], tx.transaction, + tokenSignature) +validSignature, txID = validateSignature.validate(raw_tx, result[0:65], + accounts[1]['publicKey'][2:]) logger.debug('- RAW: {}'.format(raw_tx)) logger.debug('- txID: {}'.format(txID)) logger.debug('- Signature: {}'.format(binascii.hexlify(result[0:65]))) @@ -227,21 +250,20 @@ def address_hex(address): tx = tron.Transaction() newContract = contract.ExchangeCreateContract( - owner_address=bytes.fromhex(accounts[1]['addressHex']), - first_token_id="_".encode(), - first_token_balance=10000000000, - second_token_id="1000166".encode(), - second_token_balance=10000000 - ) + owner_address=bytes.fromhex(accounts[1]['addressHex']), + first_token_id="_".encode(), + first_token_balance=10000000000, + second_token_id="1000166".encode(), + second_token_balance=10000000) c = tx.raw_data.contract.add() c.type = tron.Transaction.Contract.ExchangeCreateContract param = Any() param.Pack(newContract) c.parameter.CopyFrom(param) - -raw_tx, result = ledgerSign(accounts[1]['path'],tx) -validSignature, txID = validateSignature.validate(raw_tx,result[0:65],accounts[1]['publicKey'][2:]) +raw_tx, result = ledgerSign(accounts[1]['path'], tx) +validSignature, txID = validateSignature.validate(raw_tx, result[0:65], + accounts[1]['publicKey'][2:]) logger.debug('- RAW: {}'.format(raw_tx)) logger.debug('- txID: {}'.format(txID)) logger.debug('- Signature: {}'.format(binascii.hexlify(result[0:65]))) @@ -258,25 +280,27 @@ def address_hex(address): tx = tron.Transaction() newContract = contract.ExchangeCreateContract( - owner_address=bytes.fromhex(accounts[1]['addressHex']), - first_token_id="_".encode(), - first_token_balance=10000000000, - second_token_id="1000166".encode(), - second_token_balance=10000000 - ) + owner_address=bytes.fromhex(accounts[1]['addressHex']), + first_token_id="_".encode(), + first_token_balance=10000000000, + second_token_id="1000166".encode(), + second_token_balance=10000000) c = tx.raw_data.contract.add() c.type = tron.Transaction.Contract.ExchangeCreateContract param = Any() param.Pack(newContract) c.parameter.CopyFrom(param) -# Token Signature -# Token 1: _ TRX +# Token Signature +# Token 1: _ TRX # Token 2: 1000166 CCT -tokenSignature = ["0a0354525810061a463044022037c53ecb06abe1bfd708bd7afd047720b72e2bfc0a2e4b6ade9a33ae813565a802200a7d5086dc08c4a6f866aad803ac7438942c3c0a6371adcb6992db94487f66c7", - "0a0b43727970746f436861696e10001a4730450221008417d04d1caeae31f591ae50f7d19e53e0dfb827bd51c18e66081941bf04639802203c73361a521c969e3fd7f62e62b46d61aad00e47d41e7da108546d954278a6b1"] -raw_tx, result = ledgerSign(accounts[1]['path'],tx, tokenSignature) -validSignature, txID = validateSignature.validate(raw_tx,result[0:65],accounts[1]['publicKey'][2:]) +tokenSignature = [ + "0a0354525810061a463044022037c53ecb06abe1bfd708bd7afd047720b72e2bfc0a2e4b6ade9a33ae813565a802200a7d5086dc08c4a6f866aad803ac7438942c3c0a6371adcb6992db94487f66c7", + "0a0b43727970746f436861696e10001a4730450221008417d04d1caeae31f591ae50f7d19e53e0dfb827bd51c18e66081941bf04639802203c73361a521c969e3fd7f62e62b46d61aad00e47d41e7da108546d954278a6b1" +] +raw_tx, result = ledgerSign(accounts[1]['path'], tx, tokenSignature) +validSignature, txID = validateSignature.validate(raw_tx, result[0:65], + accounts[1]['publicKey'][2:]) logger.debug('- RAW: {}'.format(raw_tx)) logger.debug('- txID: {}'.format(txID)) logger.debug('- Signature: {}'.format(binascii.hexlify(result[0:65]))) @@ -292,12 +316,11 @@ def address_hex(address): logger.debug('\n\nExchange Inject Contract:') tx = tron.Transaction() -newContract = contract.ExchangeInjectContract( - owner_address=bytes.fromhex(accounts[1]['addressHex']), - exchange_id=6, - token_id="1000166".encode(), - quant=10000000 - ) +newContract = contract.ExchangeInjectContract(owner_address=bytes.fromhex( + accounts[1]['addressHex']), + exchange_id=6, + token_id="1000166".encode(), + quant=10000000) c = tx.raw_data.contract.add() c.type = tron.Transaction.Contract.ExchangeInjectContract param = Any() @@ -305,9 +328,12 @@ def address_hex(address): c.parameter.CopyFrom(param) # Exchange 6 CCT <-> TRX -exchangeSignature = ["08061207313030303136361a0b43727970746f436861696e20002a015f3203545258380642473045022100fe276f30a63173b2440991affbbdc5d6d2d22b61b306b24e535a2fb866518d9c02205f7f41254201131382ec6c8b3c78276a2bb136f910b9a1f37bfde192fc448793"] -raw_tx, result = ledgerSign(accounts[1]['path'],tx, exchangeSignature) -validSignature, txID = validateSignature.validate(raw_tx,result[0:65],accounts[1]['publicKey'][2:]) +exchangeSignature = [ + "08061207313030303136361a0b43727970746f436861696e20002a015f3203545258380642473045022100fe276f30a63173b2440991affbbdc5d6d2d22b61b306b24e535a2fb866518d9c02205f7f41254201131382ec6c8b3c78276a2bb136f910b9a1f37bfde192fc448793" +] +raw_tx, result = ledgerSign(accounts[1]['path'], tx, exchangeSignature) +validSignature, txID = validateSignature.validate(raw_tx, result[0:65], + accounts[1]['publicKey'][2:]) logger.debug('- RAW: {}'.format(raw_tx)) logger.debug('- txID: {}'.format(txID)) logger.debug('- Signature: {}'.format(binascii.hexlify(result[0:65]))) @@ -323,12 +349,11 @@ def address_hex(address): logger.debug('\n\nExchange Withdraw Contract:') tx = tron.Transaction() -newContract = contract.ExchangeWithdrawContract( - owner_address=bytes.fromhex(accounts[1]['addressHex']), - exchange_id=6, - token_id="1000166".encode(), - quant=1000000 - ) +newContract = contract.ExchangeWithdrawContract(owner_address=bytes.fromhex( + accounts[1]['addressHex']), + exchange_id=6, + token_id="1000166".encode(), + quant=1000000) c = tx.raw_data.contract.add() c.type = tron.Transaction.Contract.ExchangeWithdrawContract param = Any() @@ -336,9 +361,12 @@ def address_hex(address): c.parameter.CopyFrom(param) # Exchange 6 CCT <-> TRX -exchangeSignature = ["08061207313030303136361a0b43727970746f436861696e20002a015f3203545258380642473045022100fe276f30a63173b2440991affbbdc5d6d2d22b61b306b24e535a2fb866518d9c02205f7f41254201131382ec6c8b3c78276a2bb136f910b9a1f37bfde192fc448793"] -raw_tx, result = ledgerSign(accounts[1]['path'],tx, exchangeSignature) -validSignature, txID = validateSignature.validate(raw_tx,result[0:65],accounts[1]['publicKey'][2:]) +exchangeSignature = [ + "08061207313030303136361a0b43727970746f436861696e20002a015f3203545258380642473045022100fe276f30a63173b2440991affbbdc5d6d2d22b61b306b24e535a2fb866518d9c02205f7f41254201131382ec6c8b3c78276a2bb136f910b9a1f37bfde192fc448793" +] +raw_tx, result = ledgerSign(accounts[1]['path'], tx, exchangeSignature) +validSignature, txID = validateSignature.validate(raw_tx, result[0:65], + accounts[1]['publicKey'][2:]) logger.debug('- RAW: {}'.format(raw_tx)) logger.debug('- txID: {}'.format(txID)) logger.debug('- Signature: {}'.format(binascii.hexlify(result[0:65]))) @@ -348,20 +376,18 @@ def address_hex(address): logger.error('- Valid: {}'.format(validSignature)) sys.exit(0) - ############################## # TRC10 Exchange Transaction # ############################## logger.debug('\n\nExchange Transaction Contract:') tx = tron.Transaction() -newContract = contract.ExchangeTransactionContract( - owner_address=bytes.fromhex(accounts[1]['addressHex']), - exchange_id=6, - token_id="1000166".encode(), - quant=10000, - expected=100 - ) +newContract = contract.ExchangeTransactionContract(owner_address=bytes.fromhex( + accounts[1]['addressHex']), + exchange_id=6, + token_id="1000166".encode(), + quant=10000, + expected=100) c = tx.raw_data.contract.add() c.type = tron.Transaction.Contract.ExchangeTransactionContract param = Any() @@ -369,9 +395,12 @@ def address_hex(address): c.parameter.CopyFrom(param) # Exchange 6 CCT <-> TRX -exchangeSignature = ["08061207313030303136361a0b43727970746f436861696e20002a015f3203545258380642473045022100fe276f30a63173b2440991affbbdc5d6d2d22b61b306b24e535a2fb866518d9c02205f7f41254201131382ec6c8b3c78276a2bb136f910b9a1f37bfde192fc448793"] -raw_tx, result = ledgerSign(accounts[1]['path'],tx, exchangeSignature) -validSignature, txID = validateSignature.validate(raw_tx,result[0:65],accounts[1]['publicKey'][2:]) +exchangeSignature = [ + "08061207313030303136361a0b43727970746f436861696e20002a015f3203545258380642473045022100fe276f30a63173b2440991affbbdc5d6d2d22b61b306b24e535a2fb866518d9c02205f7f41254201131382ec6c8b3c78276a2bb136f910b9a1f37bfde192fc448793" +] +raw_tx, result = ledgerSign(accounts[1]['path'], tx, exchangeSignature) +validSignature, txID = validateSignature.validate(raw_tx, result[0:65], + accounts[1]['publicKey'][2:]) logger.debug('- RAW: {}'.format(raw_tx)) logger.debug('- txID: {}'.format(txID)) logger.debug('- Signature: {}'.format(binascii.hexlify(result[0:65]))) @@ -388,26 +417,30 @@ def address_hex(address): tx = tron.Transaction() newContract = contract.VoteWitnessContract( - owner_address=bytes.fromhex(accounts[1]['addressHex']) - ) + owner_address=bytes.fromhex(accounts[1]['addressHex'])) tx.raw_data.ref_block_bytes = b'0000' tx.raw_data.timestamp = 110101010101 -# Vote list +# Vote list v1 = newContract.votes.add() -v1.vote_address=bytes.fromhex(address_hex("TKSXDA8HfE9E1y39RczVQ1ZascUEtaSToF")) -v1.vote_count=1 +v1.vote_address = bytes.fromhex( + address_hex("TKSXDA8HfE9E1y39RczVQ1ZascUEtaSToF")) +v1.vote_count = 1 v2 = newContract.votes.add() -v2.vote_address=bytes.fromhex(address_hex("TE7hnUtWRRBz3SkFrX8JESWUmEvxxAhoPt")) -v2.vote_count=1 +v2.vote_address = bytes.fromhex( + address_hex("TE7hnUtWRRBz3SkFrX8JESWUmEvxxAhoPt")) +v2.vote_count = 1 v3 = newContract.votes.add() -v3.vote_address=bytes.fromhex(address_hex("TTcYhypP8m4phDhN6oRexz2174zAerjEWP")) -v3.vote_count=1000 +v3.vote_address = bytes.fromhex( + address_hex("TTcYhypP8m4phDhN6oRexz2174zAerjEWP")) +v3.vote_count = 1000 v4 = newContract.votes.add() -v4.vote_address=bytes.fromhex(address_hex("TY65QiDt4hLTMpf3WRzcX357BnmdxT2sw9")) -v4.vote_count=1000 +v4.vote_address = bytes.fromhex( + address_hex("TY65QiDt4hLTMpf3WRzcX357BnmdxT2sw9")) +v4.vote_count = 1000 v5 = newContract.votes.add() -v5.vote_address=bytes.fromhex(address_hex("TSNbzxac4WhxN91XvaUfPTKP2jNT18mP6T")) -v5.vote_count=1000 +v5.vote_address = bytes.fromhex( + address_hex("TSNbzxac4WhxN91XvaUfPTKP2jNT18mP6T")) +v5.vote_count = 1000 # End vote list c = tx.raw_data.contract.add() c.type = tron.Transaction.Contract.VoteWitnessContract @@ -415,9 +448,10 @@ def address_hex(address): param.Pack(newContract) c.parameter.CopyFrom(param) -print( tx.raw_data.SerializeToString().hex() ) -raw_tx, result = ledgerSign(accounts[1]['path'],tx) -validSignature, txID = validateSignature.validate(raw_tx,result[0:65],accounts[1]['publicKey'][2:]) +print(tx.raw_data.SerializeToString().hex()) +raw_tx, result = ledgerSign(accounts[1]['path'], tx) +validSignature, txID = validateSignature.validate(raw_tx, result[0:65], + accounts[1]['publicKey'][2:]) logger.debug('- RAW: {}'.format(raw_tx)) logger.debug('- txID: {}'.format(txID)) logger.debug('- Signature: {}'.format(binascii.hexlify(result[0:65]))) @@ -427,27 +461,26 @@ def address_hex(address): logger.error('- Valid: {}'.format(validSignature)) sys.exit(0) - ##################### # Freeze Balance BW # ##################### logger.debug('\n\nFreeze Contract bandwidth:') tx = tron.Transaction() -newContract = contract.FreezeBalanceContract( - owner_address=bytes.fromhex(accounts[1]['addressHex']), - frozen_balance=10000000000, - frozen_duration=3, - resource=contract.BANDWIDTH - ) +newContract = contract.FreezeBalanceContract(owner_address=bytes.fromhex( + accounts[1]['addressHex']), + frozen_balance=10000000000, + frozen_duration=3, + resource=contract.BANDWIDTH) c = tx.raw_data.contract.add() c.type = tron.Transaction.Contract.FreezeBalanceContract param = Any() param.Pack(newContract) c.parameter.CopyFrom(param) -raw_tx, result = ledgerSign(accounts[1]['path'],tx) -validSignature, txID = validateSignature.validate(raw_tx,result[0:65],accounts[1]['publicKey'][2:]) +raw_tx, result = ledgerSign(accounts[1]['path'], tx) +validSignature, txID = validateSignature.validate(raw_tx, result[0:65], + accounts[1]['publicKey'][2:]) logger.debug('- RAW: {}'.format(raw_tx)) logger.debug('- txID: {}'.format(txID)) logger.debug('- Signature: {}'.format(binascii.hexlify(result[0:65]))) @@ -457,7 +490,6 @@ def address_hex(address): logger.error('- Valid: {}'.format(validSignature)) sys.exit(0) - ################################# # Freeze Balance Delegate Energy# ################################# @@ -465,20 +497,21 @@ def address_hex(address): tx = tron.Transaction() newContract = contract.FreezeBalanceContract( - owner_address=bytes.fromhex(accounts[1]['addressHex']), - frozen_balance=10000000000, - frozen_duration=3, - resource=contract.ENERGY, - receiver_address=bytes.fromhex(accounts[0]['addressHex']), - ) + owner_address=bytes.fromhex(accounts[1]['addressHex']), + frozen_balance=10000000000, + frozen_duration=3, + resource=contract.ENERGY, + receiver_address=bytes.fromhex(accounts[0]['addressHex']), +) c = tx.raw_data.contract.add() c.type = tron.Transaction.Contract.FreezeBalanceContract param = Any() param.Pack(newContract) c.parameter.CopyFrom(param) -raw_tx, result = ledgerSign(accounts[1]['path'],tx) -validSignature, txID = validateSignature.validate(raw_tx,result[0:65],accounts[1]['publicKey'][2:]) +raw_tx, result = ledgerSign(accounts[1]['path'], tx) +validSignature, txID = validateSignature.validate(raw_tx, result[0:65], + accounts[1]['publicKey'][2:]) logger.debug('- RAW: {}'.format(raw_tx)) logger.debug('- txID: {}'.format(txID)) logger.debug('- Signature: {}'.format(binascii.hexlify(result[0:65]))) @@ -488,25 +521,24 @@ def address_hex(address): logger.error('- Valid: {}'.format(validSignature)) sys.exit(0) - ###################### # Unfreeze Balance BW# ###################### logger.debug('\n\nUnfreeze Contract bandwidth:') tx = tron.Transaction() -newContract = contract.UnfreezeBalanceContract( - owner_address=bytes.fromhex(accounts[1]['addressHex']), - resource=contract.BANDWIDTH - ) +newContract = contract.UnfreezeBalanceContract(owner_address=bytes.fromhex( + accounts[1]['addressHex']), + resource=contract.BANDWIDTH) c = tx.raw_data.contract.add() c.type = tron.Transaction.Contract.UnfreezeBalanceContract param = Any() param.Pack(newContract) c.parameter.CopyFrom(param) -raw_tx, result = ledgerSign(accounts[1]['path'],tx) -validSignature, txID = validateSignature.validate(raw_tx,result[0:65],accounts[1]['publicKey'][2:]) +raw_tx, result = ledgerSign(accounts[1]['path'], tx) +validSignature, txID = validateSignature.validate(raw_tx, result[0:65], + accounts[1]['publicKey'][2:]) logger.debug('- RAW: {}'.format(raw_tx)) logger.debug('- txID: {}'.format(txID)) logger.debug('- Signature: {}'.format(binascii.hexlify(result[0:65]))) @@ -523,18 +555,19 @@ def address_hex(address): tx = tron.Transaction() newContract = contract.UnfreezeBalanceContract( - owner_address=bytes.fromhex(accounts[1]['addressHex']), - resource=contract.ENERGY, - receiver_address=bytes.fromhex(accounts[0]['addressHex']), - ) + owner_address=bytes.fromhex(accounts[1]['addressHex']), + resource=contract.ENERGY, + receiver_address=bytes.fromhex(accounts[0]['addressHex']), +) c = tx.raw_data.contract.add() c.type = tron.Transaction.Contract.UnfreezeBalanceContract param = Any() param.Pack(newContract) c.parameter.CopyFrom(param) -raw_tx, result = ledgerSign(accounts[1]['path'],tx) -validSignature, txID = validateSignature.validate(raw_tx,result[0:65],accounts[1]['publicKey'][2:]) +raw_tx, result = ledgerSign(accounts[1]['path'], tx) +validSignature, txID = validateSignature.validate(raw_tx, result[0:65], + accounts[1]['publicKey'][2:]) logger.debug('- RAW: {}'.format(raw_tx)) logger.debug('- txID: {}'.format(txID)) logger.debug('- Signature: {}'.format(binascii.hexlify(result[0:65]))) @@ -544,7 +577,6 @@ def address_hex(address): logger.error('- Valid: {}'.format(validSignature)) sys.exit(0) - ##################### # Widthdraw Balance # ##################### @@ -553,16 +585,16 @@ def address_hex(address): tx = tron.Transaction() newContract = contract.WithdrawBalanceContract( - owner_address=bytes.fromhex(accounts[1]['addressHex']) - ) + owner_address=bytes.fromhex(accounts[1]['addressHex'])) c = tx.raw_data.contract.add() c.type = tron.Transaction.Contract.WithdrawBalanceContract param = Any() param.Pack(newContract) c.parameter.CopyFrom(param) -raw_tx, result = ledgerSign(accounts[0]['path'],tx) -validSignature, txID = validateSignature.validate(raw_tx,result[0:65],accounts[0]['publicKey'][2:]) +raw_tx, result = ledgerSign(accounts[0]['path'], tx) +validSignature, txID = validateSignature.validate(raw_tx, result[0:65], + accounts[0]['publicKey'][2:]) logger.debug('- RAW: {}'.format(raw_tx)) logger.debug('- txID: {}'.format(txID)) logger.debug('- Signature: {}'.format(binascii.hexlify(result[0:65]))) @@ -572,7 +604,6 @@ def address_hex(address): logger.error('- Valid: {}'.format(validSignature)) sys.exit(0) - ################### # Proposal Create # ################### @@ -580,9 +611,8 @@ def address_hex(address): logger.debug('\n\Proposal Create Contract:') tx = tron.Transaction() -newContract = contract.ProposalCreateContract( - owner_address=bytes.fromhex(accounts[1]['addressHex']), - ) +newContract = contract.ProposalCreateContract(owner_address=bytes.fromhex( + accounts[1]['addressHex']), ) newContract.parameters[1] = 10000000 c = tx.raw_data.contract.add() c.type = tron.Transaction.Contract.ProposalCreateContract @@ -590,8 +620,9 @@ def address_hex(address): param.Pack(newContract) c.parameter.CopyFrom(param) -raw_tx, result = ledgerSign(accounts[1]['path'],tx) -validSignature, txID = validateSignature.validate(raw_tx,result[0:65],accounts[1]['publicKey'][2:]) +raw_tx, result = ledgerSign(accounts[1]['path'], tx) +validSignature, txID = validateSignature.validate(raw_tx, result[0:65], + accounts[1]['publicKey'][2:]) logger.debug('- RAW: {}'.format(raw_tx)) logger.debug('- txID: {}'.format(txID)) logger.debug('- Signature: {}'.format(binascii.hexlify(result[0:65]))) @@ -601,7 +632,6 @@ def address_hex(address): logger.error('- Valid: {}'.format(validSignature)) sys.exit(0) - #################### # Proposal Approve # #################### @@ -610,11 +640,10 @@ def address_hex(address): tx = tron.Transaction() -newContract = contract.ProposalApproveContract( - owner_address=bytes.fromhex(accounts[1]['addressHex']), - proposal_id=10, - is_add_approval=True - ) +newContract = contract.ProposalApproveContract(owner_address=bytes.fromhex( + accounts[1]['addressHex']), + proposal_id=10, + is_add_approval=True) c = tx.raw_data.contract.add() c.type = tron.Transaction.Contract.ProposalApproveContract @@ -622,8 +651,9 @@ def address_hex(address): param.Pack(newContract) c.parameter.CopyFrom(param) -raw_tx, result = ledgerSign(accounts[1]['path'],tx) -validSignature, txID = validateSignature.validate(raw_tx,result[0:65],accounts[1]['publicKey'][2:]) +raw_tx, result = ledgerSign(accounts[1]['path'], tx) +validSignature, txID = validateSignature.validate(raw_tx, result[0:65], + accounts[1]['publicKey'][2:]) logger.debug('- RAW: {}'.format(raw_tx)) logger.debug('- txID: {}'.format(txID)) logger.debug('- Signature: {}'.format(binascii.hexlify(result[0:65]))) @@ -633,7 +663,6 @@ def address_hex(address): logger.error('- Valid: {}'.format(validSignature)) sys.exit(0) - ################### # Proposal Delete # ################### @@ -643,9 +672,9 @@ def address_hex(address): tx = tron.Transaction() newContract = contract.ProposalDeleteContract( - owner_address=bytes.fromhex(accounts[1]['addressHex']), - proposal_id=10, - ) + owner_address=bytes.fromhex(accounts[1]['addressHex']), + proposal_id=10, +) c = tx.raw_data.contract.add() c.type = tron.Transaction.Contract.ProposalDeleteContract @@ -653,8 +682,9 @@ def address_hex(address): param.Pack(newContract) c.parameter.CopyFrom(param) -raw_tx, result = ledgerSign(accounts[1]['path'],tx) -validSignature, txID = validateSignature.validate(raw_tx,result[0:65],accounts[1]['publicKey'][2:]) +raw_tx, result = ledgerSign(accounts[1]['path'], tx) +validSignature, txID = validateSignature.validate(raw_tx, result[0:65], + accounts[1]['publicKey'][2:]) logger.debug('- RAW: {}'.format(raw_tx)) logger.debug('- txID: {}'.format(txID)) logger.debug('- Signature: {}'.format(binascii.hexlify(result[0:65]))) @@ -664,7 +694,6 @@ def address_hex(address): logger.error('- Valid: {}'.format(validSignature)) sys.exit(0) - ################## # Account Update # ################## @@ -673,9 +702,9 @@ def address_hex(address): tx = tron.Transaction() newContract = contract.AccountUpdateContract( - account_name=b'CryptoChainTest', - owner_address=bytes.fromhex(accounts[1]['addressHex']), - ) + account_name=b'CryptoChainTest', + owner_address=bytes.fromhex(accounts[1]['addressHex']), +) c = tx.raw_data.contract.add() c.type = tron.Transaction.Contract.AccountUpdateContract @@ -683,8 +712,9 @@ def address_hex(address): param.Pack(newContract) c.parameter.CopyFrom(param) -raw_tx, result = ledgerSign(accounts[1]['path'],tx) -validSignature, txID = validateSignature.validate(raw_tx,result[0:65],accounts[1]['publicKey'][2:]) +raw_tx, result = ledgerSign(accounts[1]['path'], tx) +validSignature, txID = validateSignature.validate(raw_tx, result[0:65], + accounts[1]['publicKey'][2:]) logger.debug('- RAW: {}'.format(raw_tx)) logger.debug('- txID: {}'.format(txID)) logger.debug('- Signature: {}'.format(binascii.hexlify(result[0:65]))) @@ -694,7 +724,6 @@ def address_hex(address): logger.error('- Valid: {}'.format(validSignature)) sys.exit(0) - ################## # TRC20 Transfer # ################## @@ -703,10 +732,12 @@ def address_hex(address): tx = tron.Transaction() newContract = contract.TriggerSmartContract( - owner_address=bytes.fromhex(accounts[1]['addressHex']), - contract_address=bytes.fromhex(address_hex("TBoTZcARzWVgnNuB9SyE3S5g1RwsXoQL16")), - data=bytes.fromhex("a9059cbb000000000000000000000000364b03e0815687edaf90b81ff58e496dea7383d700000000000000000000000000000000000000000000000000000000000f4240") - ) + owner_address=bytes.fromhex(accounts[1]['addressHex']), + contract_address=bytes.fromhex( + address_hex("TBoTZcARzWVgnNuB9SyE3S5g1RwsXoQL16")), + data=bytes.fromhex( + "a9059cbb000000000000000000000000364b03e0815687edaf90b81ff58e496dea7383d700000000000000000000000000000000000000000000000000000000000f4240" + )) c = tx.raw_data.contract.add() c.type = tron.Transaction.Contract.TriggerSmartContract @@ -716,8 +747,9 @@ def address_hex(address): pprint(newContract) -raw_tx, result = ledgerSign(accounts[1]['path'],tx) -validSignature, txID = validateSignature.validate(raw_tx,result[0:65],accounts[1]['publicKey'][2:]) +raw_tx, result = ledgerSign(accounts[1]['path'], tx) +validSignature, txID = validateSignature.validate(raw_tx, result[0:65], + accounts[1]['publicKey'][2:]) logger.debug('- RAW: {}'.format(raw_tx)) logger.debug('- txID: {}'.format(txID)) logger.debug('- Signature: {}'.format(binascii.hexlify(result[0:65]))) @@ -735,10 +767,12 @@ def address_hex(address): tx = tron.Transaction() newContract = contract.TriggerSmartContract( - owner_address=bytes.fromhex(accounts[1]['addressHex']), - contract_address=bytes.fromhex(address_hex("TBoTZcARzWVgnNuB9SyE3S5g1RwsXoQL16")), - data=bytes.fromhex("095ea7b3000000000000000000000000364b03e0815687edaf90b81ff58e496dea7383d700000000000000000000000000000000000000000000000000000000000f4240") - ) + owner_address=bytes.fromhex(accounts[1]['addressHex']), + contract_address=bytes.fromhex( + address_hex("TBoTZcARzWVgnNuB9SyE3S5g1RwsXoQL16")), + data=bytes.fromhex( + "095ea7b3000000000000000000000000364b03e0815687edaf90b81ff58e496dea7383d700000000000000000000000000000000000000000000000000000000000f4240" + )) c = tx.raw_data.contract.add() c.type = tron.Transaction.Contract.TriggerSmartContract @@ -748,8 +782,9 @@ def address_hex(address): pprint(newContract) -raw_tx, result = ledgerSign(accounts[1]['path'],tx) -validSignature, txID = validateSignature.validate(raw_tx,result[0:65],accounts[1]['publicKey'][2:]) +raw_tx, result = ledgerSign(accounts[1]['path'], tx) +validSignature, txID = validateSignature.validate(raw_tx, result[0:65], + accounts[1]['publicKey'][2:]) logger.debug('- RAW: {}'.format(raw_tx)) logger.debug('- txID: {}'.format(txID)) logger.debug('- Signature: {}'.format(binascii.hexlify(result[0:65]))) diff --git a/examples/signExchangeTransaction.py b/examples/signExchangeTransaction.py index 5f5b817b..36492730 100755 --- a/examples/signExchangeTransaction.py +++ b/examples/signExchangeTransaction.py @@ -6,11 +6,12 @@ import binascii parser = argparse.ArgumentParser() -parser.add_argument('--path', help="BIP32 path to retrieve. e.g. \"44'/195'/0'/0/0\".") +parser.add_argument('--path', + help="BIP32 path to retrieve. e.g. \"44'/195'/0'/0/0\".") args = parser.parse_args() if args.path == None: - args.path = "44'/195'/0'/0/0" + args.path = "44'/195'/0'/0/0" donglePath = parse_bip32_path(args.path) @@ -24,10 +25,14 @@ signatureCheck = "a1b321a521ff05b7159fee36c34c5918a7082125ef4152debf4ab73ffd366e8f4beec9d21c35c3d0c90db6de36f3b408a3f1449dc28f08b2a5a8ff04c95c007801" # P1 = 0x00 - first message -apduMessage1 = "E004{:02x}00".format(0x00) + '{:02x}'.format(int(len(donglePath) / 2) + 1 + int(len(transactionRaw) / 2)) + '{:02x}'.format(int(len(donglePath) / 4 / 2)) + donglePath + transactionRaw +apduMessage1 = "E004{:02x}00".format(0x00) + '{:02x}'.format( + int(len(donglePath) / 2) + 1 + + int(len(transactionRaw) / 2)) + '{:02x}'.format( + int(len(donglePath) / 4 / 2)) + donglePath + transactionRaw # Exchange info # To add info P1 = 0xA0 | 0x08 END | Index = 0 -apduMessage2 = "E004{:02x}00".format(0xA0 | 0x08 | 0x00) + '{:02x}'.format(int(len(exchangeInfo) / 2) ) + exchangeInfo +apduMessage2 = "E004{:02x}00".format(0xA0 | 0x08 | 0x00) + '{:02x}'.format( + int(len(exchangeInfo) / 2)) + exchangeInfo print("-= Tron Ledger =-") print("Sign Exchange Transaction") @@ -36,7 +41,7 @@ print(apduMessage2.strip()) result = dongle.exchange(bytearray.fromhex(apduMessage2)) print(binascii.hexlify(result[0:65])) -if binascii.hexlify(result[0:65]).decode()==signatureCheck: - print("Signature Validated!") +if binascii.hexlify(result[0:65]).decode() == signatureCheck: + print("Signature Validated!") else: - print("Signature Error!") \ No newline at end of file + print("Signature Error!") diff --git a/examples/signMessage.py b/examples/signMessage.py index 2bd18e3d..46fd1f20 100755 --- a/examples/signMessage.py +++ b/examples/signMessage.py @@ -12,15 +12,21 @@ import struct from Crypto.Hash import keccak -logging.basicConfig(level=logging.DEBUG, format="%(asctime)s - %(levelname)s - %(message)s") +logging.basicConfig(level=logging.DEBUG, + format="%(asctime)s - %(levelname)s - %(message)s") logger = logging.getLogger() + def apduMessage(INS, P1, P2, PATH, MESSAGE): hexString = "" if PATH: - hexString = "E0{:02x}{:02x}{:02x}{:02x}{:02x}{}".format(INS,P1,P2,(len(PATH)+len(MESSAGE))//2+1,len(PATH)//4//2,PATH+MESSAGE) + hexString = "E0{:02x}{:02x}{:02x}{:02x}{:02x}{}".format( + INS, P1, P2, (len(PATH) + len(MESSAGE)) // 2 + 1, + len(PATH) // 4 // 2, PATH + MESSAGE) else: - hexString = "E0{:02x}{:02x}{:02x}{:02x}{}".format(INS,P1,P2,len(MESSAGE)//2,MESSAGE) + hexString = "E0{:02x}{:02x}{:02x}{:02x}{}".format( + INS, P1, P2, + len(MESSAGE) // 2, MESSAGE) print(hexString) return bytearray.fromhex(hexString) @@ -44,19 +50,21 @@ def apduMessage(INS, P1, P2, PATH, MESSAGE): dongle = getDongle(True) -result = dongle.exchange(apduMessage(0x02,0x00,0x00,donglePath, "")) -size=result[0] -if size == 65 : - publicKey = result[1:1+size].hex() +result = dongle.exchange(apduMessage(0x02, 0x00, 0x00, donglePath, "")) +size = result[0] +if size == 65: + publicKey = result[1:1 + size].hex() -result = dongle.exchange(apduMessage(0x08,0x00,0x00, donglePath, encodedTx.hex())) +result = dongle.exchange( + apduMessage(0x08, 0x00, 0x00, donglePath, encodedTx.hex())) signedMessage = SIGN_MAGIC + str(len(args.message)).encode() + args.message keccak_hash = keccak.new(digest_bits=256) keccak_hash.update(signedMessage) hash = keccak_hash.digest() -validSignature = validateSignature.validateHASH(hash,result[0:65],publicKey[2:]) +validSignature = validateSignature.validateHASH(hash, result[0:65], + publicKey[2:]) logger.debug('- HASH: {}'.format(hash)) logger.debug('- Signature: {}'.format(binascii.hexlify(result[0:65]))) logger.debug('- Valid: {}'.format(validSignature)) diff --git a/examples/signPermissionedTransaction.py b/examples/signPermissionedTransaction.py index dd106a88..4cff765e 100644 --- a/examples/signPermissionedTransaction.py +++ b/examples/signPermissionedTransaction.py @@ -1,6 +1,7 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- import sys + sys.path.append("./examples/proto") from pprint import pprint @@ -15,7 +16,8 @@ import binascii import base58 -logging.basicConfig(level=logging.DEBUG, format="%(asctime)s - %(levelname)s - %(message)s") +logging.basicConfig(level=logging.DEBUG, + format="%(asctime)s - %(levelname)s - %(message)s") logger = logging.getLogger() # Start Ledger @@ -27,50 +29,67 @@ def chunks(l, n): for i in range(0, len(l), n): yield l[i:i + n] + def apduMessage(INS, P1, P2, PATH, MESSAGE): hexString = "" if PATH: - hexString = "E0{:02x}{:02x}{:02x}{:02x}{:02x}{}".format(INS,P1,P2,(len(PATH)+len(MESSAGE))//2+1,len(PATH)//4//2,PATH+MESSAGE) + hexString = "E0{:02x}{:02x}{:02x}{:02x}{:02x}{}".format( + INS, P1, P2, (len(PATH) + len(MESSAGE)) // 2 + 1, + len(PATH) // 4 // 2, PATH + MESSAGE) else: - hexString = "E0{:02x}{:02x}{:02x}{:02x}{}".format(INS,P1,P2,len(MESSAGE)//2,MESSAGE) + hexString = "E0{:02x}{:02x}{:02x}{:02x}{}".format( + INS, P1, P2, + len(MESSAGE) // 2, MESSAGE) print(hexString) return bytearray.fromhex(hexString) + def ledgerSign(PATH, tx, tokenSignature=[]): raw_tx = tx.raw_data.SerializeToString().hex() # Sign in chunks - chunkList = list(chunks(raw_tx,420)) - if len(tokenSignature)>0: + chunkList = list(chunks(raw_tx, 420)) + if len(tokenSignature) > 0: chunkList.extend(tokenSignature) # P1 = P1_FIRST = 0x00 - if len(chunkList)>1: - result = dongle.exchange(apduMessage(0x04,0x00,0x00, PATH, chunkList[0])) + if len(chunkList) > 1: + result = dongle.exchange( + apduMessage(0x04, 0x00, 0x00, PATH, chunkList[0])) else: - result = dongle.exchange(apduMessage(0x04,0x10,0x00, PATH, chunkList[0])) + result = dongle.exchange( + apduMessage(0x04, 0x10, 0x00, PATH, chunkList[0])) - for i in range(1,len(chunkList)-1-len(tokenSignature)): + for i in range(1, len(chunkList) - 1 - len(tokenSignature)): # P1 = P1_MODE = 0x80 - result = dongle.exchange(apduMessage(0x04,0x80,0x00, None, chunkList[i])) - - for i in range(0,len(tokenSignature)-1): - result = dongle.exchange(apduMessage(0x04,0xA0 | (0x00+i), 0x00, None, tokenSignature[i])) - + result = dongle.exchange( + apduMessage(0x04, 0x80, 0x00, None, chunkList[i])) + + for i in range(0, len(tokenSignature) - 1): + result = dongle.exchange( + apduMessage(0x04, 0xA0 | (0x00 + i), 0x00, None, + tokenSignature[i])) + # P1 = P1_LAST = 0x90 - if len(chunkList)>1: - if len(tokenSignature)>0: - result = dongle.exchange(apduMessage(0x04,0xA0 | 0x08 | (0x00+len(tokenSignature)-1),0x00, None, chunkList[len(chunkList)-1])) + if len(chunkList) > 1: + if len(tokenSignature) > 0: + result = dongle.exchange( + apduMessage(0x04, + 0xA0 | 0x08 | (0x00 + len(tokenSignature) - 1), + 0x00, None, chunkList[len(chunkList) - 1])) else: - result = dongle.exchange(apduMessage(0x04,0x90,0x00, None, chunkList[len(chunkList)-1])) + result = dongle.exchange( + apduMessage(0x04, 0x90, 0x00, None, + chunkList[len(chunkList) - 1])) return raw_tx, result + def address_hex(address): return base58.b58decode_check(address).hex().upper() + # Get Addresses logger.debug('-= Tron Ledger =-') - ''' Tron Protobuf ''' @@ -90,23 +109,21 @@ def address_hex(address): ''') tx = stub.CreateTransaction2( - contract.TransferContract( - owner_address=bytes.fromhex(address_hex("TUEZSdKsoDHQMeZwihtdoBiN46zxhGWYdH")), - to_address=bytes.fromhex(address_hex("TPnYqC2ukKyhEDAjqRRobSVygMAb8nAcXM")), - amount=100000 - ) - ) + contract.TransferContract( + owner_address=bytes.fromhex( + address_hex("TUEZSdKsoDHQMeZwihtdoBiN46zxhGWYdH")), + to_address=bytes.fromhex( + address_hex("TPnYqC2ukKyhEDAjqRRobSVygMAb8nAcXM")), + amount=100000)) # use permission 2 -tx.transaction.raw_data.contract[0].Permission_id=2 - - +tx.transaction.raw_data.contract[0].Permission_id = 2 -raw_tx, sign1 = ledgerSign(parse_bip32_path("44'/195'/0'/0/0"),tx.transaction) +raw_tx, sign1 = ledgerSign(parse_bip32_path("44'/195'/0'/0/0"), tx.transaction) tx.transaction.signature.extend([bytes(sign1[0:65])]) r = stub.BroadcastTransaction(tx.transaction) if r.result == True: - print("Success") + print("Success") else: - print("Fail") + print("Fail") diff --git a/examples/signStakeV2.py b/examples/signStakeV2.py index d8e0b7cd..609ae1f8 100644 --- a/examples/signStakeV2.py +++ b/examples/signStakeV2.py @@ -8,29 +8,40 @@ import validateSignature import binascii -logging.basicConfig(level=logging.DEBUG, format="%(asctime)s - %(levelname)s - %(message)s") +logging.basicConfig(level=logging.DEBUG, + format="%(asctime)s - %(levelname)s - %(message)s") logger = logging.getLogger() + def apduMessage(INS, P1, P2, PATH, MESSAGE): hexString = "" if PATH: - hexString = "E0{:02x}{:02x}{:02x}{:02x}{:02x}{}".format(INS,P1,P2,(len(PATH)+len(MESSAGE))//2+1,len(PATH)//4//2,PATH+MESSAGE) + hexString = "E0{:02x}{:02x}{:02x}{:02x}{:02x}{}".format( + INS, P1, P2, (len(PATH) + len(MESSAGE)) // 2 + 1, + len(PATH) // 4 // 2, PATH + MESSAGE) else: - hexString = "E0{:02x}{:02x}{:02x}{:02x}{}".format(INS,P1,P2,len(MESSAGE)//2,MESSAGE) + hexString = "E0{:02x}{:02x}{:02x}{:02x}{}".format( + INS, P1, P2, + len(MESSAGE) // 2, MESSAGE) print(hexString) return bytearray.fromhex(hexString) + parser = argparse.ArgumentParser() -parser.add_argument('--path', help="BIP32 path to retrieve. e.g. \"44'/195'/0'/0/0\".") +parser.add_argument('--path', + help="BIP32 path to retrieve. e.g. \"44'/195'/0'/0/0\".") args = parser.parse_args() if args.path == None: - args.path = "44'/195'/0'/0/0" + args.path = "44'/195'/0'/0/0" donglePath = parse_bip32_path(args.path) # get pubKey -apduMessage = "E0020000" + '{:02x}'.format(len(donglePath) + 1) + '{:02x}'.format(int(len(donglePath) / 4 / 2)) + donglePath +apduMessage = "E0020000" + '{:02x}'.format(len(donglePath) + + 1) + '{:02x}'.format( + int(len(donglePath) / 4 / + 2)) + donglePath apdu = bytearray.fromhex(apduMessage) print("-= Tron Ledger =-") @@ -38,10 +49,10 @@ def apduMessage(INS, P1, P2, PATH, MESSAGE): dongle = getDongle(True) result = dongle.exchange(apdu) -size=result[0] +size = result[0] pubKey = "" -if size == 65 : - pubKey = result[1:1+size].hex() +if size == 65: + pubKey = result[1:1 + size].hex() else: print("Error... Public Key Size: {:d}".format(size)) sys.exit(0) @@ -50,31 +61,38 @@ def apduMessage(INS, P1, P2, PATH, MESSAGE): # create freezeBalancev2 tx transactionRaw = "0a024e2c2208f311309df22deb2040a8c7a7eee6305a59083612550a34747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e467265657a6542616c616e63655632436f6e7472616374121d0a15414e70ab426c186222a7e7f7bd0dbc2a4160073098108094ebdc03708088a4eee630" -apduMessage = "E0041000" + '{:02x}'.format(int(len(donglePath) / 2) + 1 + int(len(transactionRaw) / 2)) + '{:02x}'.format(int(len(donglePath) / 4 / 2)) + donglePath + transactionRaw +apduMessage = "E0041000" + '{:02x}'.format( + int(len(donglePath) / 2) + 1 + + int(len(transactionRaw) / 2)) + '{:02x}'.format( + int(len(donglePath) / 4 / 2)) + donglePath + transactionRaw apdu = bytearray.fromhex(apduMessage) print("Sign FreezeBalance") print(apduMessage.strip()) result = dongle.exchange(bytearray.fromhex(apduMessage)) -validSignature, txID = validateSignature.validate(transactionRaw,result[0:65],pubKey[2:]) +validSignature, txID = validateSignature.validate(transactionRaw, result[0:65], + pubKey[2:]) if (validSignature): logger.debug('- Valid: {}'.format(validSignature)) else: logger.error('- Valid: {}'.format(validSignature)) sys.exit(0) - # create unfreezeBalancev2 tx transactionRaw = "0a0298ee22084ad65d67e05fbae340e8f5c8cce5305a59083712550a36747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e556e667265657a6542616c616e63655632436f6e7472616374121b0a154130ce79d807768856f5d60fb4bb3e3cdeb8c2978010c0843d70eeb4c5cce530" -apduMessage = "E0041000" + '{:02x}'.format(int(len(donglePath) / 2) + 1 + int(len(transactionRaw) / 2)) + '{:02x}'.format(int(len(donglePath) / 4 / 2)) + donglePath + transactionRaw +apduMessage = "E0041000" + '{:02x}'.format( + int(len(donglePath) / 2) + 1 + + int(len(transactionRaw) / 2)) + '{:02x}'.format( + int(len(donglePath) / 4 / 2)) + donglePath + transactionRaw apdu = bytearray.fromhex(apduMessage) print("Sign UnfreezeBalance") print(apduMessage.strip()) result = dongle.exchange(bytearray.fromhex(apduMessage)) -validSignature, txID = validateSignature.validate(transactionRaw,result[0:65],pubKey[2:]) +validSignature, txID = validateSignature.validate(transactionRaw, result[0:65], + pubKey[2:]) if (validSignature): logger.debug('- Valid: {}'.format(validSignature)) else: @@ -83,14 +101,18 @@ def apduMessage(INS, P1, P2, PATH, MESSAGE): # create WithdrawExpireUnfreeze tx transactionRaw = "0a0200fd220847e21951633b761c40e0d0f6f1e6305a5a083812560a3b747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5769746864726177457870697265556e667265657a65436f6e747261637412170a15414607716a6ca8fe2dc8f9e27c349a435191e4863970b5fdf2f1e630" -apduMessage = "E0041000" + '{:02x}'.format(int(len(donglePath) / 2) + 1 + int(len(transactionRaw) / 2)) + '{:02x}'.format(int(len(donglePath) / 4 / 2)) + donglePath + transactionRaw +apduMessage = "E0041000" + '{:02x}'.format( + int(len(donglePath) / 2) + 1 + + int(len(transactionRaw) / 2)) + '{:02x}'.format( + int(len(donglePath) / 4 / 2)) + donglePath + transactionRaw apdu = bytearray.fromhex(apduMessage) print("Sign WithdrawExpireUnfreeze") print(apduMessage.strip()) result = dongle.exchange(bytearray.fromhex(apduMessage)) -validSignature, txID = validateSignature.validate(transactionRaw,result[0:65],pubKey[2:]) +validSignature, txID = validateSignature.validate(transactionRaw, result[0:65], + pubKey[2:]) if (validSignature): logger.debug('- Valid: {}'.format(validSignature)) else: @@ -99,14 +121,18 @@ def apduMessage(INS, P1, P2, PATH, MESSAGE): # create delegateResource tx transactionRaw = "0a02b54922080ed077fa5aa937754090a287d7e5305a6f0839126b0a35747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e44656c65676174655265736f75726365436f6e747261637412320a154130ce79d807768856f5d60fb4bb3e3cdeb8c2978018c0843d221541eaba05c556d953be0031b6ba4eeab309f20ab2cf7087e383d7e530" -apduMessage = "E0041000" + '{:02x}'.format(int(len(donglePath) / 2) + 1 + int(len(transactionRaw) / 2)) + '{:02x}'.format(int(len(donglePath) / 4 / 2)) + donglePath + transactionRaw +apduMessage = "E0041000" + '{:02x}'.format( + int(len(donglePath) / 2) + 1 + + int(len(transactionRaw) / 2)) + '{:02x}'.format( + int(len(donglePath) / 4 / 2)) + donglePath + transactionRaw apdu = bytearray.fromhex(apduMessage) print("Sign DelegateResource") print(apduMessage.strip()) result = dongle.exchange(bytearray.fromhex(apduMessage)) -validSignature, txID = validateSignature.validate(transactionRaw,result[0:65],pubKey[2:]) +validSignature, txID = validateSignature.validate(transactionRaw, result[0:65], + pubKey[2:]) if (validSignature): logger.debug('- Valid: {}'.format(validSignature)) else: @@ -115,17 +141,20 @@ def apduMessage(INS, P1, P2, PATH, MESSAGE): # create unDelegateResource tx transactionRaw = "0a024fe02208f346e938a781860d40e88ff8eee6305a71083a126d0a37747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e556e44656c65676174655265736f75726365436f6e747261637412320a154130ce79d807768856f5d60fb4bb3e3cdeb8c2978018c0843d221541eaba05c556d953be0031b6ba4eeab309f20ab2cf70a6d1f4eee630" -apduMessage = "E0041000" + '{:02x}'.format(int(len(donglePath) / 2) + 1 + int(len(transactionRaw) / 2)) + '{:02x}'.format(int(len(donglePath) / 4 / 2)) + donglePath + transactionRaw +apduMessage = "E0041000" + '{:02x}'.format( + int(len(donglePath) / 2) + 1 + + int(len(transactionRaw) / 2)) + '{:02x}'.format( + int(len(donglePath) / 4 / 2)) + donglePath + transactionRaw apdu = bytearray.fromhex(apduMessage) print("Sign UnDelegateResource") print(apduMessage.strip()) result = dongle.exchange(bytearray.fromhex(apduMessage)) -validSignature, txID = validateSignature.validate(transactionRaw,result[0:65],pubKey[2:]) +validSignature, txID = validateSignature.validate(transactionRaw, result[0:65], + pubKey[2:]) if (validSignature): logger.debug('- Valid: {}'.format(validSignature)) else: logger.error('- Valid: {}'.format(validSignature)) sys.exit(0) - diff --git a/examples/signTRC10WithName.py b/examples/signTRC10WithName.py index b53e20a5..b14c0e0c 100755 --- a/examples/signTRC10WithName.py +++ b/examples/signTRC10WithName.py @@ -6,11 +6,12 @@ import binascii parser = argparse.ArgumentParser() -parser.add_argument('--path', help="BIP32 path to retrieve. e.g. \"44'/195'/0'/0/0\".") +parser.add_argument('--path', + help="BIP32 path to retrieve. e.g. \"44'/195'/0'/0/0\".") args = parser.parse_args() if args.path == None: - args.path = "44'/195'/0'/0/0" + args.path = "44'/195'/0'/0/0" donglePath = parse_bip32_path(args.path) @@ -24,10 +25,14 @@ signatureCheck = "c1a32ee50f112f2c38fd7f75961412f9af60d69adb822c507e2442a01275ff3738447c9392aaaaebefde0768936958cbf78c04a896c36b453a220ad5d07d555a00" # P1 = 0x00 - first message -apduMessage1 = "E004{:02x}00".format(0x00) + '{:02x}'.format(int(len(donglePath) / 2) + 1 + int(len(transactionRaw) / 2)) + '{:02x}'.format(int(len(donglePath) / 4 / 2)) + donglePath + transactionRaw +apduMessage1 = "E004{:02x}00".format(0x00) + '{:02x}'.format( + int(len(donglePath) / 2) + 1 + + int(len(transactionRaw) / 2)) + '{:02x}'.format( + int(len(donglePath) / 4 / 2)) + donglePath + transactionRaw # Token info # To add info P1 = 0xA0 | 0x08 END | Index = 0 -apduMessage2 = "E004{:02x}00".format(0xA0 | 0x08 | 0x00) + '{:02x}'.format(int(len(tokenInfo) / 2) ) + tokenInfo +apduMessage2 = "E004{:02x}00".format(0xA0 | 0x08 | 0x00) + '{:02x}'.format( + int(len(tokenInfo) / 2)) + tokenInfo print("-= Tron Ledger =-") print("Sign Exchange Transaction") @@ -36,7 +41,7 @@ print(apduMessage2.strip()) result = dongle.exchange(bytearray.fromhex(apduMessage2)) print(binascii.hexlify(result[0:65])) -if binascii.hexlify(result[0:65]).decode()==signatureCheck: - print("Signature Validated!") +if binascii.hexlify(result[0:65]).decode() == signatureCheck: + print("Signature Validated!") else: - print("Signature Error!") \ No newline at end of file + print("Signature Error!") diff --git a/examples/signTip712Message.py b/examples/signTip712Message.py new file mode 100644 index 00000000..3fc16bae --- /dev/null +++ b/examples/signTip712Message.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from ledgerblue.comm import getDongle +from Crypto.Hash import keccak +from eth_keys import KeyAPI +from base import parse_bip32_path_to_bytes, parse_bip32_path, apduMessage +from eth_keys.datatypes import PublicKey +import argparse +import binascii +import sys +import validateSignature + +# Define here Chain_ID +CHAIN_ID = 0 + +# Magic define +SIGN_MAGIC = b'\x19\x01' + +parser = argparse.ArgumentParser() +parser.add_argument('--path', help="BIP 32 path to sign with") +parser.add_argument('--domainHash', help="Domain Hash (hex)") +parser.add_argument('--messageHash', help='Message Hash (hex)') +args = parser.parse_args() + +if args.path == None: + args.path = "44'/195'/0'/0/0" +if args.domainHash == None: + args.domainHash = "0101010101010101010101010101010101010101010101010101010101010101" +if args.messageHash == None: + args.messageHash = "0202020202020202020202020202020202020202020202020202020202020202" + +# get pubKey +donglePathStr = parse_bip32_path(args.path) +dongle = getDongle(True) +result = dongle.exchange(apduMessage(0x02, 0x00, 0x00, donglePathStr, "")) +size = result[0] +pubKey = "" +if size == 65: + pubKey = result[1:1 + size].hex() +else: + print("Error... Public Key Size: {:d}".format(size)) + sys.exit(0) +publicKey = PublicKey(bytes.fromhex(pubKey[2:])) + +domainHash = binascii.unhexlify(args.domainHash) +messageHash = binascii.unhexlify(args.messageHash) +encodedTx = domainHash + messageHash +donglePath = parse_bip32_path_to_bytes(args.path) +apdu = bytearray.fromhex("e00c0000") +apdu.append(len(donglePath) + 1 + len(encodedTx)) +apdu.append(len(donglePath) // 4) +apdu += donglePath + encodedTx +result = dongle.exchange(bytes(apdu)) +signature = KeyAPI.Signature(signature_bytes=result[0:65]) +msg_to_sign = SIGN_MAGIC + domainHash + messageHash +hash = keccak.new(digest_bits=256, data=msg_to_sign).digest() +pubkey = KeyAPI.PublicKey.recover_from_msg_hash(hash, signature) +validSignature = validateSignature.validateHASH(hash, result[0:65], pubKey[2:]) + +print("[INFO] Hash is: 0x", binascii.hexlify(hash).decode(), sep='') +print('{') +print(' "address get": "', publicKey.to_address(), '",', sep='') +print(' "address recover": "', pubkey.to_address(), '",', sep='') +print(' "domain hash": "', binascii.hexlify(domainHash), '",', sep='') +print(' "message hash": "', binascii.hexlify(messageHash), '",', sep='') +print(' "sig": "', signature, '",', sep='') +print(' "valid": "', validSignature, '",', sep='') +print(' "version": "3"') +print(' "signed": "ledger"') +print('}') diff --git a/examples/signTransaction.py b/examples/signTransaction.py index 1d857f48..58b2be78 100755 --- a/examples/signTransaction.py +++ b/examples/signTransaction.py @@ -6,15 +6,15 @@ import binascii parser = argparse.ArgumentParser() -parser.add_argument('--path', help="BIP32 path to retrieve. e.g. \"44'/195'/0'/0/0\".") +parser.add_argument('--path', + help="BIP32 path to retrieve. e.g. \"44'/195'/0'/0/0\".") args = parser.parse_args() if args.path == None: - args.path = "44'/195'/0'/0/0" + args.path = "44'/195'/0'/0/0" donglePath = parse_bip32_path(args.path) - # Create APDU message. transactionRaw = "0a027d52220889fd90c45b71f24740e0bcb0f2be2c5a67080112630a2d747970" \ "652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e5472616e7366"\ @@ -26,7 +26,10 @@ "3185edd8a4dfda2d03aad569b856cfb3ed9db387b6589451797ff01c9c353583"\ "01" -apduMessage = "E0041000" + '{:02x}'.format(int(len(donglePath) / 2) + 1 + int(len(transactionRaw) / 2)) + '{:02x}'.format(int(len(donglePath) / 4 / 2)) + donglePath + transactionRaw +apduMessage = "E0041000" + '{:02x}'.format( + int(len(donglePath) / 2) + 1 + + int(len(transactionRaw) / 2)) + '{:02x}'.format( + int(len(donglePath) / 4 / 2)) + donglePath + transactionRaw apdu = bytearray.fromhex(apduMessage) print("-= Tron Ledger =-") @@ -36,7 +39,7 @@ print(apduMessage.strip()) result = dongle.exchange(bytearray.fromhex(apduMessage)) print(binascii.hexlify(result[0:65])) -if binascii.hexlify(result[0:65]).decode()==signatureCheck: - print("Signature Validated!") +if binascii.hexlify(result[0:65]).decode() == signatureCheck: + print("Signature Validated!") else: - print("Signature Error!") \ No newline at end of file + print("Signature Error!") diff --git a/examples/signTransactionExtension.py b/examples/signTransactionExtension.py index 6df7a71e..573ed873 100755 --- a/examples/signTransactionExtension.py +++ b/examples/signTransactionExtension.py @@ -6,20 +6,19 @@ import binascii parser = argparse.ArgumentParser() -parser.add_argument('--path', help="BIP32 path to retrieve. e.g. \"44'/195'/0'/0/0\".") +parser.add_argument('--path', + help="BIP32 path to retrieve. e.g. \"44'/195'/0'/0/0\".") args = parser.parse_args() if args.path == None: - args.path = "44'/195'/0'/0/0" + args.path = "44'/195'/0'/0/0" donglePath = parse_bip32_path(args.path) - transactionRaw = "0a02ee332208c90c7f40dfbdc51540e0dfe3ada62d5a860108041281010a30747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e566f74655769746e657373436f6e7472616374124d0a15417773ff0ebd2d2c85761db01ae2b00c417bf1539312190a154167e39013be3cdd3814bed152d7439fb5b6791409100212190a1541c189fa6fc9ed7a3580c3fe291915d5c6a6259be710027089a2e0ada62d" transactionRawFIRST = "0a02ee332208c90c7f40dfbdc51540e0dfe3ada62d5a860108041281010a30747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e566f74655769746e657373436f6e7472616374124d0a15417773ff0ebd2d2c85761db01ae2b00c417bf1539312190a154167e39013be3cdd3814" transactionRawEND = "bed152d7439fb5b6791409100212190a1541c189fa6fc9ed7a3580c3fe291915d5c6a6259be710027089a2e0ada62d" - transactionBIG1 = "0a02e85a2208c2b05ed1144dbfb240d8b9c98bf52d5ad901080412d4010a30747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e566f74655769746e657373436f6e7472616374129f010a1541978dbd103cfe59c35e753d09dd44ae1ae64621c7121a0a154167e39013be3cdd38" transactionBIG2 = "14bed152d7439fb5b679140910e80712190a15412d7bdb9846499a2e5e6c5a7e6fb05731c83107c7106412190a1541c189fa6fc9" transactionBIG3 = "ed7a3580c3fe291915d5c6a6259be7100a12190a154138e3e3a163163db1f6cfceca1d1c64594dd1f0ca100112190a154178c842" @@ -31,33 +30,46 @@ # P1 = P1_SIGN = 0x10 dongle = getDongle(True) -apduMessage = "E0041000" + '{:02x}'.format(int(len(donglePath) / 2) + 1 + int(len(transactionRaw) / 2)) + '{:02x}'.format(int(len(donglePath) / 4 / 2)) + donglePath + transactionRaw +apduMessage = "E0041000" + '{:02x}'.format( + int(len(donglePath) / 2) + 1 + + int(len(transactionRaw) / 2)) + '{:02x}'.format( + int(len(donglePath) / 4 / 2)) + donglePath + transactionRaw result1 = dongle.exchange(bytearray.fromhex(apduMessage)) # P1 = P1_FIRST = 0x00 -apduMessage = "E0040000" + '{:02x}'.format(int(len(donglePath) / 2) + 1 + int(len(transactionRawFIRST) / 2)) + '{:02x}'.format(int(len(donglePath) / 4 / 2)) + donglePath + transactionRawFIRST +apduMessage = "E0040000" + '{:02x}'.format( + int(len(donglePath) / 2) + 1 + + int(len(transactionRawFIRST) / 2)) + '{:02x}'.format( + int(len(donglePath) / 4 / 2)) + donglePath + transactionRawFIRST result = dongle.exchange(bytearray.fromhex(apduMessage)) # P1 = P1_LAST = 0x90 -apduMessage = "E0049000" + '{:02x}'.format( int(len(transactionRawEND) / 2)) + transactionRawEND +apduMessage = "E0049000" + '{:02x}'.format(int( + len(transactionRawEND) / 2)) + transactionRawEND result2 = dongle.exchange(bytearray.fromhex(apduMessage)) -if (binascii.hexlify(result1[0:65]).decode()==binascii.hexlify(result2[0:65]).decode()): - print("Hash signature match") +if (binascii.hexlify(result1[0:65]).decode() == binascii.hexlify( + result2[0:65]).decode()): + print("Hash signature match") else: - print("Hash signature error") - + print("Hash signature error") # Sign in 4 batch # P1 = P1_FIRST = 0x00 -apduMessage = "E0040000" + '{:02x}'.format(int(len(donglePath) / 2) + 1 + int(len(transactionBIG1) / 2)) + '{:02x}'.format(int(len(donglePath) / 4 / 2)) + donglePath + transactionBIG1 +apduMessage = "E0040000" + '{:02x}'.format( + int(len(donglePath) / 2) + 1 + + int(len(transactionBIG1) / 2)) + '{:02x}'.format( + int(len(donglePath) / 4 / 2)) + donglePath + transactionBIG1 result1 = dongle.exchange(bytearray.fromhex(apduMessage)) # P1 = P1_MODE = 0x80 -apduMessage = "E0048000" + '{:02x}'.format( int(len(transactionBIG2) / 2)) + transactionBIG2 +apduMessage = "E0048000" + '{:02x}'.format(int( + len(transactionBIG2) / 2)) + transactionBIG2 result2 = dongle.exchange(bytearray.fromhex(apduMessage)) # P1 = P1_MODE = 0x80 -apduMessage = "E0048000" + '{:02x}'.format( int(len(transactionBIG3) / 2)) + transactionBIG3 +apduMessage = "E0048000" + '{:02x}'.format(int( + len(transactionBIG3) / 2)) + transactionBIG3 result3 = dongle.exchange(bytearray.fromhex(apduMessage)) # P1 = P1_LAST = 0x90 -apduMessage = "E0049000" + '{:02x}'.format( int(len(transactionBIG4) / 2)) + transactionBIG4 +apduMessage = "E0049000" + '{:02x}'.format(int( + len(transactionBIG4) / 2)) + transactionBIG4 result4 = dongle.exchange(bytearray.fromhex(apduMessage)) print("Signature: {}".format(binascii.hexlify(result4[0:65]).decode())) diff --git a/examples/testCustomContracts.py b/examples/testCustomContracts.py index 3b5d4c08..5bc25611 100755 --- a/examples/testCustomContracts.py +++ b/examples/testCustomContracts.py @@ -1,6 +1,7 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- import sys + sys.path.append("./examples/proto") from pprint import pprint @@ -15,7 +16,8 @@ import binascii import base58 -logging.basicConfig(level=logging.DEBUG, format="%(asctime)s - %(levelname)s - %(message)s") +logging.basicConfig(level=logging.DEBUG, + format="%(asctime)s - %(levelname)s - %(message)s") logger = logging.getLogger() @@ -24,79 +26,94 @@ def chunks(l, n): for i in range(0, len(l), n): yield l[i:i + n] + def apduMessage(INS, P1, P2, PATH, MESSAGE): hexString = "" if PATH: - hexString = "E0{:02x}{:02x}{:02x}{:02x}{:02x}{}".format(INS,P1,P2,(len(PATH)+len(MESSAGE))//2+1,len(PATH)//4//2,PATH+MESSAGE) + hexString = "E0{:02x}{:02x}{:02x}{:02x}{:02x}{}".format( + INS, P1, P2, (len(PATH) + len(MESSAGE)) // 2 + 1, + len(PATH) // 4 // 2, PATH + MESSAGE) else: - hexString = "E0{:02x}{:02x}{:02x}{:02x}{}".format(INS,P1,P2,len(MESSAGE)//2,MESSAGE) + hexString = "E0{:02x}{:02x}{:02x}{:02x}{}".format( + INS, P1, P2, + len(MESSAGE) // 2, MESSAGE) print(hexString) return bytearray.fromhex(hexString) + def ledgerSign(PATH, tx, tokenSignature=[]): raw_tx = tx.raw_data.SerializeToString().hex() # Sign in chunks - chunkList = list(chunks(raw_tx,420)) - if len(tokenSignature)>0: + chunkList = list(chunks(raw_tx, 420)) + if len(tokenSignature) > 0: chunkList.extend(tokenSignature) # P1 = P1_FIRST = 0x00 - if len(chunkList)>1: - result = dongle.exchange(apduMessage(0x04,0x00,0x00, PATH, chunkList[0])) + if len(chunkList) > 1: + result = dongle.exchange( + apduMessage(0x04, 0x00, 0x00, PATH, chunkList[0])) else: - result = dongle.exchange(apduMessage(0x04,0x10,0x00, PATH, chunkList[0])) + result = dongle.exchange( + apduMessage(0x04, 0x10, 0x00, PATH, chunkList[0])) - for i in range(1,len(chunkList)-1-len(tokenSignature)): + for i in range(1, len(chunkList) - 1 - len(tokenSignature)): # P1 = P1_MODE = 0x80 - result = dongle.exchange(apduMessage(0x04,0x80,0x00, None, chunkList[i])) - - for i in range(0,len(tokenSignature)-1): - result = dongle.exchange(apduMessage(0x04,0xA0 | (0x00+i), 0x00, None, tokenSignature[i])) - + result = dongle.exchange( + apduMessage(0x04, 0x80, 0x00, None, chunkList[i])) + + for i in range(0, len(tokenSignature) - 1): + result = dongle.exchange( + apduMessage(0x04, 0xA0 | (0x00 + i), 0x00, None, + tokenSignature[i])) + # P1 = P1_LAST = 0x90 - if len(chunkList)>1: - if len(tokenSignature)>0: - result = dongle.exchange(apduMessage(0x04,0xA0 | 0x08 | (0x00+len(tokenSignature)-1),0x00, None, chunkList[len(chunkList)-1])) + if len(chunkList) > 1: + if len(tokenSignature) > 0: + result = dongle.exchange( + apduMessage(0x04, + 0xA0 | 0x08 | (0x00 + len(tokenSignature) - 1), + 0x00, None, chunkList[len(chunkList) - 1])) else: - result = dongle.exchange(apduMessage(0x04,0x90,0x00, None, chunkList[len(chunkList)-1])) + result = dongle.exchange( + apduMessage(0x04, 0x90, 0x00, None, + chunkList[len(chunkList) - 1])) return raw_tx, result + def address_hex(address): return base58.b58decode_check(address).hex().upper() + accounts = [{ - "path": parse_bip32_path("44'/195'/0'/0/0"), - }, - { - "path": parse_bip32_path("44'/195'/1'/0/0"), - }] + "path": parse_bip32_path("44'/195'/0'/0/0"), +}, { + "path": parse_bip32_path("44'/195'/1'/0/0"), +}] # Get Addresses logger.debug('-= Tron Ledger =-') logger.debug('Requesting Public Keys...') dongle = getDongle(True) for i in range(2): - result = dongle.exchange(apduMessage(0x02,0x00,0x00,accounts[i]['path'], "")) - size=result[0] - if size == 65 : - accounts[i]['publicKey'] = result[1:1+size].hex() - size=result[size+1] - if size == 34 : - accounts[i]['address'] = result[67:67+size].decode() + result = dongle.exchange( + apduMessage(0x02, 0x00, 0x00, accounts[i]['path'], "")) + size = result[0] + if size == 65: + accounts[i]['publicKey'] = result[1:1 + size].hex() + size = result[size + 1] + if size == 34: + accounts[i]['address'] = result[67:67 + size].decode() accounts[i]['addressHex'] = address_hex(accounts[i]['address']) else: logger.error('Error... Address Size: {:d}'.format(size)) else: logger.error('Error... Public Key Size: {:d}'.format(size)) - logger.debug('Test Accounts:') for i in range(2): logger.debug('- Public Key {}: {}'.format(i, accounts[i]['publicKey'])) - logger.debug('- Address {}: {}'.format(i,accounts[i]['address'])) - - + logger.debug('- Address {}: {}'.format(i, accounts[i]['address'])) ''' Tron Protobuf ''' @@ -118,7 +135,7 @@ def address_hex(address): # check if device have custom contracts enable result = dongle.exchange(bytearray.fromhex("E0060000FF")) customAllowed = result[0] & 0x02 -if customAllowed==0: +if customAllowed == 0: print("Custom Contract not allowed, test should fail...") sys.exit(0) @@ -127,18 +144,20 @@ def address_hex(address): #################### logger.debug('\n\SmartContract Trigger: Deposit TRX in TWM Contract') data = '{:08x}'.format(0xd0e30db0) -tx = stub.TriggerContract(contract.TriggerSmartContract( +tx = stub.TriggerContract( + contract.TriggerSmartContract( owner_address=bytes.fromhex(accounts[1]['addressHex']), - contract_address=bytes.fromhex(address_hex("TTg3AAJBYsDNjx5Moc5EPNsgJSa4anJQ3M")), + contract_address=bytes.fromhex( + address_hex("TTg3AAJBYsDNjx5Moc5EPNsgJSa4anJQ3M")), call_value=1000000, - data=bytes.fromhex(data) - )) + data=bytes.fromhex(data))) -raw_tx, result = ledgerSign(accounts[1]['path'],tx.transaction) +raw_tx, result = ledgerSign(accounts[1]['path'], tx.transaction) tx.transaction.signature.extend([bytes(result[0:65])]) #r = stub.BroadcastTransaction(tx.transaction) -validSignature, txID = validateSignature.validate(raw_tx,result[0:65],accounts[1]['publicKey'][2:]) +validSignature, txID = validateSignature.validate(raw_tx, result[0:65], + accounts[1]['publicKey'][2:]) logger.debug('- RAW: {}'.format(raw_tx)) logger.debug('- txID: {}'.format(txID)) logger.debug('- Signature: {}'.format(binascii.hexlify(result[0:65]))) @@ -148,25 +167,26 @@ def address_hex(address): logger.error('- Valid: {}'.format(validSignature)) sys.exit(0) - ###################### # TWM Deposit Token # ###################### logger.debug('\n\SmartContract Trigger: Deposit BTT in TWM Contract') data = '{:08x}'.format(0xd0e30db0) -tx = stub.TriggerContract(contract.TriggerSmartContract( +tx = stub.TriggerContract( + contract.TriggerSmartContract( owner_address=bytes.fromhex(accounts[1]['addressHex']), - contract_address=bytes.fromhex(address_hex("TTg3AAJBYsDNjx5Moc5EPNsgJSa4anJQ3M")), + contract_address=bytes.fromhex( + address_hex("TTg3AAJBYsDNjx5Moc5EPNsgJSa4anJQ3M")), call_token_value=1000000, token_id=1002000, - data=bytes.fromhex(data) - )) + data=bytes.fromhex(data))) -raw_tx, result = ledgerSign(accounts[1]['path'],tx.transaction) +raw_tx, result = ledgerSign(accounts[1]['path'], tx.transaction) tx.transaction.signature.extend([bytes(result[0:65])]) #r = stub.BroadcastTransaction(tx.transaction) -validSignature, txID = validateSignature.validate(raw_tx,result[0:65],accounts[1]['publicKey'][2:]) +validSignature, txID = validateSignature.validate(raw_tx, result[0:65], + accounts[1]['publicKey'][2:]) logger.debug('- RAW: {}'.format(raw_tx)) logger.debug('- txID: {}'.format(txID)) logger.debug('- Signature: {}'.format(binascii.hexlify(result[0:65]))) @@ -180,21 +200,20 @@ def address_hex(address): # TWM Withdraw TRX # #################### logger.debug('\n\SmartContract Trigger: Withdraw TRX in TWM Contract') -data = '{:08x}{:064x}'.format( - 0x0a857040, - int(10000) - ) -tx = stub.TriggerContract(contract.TriggerSmartContract( +data = '{:08x}{:064x}'.format(0x0a857040, int(10000)) +tx = stub.TriggerContract( + contract.TriggerSmartContract( owner_address=bytes.fromhex(accounts[1]['addressHex']), - contract_address=bytes.fromhex(address_hex("TTg3AAJBYsDNjx5Moc5EPNsgJSa4anJQ3M")), - data=bytes.fromhex(data) - )) + contract_address=bytes.fromhex( + address_hex("TTg3AAJBYsDNjx5Moc5EPNsgJSa4anJQ3M")), + data=bytes.fromhex(data))) -raw_tx, result = ledgerSign(accounts[1]['path'],tx.transaction) +raw_tx, result = ledgerSign(accounts[1]['path'], tx.transaction) tx.transaction.signature.extend([bytes(result[0:65])]) #r = stub.BroadcastTransaction(tx.transaction) -validSignature, txID = validateSignature.validate(raw_tx,result[0:65],accounts[1]['publicKey'][2:]) +validSignature, txID = validateSignature.validate(raw_tx, result[0:65], + accounts[1]['publicKey'][2:]) logger.debug('- RAW: {}'.format(raw_tx)) logger.debug('- txID: {}'.format(txID)) logger.debug('- Signature: {}'.format(binascii.hexlify(result[0:65]))) @@ -204,8 +223,6 @@ def address_hex(address): logger.error('- Valid: {}'.format(validSignature)) sys.exit(0) - - ####################### # TWM Withdraw Token # ####################### @@ -214,18 +231,20 @@ def address_hex(address): 0xa1afaf8e, int(1002000), int(1000000), - ) -tx = stub.TriggerContract(contract.TriggerSmartContract( +) +tx = stub.TriggerContract( + contract.TriggerSmartContract( owner_address=bytes.fromhex(accounts[1]['addressHex']), - contract_address=bytes.fromhex(address_hex("TTg3AAJBYsDNjx5Moc5EPNsgJSa4anJQ3M")), - data=bytes.fromhex(data) - )) + contract_address=bytes.fromhex( + address_hex("TTg3AAJBYsDNjx5Moc5EPNsgJSa4anJQ3M")), + data=bytes.fromhex(data))) -raw_tx, result = ledgerSign(accounts[1]['path'],tx.transaction) +raw_tx, result = ledgerSign(accounts[1]['path'], tx.transaction) tx.transaction.signature.extend([bytes(result[0:65])]) #r = stub.BroadcastTransaction(tx.transaction) -validSignature, txID = validateSignature.validate(raw_tx,result[0:65],accounts[1]['publicKey'][2:]) +validSignature, txID = validateSignature.validate(raw_tx, result[0:65], + accounts[1]['publicKey'][2:]) logger.debug('- RAW: {}'.format(raw_tx)) logger.debug('- txID: {}'.format(txID)) logger.debug('- Signature: {}'.format(binascii.hexlify(result[0:65]))) diff --git a/examples/validateSignature.py b/examples/validateSignature.py index c1ebd75e..67734522 100755 --- a/examples/validateSignature.py +++ b/examples/validateSignature.py @@ -4,7 +4,8 @@ import hashlib import logging -logging.basicConfig(level=logging.DEBUG, format="%(asctime)s - %(levelname)s - %(message)s") +logging.basicConfig(level=logging.DEBUG, + format="%(asctime)s - %(levelname)s - %(message)s") logger = logging.getLogger() @@ -12,25 +13,26 @@ def getPublicKey(transaction, signature): s = Signature(signature_bytes=bytes.fromhex(signature)) txID = hashlib.sha256(bytes.fromhex(transaction)).digest() keys = KeyAPI('eth_keys.backends.NativeECCBackend') - public_key = keys.ecdsa_recover(txID,s) + public_key = keys.ecdsa_recover(txID, s) logger.debug(' PublicKey: {}'.format(public_key)) return public_key + def validate(transaction, signature, public_key): try: s = Signature(signature_bytes=signature) txID = hashlib.sha256( - bytes.fromhex(transaction) if type(transaction) is str else transaction - ).digest() + bytes.fromhex(transaction) if type(transaction) is + str else transaction).digest() keys = KeyAPI('eth_keys.backends.NativeECCBackend') publicKey = PublicKey(bytes.fromhex(public_key)) - return keys.ecdsa_verify(txID,s,publicKey), txID.hex() + return keys.ecdsa_verify(txID, s, publicKey), txID.hex() except: return False, "" + def validateHASH(txID, signature, public_key): s = Signature(signature_bytes=signature) keys = KeyAPI('eth_keys.backends.NativeECCBackend') publicKey = PublicKey(bytes.fromhex(public_key)) - return keys.ecdsa_verify(txID,s,publicKey) - + return keys.ecdsa_verify(txID, s, publicKey) diff --git a/src/handlers/dispatcher.c b/src/handlers/dispatcher.c index 1695fe03..bd26593b 100644 --- a/src/handlers/dispatcher.c +++ b/src/handlers/dispatcher.c @@ -64,6 +64,9 @@ int apdu_dispatcher(const command_t *cmd) { case INS_SIGN_PERSONAL_MESSAGE: return handleSignPersonalMessage(cmd->p1, cmd->p2, cmd->data, cmd->lc); + case INS_SIGN_TIP_712_MESSAGE: + return handleSignTIP712Message(cmd->p1, cmd->p2, cmd->data, cmd->lc); + default: return io_send_sw(E_INS_NOT_SUPPORTED); } diff --git a/src/handlers/handlers.h b/src/handlers/handlers.h index 8dbd6237..573f9ade 100644 --- a/src/handlers/handlers.h +++ b/src/handlers/handlers.h @@ -29,6 +29,7 @@ #define INS_GET_APP_CONFIGURATION 0x06 // version and settings #define INS_SIGN_PERSONAL_MESSAGE 0x08 #define INS_GET_ECDH_SECRET 0x0A +#define INS_SIGN_TIP_712_MESSAGE 0x0C #define P1_CONFIRM 0x01 #define P1_NON_CONFIRM 0x00 @@ -51,3 +52,4 @@ int handleSignByHash(uint8_t p1, uint8_t p2, uint8_t *workBuffer, uint16_t dataL int handleGetAppConfiguration(uint8_t p1, uint8_t p2, uint8_t *workBuffer, uint16_t dataLength); int handleSignPersonalMessage(uint8_t p1, uint8_t p2, uint8_t *workBuffer, uint16_t dataLength); int handleECDHSecret(uint8_t p1, uint8_t p2, uint8_t *workBuffer, uint16_t dataLength); +int handleSignTIP712Message(uint8_t p1, uint8_t p2, uint8_t *workBuffer, uint16_t dataLength); diff --git a/src/handlers/sign_tip712_message.c b/src/handlers/sign_tip712_message.c new file mode 100644 index 00000000..4fd3769b --- /dev/null +++ b/src/handlers/sign_tip712_message.c @@ -0,0 +1,69 @@ +/******************************************************************************* + * Tron Ledger Wallet + * (c) 2023 Ledger + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ********************************************************************************/ +#include +#include + +#include "cx.h" +#include "io.h" + +#include "format.h" + +#include "helpers.h" +#include "ui_review_menu.h" +#include "app_errors.h" +#include "handlers.h" +#include "parse.h" +#include "ui_globals.h" +#include "settings.h" + +int handleSignTIP712Message(uint8_t p1, uint8_t p2, uint8_t *workBuffer, uint16_t dataLength) { + uint8_t i; + if (!HAS_SETTING(S_SIGN_BY_HASH)) { + return io_send_sw(E_MISSING_SETTING_SIGN_BY_HASH); + } + + if ((p1 != 00) || (p2 != 00)) { + return io_send_sw(E_INCORRECT_P1_P2); + } + if (dataLength < 1) { + return io_send_sw(E_INCORRECT_DATA); + } + messageSigningContext712.pathLength = workBuffer[0]; + if ((messageSigningContext712.pathLength < 0x01) || + (messageSigningContext712.pathLength > MAX_BIP32_PATH)) { + return io_send_sw(E_INCORRECT_DATA); + } + workBuffer++; + dataLength--; + for (i = 0; i < messageSigningContext712.pathLength; i++) { + if (dataLength < 4) { + return io_send_sw(E_INCORRECT_DATA); + } + messageSigningContext712.bip32Path[i] = U4BE(workBuffer, 0); + workBuffer += 4; + dataLength -= 4; + } + if (dataLength < HASH_SIZE * 2) { + return io_send_sw(E_INCORRECT_DATA); + } + memmove(messageSigningContext712.domainHash, workBuffer, HASH_SIZE); + memmove(messageSigningContext712.messageHash, workBuffer + HASH_SIZE, HASH_SIZE); + + ux_flow_display(APPROVAL_SIGN_TIP72_TRANSACTION, false); + + return 0; +} diff --git a/src/parse.c b/src/parse.c index dd03cd6b..d8cb924e 100644 --- a/src/parse.c +++ b/src/parse.c @@ -19,7 +19,7 @@ #include "pb.h" #include "misc/TronApp.pb.h" - +#include "format.h" #include "parse.h" #include "settings.h" #include "tokens.h" @@ -889,3 +889,20 @@ parserStatus_e processTx(uint8_t *buffer, uint32_t length, txContent_t *content) return USTREAM_PROCESSING; } + +int bytes_to_string(char *out, size_t outl, const void *value, size_t len) { + if (outl <= 2) { + // Need at least '0x' and 1 digit + return -1; + } + if (strlcpy(out, "0x", outl) != 2) { + goto err; + } + if (format_hex(value, len, out + 2, outl - 2) < 0) { + goto err; + } + return 0; +err: + *out = '\0'; + return -1; +} \ No newline at end of file diff --git a/src/parse.h b/src/parse.h index 4adf6afc..c55674e6 100644 --- a/src/parse.h +++ b/src/parse.h @@ -23,6 +23,14 @@ #define MAX_RAW_SIGNATURE 65 #define MAX_TOKEN_LENGTH 67 +#define NETWORK_STRING_MAX_SIZE 16 +#ifdef TARGET_NANOS +#define SHARED_CTX_FIELD_1_SIZE 100 +#else +#define SHARED_CTX_FIELD_1_SIZE 256 +#endif +#define SHARED_CTX_FIELD_2_SIZE 40 + typedef union { protocol_TransferContract transfer_contract; protocol_TransferAssetContract transfer_asset_contract; @@ -143,6 +151,31 @@ typedef struct txContent_t { uint32_t customData; } txContent_t; +typedef struct messageSigningContext712_t { + uint8_t pathLength; + uint32_t bip32Path[MAX_BIP32_PATH]; + uint8_t domainHash[32]; + uint8_t messageHash[32]; +} messageSigningContext712_t; + +typedef struct txStringProperties_t { + char fullAddress[43]; + char fullAmount[79]; // 2^256 is 78 digits long + char maxFee[50]; + char nonce[8]; // 10M tx per account ought to be enough for everybody + char network_name[NETWORK_STRING_MAX_SIZE]; +} txStringProperties_t; + +typedef struct strDataTmp_t { + char tmp[SHARED_CTX_FIELD_1_SIZE]; + char tmp2[SHARED_CTX_FIELD_2_SIZE]; +} strDataTmp_t; + +typedef union { + txStringProperties_t common; + strDataTmp_t tmp; +} strings_t; + bool setContractType(contractType_e type, char *out, size_t outlen); bool setExchangeContractDetail(contractType_e type, char *out, size_t outlen); @@ -163,4 +196,6 @@ parserStatus_e processTx(uint8_t *buffer, uint32_t length, txContent_t *content) extern txContent_t txContent; extern txContext_t txContext; +int bytes_to_string(char *out, size_t outl, const void *value, size_t len); + #endif diff --git a/src/ui/ui_globals.c b/src/ui/ui_globals.c index c876757f..13543a5c 100644 --- a/src/ui/ui_globals.c +++ b/src/ui/ui_globals.c @@ -34,6 +34,8 @@ char fullHash[HASH_SIZE * 2 + 1]; int8_t votes_count; transactionContext_t transactionContext; publicKeyContext_t publicKeyContext; +messageSigningContext712_t messageSigningContext712; +strings_t strings; bool ui_callback_address_ok(bool display_menu) { helper_send_response_pubkey(&publicKeyContext); @@ -147,3 +149,138 @@ bool ui_callback_ecdh_ok(bool display_menu) { return false; } } + +static const uint8_t TIP_712_MAGIC[] = {0x19, 0x01}; + +void format_signature_out(const uint8_t *signature) { + memset(G_io_apdu_buffer, 0x00, 64); + uint8_t offset = 0; + uint8_t xoffset = 4; // point to r value + // copy r + uint8_t xlength = signature[xoffset - 1]; + if (xlength == 33) { + xlength = 32; + xoffset++; + } + memmove(G_io_apdu_buffer + offset + 32 - xlength, signature + xoffset, xlength); + offset += 32; + xoffset += xlength + 2; // move over rvalue and TagLEn + // copy s value + xlength = signature[xoffset - 1]; + if (xlength == 33) { + xlength = 32; + xoffset++; + } + memmove(G_io_apdu_buffer + offset + 32 - xlength, signature + xoffset, xlength); +} + +bool ui_callback_signMessage712_v0_ok(bool display_menu) { + uint32_t tx = 0; + cx_err_t err; + + cx_ecfp_private_key_t privateKey; + uint8_t signature[100]; + unsigned int info = 0; + + cx_sha3_t sha3; + uint8_t hash[32]; + io_seproxyhal_io_heartbeat(); + + if (cx_keccak_init_no_throw(&sha3, 256) != CX_OK) { + return false; + } + + if (cx_hash_no_throw((cx_hash_t *) &sha3, + 0, + (uint8_t *) TIP_712_MAGIC, + sizeof(TIP_712_MAGIC), + NULL, + 0) != CX_OK) { + return false; + } + + if (cx_hash_no_throw((cx_hash_t *) &sha3, + 0, + messageSigningContext712.domainHash, + sizeof(messageSigningContext712.domainHash), + NULL, + 0) != CX_OK) { + return false; + } + + if (cx_hash_no_throw((cx_hash_t *) &sha3, + CX_LAST, + messageSigningContext712.messageHash, + sizeof(messageSigningContext712.messageHash), + hash, + sizeof(hash)) != CX_OK) { + return false; + } + PRINTF("TIP712 hash to sign %.*H\n", 32, hash); + + io_seproxyhal_io_heartbeat(); + // Get private key + err = bip32_derive_init_privkey_256(CX_CURVE_256K1, + messageSigningContext712.bip32Path, + messageSigningContext712.pathLength, + &privateKey, + NULL); + if (err != CX_OK) { + goto end; + } + + io_seproxyhal_io_heartbeat(); + unsigned int signatureLength = sizeof(signature); + if (cx_ecdsa_sign_no_throw(&privateKey, + CX_RND_RFC6979 | CX_LAST, + CX_SHA256, + hash, + sizeof(hash), + signature, + &signatureLength, + &info) != CX_OK) { + return false; + } + + format_signature_out(signature); + G_io_apdu_buffer[64] = 0; + if (info & CX_ECCINFO_PARITY_ODD) { + G_io_apdu_buffer[64]++; + } + tx = 65; + +end: + // Clear tmp buffer data + explicit_bzero(&privateKey, sizeof(privateKey)); + + if (err == CX_OK) { + // Send back the response, do not restart the event loop + io_send_response_pointer(G_io_apdu_buffer, tx, E_OK); + } else { + io_send_sw(E_SECURITY_STATUS_NOT_SATISFIED); + } + + if (display_menu) { + // Display back the original UX + ui_idle(); + } + + if (err == CX_OK) { + return true; + } else { + return false; + } +} + +bool ui_callback_signMessage712_v0_cancel(bool display_menu) { + G_io_apdu_buffer[0] = 0x69; + G_io_apdu_buffer[1] = 0x85; + // Send back the response, do not restart the event loop + io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 2); + if (display_menu) { + // Display back the original UX + ui_idle(); + } + + return true; +} \ No newline at end of file diff --git a/src/ui/ui_globals.h b/src/ui/ui_globals.h index 506cef0d..43b00aa8 100644 --- a/src/ui/ui_globals.h +++ b/src/ui/ui_globals.h @@ -43,9 +43,13 @@ extern char fullHash[HASH_SIZE * 2 + 1]; extern int8_t votes_count; extern transactionContext_t transactionContext; extern publicKeyContext_t publicKeyContext; +extern messageSigningContext712_t messageSigningContext712; +extern strings_t strings; bool ui_callback_tx_ok(bool display_menu); bool ui_callback_tx_cancel(bool display_menu); bool ui_callback_address_ok(bool display_menu); bool ui_callback_signMessage_ok(bool display_menu); bool ui_callback_ecdh_ok(bool display_menu); +bool ui_callback_signMessage712_v0_cancel(bool display_menu); +bool ui_callback_signMessage712_v0_ok(bool display_menu); \ No newline at end of file diff --git a/src/ui/ui_review_menu.h b/src/ui/ui_review_menu.h index ef47b3b7..f81c885e 100644 --- a/src/ui/ui_review_menu.h +++ b/src/ui/ui_review_menu.h @@ -37,6 +37,7 @@ typedef enum { APPROVAL_DELEGATE_RESOURCE_TRANSACTION, APPROVAL_UNDELEGATE_RESOURCE_TRANSACTION, APPROVAL_WITHDRAWEXPIREUNFREEZE_TRANSACTION, + APPROVAL_SIGN_TIP72_TRANSACTION, } ui_approval_state_t; void ux_flow_display(ui_approval_state_t state, bool warning); diff --git a/src/ui/ui_review_menu_bagl.c b/src/ui/ui_review_menu_bagl.c index 388b86fa..eb1ccdf4 100644 --- a/src/ui/ui_review_menu_bagl.c +++ b/src/ui/ui_review_menu_bagl.c @@ -756,6 +756,77 @@ UX_DEF(ux_sign_flow, &ux_sign_flow_4_step, &ux_sign_flow_5_step); +// Sign TRC712 message +////////////////////////////////////////////////////////////////////// + +void prepare_domain_hash_v0() { + bytes_to_string(strings.tmp.tmp, + sizeof(strings.tmp.tmp), + messageSigningContext712.domainHash, + 32); +} + +void prepare_message_hash_v0() { + bytes_to_string(strings.tmp.tmp, + sizeof(strings.tmp.tmp), + messageSigningContext712.messageHash, + 32); +} + +UX_STEP_NOCB(ux_sign_712_v0_1_step, + pnn, + { + &C_icon_certificate, + "Sign", + "typed message", + }); +UX_STEP_NOCB_INIT(ux_sign_712_v0_2_step, + bnnn_paging, + prepare_domain_hash_v0(), + { + .title = "Domain hash", + .text = strings.tmp.tmp, + }); +UX_STEP_NOCB_INIT(ux_sign_712_v0_3_step, + bnnn_paging, + prepare_message_hash_v0(), + { + .title = "Message hash", + .text = strings.tmp.tmp, + }); +UX_STEP_VALID(ux_sign_712_v0_4_step, + pbb, + ui_callback_signMessage712_v0_ok(true), + { + &C_icon_validate_14, + "Sign", + "message", + }); +UX_STEP_VALID(ux_sign_712_v0_5_step, + pbb, + ui_callback_signMessage712_v0_cancel(true), + { + &C_icon_crossmark, + "Cancel", + "signature", + }); + +// UX_DEF(ux_sign_712_v0_flow, +// &ux_sign_712_v0_1_step, +// &ux_sign_712_v0_2_step, +// &ux_sign_712_v0_3_step, +// &ux_sign_712_v0_4_step, +// &ux_sign_712_v0_5_step); + +const ux_flow_step_t *const ux_sign_712_v0_flow[] = { + &ux_sign_712_v0_1_step, + &ux_sign_712_v0_2_step, + &ux_sign_712_v0_3_step, + &ux_sign_712_v0_4_step, + &ux_sign_712_v0_5_step, + FLOW_END_STEP, +}; + // CUSTOM CONTRACT ////////////////////////////////////////////////////////////////////// UX_STEP_NOCB(ux_approval_custom_contract_1_step, @@ -969,6 +1040,9 @@ void ux_flow_display(ui_approval_state_t state, bool data_warning) { : ux_approval_withdraw_expire_unfreeze_flow), NULL); break; + case APPROVAL_SIGN_TIP72_TRANSACTION: + ux_flow_init(0, ux_sign_712_v0_flow, NULL); + break; default: PRINTF("This should not happen !\n"); break; diff --git a/src/ui/ui_review_menu_nbgl.c b/src/ui/ui_review_menu_nbgl.c index 90e1a572..0b9ab510 100644 --- a/src/ui/ui_review_menu_nbgl.c +++ b/src/ui/ui_review_menu_nbgl.c @@ -138,6 +138,8 @@ static void reviewChoice(bool confirm) { ret = ui_callback_signMessage_ok(false); } else if (txInfos.state == APPROVAL_SHARED_ECDH_SECRET) { ret = ui_callback_ecdh_ok(false); + } else if (txInfos.state == APPROVAL_SIGN_TIP72_TRANSACTION) { + ret = ui_callback_signMessage712_v0_ok(false); } else { ret = ui_callback_tx_ok(false); } @@ -153,7 +155,11 @@ static void reviewChoice(bool confirm) { } static void rejectConfirmation(void) { - ui_callback_tx_cancel(false); + if (txInfos.state == APPROVAL_SIGN_TIP72_TRANSACTION) { + ui_callback_signMessage712_v0_cancel(false); + } else { + ui_callback_tx_cancel(false); + } nbgl_useCaseReviewStatus(STATUS_TYPE_TRANSACTION_REJECTED, ui_idle); } @@ -165,6 +171,11 @@ static void rejectChoice(void) { rejectConfirmation); } +static char *format_hash(const uint8_t *hash, char *buffer, size_t buffer_size, size_t offset) { + bytes_to_string(buffer + offset, buffer_size - offset, hash, 32); + return buffer + offset; +} + static void prepareTxInfos(ui_approval_state_t state, bool data_warning) { memset(&txInfos, 0, sizeof(txInfos)); memset(&infoLongPress, 0, sizeof(infoLongPress)); @@ -308,6 +319,21 @@ static void prepareTxInfos(ui_approval_state_t state, bool data_warning) { txInfos.flowTitle = "Review message"; infoLongPress.text = "Sign message"; break; + case APPROVAL_SIGN_TIP72_TRANSACTION: + txInfos.fields[0].item = "Domain hash"; + txInfos.fields[0].value = format_hash(messageSigningContext712.domainHash, + strings.tmp.tmp, + sizeof(strings.tmp.tmp), + 0); + txInfos.fields[1].item = "Message hash"; + txInfos.fields[1].value = format_hash(messageSigningContext712.messageHash, + strings.tmp.tmp, + sizeof(strings.tmp.tmp), + 70); + pairList.nbPairs = 2; + txInfos.flowTitle = "Review message"; + infoLongPress.text = "Sign message"; + break; case APPROVAL_CUSTOM_CONTRACT: txInfos.warnings[CUSTOM_CONTRACT_WARNING] = true; txInfos.fields[0].item = "Contract"; diff --git a/tests/snapshots/nanos/test_trx_sign_tip712/00000.png b/tests/snapshots/nanos/test_trx_sign_tip712/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..910bc4302f985d6662a4ac1db98ae5a445448805 GIT binary patch literal 414 zcmV;P0b%}$P)u4+VS)XAz z7Crj%499dp+qfp9k&{t8C`IMLs_o?&YT5+_fmV{1F#|D+T2QrB5CMGAAF~-IQrvm!OcaT6+-JB~bHnd)5#Nq1=fX3z1mKQVcB&Mphr3%Z&%oXJZNQ9;y@ZA+3QNfHOopVMc!@quctUbWR) z8kP)qg^3tx-oV|1k^xX9YHN1@z5{&_brSnSN{Ub@h}I&pn!ICS9n~gJndg$tXJ&x9 z9hyR`sk!@@R*i_@%07*qoM6N<$g6+BDsQ>@~ literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_trx_sign_tip712/00003.png b/tests/snapshots/nanos/test_trx_sign_tip712/00003.png new file mode 100644 index 0000000000000000000000000000000000000000..21e9617519da8a0c0fd6549c3db717a4ab8d510d GIT binary patch literal 494 zcmVl}&@VmZ+ppUi)Vn>nuw)gu1vp~rgW{SA##V$By~|o91{oQxZyR{Xm?@@bM_0y&) k)$iUkNs=T&djJ3c07*qoM6N<$f}HK!^#A|> literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_trx_sign_tip712/00004.png b/tests/snapshots/nanos/test_trx_sign_tip712/00004.png new file mode 100644 index 0000000000000000000000000000000000000000..a2b48cba4152b5926a5e3daed47e10258f416dc1 GIT binary patch literal 457 zcmV;)0XF`LP)!SCyuop9x?$T+&xPbis-f5Y z3A&q$0|3)#Et(P+)2or#u<1w$f*=TjAb1ELM!GnSidi=r00000NkvXXu0mjfkOas# literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_trx_sign_tip712/00005.png b/tests/snapshots/nanos/test_trx_sign_tip712/00005.png new file mode 100644 index 0000000000000000000000000000000000000000..d0c22057f9d529fd48dedd5e84e2d97ba6226057 GIT binary patch literal 528 zcmV+r0`L8aP)YT4B`|lg8uH0FaDjlV;KU zV-~fXS0%l*&-l=Fk7-Nx(PHHaC?(}=DvPAAt|?|#HsgtxDN2rv4nSUa+M!C4gFyOI z6~&4?TC=y?t#CK-_35QQr2MK)xC)dwZf>vX6RmG_KwJKae~NsV9fHbEGMli#u$%kF z?3tzpQz0PPGOLku{Omfr>qKu_zr~r8M)^yIh}0oy!6p+NKwWKPQjnWfQg3`n$NKmuBsw!}KZm@YYvIUot6 z>zESrX)9HLt!uS7Ed%NR2~Y^ElP*~}Z^E2X)O_HW+s$^6t!6P*^NgD?A4ZnGly0;n znWcww$vFU~QZPe@ukYT`%Jp$WykoV}g}P45dYQ@KTw0KhHUYWA^KYMLT{Ig#KspD2 zoM;;GJ>aspzZCBmjt_7E$iT`ZILDgvBQa|a7%*MUm>h*BZc9NB1VIo4kK+&3_=L%i S6HzVz0000!9B-6%Oz%=B9MY3dg@ z)=N4i{dHOY7Tfdx;@IWuTr$9d0my=qQ1DhPY1LAi(|vLq?y!qA9;XI?)L6Mr`K@>% z-tuzX6t!SUmUSl3QaBoWd8OA#RdEIeARY?v4>7u$N zDe`d7z1?nwyIwy^6~6RcWAkv-@lXXyJ#KE#=@ZRvl%v1XBr;3&3Z5N;%1$C5VQPe| z(uVsqX$57odTLAjR)ceVG)!H!qZeDhM9g5L;34D9qkg<%?FShx3|>3;Gx_{^6Fn;s zy7tAry(cjSS913#^xb^Ea5&eHwvMCZ6G*X*`V!mZVZDAN}s*c^hdmK!k- z<~>4L1JKHy@rKRAI+79NHcD{l^4!wtNS)@V$V<2OH8XNSbJM>i;C29{HFCs4yl)Be z%qXCC#sG}GltqXy5z*qzF4hAKFn#MegI-tazRH&ges!K~` z=8>GeW?SiQ;^&j0Kg9eoO(BdXQR2M0J*RK9zR&?~<(J0KlG!P!Hj+7n6U^PkHt(5f zCFSn&EbB}FosF}rZuF}3OO!b&lze3T;n5DSi2XnTN`u$#{etrTyoo+5pqTc>*4`80 zgDY|OEcD%Y|Hzv%+^x6BVvEHA-~Z$bxtVOe^(-k;mQ_3B^#QivvXxXu)u#`p9$ODt zl>j`GujJshvdvU)08dgeOtdleCCt0`%zbyoUHQ8EH}?_-(FY3UfSZ*88lH34dU=v- zrCg6PoCBED4?tR|=1>xHAJpZ)f%>a8v#~|pf1XV_sTKrEgX+mPRz&o!m0wW0!Q!bp zY(b`)_?1`c zH6Ftrxaf}}&h@q%GBAJLEoHJP$waUy*0fqF-RU~H3|GkYZ@YbHOqpq;#lGIk{P9XiM ziX?d+uGu@_mb-K5;fK5B0CgFQ*(X3GEm%3}img-kSJMVWKGSN5$XHBWfbuRvE@5i8 ztWt*SG-1ua1oR?YDlTN36}cP5g?5ry%5 zj`B%w0$MU?gNNaC^u#4SAOgN#kUjPi#%JIAnl)8{FH)pauN%oIIWd@{azP1xy8DKW zw8e9-c($&(LUNMH|@ zz8wshkB{~MB4`H0-uM*3M1j}m%A!300N{kCpu~9KJs1LQ1E{7`qHO>OJQ#XfRy9Bv z^==(ieYk597RD@{OEdS6GT+Lmuf_h$vek1^KVM4p7nbmHWt7bot=9>X{;(33tDmYc z&D9U$Wf)T#sV`+WTVz^Qo=ISYs`0?ozXTD=g%{*$&h`n6Q%*!K%L9vjA?<}S_3O~y z51_40w#ON-)XL64x@JligSXK^F9>U5TpZCDR;l1-dd45KJ?)^knt8<|^tT^?&`+$? zRq8>0Bcb3GkI=CJNF3=@I3K*Rlqo0JRixhcTL&d5MMji-{W*PXyu+hM-x=UTI}_BI zGx^;Gypw%}(Vkv=s~wl1InZ7QJjtlNRl_ihQog8p&yJp0VZ8tV002ovPDHLkV1iJ- Bw$=au literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanos/test_trx_sign_tip712/00010.png b/tests/snapshots/nanos/test_trx_sign_tip712/00010.png new file mode 100644 index 0000000000000000000000000000000000000000..c76320e2e1ceef84cf2c5190c53234a8e73a54ac GIT binary patch literal 397 zcmV;80doF{P)Q#QfD*Zmww)5@L-3v34oBt2jz5c|YM!_bcn1`}(?T{DRnEf-wHdtwk`DrZRGi;7 zqYV)H>nIx4swJcb!0#h=-eSys3~f6gSGwTH0x>6#Lik9$6XGR-+pt~JAxw;#fb;l% zfG{-sa&h_!D&Hh2=z%byrb?l%q$-X*~V@QDOU( z#HAS$1f^!2ici(}X0h;|83WzWND3*m4e(Xl%}$or=mlJ9IZoJVO-6q+J3!Xy49NF8 rnb2v)s#T1IAZI~jCA#A{&I9-WZyow~Rx;MQ00000NkvXXu0mjf>l(7_ literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanosp/test_trx_sign_tip712/00000.png b/tests/snapshots/nanosp/test_trx_sign_tip712/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..00a89fd69969482dbf568f243c7f23ee15f59837 GIT binary patch literal 473 zcmV;~0Ve*5P)=q9}++yIP#$#j!m5^exS zz+}2fFX=r8JdElH5Z(1#dLzJ@d7d#T0RR9zkLvC@{o4-b#&d>V@Olw{Qhp=JC*hP* ze&(v$CdMdHq04bD8(yuPe6}+mUxbB+j@Sq&JG)G;>8tv_Of9IF`aC{V8pehyFamrk zsn2Y*0u8Xun9W@KS20j;W!56I20WGIe?vDCyM6$`aiZIsFI~S2dUn1pckwRBmM6XP%`s%YvTHqZ3lwXSA8(yvzTEo$z)$(N682X1xVDy4{PzgV-)>~P%m z(SxSeRT|*hab4YQn?v%8>M*os9$Wn$H1mutMdS&3k#ezJft*eqW4tHkAtS*5@x-oX zb|Lk%2&YUpGG7h%y~aaI0W0RR910Dz=F-WV#{$lGiw P00000NkvXXu0mjfFUZz( literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanosp/test_trx_sign_tip712/00001.png b/tests/snapshots/nanosp/test_trx_sign_tip712/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..9ef4af9e16eb8f6328808234e4bd8d48f8ed34d0 GIT binary patch literal 894 zcmV-^1A+XBP)H57}G)Dp72lkM+mmk~nz$fU4G-Hqot+oDu(9=SvsZlaUKCV8ljQ-lZaBH zErb!`Vlam|SD6iDExS>}r*vX_mUXvmm`8K2@_N(s_2TYj+^5`I#*B`i zayv4b9!__FYzaw%<>|}zdGgF~{TwcoF|0($Q~xVAl8N z!sgvRG*MdGEM|t#lvwgwLf>Mik%AQersjoAl){X$JatMuyYF+flIZepp$X{v3zi4T z<)ZJyIsu~(+k~@#*nnx*J~)N4hZdXtm~kyjaFz&#q#IBNnWKLjo1y0D-wfyANtlJ6 z#2IAH!KKLI^}h`@4r++dh+Isz_ZQoLE{3!;tCiaa*5Z4~BF04}PpzUXL^Mc5utcIt zNTf)uCe&Gt%y&T_ciX%leC?xB1mdx3$7vUA*T0rwj5jUYTDX7BVf`8fH=R-9CK)%Y zEXD(^btJGWQVN3!x;mv{>ml(#`vcT4(h7>(mz-xwObykh@e=td7(*3cU#h|=xCv_!Bez8DY8vVua&tBU zK$-?`yx`q?MxB8E^$V>;-?lH9wl;^1@Z31lJ2ljoQ0ljK0FuI@;veGhq9o($wdH+5 zuqFV}DL>`YOeD5YU#dF0pMb4+d6<{Cnc7W}NPe$sE9&1BUr!n(gb+dqA>=~-0wLot UBw>6ScK`qY07*qoM6N<$g6Orfz5oCK literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanosp/test_trx_sign_tip712/00002.png b/tests/snapshots/nanosp/test_trx_sign_tip712/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..9da987bedee81cf876984d20ebc7ba635bf68b0b GIT binary patch literal 522 zcmV+l0`>igP)8EboRE|N004l?{rE$3&h@{?am04z zo!^tzAGvUC&bho>Zdt_FN!pk?!_cq4>!lgdaFmkyM)ggpqg>Rlw=w>~d2RK#X-}+z z(mxSU_fIUh63|{{H)`Z;lh~Qn}Qh%`wH?luxySI!P-5=Ab z3bDHb+GaczFuZ)(IRl>=YO0<50Xtw;>26@f@8wj>&TQKK7{l%aw1as2gH+g`X;1lD zZen@@a?WDMwVwxUB|fka^>XG9Pv1oCuK#%dt=3x+lj5Ew-za2R#ICKc6EXoIJplmx za}%ebL+Wv9`uVlKOXc%bO|Wqcao|?^htMXBbKM!-muJNQ0`9O+ zfJt`^7D!kzSB40!n5gD3{Y*Hgo`BJ#>AekHe$so3SkwaZHpCDB&$(H4HZtckQG&bz zZG!6$MpP<3!j$JN-pEG4QVIHu*H`pql^4+BEg9j>9D)x?yG=R4?|j{&%k17YbP$m> zFhj4zbI3!T16;PO+|WsI5`GwOKUx$;QJjEMLrIYY>k6ZZ)@MMA8OB754h*yaD|0My zUtUN#7#RR>x6P}euw{;}-I@c1R(Me05R6WSWRly4&M7ma`Lv{kTNtZd?Df2Q623BJ z1OpzrJ(o6hKxp{{e&7u@BGP+@PI?w@B}c35-DzPG5b8{ zs@b$?k(&T=RyAHNdNTV*@periastNtC#zVvb;FRa5X`Q3z{JpE#q=sHXch$!) z!A){y|1peISN0#K=HN}L3cX2?Dn|Cr33;R7kcd-|BjCLYGQ2X>c! zNiuW9^$8|GD?greGYWyEE2a-94k^!GoL;eFTro)xH#IxI4-k!8By};wwB}`+nBFEL z_q1Ln+6@!1l9WT3No3-jTQ@7U2u%Rq;pv(Ksu1($U}RCIrK#VNdU1v~XvWDauM^s8 zQ4~c{6vdZ7{eOViPI+2m?@WHZ?rEsPJhT=2`jq?`#={>5b#lCcaxh}Rc!`%qP2o_t zq-^!)?Lww`2{!_Es-gTLa7C!tB62+7lZ28Y$P?*e_Q})ov~AWWX{*Og1w%~$Q~Gg~ zOnUfSxO(fc_(T8d5^$iAuF+0=$ifj(9~l z%-S-mp7(j^JrPfU_XSYDip|NMdK6xCyi|%)@+Tj5xDy49MNt$*Q4~e-i}(l5lZF1> Sx+UfS0000EaktG3V_J$D+duJg%P0 z%^&`A{}j6`;go@s5Yugo%=^)*5_a;EDGI7UO$-fh_xw42yl{%VW%}wTkzMmmjSp`- zUdY3KuWQA_PkU>1fBaLwlA)%2YU;K<>n~r=|Jk?uq~+?U+{F8}dtAQ03JJ4iIT}6j z#H?*{yuG}ZyO~~Phr8?9Y*qa^{mRk3Yaf?iH1F*AK6P&4Oy&NE6?!h=4PIAE!`$qz zx6OML%MeCt_rIs)U?d4w2+fvx~PV4a04LGi_t6;;Ct6PNCFQqt^DX~U! zMjbtGZ>JP|RMt;ZU)!R7u2Xlg=8BTA^pZ=Lx`UI>iZ5JNCb<2|X}?a6|D~0dziOB5 zEt9(2+A-^Mo7~6Z$sEraCa+$$cD=C$Xa2EU{Y(r8WMe+_3Y6Eq>fESMR(kE>39DSI z?VJ66PMO@1P_;TXZGY{Sx)r&h6BjmpJ&`X|QgrFChQ_-dWmnIv$uzvPqVI% z*UPn}X|CS#iB)oT#w#|53kt3=*|n`I>(kfUQFHaUxmF7Ot%&aaDjslWOJ%{SBdt5L zrOPGa{36~o2#)XYW8#p00i_>zopr E0M0b|TmS$7 literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanosp/test_trx_sign_tip712/00005.png b/tests/snapshots/nanosp/test_trx_sign_tip712/00005.png new file mode 100644 index 0000000000000000000000000000000000000000..e7ffedd90f5279e10fd67907e6122c12c1bbafd7 GIT binary patch literal 457 zcmV;)0XF`LP)Bo7fQz-)#Q&A!PMpz3O%n|+fjfT!4#E}eZd``R7A6>%04 z&A!Rq0acf7-Rx_VTk-<{0APxR-Amm`Z_ezOhUqW=r@`mED)n>^wO4fWLn<5k8hwp+ z*c7VQlDSFeL7Ml1+K3Zc$L1++d!-5U?%MEvn{hd75c|*Sy20_M8!B3Zc2Y_%-kP`W z6B3uv5sEp6+7}?3cGS-jo%#RmC+k+Iq6=2ZCt{yO@|m#fhCEXc001~`+bXE-Sq__* zaSL|sh|S-mJG0AswVnF_Z;Zqai5F&=srY7G+YlXo%RjEI;O00000NkvXXu0mjf&CAl) literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanosp/test_trx_sign_tip712/00006.png b/tests/snapshots/nanosp/test_trx_sign_tip712/00006.png new file mode 100644 index 0000000000000000000000000000000000000000..d3bef128eecbd19bc12dae757de34ba80dbf4fa3 GIT binary patch literal 455 zcmV;&0XY7NP)PdSutjpb#+YZDo2?2y^itke z`ukQ+MB;@b-`WkhOgSlGle_|Z%>CphBY@mj<2wECfZhiH0255yGMsM2hb0FS7q8xo zPpbAO&N9;JLfI<)9kJ$q)_9YvS&I%Kh_lLIryrYV&HTk{iNYYG^WkD65YTp1*nz+u})( zZ_@oUU*H`7^1Jm^byh||X(l(D|DEBHxd7xTWgLV0UE_7o9&-Um7R}DN3}=q9}++yIP#$#j!m5^exS zz+}2fFX=r8JdElH5Z(1#dLzJ@d7d#T0RR9zkLvC@{o4-b#&d>V@Olw{Qhp=JC*hP* ze&(v$CdMdHq04bD8(yuPe6}+mUxbB+j@Sq&JG)G;>8tv_Of9IF`aC{V8pehyFamrk zsn2Y*0u8Xun9W@KS20j;W!56I20WGIe?vDCyM6$`aiZIsFI~S2dUn1pckwRBmM6XP%`s%YvTHqZ3lwXSA8(yvzTEo$z)$(N682X1xVDy4{PzgV-)>~P%m z(SxSeRT|*hab4YQn?v%8>M*os9$Wn$H1mutMdS&3k#ezJft*eqW4tHkAtS*5@x-oX zb|Lk%2&YUpGG7h%y~aaI0W0RR910Dz=F-WV#{$lGiw P00000NkvXXu0mjfFUZz( literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanox/test_trx_sign_tip712/00001.png b/tests/snapshots/nanox/test_trx_sign_tip712/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..9ef4af9e16eb8f6328808234e4bd8d48f8ed34d0 GIT binary patch literal 894 zcmV-^1A+XBP)H57}G)Dp72lkM+mmk~nz$fU4G-Hqot+oDu(9=SvsZlaUKCV8ljQ-lZaBH zErb!`Vlam|SD6iDExS>}r*vX_mUXvmm`8K2@_N(s_2TYj+^5`I#*B`i zayv4b9!__FYzaw%<>|}zdGgF~{TwcoF|0($Q~xVAl8N z!sgvRG*MdGEM|t#lvwgwLf>Mik%AQersjoAl){X$JatMuyYF+flIZepp$X{v3zi4T z<)ZJyIsu~(+k~@#*nnx*J~)N4hZdXtm~kyjaFz&#q#IBNnWKLjo1y0D-wfyANtlJ6 z#2IAH!KKLI^}h`@4r++dh+Isz_ZQoLE{3!;tCiaa*5Z4~BF04}PpzUXL^Mc5utcIt zNTf)uCe&Gt%y&T_ciX%leC?xB1mdx3$7vUA*T0rwj5jUYTDX7BVf`8fH=R-9CK)%Y zEXD(^btJGWQVN3!x;mv{>ml(#`vcT4(h7>(mz-xwObykh@e=td7(*3cU#h|=xCv_!Bez8DY8vVua&tBU zK$-?`yx`q?MxB8E^$V>;-?lH9wl;^1@Z31lJ2ljoQ0ljK0FuI@;veGhq9o($wdH+5 zuqFV}DL>`YOeD5YU#dF0pMb4+d6<{Cnc7W}NPe$sE9&1BUr!n(gb+dqA>=~-0wLot UBw>6ScK`qY07*qoM6N<$g6Orfz5oCK literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanox/test_trx_sign_tip712/00002.png b/tests/snapshots/nanox/test_trx_sign_tip712/00002.png new file mode 100644 index 0000000000000000000000000000000000000000..9da987bedee81cf876984d20ebc7ba635bf68b0b GIT binary patch literal 522 zcmV+l0`>igP)8EboRE|N004l?{rE$3&h@{?am04z zo!^tzAGvUC&bho>Zdt_FN!pk?!_cq4>!lgdaFmkyM)ggpqg>Rlw=w>~d2RK#X-}+z z(mxSU_fIUh63|{{H)`Z;lh~Qn}Qh%`wH?luxySI!P-5=Ab z3bDHb+GaczFuZ)(IRl>=YO0<50Xtw;>26@f@8wj>&TQKK7{l%aw1as2gH+g`X;1lD zZen@@a?WDMwVwxUB|fka^>XG9Pv1oCuK#%dt=3x+lj5Ew-za2R#ICKc6EXoIJplmx za}%ebL+Wv9`uVlKOXc%bO|Wqcao|?^htMXBbKM!-muJNQ0`9O+ zfJt`^7D!kzSB40!n5gD3{Y*Hgo`BJ#>AekHe$so3SkwaZHpCDB&$(H4HZtckQG&bz zZG!6$MpP<3!j$JN-pEG4QVIHu*H`pql^4+BEg9j>9D)x?yG=R4?|j{&%k17YbP$m> zFhj4zbI3!T16;PO+|WsI5`GwOKUx$;QJjEMLrIYY>k6ZZ)@MMA8OB754h*yaD|0My zUtUN#7#RR>x6P}euw{;}-I@c1R(Me05R6WSWRly4&M7ma`Lv{kTNtZd?Df2Q623BJ z1OpzrJ(o6hKxp{{e&7u@BGP+@PI?w@B}c35-DzPG5b8{ zs@b$?k(&T=RyAHNdNTV*@periastNtC#zVvb;FRa5X`Q3z{JpE#q=sHXch$!) z!A){y|1peISN0#K=HN}L3cX2?Dn|Cr33;R7kcd-|BjCLYGQ2X>c! zNiuW9^$8|GD?greGYWyEE2a-94k^!GoL;eFTro)xH#IxI4-k!8By};wwB}`+nBFEL z_q1Ln+6@!1l9WT3No3-jTQ@7U2u%Rq;pv(Ksu1($U}RCIrK#VNdU1v~XvWDauM^s8 zQ4~c{6vdZ7{eOViPI+2m?@WHZ?rEsPJhT=2`jq?`#={>5b#lCcaxh}Rc!`%qP2o_t zq-^!)?Lww`2{!_Es-gTLa7C!tB62+7lZ28Y$P?*e_Q})ov~AWWX{*Og1w%~$Q~Gg~ zOnUfSxO(fc_(T8d5^$iAuF+0=$ifj(9~l z%-S-mp7(j^JrPfU_XSYDip|NMdK6xCyi|%)@+Tj5xDy49MNt$*Q4~e-i}(l5lZF1> Sx+UfS0000EaktG3V_J$D+duJg%P0 z%^&`A{}j6`;go@s5Yugo%=^)*5_a;EDGI7UO$-fh_xw42yl{%VW%}wTkzMmmjSp`- zUdY3KuWQA_PkU>1fBaLwlA)%2YU;K<>n~r=|Jk?uq~+?U+{F8}dtAQ03JJ4iIT}6j z#H?*{yuG}ZyO~~Phr8?9Y*qa^{mRk3Yaf?iH1F*AK6P&4Oy&NE6?!h=4PIAE!`$qz zx6OML%MeCt_rIs)U?d4w2+fvx~PV4a04LGi_t6;;Ct6PNCFQqt^DX~U! zMjbtGZ>JP|RMt;ZU)!R7u2Xlg=8BTA^pZ=Lx`UI>iZ5JNCb<2|X}?a6|D~0dziOB5 zEt9(2+A-^Mo7~6Z$sEraCa+$$cD=C$Xa2EU{Y(r8WMe+_3Y6Eq>fESMR(kE>39DSI z?VJ66PMO@1P_;TXZGY{Sx)r&h6BjmpJ&`X|QgrFChQ_-dWmnIv$uzvPqVI% z*UPn}X|CS#iB)oT#w#|53kt3=*|n`I>(kfUQFHaUxmF7Ot%&aaDjslWOJ%{SBdt5L zrOPGa{36~o2#)XYW8#p00i_>zopr E0M0b|TmS$7 literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanox/test_trx_sign_tip712/00005.png b/tests/snapshots/nanox/test_trx_sign_tip712/00005.png new file mode 100644 index 0000000000000000000000000000000000000000..e7ffedd90f5279e10fd67907e6122c12c1bbafd7 GIT binary patch literal 457 zcmV;)0XF`LP)Bo7fQz-)#Q&A!PMpz3O%n|+fjfT!4#E}eZd``R7A6>%04 z&A!Rq0acf7-Rx_VTk-<{0APxR-Amm`Z_ezOhUqW=r@`mED)n>^wO4fWLn<5k8hwp+ z*c7VQlDSFeL7Ml1+K3Zc$L1++d!-5U?%MEvn{hd75c|*Sy20_M8!B3Zc2Y_%-kP`W z6B3uv5sEp6+7}?3cGS-jo%#RmC+k+Iq6=2ZCt{yO@|m#fhCEXc001~`+bXE-Sq__* zaSL|sh|S-mJG0AswVnF_Z;Zqai5F&=srY7G+YlXo%RjEI;O00000NkvXXu0mjf&CAl) literal 0 HcmV?d00001 diff --git a/tests/snapshots/nanox/test_trx_sign_tip712/00006.png b/tests/snapshots/nanox/test_trx_sign_tip712/00006.png new file mode 100644 index 0000000000000000000000000000000000000000..d3bef128eecbd19bc12dae757de34ba80dbf4fa3 GIT binary patch literal 455 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 I$L+~~0UC_Qga7~l literal 0 HcmV?d00001 diff --git a/tests/snapshots/stax/test_trx_sign_tip712/00001.png b/tests/snapshots/stax/test_trx_sign_tip712/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..dbf96d9154bcf41af109981ffdcbfd157968687b GIT binary patch literal 15596 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 v#V4)Ir1j7U)+pFIUk(Z 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 literal 0 HcmV?d00001 diff --git a/tests/snapshots/stax/test_trx_sign_tip712/00003.png b/tests/snapshots/stax/test_trx_sign_tip712/00003.png new file mode 100644 index 0000000000000000000000000000000000000000..4c004ba39e9e2426dab299afed0002e040f1ba79 GIT binary patch literal 8756 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 AbpQYW literal 0 HcmV?d00001 diff --git a/tests/test_trx.py b/tests/test_trx.py index 4e6c1466..bbfcf0a9 100644 --- a/tests/test_trx.py +++ b/tests/test_trx.py @@ -6,6 +6,7 @@ import sys import struct import re +import binascii from ragger.error import ExceptionRAPDU from contextlib import contextmanager from pathlib import Path @@ -15,6 +16,7 @@ from tron import TronClient, Errors, CLA, InsType from ragger.bip import pack_derivation_path from utils import check_tx_signature, check_hash_signature +from eth_keys import KeyAPI ''' Tron Protobuf ''' @@ -60,7 +62,7 @@ def test_trx_get_version(self, backend, firmware, navigator): major, minor, patch = client.unpackGetVersionResponse(resp.data) path = str(Path(__file__).parent.parent.resolve()) + "/VERSION" version_file = open(path, "r").read() - version = re.findall("(\d)\.(\d)\.(\d)", version_file) + version = re.findall(r"(\d)\.(\d)\.(\d)", version_file) assert (major == int(version[0][0])) assert (minor == int(version[0][1])) assert (patch == int(version[0][2])) @@ -506,6 +508,34 @@ def test_trx_sign_hash(self, backend, firmware, navigator): assert check_hash_signature(hash_to_sign, resp.data[0:65], client.getAccount(0)['publicKey'][2:]) + def test_trx_sign_tip712(self, backend, firmware, navigator): + client = TronClient(backend, firmware, navigator) + domainHash = bytes.fromhex( + '6137beb405d9ff777172aa879e33edb34a1460e701802746c5ef96e741710e59') + messageHash = bytes.fromhex( + 'eb4221181ff3f1a83ea7313993ca9218496e424604ba9492bb4052c03d5c3df8') + data = pack_derivation_path(client.getAccount(0)['path']) + data += domainHash + data += messageHash + + with backend.exchange_async(CLA, InsType.SIGN_TIP_712_MESSAGE, 0x00, + 0x00, data): + if firmware.device == "stax": + text = "Hold to sign" + else: + text = "message" + client.navigate(Path(currentframe().f_code.co_name), text) + + resp = backend.last_async_response + + # Magic define + SIGN_MAGIC = b'\x19\x01' + msg_to_sign = SIGN_MAGIC + domainHash + messageHash + hash = keccak.new(digest_bits=256, data=msg_to_sign).digest() + + assert check_hash_signature(hash, resp.data[0:65], + client.getAccount(0)['publicKey'][2:]) + def test_trx_send_permissioned(self, backend, firmware, navigator): client = TronClient(backend, firmware, navigator) tx = client.packContract( diff --git a/tests/tron.py b/tests/tron.py index 43b326d0..96a04177 100644 --- a/tests/tron.py +++ b/tests/tron.py @@ -61,6 +61,7 @@ class InsType(IntEnum): GET_APP_CONFIGURATION = 0x06 # Version and settings SIGN_PERSONAL_MESSAGE = 0x08 GET_ECDH_SECRET = 0x0A + SIGN_TIP_712_MESSAGE = 0x0C class Errors(IntEnum): From 77c14f82fd50b6d96275bba4b94962f5b68713e6 Mon Sep 17 00:00:00 2001 From: barbatos2011 Date: Tue, 4 Jun 2024 10:43:53 +0800 Subject: [PATCH 2/2] fix conflicts and support flex --- .../flex/test_trx_sign_tip712/00000.png | Bin 0 -> 9019 bytes .../flex/test_trx_sign_tip712/00001.png | Bin 0 -> 16640 bytes .../flex/test_trx_sign_tip712/00002.png | Bin 0 -> 16468 bytes .../flex/test_trx_sign_tip712/00003.png | Bin 0 -> 9393 bytes .../flex/test_trx_sign_tip712/00004.png | Bin 0 -> 6357 bytes .../flex/test_trx_sign_tip712/00005.png | Bin 0 -> 11256 bytes .../stax/test_trx_sign_tip712/00000.png | Bin 8035 -> 8069 bytes .../stax/test_trx_sign_tip712/00001.png | Bin 15596 -> 15714 bytes .../stax/test_trx_sign_tip712/00002.png | Bin 15835 -> 15835 bytes .../stax/test_trx_sign_tip712/00003.png | Bin 8756 -> 8758 bytes .../stax/test_trx_sign_tip712/00004.png | Bin 6108 -> 5153 bytes tests/test_trx.py | 6 +++--- 12 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 tests/snapshots/flex/test_trx_sign_tip712/00000.png create mode 100644 tests/snapshots/flex/test_trx_sign_tip712/00001.png create mode 100644 tests/snapshots/flex/test_trx_sign_tip712/00002.png create mode 100644 tests/snapshots/flex/test_trx_sign_tip712/00003.png create mode 100644 tests/snapshots/flex/test_trx_sign_tip712/00004.png create mode 100644 tests/snapshots/flex/test_trx_sign_tip712/00005.png diff --git a/tests/snapshots/flex/test_trx_sign_tip712/00000.png b/tests/snapshots/flex/test_trx_sign_tip712/00000.png new file mode 100644 index 0000000000000000000000000000000000000000..80e6cfdff4f63f9f48ebae3a6d335410e56e2d55 GIT binary patch literal 9019 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 NtEI15sqy0V{{XUsLRJ6( literal 0 HcmV?d00001 diff --git a/tests/snapshots/flex/test_trx_sign_tip712/00003.png b/tests/snapshots/flex/test_trx_sign_tip712/00003.png new file mode 100644 index 0000000000000000000000000000000000000000..aa088be4a1a2c0b06866d5bb1aae6e06c4da404c GIT binary patch literal 9393 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 UPsf12D=dzNgdJ`>c;@PV1L0-a-2eap literal 0 HcmV?d00001 diff --git a/tests/snapshots/flex/test_trx_sign_tip712/00005.png b/tests/snapshots/flex/test_trx_sign_tip712/00005.png new file mode 100644 index 0000000000000000000000000000000000000000..8a75d8c403abced3a4c28f65dc8f80b64b3a5bd0 GIT binary patch literal 11256 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 literal 0 HcmV?d00001 diff --git a/tests/snapshots/stax/test_trx_sign_tip712/00000.png b/tests/snapshots/stax/test_trx_sign_tip712/00000.png index 325bfe606acc8906391194d10ac53b1383a3a6fa..338de560f9509a803a312b86921393c47b2ada51 100644 GIT binary patch literal 8069 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 WO?KT98~D90VFk6jRB^%Q-hTicwCy(l literal 8035 zcmeHMXIN8Nw?;t63M$2sI*I}U(uO94@F{}Q1q4EG(rZG85JVjK04Yk78l~3&QbPh^ zL_k2yP$MNELO_TCNeD4Ol6#zc|J~o;y?-Woo;=Svd!Mzl)?WKv?|M(_1M_?5PK%u8 z;^I1IbpNgu7uT_DE-vm@C%J(;+7{RbE-pzqqr0~sMwd{C3o&1e7c?AVokO@koS(k( z7x4XjKJ=s(uMV#O_fxk!kI(lkO4HZ+;$&03l@TkT!(rUJ z?LvP6gG0n{amAlf`0Z@s@uyc>9xL+-pHJ@RetRDBuV1;(oYZ$a=6>>@!GD7APbU1Y zm z{49CE>iDW6ukbkR1lx#UM$B~9zS&OAz}6)7 zm)l%-MG0M(88GplFmzK9VReCLCT_F+EU&itUTe{!2p8JKZ1=dVys)1>rNB-g);(nI zzg6>VcsHWZb4uZ$$F?XuYvhG}_<6_?60DC>43yZvd|R%~7g%}rftxLIbJ9 z!Sg&l?LC-JqIS>%(OkF}cRJ@Q@&Zf#HeK||z^HWFdB|CUOxp>){Y3~g$6l|bzkI7P z84~4PnrDk+H-tc$Mxdh)RaR$bT)+QCJS!$_B$2^h;T0xWCj6=Yhp|9`07OlTkq4op z0y6E|pQ z!`^cf`4i_Mdl7>WsAIM}udu$;3$5TYsxSM$lvVzmT(UyFcP7FadMa^nrsSEj-{2p- z!W+9Bjj(&%=_~W9U)MNyYGVhLxzmetY@O2kzXTS9_nOEn0*>Akr#LV_NSzBbfIFR>Z42lA|E>iG zcQS`pccZaUH$IaOmV3{H>I0XdTJ7!HRw+XkCaGsL*#(C)z6TYN! z7_NOYt-MuvB(~Q)LD1m2ZLV>&me{0B-a#BYQcVP?;yE3M>|!S+h@#^`o&_qPU!izh zI>fxF!D3gVcpP{NQ!AUsgqL|6NoH#Em;I@;Rt#yfm0X@ClLMAMWR6g8+Y1`3@@CZR z`KkfY+u7O4OAVWCzu6R2F;{b&_6S4N_?Txta5O`s(S)MjM_p~{ z;U=?Ky>agb9;w!e$;N-&2i<0Ne>>TDZ1DX8SRza3wDN(b?4PbL+42G!47Rt=_;(P4 z!?x5B7>A}&p^R8xz6Badw6SeYVP}cDB^P$?Wfhhuy*xTD&cvvd7(6zJLfVteK4QL5 zC^v&1##{?yy}#V4--kp>KuG3{Q9tW47KPH}IYb~3sCLAl5AbBW7v(owPF#|bWaZ)I zEv=SsiPty{uTPt}@QojAvt&#A^TgGob7oQSYczzXZY@Db)jy?R)Y9te68-^+w7wc?)ZBpdv^RSBO+?e7$<(tK}4Jh;)T7 zh?c+Hm>q0caOq`olTyJLO!q4PrLVUjj29lccC8DPNgHkc8d?4uvit{l1|2VM4sX&S z7X(t_U<*uq*8+=%*PGhhTYC>gN-h7Et{-lJLbY(RUCQos6cA5x6DhEsg~}o{^(vER zswsUD$e1xX@dc8+OAJ#S)7zRH;jSX*$pDKQ9yqS#05VuXJevw*YC@b|^>~Q_! z)`y7vqv2>!-^A*JJdbJegSxW-zz8WJ8~mPt<{qi0stUKh8Cjt0Gnr_s9|J2bF3pk> z66_(*^wLbWO@&`!lB`ZUer@j#8SrY!gC z*dF&dL@Pu=I6YTu^Ys%r9{@(U1deU6Ynjd%uqrLncy)S;ej~4Px5|*YHB%}r)8_q& zk74w#Be#=H%_>7N{hs;uu^Az@ zPQ6CaOlbmzaY*%B)X2o*6-Zyy6>D~D1=)m8-D{5Dvb%qRCu*_jL4u?$)9oh1 zh@mNwMH_KK+^0NhSm_yj?{y#FT!kBRFJ%J=F-B5#UYQc`=b4QVDhPo&$8yOILx=S% zWPENAnzp3o4R3Z-!ZOr3r-g!$%N{B3=wUn!N4^2EPdko+(8YBWI-+=d9goz@%F4>n zOg60ANCV;w7PA1)K#3k}a|CjP_M-fF?-3q*bl4Z{`(0X+FJ+pvcgWZoLT`z$@p#{= zqqx04j6plihWT_Ybo45$$)$W@?0ObImE;6<%q%F7peo`6uS9Xe!f&EvYbm^7PX2AhgGlV?N(0&CHKl$9o=uB$4?v@}f zMN%9h$q^59PH21$I~w1h0ayZjjKwQg^G@X5&@uFk1ertwIow9DXfx(%X?mIwd;yZA zi9Vt{QjI|%T$*fwY$4(0uU}R+sd5AMXZ%IIC&}1;cz-qz>C#xUK?45y_bDE7Mfj0= z*+Ut}(4hEQBj&u;RwFhX=duo*LVV89CFNXe%mx?Zn_(hdB|HZcw=9xEEY&d?Zt5wQ z?a{2KPDkZmtUsiyUXn;#PU=6vKcfE<4y5PO(vnElCQ!+I!oAS-%PMmt40mU%XViD} z5T%&d{m8$qg?ZHkf+V6A#XwQ{qv@AN4?FP#FB@k3!AJ`L`NNCmlQ(HOI|Du69~_xEqf^1Y?gE z5)P*_6HVRzwA&>Un)g!L-i+hLXStA@p;{m?m<=FE5ChfB4!b~))M~75VdbR0)jb$^V)4RtxlD|m zr&nlRGg)6OA`GvemixdtNBX+VNqw`*xq3|i=&6gI{?k|gBQE@ZDl8mK)Um!idTcyM z!onP&h(oKpGPxVW^OVRj5=>2`x36yrqu`X&-&0Ktj?xk{H`kEJ@@bos$*u9|TF4k) zEtdr+%ydn4TLL`O`Bo%`_(&CPJ<$zLj4;a?0oaCE)-W;HPSAi9USwW_bZMUm?uv_v zxsmphrqc)rsUT5xB;NX*i9`JF+~guTdiCEF*|1^)4#ruhB5DEJ4^h~5K8><)i$C=@ z?GJA!0H=C;-&i2)V1z0I(BpPHcW4f?c zXRTlc63GCF{=&PtXpmwQswzf4KFGqtqAslfrz^&%q@+ZqAFSEt`dE00W)0sc9tT%>?qF?wwer~sS*?b66Ds8w%;YMgNc306qH;nQ?o zJ<+bg#w!unU3G00|f16Gs_4AE*_GDa!QW${}Po0a~7rd7uG7%z0Z6A%bQe7u=! zDJFmDkROf1R)B~o%%{u@V@ZD@ms05!79|q%&|*YHCLo|d$l$q%`oIZ`@I?g^$w=hL z=0c9tn4;4dA$PPyWIe;xV6j%o+>L0>5_YfWK8sR3H#_TGS|38XEhOYqnv+DJ=EbwK z=sBkvF>`?$b!I9|yFR}eVo>;*l!4c+(0N^|?_S94V(d-Vxp3{?u_RkP;OG?R+UDK< zm-zhFZ=0v}en64!{X_nD4q9~X!QMw^ed-Cl>3a8iQCOkAAUp1_O@t4fhOMaS1Utzt zSBip6RjxaG=2p%`D4{*~YieqMMiy4a=Q8Fq8t|aC9d@tF$c!I zr!GM9LZ(hOTH<`d=eM-{8a+k0?Ah3jq->^!m)Ab12vo|sgd#0w^gM6~6miW5`-wR@ zNE|w_k3zK?31l@9a?f%7obSQwG$v5yfa3~>f3Tygp=x%|n$Fa!nX8ssGFLjlK5<3l zXb>0#dN#ZY!;g8i-e1K5tb!gFL7>sXy!Q8MKYzukgs(V!B-WaI@NOf)Vn7l=w@iDL z0(4_&{TG_`Y$+gjM;^fn2rzhvKO`z=NjCdqm)e_^P%YD%smuz{xiAa;HERbm=^S=* zI>25&%GjW*^M}H!MII;`iSW;D95v(19O_87nFY;19lE;(QOLskll@Ia)eB8WMe~vg zG0yL99yv7GZbKIdE1~c2#VqiWhM_6FO|RedcY-ULzjr3PYiszoOy|smwfa@`Ez4iT z37Wkom4oVse!MUX;7Bt;r zE}!XX095PVrL%%W2&BJ&4yYeK;K6yNxPg-s?>AgC$S`HFTnu zI&Y+x%XV4M_dH!*UM8E6%d`?O5CwoSQ|lo1cdp}r&@3!Ct~v;(4ljWvthynhmC3SYFczUUMO~xU5L*kXWTgTSPMnE?i zN>Zr#6sQ3REQhQtpJ6CL0hF)#0n(^t z*&EJ$^P6Rngl_DohfTnmq?(1j-55QWK9XEum12zymf(6+oITHvbm0f45e?DWB_lI=XRh!F(&$BJC~ zc$D9$XvD0E-w59^RTcY-SlAHhH!JYE;PE&m`+BEwLlRd){qE!><0RYUc2f%~;qH zd@rF?bcLUvKLfAqd^N&Z7X+%Lm<`;UCDW&-rhx5A ztMM2?3AVn5aiPl3~<9vW!J_<0Oa>XXiH=c76)IU0nT*3#aFl&VAXUA*j+mi`detW&1ALb~AI2V>%>o5{F*XX`{gMcdTV3o}_Q26y6_U^<(emOx zA4eEA`+6I3OPL_@(dEcD#NcNJ$X=Dtoq@=ak3=C?_g5o~YNH=>qdek7y(eua8}YUh zWwb(`>d&I*A;>1#v}q}_7ba9O9)dJ8|I^L?Kl*}sm2+&{Shv$&s>Tg?dCp~IV15^M I$L+~~0UC_Qga7~l diff --git a/tests/snapshots/stax/test_trx_sign_tip712/00001.png b/tests/snapshots/stax/test_trx_sign_tip712/00001.png index dbf96d9154bcf41af109981ffdcbfd157968687b..f0b6265369efb8987f6b4b151a1a6236ac6ed0fb 100644 GIT binary patch literal 15714 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 V2LxZi181lCz{Zw0tFOB~{vYf3=rI5Q literal 15596 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 v#V4)Ir1j7U)+pFIUk(Z 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 diff --git a/tests/snapshots/stax/test_trx_sign_tip712/00003.png b/tests/snapshots/stax/test_trx_sign_tip712/00003.png index 4c004ba39e9e2426dab299afed0002e040f1ba79..3e7332418778d7ee5d52eb6b1645afe5d8392c10 100644 GIT binary patch literal 8758 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 D?rH^~ literal 6108 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