Browse Source

Merge pull request #12 from Foundation-Devices/dev-1.0.5

v1.0.5 changes
PASS1-98_PASS1-114 v1.0.5
Ken Carpenter 4 years ago
committed by GitHub
parent
commit
1d84e88492
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 16
      .githooks/pre-commit
  2. 8
      ports/stm32/boards/Passport/modules/actions.py
  3. 9
      ports/stm32/boards/Passport/modules/auth.py
  4. 1
      ports/stm32/boards/Passport/modules/common.py
  5. 2
      ports/stm32/boards/Passport/modules/constants.py
  6. 2
      ports/stm32/boards/Passport/modules/data_codecs/data_decoder.py
  7. 3
      ports/stm32/boards/Passport/modules/data_codecs/qr_codec.py
  8. 6
      ports/stm32/boards/Passport/modules/data_codecs/ur1_codec.py
  9. 21
      ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py
  10. 15
      ports/stm32/boards/Passport/modules/psbt.py
  11. 6
      ports/stm32/boards/Passport/modules/sflash.py
  12. 10
      ports/stm32/boards/Passport/modules/ur2/ur_decoder.py
  13. 14
      ports/stm32/boards/Passport/modules/ur2/utils.py
  14. 6
      ports/stm32/boards/Passport/modules/ux.py
  15. 4
      ports/stm32/boards/Passport/trezor-firmware/core/embed/extmod/modtrezorcrypto/modtrezorcrypto-bip32.h

16
.githooks/pre-commit

@ -0,0 +1,16 @@
#!/bin/bash
RESULTS=$(find . -name '*.py' -exec grep -H fake_it[\ ]*=[\ ]*True {} +)
LEN=`expr length "$RESULTS"`
echo $RESULTS
# echo $LEN
if [[ $LEN -gt 0 ]]; then
echo
echo "======================================================"
echo "ERROR: Never commit code with fake seeds or passwords!"
echo "======================================================"
exit 1
else
exit 0
fi

8
ports/stm32/boards/Passport/modules/actions.py

@ -14,6 +14,7 @@
import pyb import pyb
import version import version
import gc
from files import CardMissingError, CardSlot from files import CardMissingError, CardSlot
# import main # import main
from uasyncio import sleep_ms from uasyncio import sleep_ms
@ -1356,11 +1357,18 @@ async def handle_psbt_data_format(data):
try: try:
from auth import sign_psbt_buf from auth import sign_psbt_buf
gc.collect()
# print('Available RAM: psbt 1 = {}'.format(gc.mem_free()))
# The data can be a string or may already be a bytes object # The data can be a string or may already be a bytes object
if isinstance(data, bytes): if isinstance(data, bytes):
data_buf = data data_buf = data
else: else:
data_buf = bytes(data, 'utf-8') data_buf = bytes(data, 'utf-8')
gc.collect() # Try to avoid excessive fragmentation
# print('Available RAM: psbt 2 = {}'.format(gc.mem_free()))
# print("data_buf={}".format(data_buf)) # print("data_buf={}".format(data_buf))
system.show_busy_bar() system.show_busy_bar()
dis.fullscreen('Analyzing...') dis.fullscreen('Analyzing...')

9
ports/stm32/boards/Passport/modules/auth.py

@ -905,7 +905,7 @@ async def sign_psbt_buf(psbt_buf):
# Create a new BytesIO() to hold the result # Create a new BytesIO() to hold the result
async def done(psbt): async def done(psbt):
from common import system, last_scanned_qr_type from common import system, last_scanned_qr_type, last_scanned_ur_prefix
system.hide_busy_bar() system.hide_busy_bar()
signed_bytes = None signed_bytes = None
with BytesIO() as bfd: with BytesIO() as bfd:
@ -928,13 +928,16 @@ async def sign_psbt_buf(psbt_buf):
# print('last_scanned_qr_type={}'.format(last_scanned_qr_type)) # print('last_scanned_qr_type={}'.format(last_scanned_qr_type))
# Text format for UR1, but binary for UR2 # Text format for UR1, but binary for UR2
o = DisplayURCode('Signed Txn', signed_bytes if last_scanned_qr_type == QRType.UR2 else signed_hex, last_scanned_qr_type or QRType.UR2, None, is_binary=True) # def __init__(self, title, qr_text, qr_type, qr_args=None, msg=None, left_btn='DONE', right_btn='RESIZE', is_binary=False):
o = DisplayURCode('Signed Txn', signed_bytes if last_scanned_qr_type == QRType.UR2 else signed_hex, last_scanned_qr_type or QRType.UR2, {'prefix': last_scanned_ur_prefix }, is_binary=True)
result = await o.interact_bare() result = await o.interact_bare()
UserAuthorizedAction.cleanup() UserAuthorizedAction.cleanup()
UserAuthorizedAction.active_request = ApproveTransaction(psbt_len, approved_cb=done) UserAuthorizedAction.active_request = ApproveTransaction(psbt_len, approved_cb=done)
# kill any menu stack, and put our thing at the top # Kill any menu stack, and put our thing at the top - whatever async chain started off this signing process will
# now resume and complete, and then the following action will become active.
abort_and_goto(UserAuthorizedAction.active_request) abort_and_goto(UserAuthorizedAction.active_request)

