This repository has been archived by the owner on Aug 10, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 9
/
cli.py
96 lines (70 loc) · 3.2 KB
/
cli.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
"""
Basic script show casing all commands
Requirements:
pip install neo-mamba==0.9 ledgerblue
"""
import struct
import enum
from ledgerblue.commTCP import getDongle
from ledgerblue.comm import getDongle as usb_getDongle
from neo3.core import cryptography, types, serialization
from neo3.network import payloads
class INS(enum.IntEnum):
GET_APP_NAME = 0x0 # name of the application
GET_VERSION = 0x01 # version of the application
SIGN_TX = 0x02 # sign transaction with BIP44 path and return signature
GET_PUBLIC_KEY = 0x04 # public key of corresponding BIP44 path and return uncompressed public key
P2_MORE = 0x80 # specific for SIGN_TX instruction
P2_LAST = 0x00 # specific for SIGN_TX instruction
BIP44 = bytes.fromhex("8000002C80000378800000000000000000000000")
NETWORK_MAGIC = struct.pack("I", 860833102)
def apdu(ins: int, p1: int, p2: int, cdata: bytes = None, cla: int = 0x80):
""" Helper for sending a basic APDU """
if cdata is None:
cdata = b''
return struct.pack("BBBBB",
cla,
ins,
p1,
p2,
len(cdata)) + cdata
def get_app_name(conn) -> str:
result = conn.exchange(apdu(INS.GET_APP_NAME, p1=0, p2=0))
return result.decode()
def get_app_version(conn) -> str:
result = conn.exchange(apdu(INS.GET_VERSION, p1=0, p2=0))
return "%d.%d.%d" % struct.unpack("BBB", result)
def get_public_key(conn) -> cryptography.ECPoint:
result = conn.exchange(apdu(INS.GET_PUBLIC_KEY, p1=0, p2=0, cdata=BIP44))
return cryptography.ECPoint(bytes(result), cryptography.ECCCurve.SECP256R1, validate=True)
def sign_tx(conn, tx_unsigned_data: bytes) -> str:
conn.exchange(apdu(INS.SIGN_TX, p1=0, p2=P2_MORE, cdata=BIP44)) # send BIP44 path
conn.exchange(apdu(INS.SIGN_TX, p1=1, p2=P2_MORE, cdata=NETWORK_MAGIC))
result = conn.exchange(apdu(INS.SIGN_TX, p1=2, p2=P2_LAST, cdata=tx_unsigned_data))
return result.hex()
def main():
conn = getDongle('127.0.0.1', 9999, debug=True) # Use this when testing via the Speculos emulator
# conn = usb_getDongle(debug=True) # Use this when testing on physical device
print(f"App name: {get_app_name(conn)}")
print(f"App version: {get_app_version(conn)}")
print(f"Public key (compressed): {get_public_key(conn)}")
# Create a TX to be signed
signer = payloads.Signer(account=types.UInt160.from_string("d7678dd97c000be3f33e9362e673101bac4ca654"),
scope=payloads.WitnessScope.CALLED_BY_ENTRY)
tx = payloads.Transaction(version=0,
nonce=123,
system_fee=456,
network_fee=789,
valid_until_block=1,
attributes=[],
signers=[signer],
script=b'\x01',
witnesses=[])
with serialization.BinaryWriter() as br:
tx.serialize_unsigned(br)
tx_unsigned_raw = br.to_array()
# Requires confirmation by the user
print(f"Signature: {sign_tx(conn, tx_unsigned_raw)}")
conn.close()
if __name__ == "__main__":
main()