jade: update Jade api to 1.0.31
This extends the serial api to recognise recently supported hardware.
This commit is contained in:
committed by
SomberNight
parent
5f43627b7e
commit
9a84bb3211
@@ -26,14 +26,15 @@ _logger = get_logger(__name__)
|
|||||||
#import logging
|
#import logging
|
||||||
#LOGGING = logging.INFO
|
#LOGGING = logging.INFO
|
||||||
#if LOGGING:
|
#if LOGGING:
|
||||||
# logger = logging.getLogger('jade')
|
# logger = logging.getLogger('electrum.plugins.jade.jadepy.jade')
|
||||||
# logger.setLevel(LOGGING)
|
# logger.setLevel(LOGGING)
|
||||||
# device_logger = logging.getLogger('jade-device')
|
# device_logger = logging.getLogger('electrum.plugins.jade.jadepy.jade-device')
|
||||||
# device_logger.setLevel(LOGGING)
|
# device_logger.setLevel(LOGGING)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Do imports
|
# Do imports
|
||||||
from .jadepy.jade import JadeAPI
|
from .jadepy.jade import JadeAPI
|
||||||
|
from .jadepy.jade_serial import JadeSerialImpl
|
||||||
from serial.tools import list_ports
|
from serial.tools import list_ports
|
||||||
except ImportError as e:
|
except ImportError as e:
|
||||||
_logger.exception('error importing Jade plugin deps')
|
_logger.exception('error importing Jade plugin deps')
|
||||||
@@ -352,12 +353,9 @@ class Jade_KeyStore(Hardware_KeyStore):
|
|||||||
class JadePlugin(HW_PluginBase):
|
class JadePlugin(HW_PluginBase):
|
||||||
keystore_class = Jade_KeyStore
|
keystore_class = Jade_KeyStore
|
||||||
minimum_library = (0, 0, 1)
|
minimum_library = (0, 0, 1)
|
||||||
DEVICE_IDS = [(0x10c4, 0xea60), # Development Jade device
|
DEVICE_IDS = JadeSerialImpl.JADE_DEVICE_IDS
|
||||||
(0x1a86, 0x55d4), # Retail Blockstream Jade (And some DIY devices)
|
|
||||||
(0x0403, 0x6001), # DIY FTDI Based Devices (Eg: M5StickC-Plus)
|
|
||||||
(0x1a86, 0x7523)] # DIY CH340 Based devices (Eg: ESP32-Wrover)
|
|
||||||
SUPPORTED_XTYPES = ('standard', 'p2wpkh-p2sh', 'p2wpkh', 'p2wsh-p2sh', 'p2wsh')
|
SUPPORTED_XTYPES = ('standard', 'p2wpkh-p2sh', 'p2wpkh', 'p2wsh-p2sh', 'p2wsh')
|
||||||
MIN_SUPPORTED_FW_VERSION = (0, 1, 32)
|
MIN_SUPPORTED_FW_VERSION = (0, 1, 47)
|
||||||
|
|
||||||
# For testing with qemu simulator (experimental)
|
# For testing with qemu simulator (experimental)
|
||||||
SIMULATOR_PATH = None # 'tcp:127.0.0.1:2222'
|
SIMULATOR_PATH = None # 'tcp:127.0.0.1:2222'
|
||||||
|
|||||||
@@ -2,10 +2,9 @@
|
|||||||
|
|
||||||
This is a slightly modified version of the official [Jade](https://github.com/Blockstream/Jade) python library.
|
This is a slightly modified version of the official [Jade](https://github.com/Blockstream/Jade) python library.
|
||||||
|
|
||||||
This modified version was made from tag [1.0.29](https://github.com/Blockstream/Jade/releases/tag/1.0.29).
|
This modified version was made from tag [1.0.31](https://github.com/Blockstream/Jade/releases/tag/1.0.31).
|
||||||
|
|
||||||
Intention is to fold these modifications back into Jade repo, for future api release.
|
|
||||||
|
|
||||||
## Changes
|
## Changes
|
||||||
|
|
||||||
- Removed BLE module, reducing transitive dependencies
|
- Removed BLE module, reducing transitive dependencies
|
||||||
- _http_request() function removed, so cannot be used as unintentional fallback
|
- _http_request() function removed, so cannot be used as unintentional fallback
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
from .jade import JadeAPI
|
from .jade import JadeAPI
|
||||||
from .jade_error import JadeError
|
from .jade_error import JadeError
|
||||||
|
|
||||||
__version__ = "0.2.0"
|
__version__ = "1.0.31"
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import collections
|
|||||||
import collections.abc
|
import collections.abc
|
||||||
import traceback
|
import traceback
|
||||||
import random
|
import random
|
||||||
|
import socket
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
# JadeError
|
# JadeError
|
||||||
@@ -24,7 +25,7 @@ device_logger = logging.getLogger(f'{__name__}-device')
|
|||||||
# It relies on the BLE dependencies being available
|
# It relies on the BLE dependencies being available
|
||||||
try:
|
try:
|
||||||
from .jade_ble import JadeBleImpl
|
from .jade_ble import JadeBleImpl
|
||||||
except ImportError as e:
|
except (ImportError, FileNotFoundError) as e:
|
||||||
logger.warning(e)
|
logger.warning(e)
|
||||||
logger.warning('BLE scanning/connectivity will not be available')
|
logger.warning('BLE scanning/connectivity will not be available')
|
||||||
|
|
||||||
@@ -123,6 +124,32 @@ def _hexlify(data):
|
|||||||
# logger.info(e)
|
# logger.info(e)
|
||||||
# logger.info('Default _http_requests() function will not be available')
|
# logger.info('Default _http_requests() function will not be available')
|
||||||
|
|
||||||
|
def generate_dump():
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
with socket.create_connection(("localhost", 4444)) as s:
|
||||||
|
output = b""
|
||||||
|
while b"Open On-Chip Debugger" not in output:
|
||||||
|
data = s.recv(1024)
|
||||||
|
if not data:
|
||||||
|
continue
|
||||||
|
output += data
|
||||||
|
|
||||||
|
s.sendall(b"esp gcov dump\n")
|
||||||
|
|
||||||
|
output = b""
|
||||||
|
while b"Targets disconnected." not in output:
|
||||||
|
data = s.recv(1024)
|
||||||
|
if not data:
|
||||||
|
continue
|
||||||
|
output += data
|
||||||
|
s.sendall(b"resume\n")
|
||||||
|
time.sleep(1)
|
||||||
|
return
|
||||||
|
except ConnectionRefusedError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class JadeAPI:
|
class JadeAPI:
|
||||||
"""
|
"""
|
||||||
High-Level Jade Client API
|
High-Level Jade Client API
|
||||||
@@ -431,7 +458,8 @@ class JadeAPI:
|
|||||||
"""
|
"""
|
||||||
return self._jadeRpc('logout')
|
return self._jadeRpc('logout')
|
||||||
|
|
||||||
def ota_update(self, fwcmp, fwlen, chunksize, fwhash=None, patchlen=None, cb=None):
|
def ota_update(self, fwcmp, fwlen, chunksize, fwhash=None, patchlen=None, cb=None,
|
||||||
|
gcov_dump=False):
|
||||||
"""
|
"""
|
||||||
RPC call to attempt to update the unit's firmware.
|
RPC call to attempt to update the unit's firmware.
|
||||||
|
|
||||||
@@ -507,6 +535,9 @@ class JadeAPI:
|
|||||||
if (cb):
|
if (cb):
|
||||||
cb(written, cmplen)
|
cb(written, cmplen)
|
||||||
|
|
||||||
|
if gcov_dump:
|
||||||
|
self.run_remote_gcov_dump()
|
||||||
|
|
||||||
# All binary data uploaded
|
# All binary data uploaded
|
||||||
return self._jadeRpc('ota_complete')
|
return self._jadeRpc('ota_complete')
|
||||||
|
|
||||||
@@ -523,6 +554,22 @@ class JadeAPI:
|
|||||||
"""
|
"""
|
||||||
return self._jadeRpc('debug_selfcheck', long_timeout=True)
|
return self._jadeRpc('debug_selfcheck', long_timeout=True)
|
||||||
|
|
||||||
|
def run_remote_gcov_dump(self):
|
||||||
|
"""
|
||||||
|
RPC call to run in-built gcov-dump.
|
||||||
|
NOTE: Only available in a DEBUG build of the firmware.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
bool
|
||||||
|
Always True.
|
||||||
|
"""
|
||||||
|
result = self._jadeRpc('debug_gcov_dump', long_timeout=True)
|
||||||
|
time.sleep(0.5)
|
||||||
|
generate_dump()
|
||||||
|
time.sleep(2)
|
||||||
|
return result
|
||||||
|
|
||||||
def capture_image_data(self, check_qr=False):
|
def capture_image_data(self, check_qr=False):
|
||||||
"""
|
"""
|
||||||
RPC call to capture raw image data from the camera.
|
RPC call to capture raw image data from the camera.
|
||||||
@@ -951,6 +998,42 @@ class JadeAPI:
|
|||||||
params = {'multisig_file': multisig_file}
|
params = {'multisig_file': multisig_file}
|
||||||
return self._jadeRpc('register_multisig', params)
|
return self._jadeRpc('register_multisig', params)
|
||||||
|
|
||||||
|
def get_registered_descriptors(self):
|
||||||
|
"""
|
||||||
|
RPC call to fetch brief summaries of any descriptor wallets registered to this signer.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
dict
|
||||||
|
Brief description of registered descriptor, keyed by registration name.
|
||||||
|
Each entry contains keys:
|
||||||
|
descriptor_len - int, length of descriptor output script
|
||||||
|
num_datavalues - int, total number of substitution placeholders passed with script
|
||||||
|
master_blinding_key - 32-bytes, any liquid master blinding key for this wallet
|
||||||
|
"""
|
||||||
|
return self._jadeRpc('get_registered_descriptors')
|
||||||
|
|
||||||
|
def get_registered_descriptor(self, descriptor_name):
|
||||||
|
"""
|
||||||
|
RPC call to fetch details of a named descriptor wallet registered to this signer.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
descriptor_name : string
|
||||||
|
Name of descriptor registration record to return.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
dict
|
||||||
|
Description of registered descriptor wallet identified by registration name.
|
||||||
|
Contains keys:
|
||||||
|
descriptor_name - str, name of descritpor registration
|
||||||
|
descriptor - str, descriptor output script, may contain substitution placeholders
|
||||||
|
datavalues - dict containing placeholders for substitution into script
|
||||||
|
"""
|
||||||
|
params = {'descriptor_name': descriptor_name}
|
||||||
|
return self._jadeRpc('get_registered_descriptor', params)
|
||||||
|
|
||||||
def register_descriptor(self, network, descriptor_name, descriptor_script, datavalues=None):
|
def register_descriptor(self, network, descriptor_name, descriptor_script, datavalues=None):
|
||||||
"""
|
"""
|
||||||
RPC call to register a new descriptor wallet, which must contain the hw signer.
|
RPC call to register a new descriptor wallet, which must contain the hw signer.
|
||||||
@@ -959,7 +1042,7 @@ class JadeAPI:
|
|||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
network : string
|
network : string
|
||||||
Network to which the multisig should apply - eg. 'mainnet', 'liquid', 'testnet', etc.
|
Network to which the descriptor should apply - eg. 'mainnet', 'liquid', 'testnet', etc.
|
||||||
|
|
||||||
descriptor_name : string
|
descriptor_name : string
|
||||||
Name to use to identify this descriptor wallet registration record.
|
Name to use to identify this descriptor wallet registration record.
|
||||||
@@ -1221,6 +1304,35 @@ class JadeAPI:
|
|||||||
params = {'identity': identity, 'curve': curve, 'index': index, 'challenge': challenge}
|
params = {'identity': identity, 'curve': curve, 'index': index, 'challenge': challenge}
|
||||||
return self._jadeRpc('sign_identity', params)
|
return self._jadeRpc('sign_identity', params)
|
||||||
|
|
||||||
|
def sign_attestation(self, challenge):
|
||||||
|
"""
|
||||||
|
RPC call to sign passed challenge with embedded hw RSA-4096 key, such that the caller
|
||||||
|
can check the authenticity of the hardware unit. eg. whether it is a genuine
|
||||||
|
Blockstream production Jade unit.
|
||||||
|
Caller must have the public key of the external verifying authority they wish to validate
|
||||||
|
against (eg. Blockstream's Jade verification public key).
|
||||||
|
NOTE: only supported by ESP32S3-based hardware units.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
challenge : bytes
|
||||||
|
Challenge bytes to sign
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
dict
|
||||||
|
Contains keys:
|
||||||
|
signature - 512-bytes, hardware RSA signature of the SHA256 hash of the passed
|
||||||
|
challenge bytes.
|
||||||
|
pubkey_pem - str, PEM export of RSA pubkey of the hardware unit, to verify the returned
|
||||||
|
RSA signature.
|
||||||
|
ext_signature - bytes, RSA signature of the verifying authority over the returned
|
||||||
|
pubkey_pem data.
|
||||||
|
(Caller can verify this signature with the public key of the verifying authority.)
|
||||||
|
"""
|
||||||
|
params = {'challenge': challenge}
|
||||||
|
return self._jadeRpc('sign_attestation', params)
|
||||||
|
|
||||||
def get_master_blinding_key(self, only_if_silent=False):
|
def get_master_blinding_key(self, only_if_silent=False):
|
||||||
"""
|
"""
|
||||||
RPC call to fetch the master (SLIP-077) blinding key for the hw signer.
|
RPC call to fetch the master (SLIP-077) blinding key for the hw signer.
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import serial
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from serial.tools import list_ports
|
from serial.tools import list_ports
|
||||||
|
from .jade_error import JadeError
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -53,7 +54,10 @@ class JadeSerialImpl:
|
|||||||
assert self.ser is not None
|
assert self.ser is not None
|
||||||
|
|
||||||
if not self.ser.is_open:
|
if not self.ser.is_open:
|
||||||
self.ser.open()
|
try:
|
||||||
|
self.ser.open()
|
||||||
|
except serial.serialutil.SerialException:
|
||||||
|
raise JadeError(1, "Unable to open port", self.device)
|
||||||
|
|
||||||
# Ensure RTS and DTR are not set (as this can cause the hw to reboot)
|
# Ensure RTS and DTR are not set (as this can cause the hw to reboot)
|
||||||
self.ser.setRTS(False)
|
self.ser.setRTS(False)
|
||||||
|
|||||||
Reference in New Issue
Block a user