1
ports/stm32/boards/Passport/modules/common.py

@ -66,3 +66,4 @@ is_new_wallet_a_duplicate = False
# The QRTYpe of the last QR code that was scanned # The QRTYpe of the last QR code that was scanned
last_scanned_qr_type = None last_scanned_qr_type = None
last_scanned_ur_prefix = None

2
ports/stm32/boards/Passport/modules/constants.py

@ -27,7 +27,7 @@ FLASH_CACHE_CHECKSUM_SIZE = 32
FLASH_CACHE_MAX_JSON_LEN = FLASH_CACHE_BLOCK_SIZE - FLASH_CACHE_CHECKSUM_SIZE FLASH_CACHE_MAX_JSON_LEN = FLASH_CACHE_BLOCK_SIZE - FLASH_CACHE_CHECKSUM_SIZE
# Flash usage for PSBT signing # Flash usage for PSBT signing
PSBT_MAX_SIZE = (SPI_FLASH_TOTAL_SIZE - FLASH_CACHE_TOTAL_SIZE) // 2 PSBT_MAX_SIZE = (SPI_FLASH_TOTAL_SIZE - FLASH_CACHE_TOTAL_SIZE) # Total size available for both input and output
# Flash firmware constants # Flash firmware constants
FW_MAX_SIZE = SPI_FLASH_TOTAL_SIZE - FLASH_CACHE_TOTAL_SIZE FW_MAX_SIZE = SPI_FLASH_TOTAL_SIZE - FLASH_CACHE_TOTAL_SIZE

2
ports/stm32/boards/Passport/modules/data_codecs/data_decoder.py

@ -29,7 +29,7 @@ class DataDecoder:
def get_error(self): def get_error(self):
return None return None
def get_type(self): def get_ur_prefix(self):
return None return None
def decode(self): def decode(self):

3
ports/stm32/boards/Passport/modules/data_codecs/qr_codec.py

@ -30,6 +30,9 @@ class QRDecoder(DataDecoder):
def get_error(self): def get_error(self):
return None return None
def get_ur_prefix(self):
return None
def decode(self): def decode(self):
return self.data return self.data

6
ports/stm32/boards/Passport/modules/data_codecs/ur1_codec.py

@ -44,8 +44,8 @@ class UR1Decoder(DataDecoder):
def get_error(self): def get_error(self):
return self.error return self.error
def get_type(self): def get_ur_prefix(self):
return self.decoder.expected_type() return 'bytes' # TODO: Get the type from the UR1 decoder
def decode(self): def decode(self):
from common import system from common import system
@ -112,7 +112,7 @@ class UR1Sampler(DataSampler):
# Return True if it matches or False if not # Return True if it matches or False if not
@classmethod @classmethod
def sample(cls, data): def sample(cls, data):
r = re.compile('^ur:bytes/(\d)+of(\d)+/') r = re.compile('^ur:bytes/') # Don't look for the n of m count anymore
m = r.match(data.lower()) m = r.match(data.lower())
return m != None return m != None

21
ports/stm32/boards/Passport/modules/data_codecs/ur2_codec.py

