-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathtest.py
More file actions
96 lines (72 loc) · 3.5 KB
/
Copy pathtest.py
File metadata and controls
96 lines (72 loc) · 3.5 KB
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
"""
This stand-alone script demonstrates how to interact with a Ledger device with
the boilerplate custom app, using the `ledger_bitcoin` client library.
Similar code is also part of the pytest suite in the `tests` folder, which is
the recommended way of testing the application.
Install `ledger_bitcoin` in a virtual environment:
```
$ python -m venv venv
$ source venv/bin/activate
$ pip install ledger_bitcoin
```
Launch the app in speculos using another terminal, then launch the test script:
```
python test.py
```
The script will get the device's master fingerprint, call a custom APDU and
verify the response; then, it will sign a PSBT for a custom transaction as
supported by this boilerplate app.
"""
from ledger_bitcoin import Chain, TransportClient, WalletPolicy
from ledger_bitcoin.client import NewClient as AppClient
from ledger_bitcoin.psbt import PSBT
CLA_APP = 0xE1
INS_CUSTOM_XOR = 128
if __name__ == '__main__':
transport = TransportClient()
client = AppClient(transport, chain=Chain.TEST)
# Tests a custom APDU. A real application should implement a
# custom client instead of using raw APDUs.
data = bytes([1, 2, 3, 4, 5])
res = transport.apdu_exchange(CLA_APP, INS_CUSTOM_XOR, data, 0, 0)
assert res == bytes([1 ^ 2 ^ 3 ^ 4 ^ 5])
fpr = client.get_master_fingerprint()
print(f"Fingerprint: {fpr.hex()}")
if fpr.hex() != "f5acc2fd":
print("This test assumes that the device is onboarded with the default mnemonic of Speculos")
client.stop()
exit(1)
wallet = WalletPolicy(
"",
"tr(@0/**)",
[
"[f5acc2fd/86'/1'/0']tpubDDKYE6BREvDsSWMazgHoyQWiJwYaDDYPbCFjYxN3HFXJP5fokeiK4hwK5tTLBNEDBwrDXn8cQ4v9b2xdW62Xr5yxoQdMu1v6c7UDXYVH27U"
],
)
psbt = PSBT()
psbt.deserialize("cHNidP8BAJUCAAAAAqG4I9IzbWlLSTTvm25bfeF6BVE9qKKdsCouy8eppv5tAQAAAAD9////FveaMWPsN+g8VMbi6P9s2IOOg17zrcPf1ZYnyUnsJAkAAAAAAP3///8C8qapAAAAAAAiUSALjnSGvDBqCu+3p8AK8EBVQtsazXPuzKgnccz1/l62DwAAAAAAAAAABWoDRk9PAAAAAAABASunhqkAAAAAACJRINj08dGJltthuxyvVCPeJdih7unJUNN+b/oCMBLV5i4NIRYhLqKFalzxEOZqK+nXNTFHk/28s4iyuPE/K2remC569RkA9azC/VYAAIABAACAAAAAgAEAAAAAAAAAARcgIS6ihWpc8RDmaivp1zUxR5P9vLOIsrjxPytq3pguevUAAQErOTAAAAAAAAAiUSCHtA8hlu4BzfGu7dqCwmls1lYlShMPirSpdE1UaM3XBSEWh7QPIZbuAc3xru3agsJpbNZWJUoTD4q0qXRNVGjN1wURAPWswv1WAACAAQAAgGMAAIABFyCHtA8hlu4BzfGu7dqCwmls1lYlShMPirSpdE1UaM3XBQABBSACkIHs5WFqocuZMZ/Eh07+5H8IzrpfYARjbIxDQJpfCiEHApCB7OVhaqHLmTGfxIdO/uR/CM66X2AEY2yMQ0CaXwoZAPWswv1WAACAAQAAgAAAAIABAAAAAgAAAAAA")
try:
sign_results = client.sign_psbt(psbt, wallet, None)
except Exception as e:
print("Error signing PSBT:", e)
client.stop()
exit(1)
print("Results of sign_psbt:", sign_results)
assert len(sign_results) == 2
signatures = list(sorted(sign_results))
# Test that the signature is for the correct pubkey
i_0, psig_0 = signatures[0]
assert i_0 == 0
# This is the key derived at m/86'/1'/0'/1/0, tweaked as per BIP-86
assert psig_0.pubkey == bytes.fromhex(
"d8f4f1d18996db61bb1caf5423de25d8a1eee9c950d37e6ffa023012d5e62e0d")
i_1, psig_1 = signatures[1]
assert i_1 == 1
# This is the key derived at m/86'/1'/99'/1/0, and it is NOT tweaked
assert psig_1.pubkey == bytes.fromhex(
"87b40f2196ee01cdf1aeedda82c2696cd656254a130f8ab4a9744d5468cdd705")
# Add partial signatures to the PSBT
psbt.inputs[0].tap_key_sig = psig_0.signature
psbt.inputs[1].tap_key_sig = psig_1.signature
print("Signed PSBT:", psbt.serialize())
client.stop()