@ -49,7 +49,7 @@ class UR2Decoder(DataDecoder):
else: else:
return None return None
def get_type(self): def get_ur_prefix(self):
return self.decoder.expected_type() return self.decoder.expected_type()
def decode(self): def decode(self):
@ -69,9 +69,13 @@ class UR2Decoder(DataDecoder):
return QRType.UR2 return QRType.UR2
class UR2Encoder(DataEncoder): class UR2Encoder(DataEncoder):
def __init__(self, _args): def __init__(self, args):
self.qr_sizes = [280, 100, 70] self.qr_sizes = [280, 100, 70]
self.type = None self.type = None
if isinstance(args, dict):
self.prefix = args['prefix'] or 'bytes'
else:
self.prefix = 'bytes'
def get_num_supported_sizes(self): def get_num_supported_sizes(self):
return len(self.qr_sizes) return len(self.qr_sizes)
@ -87,7 +91,7 @@ class UR2Encoder(DataEncoder):
# print('UR2: data={}'.format(to_str(data))) # print('UR2: data={}'.format(to_str(data)))
encoder.encodeBytes(data) encoder.encodeBytes(data)
# TODO: Need to change this interface most likely to allow for different types like crypto-psbt # TODO: Need to change this interface most likely to allow for different types like crypto-psbt
ur_obj = UR("bytes", encoder.get_bytes()) ur_obj = UR(self.prefix, encoder.get_bytes())
self.ur_encoder = UREncoder(ur_obj, max_fragment_len) self.ur_encoder = UREncoder(ur_obj, max_fragment_len)
# UR2.0's next_part() returns the initial pieces split into max_fragment_len bytes, but then switches over to # UR2.0's next_part() returns the initial pieces split into max_fragment_len bytes, but then switches over to
@ -104,9 +108,14 @@ class UR2Sampler(DataSampler):
# Return True if it matches or False if not # Return True if it matches or False if not
@classmethod @classmethod
def sample(cls, data): def sample(cls, data):
r = re.compile('^ur:[a-z\d-]+\/(\d)+-(\d)+\/') try:
m = r.match(data.lower()) # Rather than try a complex regex here, we just let the decoder try to decode and if it fails.
return m != None # it must not be UR2.
decoder = URDecoder()
result = decoder.receive_part(data)
return result
except e:
return False
# Number of bytes required to successfully recognize this format # Number of bytes required to successfully recognize this format
@classmethod @classmethod

15
ports/stm32/boards/Passport/modules/psbt.py

@ -1392,16 +1392,31 @@ class psbtObject(psbtProxy):
for k in self.unknown: for k in self.unknown:
wr(k[0], self.unknown[k], k[1:]) wr(k[0], self.unknown[k], k[1:])
# import micropython
# print('======================================')
# micropython.mem_info(1)
# print('======================================')
# sep between globals and inputs # sep between globals and inputs
out_fd.write(b'\0') out_fd.write(b'\0')
for idx, inp in enumerate(self.inputs): for idx, inp in enumerate(self.inputs):
# print('Input {}: free mem={}'.format(idx, gc.mem_free()))
inp.serialize(out_fd, idx) inp.serialize(out_fd, idx)
out_fd.write(b'\0') out_fd.write(b'\0')
gc.collect() # Give collector a chance to run to help avoid fragmentation
for idx, outp in enumerate(self.outputs): for idx, outp in enumerate(self.outputs):
# print('Output {}: free mem={}'.format(idx, gc.mem_free()))
outp.serialize(out_fd, idx) outp.serialize(out_fd, idx)
out_fd.write(b'\0') out_fd.write(b'\0')
gc.collect() # Give collector a chance to run to help avoid fragmentation
# print('After serialize(): free mem={}'.format(gc.mem_free()))
# print('======================================')
# micropython.mem_info(1)
# print('======================================')
def sign_it(self): def sign_it(self):
# txn is approved. sign all inputs we can sign. add signatures # txn is approved. sign all inputs we can sign. add signatures

6
ports/stm32/boards/Passport/modules/sflash.py

@ -15,10 +15,10 @@
# - it wants to waste 4k on a buffer # - it wants to waste 4k on a buffer
# #
# Layout for project: # Layout for project:
# - 768 PSBT incoming (MAX_TXN_LEN) # - 917K PSBT incoming (MAX_TXN_LEN)
# - 768 PSBT outgoing (MAX_TXN_LEN) # - 917K PSBT outgoing (MAX_TXN_LEN)
# - The previous two regions are only used when signing PSBTs. # - The previous two regions are only used when signing PSBTs.
# - The same space is used to hold firmware updates. # - The same space is also used to hold firmware updates.
# - 256k flash cache - similar to settings, but for UTXOs and wallet address cache # - 256k flash cache - similar to settings, but for UTXOs and wallet address cache
# #
import machine import machine

10
ports/stm32/boards/Passport/modules/ur2/ur_decoder.py

@ -34,7 +34,7 @@ class InvalidFragment(Exception):
class URDecoder: class URDecoder:
def __init__(self): def __init__(self):
self.fountain_decoder = FountainDecoder() self.fountain_decoder = FountainDecoder()
self.expected_type = None self._expected_type = None
self.result = None self.result = None
@staticmethod @staticmethod
@ -93,13 +93,13 @@ class URDecoder:
raise InvalidSequenceComponent() raise InvalidSequenceComponent()
def validate_part(self, type): def validate_part(self, type):
if self.expected_type == None: if self._expected_type == None:
if not is_ur_type(type): if not is_ur_type(type):
return False return False
self.expected_type = type self._expected_type = type
return True return True
else: else:
return type == self.expected_type return type == self._expected_type
def receive_part(self, str): def receive_part(self, str):
try: try:
@ -148,7 +148,7 @@ class URDecoder:
return False return False
def expected_type(self): def expected_type(self):
return self.expected_type return self._expected_type
def expected_part_count(self): def expected_part_count(self):
return self.fountain_decoder.expected_part_count() return self.fountain_decoder.expected_part_count()

14
ports/stm32/boards/Passport/modules/ur2/utils.py

@ -33,14 +33,12 @@ def string_to_bytes(s):
return bytes(s, 'utf8') return bytes(s, 'utf8')
def is_ur_type(ch): def is_ur_type(type):
if 'a' <= ch and ch <= 'z': for ch in type:
return True if not (ch >= 'a' and ch <= 'z') and not(ch >= '0' and ch <= '9') and ch != '-':
if '0' <= ch and ch <= '9': return False
return True
if ch == '-': return True
return True
return False
def partition(s, n): def partition(s, n):

6
ports/stm32/boards/Passport/modules/ux.py

@ -1180,9 +1180,9 @@ class DisplayURCode(UserInteraction):
return 250 return 250
def render_qr(self, data): def render_qr(self, data):
from utils import imported from utils import imported, bytes_to_hex_str
# print('data: {}'.format(data)) # print('data: {}'.format(bytes_to_hex_str(data)))
if self.last_render_id != self.render_id: if self.last_render_id != self.render_id:
self.last_render_id = self.render_id self.last_render_id = self.render_id
@ -1488,7 +1488,9 @@ async def ux_scan_qr_code(title):
# Set the last QRType so that signed transactions know what to encode as # Set the last QRType so that signed transactions know what to encode as
common.last_scanned_qr_type = qr_decoder.get_data_format() common.last_scanned_qr_type = qr_decoder.get_data_format()
common.last_scanned_ur_prefix = qr_decoder.get_ur_prefix()
# print('common.last_scanned_qr_type={}'.format(common.last_scanned_qr_type)) # print('common.last_scanned_qr_type={}'.format(common.last_scanned_qr_type))
# print('common.last_scanned_ur_prefix={}'.format(common.last_scanned_ur_prefix))
break break
progress = '{} OF {}'.format(qr_decoder.received_parts(), qr_decoder.total_parts()) progress = '{} OF {}'.format(qr_decoder.received_parts(), qr_decoder.total_parts())

4
ports/stm32/boards/Passport/trezor-firmware/core/embed/extmod/modtrezorcrypto/modtrezorcrypto-bip32.h

@ -625,12 +625,12 @@ STATIC mp_obj_t mod_trezorcrypto_bip32_deserialize(mp_obj_t value, mp_obj_t vers
HDNode hdnode; HDNode hdnode;
uint32_t fingerprint; uint32_t fingerprint;
if (_is_public) { if (_is_public) {
printf("Calling hdnode_deserialize_public()\n"); // printf("Calling hdnode_deserialize_public()\n");
if (hdnode_deserialize_public(valueb.buf, _version, SECP256K1_NAME, &hdnode, &fingerprint) < 0) { if (hdnode_deserialize_public(valueb.buf, _version, SECP256K1_NAME, &hdnode, &fingerprint) < 0) {
mp_raise_ValueError("Failed to deserialize public"); mp_raise_ValueError("Failed to deserialize public");
} }
} else { } else {
printf("Calling hdnode_deserialize_private()\n"); // printf("Calling hdnode_deserialize_private()\n");
if (hdnode_deserialize_private(valueb.buf, _version, SECP256K1_NAME, &hdnode, &fingerprint) < 0) { if (hdnode_deserialize_private(valueb.buf, _version, SECP256K1_NAME, &hdnode, &fingerprint) < 0) {
mp_raise_ValueError("Failed to deserialize private"); mp_raise_ValueError("Failed to deserialize private");
} }

Loading…
Cancel
Save