From b6b9191145d37fbb6d754597350653141596dd12 Mon Sep 17 00:00:00 2001 From: "Peter D. Gray" Date: Wed, 18 Nov 2020 14:19:14 -0500 Subject: [PATCH] dev squashed --- COPYING-CC | 44 ++ cli/setup.py | 3 +- cli/signit.py | 3 +- docs/limitations.md | 2 + graphics/Makefile | 3 +- releases/ChangeLog.md | 9 +- shared/Makefile | 2 + shared/actions.py | 7 +- shared/auth.py | 11 +- shared/main.py | 2 +- shared/multisig.py | 454 +++++++++++------- shared/psbt.py | 134 +++--- shared/utils.py | 24 + stm32/Makefile | 5 +- stm32/bootloader/Makefile | 1 + stm32/bootloader/ae.c | 3 +- stm32/bootloader/ae.h | 3 +- stm32/bootloader/assets/convert.py | 3 +- stm32/bootloader/basics.h | 3 +- stm32/bootloader/clocks.c | 3 +- stm32/bootloader/clocks.h | 3 +- stm32/bootloader/constant_time.c | 3 +- stm32/bootloader/constant_time.h | 3 +- stm32/bootloader/delay.c | 3 +- stm32/bootloader/delay.h | 3 +- stm32/bootloader/dispatch.c | 3 +- stm32/bootloader/dispatch.h | 3 +- stm32/bootloader/enable.c | 3 +- stm32/bootloader/firmware-keys.h | 3 +- stm32/bootloader/gpio.c | 3 +- stm32/bootloader/gpio.h | 3 +- stm32/bootloader/misc.h | 3 +- stm32/bootloader/oled.c | 3 +- stm32/bootloader/oled.h | 3 +- stm32/bootloader/pins.c | 3 +- stm32/bootloader/pins.h | 3 +- stm32/bootloader/rng.c | 3 +- stm32/bootloader/rng.h | 3 +- stm32/bootloader/secel_config.py | 3 +- stm32/bootloader/secel_debug.py | 3 +- stm32/bootloader/sflash.c | 3 +- stm32/bootloader/sflash.h | 3 +- stm32/bootloader/sigheader.h | 3 +- stm32/bootloader/sigheader.py | 3 +- stm32/bootloader/stm32l4xx_hal_spi.c | 3 +- stm32/bootloader/storage.c | 4 +- stm32/bootloader/storage.h | 3 +- stm32/bootloader/verify.c | 3 +- stm32/bootloader/verify.h | 3 +- stm32/bootloader/version.c | 3 +- stm32/bootloader/version.h | 3 +- testing/Makefile | 3 +- testing/api.py | 3 +- testing/conftest.py | 3 +- testing/constants.py | 3 +- testing/data/multisig/export-p2sh-myself.txt | 1 + testing/data/multisig/export-p2wsh-myself.txt | 3 +- .../multisig/export-p2wsh-p2sh-myself.txt | 3 +- .../data/multisig/setting-p2sh-myself.json | 2 +- .../data/multisig/setting-p2wsh-myself.json | 2 +- .../multisig/setting-p2wsh-p2sh-myself.json | 2 +- testing/devtest/abort_ux.py | 2 + testing/devtest/backups.py | 2 + testing/devtest/cap-image.py | 2 + testing/devtest/cap-menu.py | 2 + testing/devtest/cap-screen.py | 2 + testing/devtest/cap-story.py | 2 + testing/devtest/check_decode.py | 2 + testing/devtest/clear_seed.py | 2 + testing/devtest/dump_private.py | 2 + testing/devtest/dump_public.py | 2 + testing/devtest/get-secrets.py | 2 + testing/devtest/get-setting.py | 2 + testing/devtest/get-settings.py | 2 + testing/devtest/get_pp_sofar.py | 2 + testing/devtest/nvram.py | 2 + testing/devtest/segwit_addr.py | 2 + testing/devtest/set_encoded_secret.py | 2 + testing/devtest/set_raw_secret.py | 2 + testing/devtest/set_seed.py | 2 + testing/devtest/set_tprv.py | 2 + testing/devtest/unit_addrs.py | 2 + testing/devtest/unit_bip143.py | 2 + testing/devtest/unit_decoding.py | 2 + testing/devtest/unit_multisig.py | 2 + testing/devtest/unit_psbt.py | 2 + testing/devtest/unit_slip132.py | 2 + testing/devtest/wipe_ms.py | 2 + testing/helpers.py | 3 +- testing/objstruct.py | 3 +- testing/psbt.py | 3 +- testing/test_addr.py | 3 +- testing/test_address_explorer.py | 3 +- testing/test_attended.py | 3 +- testing/test_bip39pw.py | 3 +- testing/test_change_pins.py | 3 +- testing/test_drv_entro.py | 3 +- testing/test_export.py | 3 +- testing/test_hsm.py | 3 +- testing/test_msg.py | 3 +- testing/test_multisig.py | 208 +++++--- testing/test_paper.py | 3 +- testing/test_pincodes.py | 3 +- testing/test_pwsave.py | 3 +- testing/test_sign.py | 7 +- testing/test_unit.py | 3 +- testing/test_upgrades.py | 3 +- testing/test_usb.py | 3 +- testing/test_ux.py | 3 +- testing/txn.py | 3 +- testing/xfp-miner.py | 4 +- unix/Makefile | 3 +- unix/headless.py | 3 +- unix/simulator.py | 3 +- 114 files changed, 716 insertions(+), 464 deletions(-) create mode 100644 COPYING-CC diff --git a/COPYING-CC b/COPYING-CC new file mode 100644 index 00000000..b52800fc --- /dev/null +++ b/COPYING-CC @@ -0,0 +1,44 @@ +(c) Copyright 2020 by Coinkite Inc. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject +to the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +"Commons Clause" License Condition v1.0 + +The Software is provided to you by the Licensor under the License, +as defined below, subject to the following condition. + +Without limiting other conditions in the License, the grant of +rights under the License will not include, and the License does not +grant to you, the right to Sell the Software. + +For purposes of the foregoing, "Sell" means practicing any or all +of the rights granted to you under the License to provide to third +parties, for a fee or other consideration (including without +limitation fees for hosting or consulting/ support services related +to the Software), a product or service whose value derives, entirely +or substantially, from the functionality of the Software. Any license +notice or attribution required by the License must also include +this Commons Clause License Condition notice. + +Software: All Coldcard associated files. +License: MIT +Licensor: Coinkite Inc. + diff --git a/cli/setup.py b/cli/setup.py index ca71cd21..ef595276 100644 --- a/cli/setup.py +++ b/cli/setup.py @@ -1,5 +1,4 @@ -# (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard -# and is covered by GPLv3 license found in COPYING. +# (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC. # # based on # diff --git a/cli/signit.py b/cli/signit.py index 4e448f36..54383b65 100755 --- a/cli/signit.py +++ b/cli/signit.py @@ -1,7 +1,6 @@ #!/usr/bin/env python3 # -# (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard -# and is covered by GPLv3 license found in COPYING. +# (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC. # # Repackage and sign the firmware image. # diff --git a/docs/limitations.md b/docs/limitations.md index 7907d873..2b79a58c 100644 --- a/docs/limitations.md +++ b/docs/limitations.md @@ -63,6 +63,8 @@ - we always store xpubs in BIP32 format, although we can read SLIP132 format (Ypub/Zpub/etc) - change outputs (indicated with paths, scripts in output section) must correspond to the active multisig wallet, and cannot be used to describe an unrelated (multisig) wallet. +- derivation path for each cosigner must be known and consistent with PSBT +- fixed: XFP values (fingerprints) for each of the co-signers must be unique (limitation removed) # SIGHASH types diff --git a/graphics/Makefile b/graphics/Makefile index 76b47b0b..be86d418 100644 --- a/graphics/Makefile +++ b/graphics/Makefile @@ -1,5 +1,4 @@ -# (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard -# and is covered by GPLv3 license found in COPYING. +# (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC. all: graphics.py diff --git a/releases/ChangeLog.md b/releases/ChangeLog.md index bda84182..df2f410a 100644 --- a/releases/ChangeLog.md +++ b/releases/ChangeLog.md @@ -1,5 +1,11 @@ -## 3.1.10 - Nov 9, 2020 +## 3.2.0 - Nov , 2020 +- Major Multisig improvements: + Tracks derivation path for each co-signer and no longer assumes + they all use a shared derivation prefix. Blocks multiple instances of same XFP in the wallet + (not supported anymore, bad idea). Various displays updated to reflect derivation path change. + Text file import: "Derivation:" line can be repeated, applies too all following xpubs. + Show Ypub/Zpub formated values from SLIP-132 when viewing details of wallet. - Enhancement: Add support for signing Payjoin PSBT files based on [BIP-78](https://github.com/bitcoin/bips/blob/master/bip-0078.mediawiki). - Enhancement: Promoted the address explorer to the main menu. It's useful! @@ -10,6 +16,7 @@ an attacker could socially-engineer you to sign a transaction on Testnet, which corresponds to real UTXO being stolen. Only developers should be using Testnet. - Bugfix: Display of amounts could be incorrect by a few sats in final digits. +- License changed from GPL to MIT+CC on files for which the GPL doesn't apply. ## 3.1.9 - Aug 6, 2020 diff --git a/shared/Makefile b/shared/Makefile index bf278ca0..8f29b2d4 100644 --- a/shared/Makefile +++ b/shared/Makefile @@ -1,3 +1,5 @@ +# (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC. +# # Just a little helper for CK devs ... so we can do "make up" in this dir. all: diff --git a/shared/actions.py b/shared/actions.py index 703c80f3..bd421bb5 100644 --- a/shared/actions.py +++ b/shared/actions.py @@ -8,7 +8,7 @@ import ckcc, pyb, version from ux import ux_show_story, the_ux, ux_confirm, ux_dramatic_pause, ux_poll_once, ux_aborted from ux import ux_enter_number -from utils import imported, pretty_short_delay +from utils import imported, pretty_short_delay, problem_file_line from main import settings from uasyncio import sleep_ms from files import CardSlot, CardMissingError @@ -1524,7 +1524,6 @@ async def import_multisig(*a): fn = await file_picker('Pick multisig wallet file to import (.txt)', suffix='.txt', min_size=100, max_size=20*200, taster=possible) - if not fn: return try: @@ -1540,7 +1539,9 @@ async def import_multisig(*a): possible_name = (fn.split('/')[-1].split('.'))[0] maybe_enroll_xpub(config=data, name=possible_name) except Exception as e: - await ux_show_story('Failed to import.\n\n\n'+str(e)) + import sys + sys.print_exception(e) + await ux_show_story('Failed to import.\n\n\n'+problem_file_line(e)) async def start_hsm_menu_item(*a): from hsm_ux import start_hsm_approval diff --git a/shared/auth.py b/shared/auth.py index d8018a7f..7c193492 100644 --- a/shared/auth.py +++ b/shared/auth.py @@ -1043,17 +1043,14 @@ def start_show_p2sh_address(M, N, addr_format, xfp_paths, witdeem_script): raise AssertionError('Unknown/unsupported addr format') # Search for matching multisig wallet that we must already know about - xfps = [i[0] for i in xfp_paths] + xs = list(xfp_paths) + xs.sort() - idx = MultisigWallet.find_match(M, N, xfps) - assert idx >= 0, 'Multisig wallet with those fingerprints not found' - - ms = MultisigWallet.get_by_idx(idx) - assert ms + ms = MultisigWallet.find_match(M, N, xs) + assert ms, 'Multisig wallet with those fingerprints not found' assert ms.M == M assert ms.N == N - UserAuthorizedAction.check_busy(ShowAddressBase) UserAuthorizedAction.active_request = ShowP2SHAddress(ms, addr_format, xfp_paths, witdeem_script) diff --git a/shared/main.py b/shared/main.py index 7bb9ca60..49fa93c0 100644 --- a/shared/main.py +++ b/shared/main.py @@ -40,7 +40,7 @@ import uasyncio.core as asyncio loop = asyncio.get_event_loop() -print("---\nColdcard Wallet from Coinkite Inc. (c) 2018.\n") +print("---\nColdcard Wallet from Coinkite Inc. (c) 2020.\n") # Setup OLED and get something onto it. from display import Display diff --git a/shared/multisig.py b/shared/multisig.py index ca71d93f..85b65dd7 100644 --- a/shared/multisig.py +++ b/shared/multisig.py @@ -5,7 +5,7 @@ # import stash, chains, ustruct, ure, uio, sys #from ubinascii import hexlify as b2a_hex -from utils import xfp2str, str2xfp, swab32, cleanup_deriv_path +from utils import xfp2str, str2xfp, swab32, cleanup_deriv_path, keypath_to_str, str_to_keypath from ux import ux_show_story, ux_confirm, ux_dramatic_pause, ux_clear_keys from files import CardSlot, CardMissingError from public_constants import AF_P2SH, AF_P2WSH_P2SH, AF_P2WSH, AFC_SCRIPT, MAX_PATH_DEPTH @@ -23,6 +23,10 @@ TRUST_VERIFY = const(0) TRUST_OFFER = const(1) TRUST_PSBT = const(2) +# when we aren't sure of the derivation of an xpub we are holding +# - should only happen from older version data +UNSURE_DERIV = '*' + class MultisigOutOfSpace(RuntimeError): pass @@ -101,19 +105,22 @@ class MultisigWallet: (AF_P2WSH_P2SH, 'p2wsh-p2sh'), ] - def __init__(self, name, m_of_n, xpubs, addr_fmt=AF_P2SH, common_prefix=None, chain_type='BTC'): + def __init__(self, name, m_of_n, xpubs, addr_fmt=AF_P2SH, chain_type='BTC'): self.storage_idx = -1 self.name = name assert len(m_of_n) == 2 self.M, self.N = m_of_n self.chain_type = chain_type or 'BTC' - self.xpubs = xpubs # list of (xfp(int), xpub(str)) - self.common_prefix = common_prefix # example: "45'" for BIP45 .. no m/ prefix + assert len(xpubs[0]) == 3 + self.xpubs = xpubs # list of (xfp(int), deriv, xpub(str)) self.addr_fmt = addr_fmt # not clear how useful that is. - # useful cache value - self.xfps = sorted(k for k,v in self.xpubs) + # calc useful cache value: numeric xfp+subpath, with lookup + self.xfp_paths = {} + for xfp, deriv, _ in self.xpubs: + self.xfp_paths[xfp] = str_to_keypath(xfp, deriv) + assert len(self.xfp_paths) == self.N, 'dup XFP' # not supported @classmethod def render_addr_fmt(cls, addr_fmt): @@ -122,19 +129,6 @@ class MultisigWallet: return v.upper() return '?' - def serialize(self): - # return a JSON-able object - - opts = dict() - if self.addr_fmt != AF_P2SH: - opts['ft'] = self.addr_fmt - if self.chain_type != 'BTC': - opts['ch'] = self.chain_type - if self.common_prefix: - opts['pp'] = self.common_prefix - - return (self.name, (self.M, self.N), self.xpubs, opts) - @property def chain(self): return chains.get_chain(self.chain_type) @@ -150,64 +144,130 @@ class MultisigWallet: return which + def serialize(self): + # return a JSON-able object + + opts = dict() + if self.addr_fmt != AF_P2SH: + opts['ft'] = self.addr_fmt + if self.chain_type != 'BTC': + opts['ch'] = self.chain_type + + # Data compression: most legs will all use same derivation. + # put a int(0) in place and set option 'pp' to be deriation + # (used to be common_prefix assumption) + pp = list(sorted(set(d for _,d,_ in self.xpubs))) + opts['d'] = pp + xp = [(a, pp.index(deriv),c) for a,deriv,c in self.xpubs] + + return (self.name, (self.M, self.N), xp, opts) + @classmethod def deserialize(cls, vals, idx=-1): # take json object, make instance. name, m_of_n, xpubs, opts = vals + if len(xpubs[0]) == 2: + # promote from old format to new: assume common prefix is the derivation + # for all of them + # PROBLEM: we don't have enough info if no common prefix can be assumed + common_prefix = opts.get('pp', None) or UNSURE_DERIV + xpubs = [(a, common_prefix, b) for a,b in xpubs] + else: + # new format decompression + if 'd' in opts: + derivs = opts.get('d', None) + xpubs = [(a, derivs[b], c) for a,b,c in xpubs] + rv = cls(name, m_of_n, xpubs, addr_fmt=opts.get('ft', AF_P2SH), - common_prefix=opts.get('pp', None), chain_type=opts.get('ch', 'BTC')) rv.storage_idx = idx return rv @classmethod - def find_match(cls, M, N, fingerprints): - # Find index of matching wallet. Don't de-serialize everything. - # - returns index, or -1 if not found - # - fingerprints are iterable of uint32's: may not be unique! - # - M, N must be known. + def find_match(cls, M, N, xfp_paths): + # Find index of matching wallet. Don't de-serialize more than needed. + # - xfp_paths is list of lists: [xfp, *path] like in psbt files + # - M and N must be known + # - returns instance, or None if not found from main import settings lst = settings.get('multisig', []) - fingerprints = sorted(fingerprints) - assert N == len(fingerprints) + fingerprints = set(f[0] for f in xfp_paths) for idx, rec in enumerate(lst): name, m_of_n, xpubs, opts = rec - if tuple(m_of_n) != (M, N): continue - if sorted(f for f,_ in xpubs) != fingerprints: continue - return idx - return -1 + if tuple(m_of_n) != (M, N): + continue + + if set(f[0] for f in xpubs) != fingerprints: continue + + rv = cls.deserialize(rec, idx) + if rv.matching_subpaths(xfp_paths): + return rv + del rv + + return None @classmethod - def find_candidates(cls, fingerprints): - # Find index of matching wallet and M value. Don't de-serialize everything. - # - returns set of matches, each with M value - # - fingerprints are iterable of uint32's + def find_candidates(cls, xfp_paths, addr_fmt=None): + # Return a list of matching wallets for various M values. + # - xpfs_paths hsould already be sorted + # - returns set of matches, of any M value from main import settings lst = settings.get('multisig', []) - fingerprints = sorted(fingerprints) - N = len(fingerprints) - rv = [] + # we know N, but not M at this point. + N = len(xfp_paths) + rv = [] for idx, rec in enumerate(lst): name, m_of_n, xpubs, opts = rec if m_of_n[1] != N: continue - if sorted(f for f,_ in xpubs) != fingerprints: continue - rv.append(idx) + if addr_fmt is not None: + af = opts.get('ft', AF_P2SH) + if af != addr_fmt: continue + + maybe = cls.deserialize(rec, idx) + if maybe.matching_subpaths(xfp_paths): + rv.append(maybe) + else: + del maybe return rv - def assert_matching(self, M, N, fingerprints): + def matching_subpaths(self, xfp_paths): + # Does this wallet use same set of xfp values, and + # the same prefix path per-each xfp, as indicated + # xfp_paths (unordered)? + # - could also check non-prefix part is all non-hardened + for x in xfp_paths: + if x[0] not in self.xfp_paths: + return False + prefix = self.xfp_paths[x[0]] + + if len(x) < len(prefix): + # PSBT specs a path shorter than wallet's xpub + #print('path len: %d vs %d' % (len(prefix), len(x))) + return False + + comm = len(prefix) + if tuple(prefix[:comm]) != tuple(x[:comm]): + # xfp => maps to wrong path + #print('path mismatch:\n%r\n%r\ncomm=%d' % (prefix[:comm], x[:comm], comm)) + return False + + return True + + def assert_matching(self, M, N, xfp_paths): # compare in-memory wallet with details recovered from PSBT + # - xfp_paths must be sorted already assert (self.M, self.N) == (M, N), "M/N mismatch" - assert len(fingerprints) == N, "XFP count" - assert sorted(fingerprints) == self.xfps, "wrong XFPs" + assert len(xfp_paths) == N, "XFP count" + assert self.matching_subpaths(xfp_paths), "wrong XFP/derivs" @classmethod def quick_check(cls, M, N, xfp_xor): @@ -222,7 +282,7 @@ class MultisigWallet: if m_of_n[1] != N: continue x = 0 - for xfp, _ in xpubs: + for xfp, _, _ in xpubs: x ^= xfp if x != xfp_xor: continue @@ -291,30 +351,34 @@ class MultisigWallet: raise MultisigOutOfSpace - - def has_dup(self): + def has_similar(self): # check if we already have a saved duplicate to this proposed wallet - # - also, flag if it's a dangerous/fraudulent attempt to replace it. + # - return (name_change, diff_items) where: + # - name_change is existing wallet that has exact match, different name + # - diff_items: text list of similarity/differences - idx = MultisigWallet.find_match(self.M, self.N, self.xfps) - if idx == -1: + similar = MultisigWallet.find_candidates(list(self.xfp_paths.values())) + if not similar: # no matches - return False, 0 + return None, [] # See if the xpubs are changing, which is risky... other differences like # name are okay. - o = self.get_by_idx(idx) + diffs = set() + name_diff = None + for c in similar: + if c.M != self.M: + diffs.add('M differs') + if c.addr_fmt != self.addr_fmt: + diffs.add('address type') + if c.name != self.name and c.matching_subpaths(c): + diffs.add('name') + name_diff = c - # Calc apx. number of xpub changes. - diffs = 0 - a = sorted(self.xpubs) - b = sorted(o.xpubs) - assert len(a) == len(b) # because same N - for idx in range(self.N): - if a[idx] != b[idx]: - diffs += 1 + if name_diff and len(diffs) == 1: + return name_diff, [] - return o, diffs + return None, diffs def delete(self): # remove saved entry @@ -324,8 +388,9 @@ class MultisigWallet: assert self.storage_idx >= 0 # safety check - expect_idx = self.find_match(self.M, self.N, self.xfps) - assert expect_idx == self.storage_idx + existing = self.find_match(self.M, self.N, list(self.xfp_paths.values())) + assert existing + assert existing.storage_idx == self.storage_idx lst = settings.get('multisig', []) del lst[self.storage_idx] @@ -336,7 +401,7 @@ class MultisigWallet: def xpubs_with_xfp(self, xfp): # return set of indexes of xpubs with indicated xfp - return set(xp_idx for xp_idx, (wxfp, _) in enumerate(self.xpubs) + return set(xp_idx for xp_idx, (wxfp, _, _) in enumerate(self.xpubs) if wxfp == xfp) def validate_script(self, redeem_script, subpaths=None, xfp_paths=None): @@ -346,7 +411,6 @@ class MultisigWallet: # redeem_script: what we expect and we were given # subpaths: pubkey => (xfp, *path) # xfp_paths: (xfp, *path) in same order as pubkeys in redeem script - from psbt import path_to_str subpath_help = [] used = set() @@ -361,10 +425,11 @@ class MultisigWallet: if subpaths: # in PSBT, we are given a map from pubkey to xfp/path, use it # while remembering it's potentially one-2-many + # TODO: this could be simpler now assert pubkey in subpaths, "unexpected pubkey" xfp, *path = subpaths[pubkey] - for xp_idx, (wxfp, xpub) in enumerate(self.xpubs): + for xp_idx, (wxfp, _, xpub) in enumerate(self.xpubs): if wxfp != xfp: continue if xp_idx in used: continue # only allow once check_these.append((xp_idx, path)) @@ -383,7 +448,7 @@ class MultisigWallet: too_shallow = False for xp_idx, path in check_these: # matched fingerprint, try to make pubkey that needs to match - xpub = self.xpubs[xp_idx][1] + xpub = self.xpubs[xp_idx][-1] node = ch.deserialize_node(xpub, AF_P2SH); assert node dp = node.depth() @@ -405,7 +470,7 @@ class MultisigWallet: # part of the path from fingerprint to here. here = '(m=%s)\n' % xfp2str(xfp) if dp != len(path): - here += 'm' + ('/_'*dp) + path_to_str(path[dp:], '/', 0) + here += 'm' + ('/_'*dp) + keypath_to_str(path[dp:], '/', 0) if found_pk != pubkey: # Not a match but not an error by itself, since might be @@ -444,6 +509,8 @@ class MultisigWallet: # where label is: # name: nameforwallet # policy: M of N + # format: p2sh (+etc) + # derivation: m/45'/0 (common prefix) # (8digithex): xpub of cosigner # # quick checks: @@ -454,11 +521,10 @@ class MultisigWallet: from main import settings my_xfp = settings.get('xfp') - common_prefix = None + deriv = None xpubs = [] - path_tops = set() M, N = -1, -1 - has_mine = False + has_mine = 0 addr_fmt = AF_P2SH expect_chain = chains.current_chain().ctype @@ -479,7 +545,7 @@ class MultisigWallet: value = ln else: # complain? - if ln: print("no colon: " + ln) + #if ln: print("no colon: " + ln) continue else: label, value = ln.split(':') @@ -501,11 +567,9 @@ class MultisigWallet: raise AssertionError('bad policy line') elif label == 'derivation': - # reveal the **common** path derivation for all keys + # reveal the path derivation for following key(s) try: - cp = cleanup_deriv_path(value) - # - not storing "m/" prefix, nor 'm' case which doesn't add any info - common_prefix = None if cp == 'm' else cp[2:] + deriv = cleanup_deriv_path(value) except BaseException as exc: raise AssertionError('bad derivation line: ' + str(exc)) @@ -527,11 +591,9 @@ class MultisigWallet: continue # deserialize, update list and lots of checks - xfp = cls.check_xpub(xfp, value, expect_chain, xpubs, path_tops) - - if xfp == my_xfp: - # not conclusive, but enough for error catching. - has_mine = True + is_mine = cls.check_xpub(xfp, value, deriv, expect_chain, my_xfp, xpubs) + if is_mine: + has_mine += 1 assert len(xpubs), 'need xpubs' @@ -555,30 +617,27 @@ class MultisigWallet: # check we're included... do not insert ourselves, even tho we # have enough info, simply because other signers need to know my xpubkey anyway - assert has_mine, 'my key not included' - - if not common_prefix and len(path_tops) == 1: - # fill in the common prefix iff we can deduce it from xpubs - common_prefix = path_tops.pop() + assert has_mine != 0, 'my key not included' + assert has_mine == 1 # 'my key included more than once' # done. have all the parts - return cls(name, (M, N), xpubs, addr_fmt=addr_fmt, - chain_type=expect_chain, common_prefix=common_prefix) + return cls(name, (M, N), xpubs, addr_fmt=addr_fmt, chain_type=expect_chain) @classmethod - def check_xpub(cls, xfp, xpub, expect_chain, xpubs, path_tops): + def check_xpub(cls, xfp, xpub, deriv, expect_chain, my_xfp, xpubs): # Shared code: consider an xpub for inclusion into a wallet, if ok, append - # to list: xpubs, and path_tops + # to list: xpubs with a tuple: (xfp, deriv, xpub) + # return T if it's our own key + # - deriv can be None, and in very limited cases can recover derivation path try: # Note: addr fmt detected here via SLIP-132 isn't useful node, chain, _ = import_xpub(xpub) except: - print(xpub) raise AssertionError('unable to parse xpub') - assert node.private_key() == None, 'no privkeys plz' - assert chain.ctype == expect_chain, 'wrong chain' + assert node.private_key() == None # 'no privkeys plz' + assert chain.ctype == expect_chain # 'wrong chain' # NOTE: could enforce all same depth, and/or all depth >= 1, but # seems like more restrictive than needed. @@ -590,23 +649,36 @@ class MultisigWallet: # generally cannot check fingerprint values, but if we can, do. assert swab32(node.fingerprint()) == xfp, 'xfp depth=1 wrong' - assert xfp, 'need fingerprint' + assert xfp # 'need fingerprint' - # detect, when possible, if it follows BIP45 ... find the path - path_top = None + # In most cases, we cannot verify the derivation path because it's hardened + # and we know none of the private keys involved. if node.depth() == 1: + # but derivation is implied at depth==1 cn = node.child_num() - path_top = str(cn & 0x7fffffff) + guess = 'm/%d' % (cn & 0x7fffffff) if cn & 0x80000000: - path_top += "'" + guess += "'" - path_tops.add(path_top) + if deriv: + assert guess == deriv, '%s != %s' % (guess, deriv) + else: + deriv = guess # reachable? doubt it + + assert deriv, 'need deriv path' + + if xfp == my_xfp: + # its supposed to be my key, so I should be able to generate pubkey + # - might indicate collision on xfp value between co-signers, and that's not supported + with stash.SensitiveValues() as sv: + chk_node = sv.derive_path(deriv) + assert node.public_key() == chk_node.public_key(), "XFP non-unique" # serialize xpub w/ BIP32 standard now. # - this has effect of stripping SLIP-132 confusion away - xpubs.append((xfp, chain.serialize_public(node, AF_P2SH))) + xpubs.append((xfp, deriv, chain.serialize_public(node, AF_P2SH))) - return xfp + return (xfp == my_xfp) def make_fname(self, prefix, suffix='txt'): rv = '%s-%s.%s' % (prefix, self.name, suffix) @@ -623,7 +695,7 @@ class MultisigWallet: ch = self.chain # the important stuff. - for idx, (xfp, xpub) in enumerate(self.xpubs): + for idx, (xfp, deriv, xpub) in enumerate(self.xpubs): if self.addr_fmt != AF_P2SH: # CHALLENGE: we must do slip-132 format [yz]pubs here when not p2sh mode. @@ -632,11 +704,13 @@ class MultisigWallet: else: xp = xpub + assert deriv != UNSURE_DERIV # also checked above + rv['x%d/' % (idx+1)] = dict( hw_type='coldcard', type='hardware', ckcc_xfp=xfp, label='Coldcard %s' % xfp2str(xfp), - derivation='m/'+self.common_prefix, xpub=xp) + derivation=deriv, xpub=xp) return rv @@ -675,15 +749,15 @@ class MultisigWallet: def render_export(self, fp): print("Name: %s\nPolicy: %d of %d" % (self.name, self.M, self.N), file=fp) - if self.common_prefix: - print("Derivation: m/%s" % self.common_prefix, file=fp) - if self.addr_fmt != AF_P2SH: print("Format: " + self.render_addr_fmt(self.addr_fmt), file=fp) - print("", file=fp) + last_deriv = None + for xfp, deriv, val in self.xpubs: + if last_deriv != deriv: + print("\nDerivation: %s\n" % deriv, file=fp) + last_deriv = deriv - for xfp, val in self.xpubs: print('%s: %s' % (xfp2str(xfp), val), file=fp) @classmethod @@ -702,6 +776,7 @@ class MultisigWallet: raise FatalPSBTIssue("XPUBs in PSBT do not match any existing wallet") # build up an in-memory version of the wallet. + # TODO: capture address format from an input? assert N == len(xpubs_list) assert 1 <= M <= N <= MAX_SIGNERS, 'M/N range' @@ -709,28 +784,37 @@ class MultisigWallet: expect_chain = chains.current_chain().ctype xpubs = [] - has_mine = False - path_tops = set() + has_mine = 0 for k, v in xpubs_list: - xfp, *path = ustruct.unpack_from('<%dI' % (len(k)/4), k, 0) + xfp, *path = ustruct.unpack_from('<%dI' % (len(k)//4), k, 0) xpub = tcc.codecs.b58_encode(v) - xfp = cls.check_xpub(xfp, xpub, expect_chain, xpubs, path_tops) - if xfp == my_xfp: - has_mine = True + is_mine = cls.check_xpub(xfp, xpub, keypath_to_str(path, skip=0), + expect_chain, my_xfp, xpubs) + if is_mine: + has_mine += 1 - assert has_mine # 'my key not included' + assert has_mine == 1 # 'my key not included' name = 'PSBT-%d-of-%d' % (M, N) - - prefix = path_tops.pop() if len(path_tops) == 1 else None - - ms = cls(name, (M, N), xpubs, chain_type=expect_chain, common_prefix=prefix) + ms = cls(name, (M, N), xpubs, chain_type=expect_chain) # may just keep just in-memory version, no approval required, if we are # trusting PSBT's today, otherwise caller will need to handle UX w.r.t new wallet return ms, (trust_mode != TRUST_PSBT) + def format_deriv_paths(self): + # show either single common derivation path, or indented list of them + ds = set(d for _,d,_ in self.xpubs) + unsure = (UNSURE_DERIV in ds) + + if len(ds) == 1: + ds = ds.pop() + else: + ds = ' ' + '\n '.join(sorted(ds)) + + return unsure, ds + async def confirm_import(self): # prompt them about a new wallet, let them see details and then commit change. M, N = self.M, self.N @@ -745,17 +829,21 @@ class MultisigWallet: exp = '{M} signatures, from {N} possible co-signers, will be required to approve spends.'.format(M=M, N=N) # Look for duplicate case. - is_dup, diff_count = self.has_dup() + name_change, diff_items = self.has_similar() - if not is_dup: - story = 'Create new multisig wallet?' - elif diff_count: + if name_change: + story = 'Update NAME only of existing multisig wallet?' + elif diff_items: + # Concern here is overwrite when similar, but we don't overwrite anymore, so + # more of a warning about funny business. story = '''\ -CAUTION: This updated wallet has %d different XPUB values, but matching fingerprints \ -and same M of N. Perhaps the derivation path has changed legitimately, otherwise, much \ -DANGER!''' % diff_count +WARNING: This new wallet is very similar to an existing wallet, but will NOT replace it. Consider deleting previous wallet first. Differences: \ +''' + ', '.join(diff_items) else: - story = 'Update existing multisig wallet?' + story = 'Create new multisig wallet?' + + _, ds = self.format_deriv_paths() + story += '''\n Wallet Name: {name} @@ -764,43 +852,63 @@ Policy: {M} of {N} {exp} +Addresses: + {at} + Derivation: - m/{deriv} + {deriv} Press (1) to see extended public keys, \ -OK to approve, X to cancel.'''.format(M=M, N=N, name=self.name, exp=exp, - deriv=self.common_prefix or 'unknown') +OK to approve, X to cancel.'''.format(M=M, N=N, name=self.name, exp=exp, deriv=ds, + at=self.render_addr_fmt(self.addr_fmt)) ux_clear_keys(True) while 1: ch = await ux_show_story(story, escape='1') if ch == '1': - # Show the xpubs; might be 2k or more rendered. - msg = uio.StringIO() - - for idx, (xfp, xpub) in enumerate(self.xpubs): - if idx: - msg.write('\n\n') - - # Not showing index numbers here because order - # is non-deterministic both here, our storage, and in usage. - msg.write('%s:\n%s' % (xfp2str(xfp), xpub)) - - await ux_show_story(msg, title='%d of %d' % (self.M, self.N)) - + await self.show_detail(verbose=False) continue if ch == 'y': # save to nvram, may raise MultisigOutOfSpace - if is_dup: - is_dup.delete() + if name_change: + name_change.delete() self.commit() await ux_dramatic_pause("Saved.", 2) break return ch + async def show_detail(self, verbose=True): + # Show the xpubs; might be 2k or more rendered. + msg = uio.StringIO() + + if verbose: + msg.write(''' +Policy: {M} of {N} +Blockchain: {ctype} +Addresses: + {at}\n\n'''.format(M=self.M, N=self.N, ctype=self.chain_type, + at=self.render_addr_fmt(self.addr_fmt))) + + # concern: the order of keys here is non-deterministic + for idx, (xfp, deriv, xpub) in enumerate(self.xpubs): + if idx: + msg.write('\n---===---\n\n') + + msg.write('%s:\n %s\n\n%s\n' % (xfp2str(xfp), deriv, xpub)) + + if self.addr_fmt != AF_P2SH: + # SLIP-132 format [yz]pubs here when not p2sh mode. + # - has some info as proper bitcoin serialization, but useful still + node = self.chain.deserialize_node(xpub, AF_P2SH) + xp = self.chain.serialize_public(node, self.addr_fmt) + + msg.write('\nSLIP-132 equiv:\n%s\n' % xp) + + return await ux_show_story(msg, title=self.name) + async def no_ms_yet(*a): # action for 'no wallets yet' menu item await ux_show_story("You don't have any multisig wallets yet.") @@ -940,13 +1048,13 @@ async def ms_wallet_electrum_export(menu, label, item): ms = item.arg from actions import electrum_export_story - prefix = ms.common_prefix - if not prefix : - return await ux_show_story("We don't know the common derivation path for " - "these keys, so cannot create Electrum wallet.") + unsure, derivs = ms.format_deriv_paths() + if unsure: + return await ux_show_story("We don't know all the derivation paths for " + "these keys, so cannot create Electrum wallet.") msg = 'The new wallet will have derivation path:\n %s\n and use %s addresses.\n' % ( - prefix, MultisigWallet.render_addr_fmt(ms.addr_fmt) ) + derivs, MultisigWallet.render_addr_fmt(ms.addr_fmt) ) if await ux_show_story(electrum_export_story(msg)) != 'y': return @@ -955,35 +1063,11 @@ async def ms_wallet_electrum_export(menu, label, item): async def ms_wallet_detail(menu, label, item): - # show details of single multisig wallet, offer to delete - import chains + # show details of single multisig wallet ms = item.arg - msg = uio.StringIO() - msg.write(''' -Policy: {M} of {N} -Blockchain: {ctype} -Addresses: - {at} -'''.format(M=ms.M, N=ms.N, ctype=ms.chain_type, - at=MultisigWallet.render_addr_fmt(ms.addr_fmt))) - - if ms.common_prefix: - msg.write('''\ -Derivation: - m/{der} -'''.format(der=ms.common_prefix)) - - msg.write('\n') - - # concern: the order of keys here is non-deterministic - for idx, (xfp, xpub) in enumerate(ms.xpubs): - if idx: - msg.write('\n') - msg.write('%s:\n%s\n' % (xfp2str(xfp), xpub)) - - await ux_show_story(msg, title=ms.name) + return await ms.show_detail() async def export_multisig_xpubs(*a): @@ -1095,7 +1179,7 @@ async def ondevice_multisig_create(mode='p2wsh', addr_fmt=AF_P2WSH): xpubs = [] files = [] - has_mine = False + has_mine = 0 deriv = None try: with CardSlot() as card: @@ -1128,16 +1212,15 @@ async def ondevice_multisig_create(mode='p2wsh', addr_fmt=AF_P2WSH): # value in file is BE32, but we want LE32 internally xfp = str2xfp(vals['xfp']) if not deriv: - deriv = vals[mode+'_deriv'] + deriv = cleanup_deriv_path(vals[mode+'_deriv']) else: assert deriv == vals[mode+'_deriv'], "wrong derivation" - node, _, _ = import_xpub(ln) + is_mine = MultisigWallet.check_xpub(xfp, ln, deriv, + chain.ctype, my_xfp, xpubs) + if is_mine: + has_mine += 1 - if xfp == my_xfp: - has_mine = True - - xpubs.append( (xfp, chain.serialize_public(node, AF_P2SH)) ) files.append(fn) except CardMissingError: @@ -1171,7 +1254,9 @@ async def ondevice_multisig_create(mode='p2wsh', addr_fmt=AF_P2WSH): if not has_mine: with stash.SensitiveValues() as sv: node = sv.derive_path(deriv) - xpubs.append( (my_xfp, chain.serialize_public(node, AF_P2SH)) ) + xpubs.append( (my_xfp, deriv, chain.serialize_public(node, AF_P2SH)) ) + else: + assert has_mine == 1, "same coldcard included" N = len(xpubs) @@ -1213,8 +1298,7 @@ Coldcard multisig setup file and an Electrum wallet file will be created automat assert 1 <= M <= N <= MAX_SIGNERS name = 'CC-%d-of-%d' % (M, N) - ms = MultisigWallet(name, (M, N), xpubs, chain_type=chain.ctype, - common_prefix=deriv[2:], addr_fmt=addr_fmt) + ms = MultisigWallet(name, (M, N), xpubs, chain_type=chain.ctype, addr_fmt=addr_fmt) from auth import NewEnrollRequest, UserAuthorizedAction diff --git a/shared/psbt.py b/shared/psbt.py index ad820ef7..cb7bd8c4 100644 --- a/shared/psbt.py +++ b/shared/psbt.py @@ -3,19 +3,19 @@ # # psbt.py - understand PSBT file format: verify and generate them # -from serializations import ser_compact_size, deser_compact_size, hash160, hash256 -from serializations import CTxIn, CTxInWitness, CTxOut, SIGHASH_ALL, ser_uint256 -from serializations import ser_sig_der, uint256_from_str, ser_push_data, uint256_from_str -from serializations import ser_string from ustruct import unpack_from, unpack, pack from ubinascii import hexlify as b2a_hex -from utils import xfp2str, B2A -import tcc, stash, gc, history +from utils import xfp2str, B2A, keypath_to_str, problem_file_line +import tcc, stash, gc, history, sys from uio import BytesIO from sffile import SizerFile from sram2 import psbt_tmp256 from multisig import MultisigWallet, MAX_SIGNERS, disassemble_multisig, disassemble_multisig_mn from exceptions import FatalPSBTIssue, FraudulentChangeOutput +from serializations import ser_compact_size, deser_compact_size, hash160, hash256 +from serializations import CTxIn, CTxInWitness, CTxOut, SIGHASH_ALL, ser_uint256 +from serializations import ser_sig_der, uint256_from_str, ser_push_data, uint256_from_str +from serializations import ser_string from public_constants import ( PSBT_GLOBAL_UNSIGNED_TX, PSBT_GLOBAL_XPUB, PSBT_IN_NON_WITNESS_UTXO, PSBT_IN_WITNESS_UTXO, @@ -59,10 +59,6 @@ def read_varint(v): return unpack_from("= 1 + xfp_paths.append(h) + + if h[0] == self.my_xfp: + has_mine += 1 + + if not has_mine: raise FatalPSBTIssue('My XFP not involved') - candidates = MultisigWallet.find_candidates(xfps) + candidates = MultisigWallet.find_candidates(xfp_paths) - match_idx = -1 if len(candidates) == 1: - # exact match (by xfp set) .. normal case - self.active_multisig = MultisigWallet.get_by_idx(candidates[0]) + # exact match (by xfp+deriv set) .. normal case + self.active_multisig = candidates[0] else: # don't want to guess M if not needed, but we need it M, N = self.guess_M_of_N() @@ -1041,13 +1041,15 @@ class psbtObject(psbtProxy): # - too slow to re-derive it here, so nothing more to validate at this point return - assert N == len(xfps) + assert N == len(xfp_paths) - if candidates: - # maybe narrowed down to single match now - match_idx = MultisigWallet.find_match(M, N, xfps) - if match_idx != -1: - self.active_multisig = MultisigWallet.get_by_idx(match_idx) + for c in candidates: + if c.M == M: + assert c.N == N + self.active_multisig = c + break + + del candidates if not self.active_multisig: # Maybe create wallet, for today, forever, or fail, etc. @@ -1063,6 +1065,16 @@ class psbtObject(psbtProxy): raise FatalPSBTIssue("Refused to import new wallet") self.active_multisig = proposed + else: + # Validate good match here. The xpubs must be exactly right, but + # we're going to use our own values from setup time anyway and not trusting + # new values without user interaction. + # Check: + # - chain codes match what we have stored already + # - pubkey vs. path will be checked later + # - xfp+path already checked above when selecting wallet + # Any issue here is a fraud attempt in some way, not innocent + self.active_multisig.validate_psbt_xpubs(self.xpubs) if not self.active_multisig: # not clear if an error... might be part-way to importing, and @@ -1070,9 +1082,6 @@ class psbtObject(psbtProxy): # we should not reach this point (ie. raise something to abort signing) return - # Could validate good match here? The xpubs must be exactly right, but - # we're going to use our own values from setup time anyway and not trusting - # these values without user interaction. async def validate(self): # Do a first pass over the txn. Raise assertions, be terse tho because @@ -1194,8 +1203,8 @@ class psbtObject(psbtProxy): continue probs.append("Output#%d: %s: %s not %s/{0~1}%s/{0~%d}%s expected" - % (nout, iss, path_to_str(path, skip=0), - path_to_str(path_prefix, skip=0), + % (nout, iss, keypath_to_str(path, skip=0), + keypath_to_str(path_prefix, skip=0), "'" if hard_pattern[-2] else "", idx_max, "'" if hard_pattern[-1] else "", )) @@ -1370,8 +1379,7 @@ class psbtObject(psbtProxy): # Double check the change outputs are right. This is slow, but critical because # it detects bad actors, not bugs or mistakes. # - equivilent check already done for p2sh outputs when we re-built the redeem script - change_outs = [n for n,o in enumerate(self.outputs) - if o.is_change and not o.is_p2sh_change] + change_outs = [n for n,o in enumerate(self.outputs) if o.is_change] if change_outs: dis.fullscreen('Change Check...') @@ -1379,17 +1387,27 @@ class psbtObject(psbtProxy): # only expecting single case, but be general dis.progress_bar_show(count / len(change_outs)) - for pubkey, subpath in self.outputs[out_idx].subpaths.items(): - # derive it - skp = path_to_str(subpath) + oup = self.outputs[out_idx] + + good = 0 + for pubkey, subpath in oup.subpaths.items(): + if subpath[0] != self.my_xfp: + # for multisig, will be N paths, and exactly one will + # be our key. For single-signer, should always be my XFP + continue + + # derive actual pubkey from private + skp = keypath_to_str(subpath) node = sv.derive_path(skp) # check the pubkey of this BIP32 node - pu = node.public_key() - if pu != pubkey: - raise FraudulentChangeOutput(out_idx, - "Deception regarding change output. " - "BIP32 path doesn't match actual address.") + if pubkey == node.public_key(): + good += 1 + + if not good: + raise FraudulentChangeOutput(out_idx, + "Deception regarding change output. " + "BIP32 path doesn't match actual address.") # progress dis.fullscreen('Signing...') @@ -1430,7 +1448,7 @@ class psbtObject(psbtProxy): # need to consider a set of possible keys, since xfp may not be unique for which_key in inp.required_key: # get node required - skp = path_to_str(inp.subpaths[which_key]) + skp = keypath_to_str(inp.subpaths[which_key]) node = sv.derive_path(skp, register=False) # expensive test, but works... and important @@ -1453,7 +1471,7 @@ class psbtObject(psbtProxy): continue # get node required - skp = path_to_str(inp.subpaths[which_key]) + skp = keypath_to_str(inp.subpaths[which_key]) node = sv.derive_path(skp, register=False) # expensive test, but works... and important diff --git a/shared/utils.py b/shared/utils.py index 3f716a6a..6e5044d9 100644 --- a/shared/utils.py +++ b/shared/utils.py @@ -247,6 +247,30 @@ def cleanup_deriv_path(bin_path, allow_star=False): return 'm/' + '/'.join(parts) +def keypath_to_str(bin_path, prefix='m/', skip=1): + # take binary path, like from a PSBT and convert into text notation + return prefix + '/'.join(str(i & 0x7fffffff) + ("'" if i & 0x80000000 else "") + for i in bin_path[skip:]) + +def str_to_keypath(xfp, path): + # Take a numeric xfp, and string derivation, and make a list of numbers, + # like occurs in a PSBT. + # - no error checking ehre + + rv = [xfp] + for i in path.split('/'): + if i == 'm': continue + if not i: continue # trailing or duplicated slashes + + if i[-1] == "'": + here = int(i[:-1]) | 0x80000000 + else: + here = int(i) + + rv.append(here) + + return rv + def match_deriv_path(patterns, path): # check for exact string match, or wildcard match (star in last position) # - both args must be cleaned by cleanup_deriv_path() already diff --git a/stm32/Makefile b/stm32/Makefile index fa58e799..b9df1272 100644 --- a/stm32/Makefile +++ b/stm32/Makefile @@ -1,5 +1,4 @@ -# (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard -# and is covered by GPLv3 license found in COPYING. +# (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC. # # Build micropython for stm32 (an ARM processor). Also handles signing of resulting firmware images. # @@ -29,7 +28,7 @@ BOOTLOADER_BASE = 0x08000000 FILESYSTEM_BASE = 0x080e0000 # Our version for this release. -VERSION_STRING = 3.1.10 +VERSION_STRING = 3.2.1 # # Sign and merge various parts diff --git a/stm32/bootloader/Makefile b/stm32/bootloader/Makefile index 47c7583d..b03961c6 100644 --- a/stm32/bootloader/Makefile +++ b/stm32/bootloader/Makefile @@ -1,3 +1,4 @@ +# (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC. # # "Bootloader" Makefile # diff --git a/stm32/bootloader/ae.c b/stm32/bootloader/ae.c index 3de008c3..921f8859 100644 --- a/stm32/bootloader/ae.c +++ b/stm32/bootloader/ae.c @@ -1,6 +1,5 @@ /* - * (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard - * and is covered by GPLv3 license found in COPYING. + * (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC. */ #include "basics.h" #include "ae.h" diff --git a/stm32/bootloader/ae.h b/stm32/bootloader/ae.h index fbf057f3..99730e88 100644 --- a/stm32/bootloader/ae.h +++ b/stm32/bootloader/ae.h @@ -1,6 +1,5 @@ /* - * (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard - * and is covered by GPLv3 license found in COPYING. + * (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC. */ #pragma once // diff --git a/stm32/bootloader/assets/convert.py b/stm32/bootloader/assets/convert.py index 254f4e81..525b0623 100644 --- a/stm32/bootloader/assets/convert.py +++ b/stm32/bootloader/assets/convert.py @@ -1,7 +1,6 @@ #!/usr/bin/env python3 # -# (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard -# and is covered by GPLv3 license found in COPYING. +# (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC. # # Plan: # - take a fixed background image and compose a number of info screens ontop diff --git a/stm32/bootloader/basics.h b/stm32/bootloader/basics.h index ccd84343..5a7ed66e 100644 --- a/stm32/bootloader/basics.h +++ b/stm32/bootloader/basics.h @@ -1,6 +1,5 @@ /* - * (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard - * and is covered by GPLv3 license found in COPYING. + * (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC. */ #pragma once #include diff --git a/stm32/bootloader/clocks.c b/stm32/bootloader/clocks.c index bd5c8c3d..6f0c94f8 100644 --- a/stm32/bootloader/clocks.c +++ b/stm32/bootloader/clocks.c @@ -1,6 +1,5 @@ /* - * (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard - * and is covered by GPLv3 license found in COPYING. + * (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC. */ /* * This file is part of the MicroPython project, http://micropython.org/ diff --git a/stm32/bootloader/clocks.h b/stm32/bootloader/clocks.h index 615baaf3..007e1efc 100644 --- a/stm32/bootloader/clocks.h +++ b/stm32/bootloader/clocks.h @@ -1,6 +1,5 @@ /* - * (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard - * and is covered by GPLv3 license found in COPYING. + * (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC. */ #pragma once diff --git a/stm32/bootloader/constant_time.c b/stm32/bootloader/constant_time.c index ed3a8149..a659b2f2 100644 --- a/stm32/bootloader/constant_time.c +++ b/stm32/bootloader/constant_time.c @@ -1,6 +1,5 @@ /* - * (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard - * and is covered by GPLv3 license found in COPYING. + * (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC. */ #include "constant_time.h" diff --git a/stm32/bootloader/constant_time.h b/stm32/bootloader/constant_time.h index 70a94912..df0dcd91 100644 --- a/stm32/bootloader/constant_time.h +++ b/stm32/bootloader/constant_time.h @@ -1,6 +1,5 @@ /* - * (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard - * and is covered by GPLv3 license found in COPYING. + * (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC. */ #pragma once #include diff --git a/stm32/bootloader/delay.c b/stm32/bootloader/delay.c index e8129683..0049810a 100644 --- a/stm32/bootloader/delay.c +++ b/stm32/bootloader/delay.c @@ -1,6 +1,5 @@ /* - * (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard - * and is covered by GPLv3 license found in COPYING. + * (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC. * * delay.c -- Software delay loops (we have no interrupts) * diff --git a/stm32/bootloader/delay.h b/stm32/bootloader/delay.h index 7de57496..dbe881e8 100644 --- a/stm32/bootloader/delay.h +++ b/stm32/bootloader/delay.h @@ -1,6 +1,5 @@ /* - * (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard - * and is covered by GPLv3 license found in COPYING. + * (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC. */ #pragma once diff --git a/stm32/bootloader/dispatch.c b/stm32/bootloader/dispatch.c index 6dc223e0..b4874c1b 100644 --- a/stm32/bootloader/dispatch.c +++ b/stm32/bootloader/dispatch.c @@ -1,6 +1,5 @@ /* - * (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard - * and is covered by GPLv3 license found in COPYING. + * (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC. * * dispatch.c * diff --git a/stm32/bootloader/dispatch.h b/stm32/bootloader/dispatch.h index 93d8cd05..738348b2 100644 --- a/stm32/bootloader/dispatch.h +++ b/stm32/bootloader/dispatch.h @@ -1,6 +1,5 @@ /* - * (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard - * and is covered by GPLv3 license found in COPYING. + * (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC. */ #pragma once diff --git a/stm32/bootloader/enable.c b/stm32/bootloader/enable.c index c8822d84..21debcb7 100644 --- a/stm32/bootloader/enable.c +++ b/stm32/bootloader/enable.c @@ -1,6 +1,5 @@ // -// (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard -// and is covered by GPLv3 license found in COPYING. +// (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC. // // // enable.c diff --git a/stm32/bootloader/firmware-keys.h b/stm32/bootloader/firmware-keys.h index 91ecad78..88f7ea8e 100644 --- a/stm32/bootloader/firmware-keys.h +++ b/stm32/bootloader/firmware-keys.h @@ -1,6 +1,5 @@ /* - * (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard - * and is covered by GPLv3 license found in COPYING. + * (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC. */ #define NUM_KNOWN_PUBKEYS 6 diff --git a/stm32/bootloader/gpio.c b/stm32/bootloader/gpio.c index 7e57e097..c3450bf0 100644 --- a/stm32/bootloader/gpio.c +++ b/stm32/bootloader/gpio.c @@ -1,6 +1,5 @@ /* - * (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard - * and is covered by GPLv3 license found in COPYING. + * (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC. * * gpio.c -- setup and control GPIO pins (and one button) * diff --git a/stm32/bootloader/gpio.h b/stm32/bootloader/gpio.h index 79936179..3de2118f 100644 --- a/stm32/bootloader/gpio.h +++ b/stm32/bootloader/gpio.h @@ -1,6 +1,5 @@ /* - * (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard - * and is covered by GPLv3 license found in COPYING. + * (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC. */ #pragma once diff --git a/stm32/bootloader/misc.h b/stm32/bootloader/misc.h index 6fdf88ad..f3daf146 100644 --- a/stm32/bootloader/misc.h +++ b/stm32/bootloader/misc.h @@ -1,6 +1,5 @@ /* - * (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard - * and is covered by GPLv3 license found in COPYING. + * (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC. */ #pragma once diff --git a/stm32/bootloader/oled.c b/stm32/bootloader/oled.c index a868acc6..1206ca97 100644 --- a/stm32/bootloader/oled.c +++ b/stm32/bootloader/oled.c @@ -1,6 +1,5 @@ /* - * (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard - * and is covered by GPLv3 license found in COPYING. + * (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC. */ #include "oled.h" #include "delay.h" diff --git a/stm32/bootloader/oled.h b/stm32/bootloader/oled.h index 8ea4f696..aaef23c4 100644 --- a/stm32/bootloader/oled.h +++ b/stm32/bootloader/oled.h @@ -1,7 +1,6 @@ #pragma once /* - * (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard - * and is covered by GPLv3 license found in COPYING. + * (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC. */ #include "basics.h" diff --git a/stm32/bootloader/pins.c b/stm32/bootloader/pins.c index 2b148576..acf07379 100644 --- a/stm32/bootloader/pins.c +++ b/stm32/bootloader/pins.c @@ -1,6 +1,5 @@ /* - * (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard - * and is covered by GPLv3 license found in COPYING. + * (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC. * * pins.c -- PIN codes and security issues * diff --git a/stm32/bootloader/pins.h b/stm32/bootloader/pins.h index ac570e66..76ea8ed2 100644 --- a/stm32/bootloader/pins.h +++ b/stm32/bootloader/pins.h @@ -1,6 +1,5 @@ /* - * (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard - * and is covered by GPLv3 license found in COPYING. + * (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC. * * pins.h -- everything to do with PIN's and their policies * diff --git a/stm32/bootloader/rng.c b/stm32/bootloader/rng.c index 4a0b652d..69b940f3 100644 --- a/stm32/bootloader/rng.c +++ b/stm32/bootloader/rng.c @@ -1,6 +1,5 @@ /* - * (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard - * and is covered by GPLv3 license found in COPYING. + * (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC. */ #include #include "rng.h" diff --git a/stm32/bootloader/rng.h b/stm32/bootloader/rng.h index 0569bd97..2ace0268 100644 --- a/stm32/bootloader/rng.h +++ b/stm32/bootloader/rng.h @@ -1,6 +1,5 @@ /* - * (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard - * and is covered by GPLv3 license found in COPYING. + * (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC. */ #pragma once #include "basics.h" diff --git a/stm32/bootloader/secel_config.py b/stm32/bootloader/secel_config.py index 54d59280..dff9fbbc 100644 --- a/stm32/bootloader/secel_config.py +++ b/stm32/bootloader/secel_config.py @@ -1,5 +1,4 @@ -# (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard -# and is covered by GPLv3 license found in COPYING. +# (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC. # # Secure Element Config Area. # diff --git a/stm32/bootloader/secel_debug.py b/stm32/bootloader/secel_debug.py index 22359a96..f7f4b7dd 100644 --- a/stm32/bootloader/secel_debug.py +++ b/stm32/bootloader/secel_debug.py @@ -1,5 +1,4 @@ -# (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard -# and is covered by GPLv3 license found in COPYING. +# (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC. # # Secure Element Config debugging tools. # diff --git a/stm32/bootloader/sflash.c b/stm32/bootloader/sflash.c index 35692e7f..cff73332 100644 --- a/stm32/bootloader/sflash.c +++ b/stm32/bootloader/sflash.c @@ -1,6 +1,5 @@ /* - * (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard - * and is covered by GPLv3 license found in COPYING. + * (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC. * * sflash.c -- talk to the serial flash * diff --git a/stm32/bootloader/sflash.h b/stm32/bootloader/sflash.h index 5532d98e..66999a55 100644 --- a/stm32/bootloader/sflash.h +++ b/stm32/bootloader/sflash.h @@ -1,6 +1,5 @@ /* - * (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard - * and is covered by GPLv3 license found in COPYING. + * (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC. */ #include "basics.h" diff --git a/stm32/bootloader/sigheader.h b/stm32/bootloader/sigheader.h index 49c21caa..6be16829 100644 --- a/stm32/bootloader/sigheader.h +++ b/stm32/bootloader/sigheader.h @@ -1,5 +1,4 @@ -// (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard -// and is covered by GPLv3 license found in COPYING. +// (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC. // #pragma once #include diff --git a/stm32/bootloader/sigheader.py b/stm32/bootloader/sigheader.py index 94d6dae2..a6b9d28b 100644 --- a/stm32/bootloader/sigheader.py +++ b/stm32/bootloader/sigheader.py @@ -1,7 +1,6 @@ # Autogen'ed file, don't edit. See bootloader/sigheader.h for original -# (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard -# and is covered by GPLv3 license found in COPYING. +# (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC. # Our simple firmware header. # Although called a header, this data is placed into the middle of the binary. diff --git a/stm32/bootloader/stm32l4xx_hal_spi.c b/stm32/bootloader/stm32l4xx_hal_spi.c index 94511d85..61cba970 100644 --- a/stm32/bootloader/stm32l4xx_hal_spi.c +++ b/stm32/bootloader/stm32l4xx_hal_spi.c @@ -1,6 +1,5 @@ /* - * (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard - * and is covered by GPLv3 license found in COPYING. + * (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC. * * NOTE: heavily trimmed! * diff --git a/stm32/bootloader/storage.c b/stm32/bootloader/storage.c index 0c27ab0b..a4a82f67 100644 --- a/stm32/bootloader/storage.c +++ b/stm32/bootloader/storage.c @@ -1,6 +1,4 @@ -// (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard -// and is covered by GPLv3 license found in COPYING. -// +// (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC. // // storage.c -- manage flash and its sensitive contents. // diff --git a/stm32/bootloader/storage.h b/stm32/bootloader/storage.h index f827b89d..689376aa 100644 --- a/stm32/bootloader/storage.h +++ b/stm32/bootloader/storage.h @@ -1,6 +1,5 @@ /* - * (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard - * and is covered by GPLv3 license found in COPYING. + * (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC. */ #pragma once diff --git a/stm32/bootloader/verify.c b/stm32/bootloader/verify.c index 6bebaba6..257378c7 100644 --- a/stm32/bootloader/verify.c +++ b/stm32/bootloader/verify.c @@ -1,6 +1,5 @@ /* - * (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard - * and is covered by GPLv3 license found in COPYING. + * (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC. * * verify.c -- Check signatures on firmware images in flash. * diff --git a/stm32/bootloader/verify.h b/stm32/bootloader/verify.h index b6cd47e7..dc4bcfb3 100644 --- a/stm32/bootloader/verify.h +++ b/stm32/bootloader/verify.h @@ -1,6 +1,5 @@ /* - * (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard - * and is covered by GPLv3 license found in COPYING. + * (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC. */ #pragma once #include "basics.h" diff --git a/stm32/bootloader/version.c b/stm32/bootloader/version.c index d26998ba..42169327 100644 --- a/stm32/bootloader/version.c +++ b/stm32/bootloader/version.c @@ -1,5 +1,4 @@ -// (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard -// and is covered by GPLv3 license found in COPYING. +// (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC. // // Version string. Careful with changes because parsed by python code and probably others. // diff --git a/stm32/bootloader/version.h b/stm32/bootloader/version.h index 6f0dc561..2ab2601f 100644 --- a/stm32/bootloader/version.h +++ b/stm32/bootloader/version.h @@ -1,6 +1,5 @@ /* - * (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard - * and is covered by GPLv3 license found in COPYING. + * (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC. */ #pragma once #include diff --git a/testing/Makefile b/testing/Makefile index 283c8d23..1576e2fd 100644 --- a/testing/Makefile +++ b/testing/Makefile @@ -1,4 +1,5 @@ - +# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. +# all: pytest . diff --git a/testing/api.py b/testing/api.py index fd3e6d44..60abfddd 100644 --- a/testing/api.py +++ b/testing/api.py @@ -1,5 +1,4 @@ -# (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard -# and is covered by GPLv3 license found in COPYING. +# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. # # Access a local bitcoin-Qt/bitcoind on testnet # diff --git a/testing/conftest.py b/testing/conftest.py index a613af07..0a5cf1f6 100644 --- a/testing/conftest.py +++ b/testing/conftest.py @@ -1,5 +1,4 @@ -# (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard -# and is covered by GPLv3 license found in COPYING. +# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. # import pytest, glob, time, sys, random, re from pprint import pprint diff --git a/testing/constants.py b/testing/constants.py index e7c25342..9f2da273 100644 --- a/testing/constants.py +++ b/testing/constants.py @@ -1,5 +1,4 @@ -# (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard -# and is covered by GPLv3 license found in COPYING. +# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. # SIM_PATH = '/tmp/ckcc-simulator.sock' diff --git a/testing/data/multisig/export-p2sh-myself.txt b/testing/data/multisig/export-p2sh-myself.txt index 093e2877..b9eac535 100644 --- a/testing/data/multisig/export-p2sh-myself.txt +++ b/testing/data/multisig/export-p2sh-myself.txt @@ -2,6 +2,7 @@ # Name: CC-2-of-4 Policy: 2 of 4 + Derivation: m/45' 0F056943: tpubD8NXmKsmWp3a3DXhbihAYbYLGaRNVdTnr6JoSxxfXYQcmwVtW2hv8QoDwng6JtEonmJoL3cNEwfd2cLXMpGezwZ2vL2dQ7259bueNKj9C8n diff --git a/testing/data/multisig/export-p2wsh-myself.txt b/testing/data/multisig/export-p2wsh-myself.txt index 0e263fe0..67d84d81 100644 --- a/testing/data/multisig/export-p2wsh-myself.txt +++ b/testing/data/multisig/export-p2wsh-myself.txt @@ -2,9 +2,10 @@ # Name: CC-2-of-4 Policy: 2 of 4 -Derivation: m/48'/1'/0'/2' Format: P2WSH +Derivation: m/48'/1'/0'/2' + 0F056943: tpubDF2rnouQaaYrXF4noGTv6rQYmx87cQ4GrUdhpvXkhtChwQPbdGTi8GA88NUaSrwZBwNsTkC9bFkkC8vDyGBVVAQTZ2AS6gs68RQXtXcCvkP 6BA6CFD0: tpubDFcrvj5n7gyaxWQkoX69k2Zij4vthiAwvN2uhYjDrE6wktKoQaE7gKVZRiTbYdrAYH1UFPGdzdtWJc6WfR2gFMq6XpxA12gCdQmoQNU9mgm 747B698E: tpubDExj5FnaUnPAn7sHGUeBqD3buoNH5dqmjAT6884vbDpH1iDYWigb7kFo2cA97dc8EHb54u13TRcZxC4kgRS9gc3Ey2xc8c5urytEzTcp3ac diff --git a/testing/data/multisig/export-p2wsh-p2sh-myself.txt b/testing/data/multisig/export-p2wsh-p2sh-myself.txt index 1291ff96..c4a00a54 100644 --- a/testing/data/multisig/export-p2wsh-p2sh-myself.txt +++ b/testing/data/multisig/export-p2wsh-p2sh-myself.txt @@ -2,9 +2,10 @@ # Name: CC-2-of-4 Policy: 2 of 4 -Derivation: m/48'/1'/0'/1' Format: P2WSH-P2SH +Derivation: m/48'/1'/0'/1' + 0F056943: tpubDF2rnouQaaYrUEy2JM1YD3RFzew4onawGM4X2Re67gguTf5CbHonBRiFGe3Xjz7DK88dxBFGf2i7K1hef3PM4cFKyUjcbJXddaY9F5tJBoP 6BA6CFD0: tpubDFcrvj5n7gyatVbr8dHCUfHT4CGvL8hREBjtxc4ge7HZgqNuPhFimPRtVg6fRRwfXiQthV9EBjNbwbpgV2VoQeL1ZNXoAWXxP2L9vMtRjax 747B698E: tpubDExj5FnaUnPAjjgzELoSiNRkuXJG8Cm1pbdiA4Hc5vkAZHphibeVcUp6mqH5LuNVKbtLVZxVSzyja5X26Cfmx6pzRH6gXBUJAH7MiqwNyuM diff --git a/testing/data/multisig/setting-p2sh-myself.json b/testing/data/multisig/setting-p2sh-myself.json index 1740aeda..e5edde04 100644 --- a/testing/data/multisig/setting-p2sh-myself.json +++ b/testing/data/multisig/setting-p2sh-myself.json @@ -1 +1 @@ -["CC-2-of-4", [2, 4], [[1130956047, "tpubD8NXmKsmWp3a3DXhbihAYbYLGaRNVdTnr6JoSxxfXYQcmwVtW2hv8QoDwng6JtEonmJoL3cNEwfd2cLXMpGezwZ2vL2dQ7259bueNKj9C8n"], [3503269483, "tpubD9429UXFGCTKJ9NdiNK4rC5ygqSUkginycYHccqSg5gkmyQ7PZRHNjk99M6a6Y3NY8ctEUUJvCu6iCCui8Ju3xrHRu3Ez1CKB4ZFoRZDdP9"], [2389277556, "tpubD97nVL37v5tWyMf9ofh5rznwhh1593WMRg6FT4o6MRJkKWANtwAMHYLrcJFsFmPfYbY1TE1LLQ4KBb84LBPt1ubvFwoosvMkcWJtMwvXgSc"], [3190206587, "tpubD9ArfXowvGHnuECKdGXVKDMfZVGdephVWg8fWGWStH3VKHzT4ph3A4ZcgXWqFu1F5xGTfxncmrnf3sLC86dup2a8Kx7z3xQ3AgeNTQeFxPa"]], {"ch": "XTN", "pp": "45'"}] \ No newline at end of file +["CC-2-of-4", [2, 4], [[1130956047, "m/45'", "tpubD8NXmKsmWp3a3DXhbihAYbYLGaRNVdTnr6JoSxxfXYQcmwVtW2hv8QoDwng6JtEonmJoL3cNEwfd2cLXMpGezwZ2vL2dQ7259bueNKj9C8n"], [3503269483, "m/45'", "tpubD9429UXFGCTKJ9NdiNK4rC5ygqSUkginycYHccqSg5gkmyQ7PZRHNjk99M6a6Y3NY8ctEUUJvCu6iCCui8Ju3xrHRu3Ez1CKB4ZFoRZDdP9"], [2389277556, "m/45'", "tpubD97nVL37v5tWyMf9ofh5rznwhh1593WMRg6FT4o6MRJkKWANtwAMHYLrcJFsFmPfYbY1TE1LLQ4KBb84LBPt1ubvFwoosvMkcWJtMwvXgSc"], [3190206587, "m/45'", "tpubD9ArfXowvGHnuECKdGXVKDMfZVGdephVWg8fWGWStH3VKHzT4ph3A4ZcgXWqFu1F5xGTfxncmrnf3sLC86dup2a8Kx7z3xQ3AgeNTQeFxPa"]], {"ch": "XTN"}] \ No newline at end of file diff --git a/testing/data/multisig/setting-p2wsh-myself.json b/testing/data/multisig/setting-p2wsh-myself.json index d8c7cb8c..070efa83 100644 --- a/testing/data/multisig/setting-p2wsh-myself.json +++ b/testing/data/multisig/setting-p2wsh-myself.json @@ -1 +1 @@ -["CC-2-of-4", [2, 4], [[1130956047, "tpubDF2rnouQaaYrXF4noGTv6rQYmx87cQ4GrUdhpvXkhtChwQPbdGTi8GA88NUaSrwZBwNsTkC9bFkkC8vDyGBVVAQTZ2AS6gs68RQXtXcCvkP"], [3503269483, "tpubDFcrvj5n7gyaxWQkoX69k2Zij4vthiAwvN2uhYjDrE6wktKoQaE7gKVZRiTbYdrAYH1UFPGdzdtWJc6WfR2gFMq6XpxA12gCdQmoQNU9mgm"], [2389277556, "tpubDExj5FnaUnPAn7sHGUeBqD3buoNH5dqmjAT6884vbDpH1iDYWigb7kFo2cA97dc8EHb54u13TRcZxC4kgRS9gc3Ey2xc8c5urytEzTcp3ac"], [3190206587, "tpubDFiuHYSJhNbHcbLJoxWdbjtUcbKR6PvLq53qC1Xq6t93CrRx78W3wcng8vJyQnY3giMJZEgNCRVzTojLb8RqPFpW5Ms2dYpjcJYofN1joyu"]], {"pp": "48'/1'/0'/2'", "ch": "XTN", "ft": 14}] \ No newline at end of file +["CC-2-of-4", [2, 4], [[1130956047, "m/48'/1'/0'/2'", "tpubDF2rnouQaaYrXF4noGTv6rQYmx87cQ4GrUdhpvXkhtChwQPbdGTi8GA88NUaSrwZBwNsTkC9bFkkC8vDyGBVVAQTZ2AS6gs68RQXtXcCvkP"], [3503269483, "m/48'/1'/0'/2'", "tpubDFcrvj5n7gyaxWQkoX69k2Zij4vthiAwvN2uhYjDrE6wktKoQaE7gKVZRiTbYdrAYH1UFPGdzdtWJc6WfR2gFMq6XpxA12gCdQmoQNU9mgm"], [2389277556, "m/48'/1'/0'/2'", "tpubDExj5FnaUnPAn7sHGUeBqD3buoNH5dqmjAT6884vbDpH1iDYWigb7kFo2cA97dc8EHb54u13TRcZxC4kgRS9gc3Ey2xc8c5urytEzTcp3ac"], [3190206587, "m/48'/1'/0'/2'", "tpubDFiuHYSJhNbHcbLJoxWdbjtUcbKR6PvLq53qC1Xq6t93CrRx78W3wcng8vJyQnY3giMJZEgNCRVzTojLb8RqPFpW5Ms2dYpjcJYofN1joyu"]], {"ch": "XTN", "ft": 14}] \ No newline at end of file diff --git a/testing/data/multisig/setting-p2wsh-p2sh-myself.json b/testing/data/multisig/setting-p2wsh-p2sh-myself.json index 15e631c7..fb130841 100644 --- a/testing/data/multisig/setting-p2wsh-p2sh-myself.json +++ b/testing/data/multisig/setting-p2wsh-p2sh-myself.json @@ -1 +1 @@ -["CC-2-of-4", [2, 4], [[1130956047, "tpubDF2rnouQaaYrUEy2JM1YD3RFzew4onawGM4X2Re67gguTf5CbHonBRiFGe3Xjz7DK88dxBFGf2i7K1hef3PM4cFKyUjcbJXddaY9F5tJBoP"], [3503269483, "tpubDFcrvj5n7gyatVbr8dHCUfHT4CGvL8hREBjtxc4ge7HZgqNuPhFimPRtVg6fRRwfXiQthV9EBjNbwbpgV2VoQeL1ZNXoAWXxP2L9vMtRjax"], [2389277556, "tpubDExj5FnaUnPAjjgzELoSiNRkuXJG8Cm1pbdiA4Hc5vkAZHphibeVcUp6mqH5LuNVKbtLVZxVSzyja5X26Cfmx6pzRH6gXBUJAH7MiqwNyuM"], [3190206587, "tpubDFiuHYSJhNbHaGtB5skiuDLg12tRboh2uVZ6KGXxr8WVr28pLcS7F3gv8SsHFa2tm1jtx3VAuw56YfgRkdo6DXyfp51oygTKY3nJFT5jBMt"]], {"pp": "48'/1'/0'/1'", "ch": "XTN", "ft": 26}] \ No newline at end of file +["CC-2-of-4", [2, 4], [[1130956047, "m/48'/1'/0'/1'", "tpubDF2rnouQaaYrUEy2JM1YD3RFzew4onawGM4X2Re67gguTf5CbHonBRiFGe3Xjz7DK88dxBFGf2i7K1hef3PM4cFKyUjcbJXddaY9F5tJBoP"], [3503269483, "m/48'/1'/0'/1'", "tpubDFcrvj5n7gyatVbr8dHCUfHT4CGvL8hREBjtxc4ge7HZgqNuPhFimPRtVg6fRRwfXiQthV9EBjNbwbpgV2VoQeL1ZNXoAWXxP2L9vMtRjax"], [2389277556, "m/48'/1'/0'/1'", "tpubDExj5FnaUnPAjjgzELoSiNRkuXJG8Cm1pbdiA4Hc5vkAZHphibeVcUp6mqH5LuNVKbtLVZxVSzyja5X26Cfmx6pzRH6gXBUJAH7MiqwNyuM"], [3190206587, "m/48'/1'/0'/1'", "tpubDFiuHYSJhNbHaGtB5skiuDLg12tRboh2uVZ6KGXxr8WVr28pLcS7F3gv8SsHFa2tm1jtx3VAuw56YfgRkdo6DXyfp51oygTKY3nJFT5jBMt"]], {"ch": "XTN", "ft": 26}] \ No newline at end of file diff --git a/testing/devtest/abort_ux.py b/testing/devtest/abort_ux.py index 278af3e1..d87ccdcb 100644 --- a/testing/devtest/abort_ux.py +++ b/testing/devtest/abort_ux.py @@ -1,3 +1,5 @@ +# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. +# # abort menu system and return to top menu from main import pa, numpad diff --git a/testing/devtest/backups.py b/testing/devtest/backups.py index 8f7a4696..330ecafb 100644 --- a/testing/devtest/backups.py +++ b/testing/devtest/backups.py @@ -1,3 +1,5 @@ +# (c) Copyright 2020 by Coinkite Inc. All rights reserved. +# # Unit test for shared/backups.py # # this will run on the simulator only diff --git a/testing/devtest/cap-image.py b/testing/devtest/cap-image.py index 56acdfcf..9b5858d0 100644 --- a/testing/devtest/cap-image.py +++ b/testing/devtest/cap-image.py @@ -1,3 +1,5 @@ +# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. +# from main import dis from ubinascii import hexlify as b2a_hex diff --git a/testing/devtest/cap-menu.py b/testing/devtest/cap-menu.py index 0f7638c3..c6918937 100644 --- a/testing/devtest/cap-menu.py +++ b/testing/devtest/cap-menu.py @@ -1,3 +1,5 @@ +# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. +# import sim_display RV.write('\n'.join(sim_display.read_menu())) diff --git a/testing/devtest/cap-screen.py b/testing/devtest/cap-screen.py index 90356320..5b62aefe 100644 --- a/testing/devtest/cap-screen.py +++ b/testing/devtest/cap-screen.py @@ -1,3 +1,5 @@ +# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. +# import sim_display RV.write(sim_display.full_contents) diff --git a/testing/devtest/cap-story.py b/testing/devtest/cap-story.py index 78464bbd..c2de7cd6 100644 --- a/testing/devtest/cap-story.py +++ b/testing/devtest/cap-story.py @@ -1,3 +1,5 @@ +# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. +# import sim_display if sim_display.story: diff --git a/testing/devtest/check_decode.py b/testing/devtest/check_decode.py index f9994bae..6ef46deb 100644 --- a/testing/devtest/check_decode.py +++ b/testing/devtest/check_decode.py @@ -1,3 +1,5 @@ +# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. +# # check we decoded the PSBT correctly, by looking under the covers. import main expect = main.EXPECT diff --git a/testing/devtest/clear_seed.py b/testing/devtest/clear_seed.py index 5bf60c44..3d690ed2 100644 --- a/testing/devtest/clear_seed.py +++ b/testing/devtest/clear_seed.py @@ -1,3 +1,5 @@ +# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. +# # quickly main wipe seed; don't install anything new from main import pa, settings, numpad, dis from pincodes import AE_SECRET_LEN, PA_IS_BLANK diff --git a/testing/devtest/dump_private.py b/testing/devtest/dump_private.py index c5f0ebce..ef83bf5e 100644 --- a/testing/devtest/dump_private.py +++ b/testing/devtest/dump_private.py @@ -1,3 +1,5 @@ +# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. +# import backups, stash with stash.SensitiveValues() as sv: diff --git a/testing/devtest/dump_public.py b/testing/devtest/dump_public.py index 703db6ea..554119cb 100644 --- a/testing/devtest/dump_public.py +++ b/testing/devtest/dump_public.py @@ -1,3 +1,5 @@ +# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. +# import backups, stash for ln in backups.generate_public_contents(): diff --git a/testing/devtest/get-secrets.py b/testing/devtest/get-secrets.py index ef251bfc..e37411f2 100644 --- a/testing/devtest/get-secrets.py +++ b/testing/devtest/get-secrets.py @@ -1,2 +1,4 @@ +# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. +# import backups RV.write(backups.render_backup_contents()) diff --git a/testing/devtest/get-setting.py b/testing/devtest/get-setting.py index 824feeb2..f78f106a 100644 --- a/testing/devtest/get-setting.py +++ b/testing/devtest/get-setting.py @@ -1,3 +1,5 @@ +# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. +# import main from main import settings from ujson import dumps diff --git a/testing/devtest/get-settings.py b/testing/devtest/get-settings.py index 65ef1e43..870fb54a 100644 --- a/testing/devtest/get-settings.py +++ b/testing/devtest/get-settings.py @@ -1,3 +1,5 @@ +# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. +# from main import settings from ujson import dumps RV.write(dumps(settings.current)) diff --git a/testing/devtest/get_pp_sofar.py b/testing/devtest/get_pp_sofar.py index bf3a095e..5f2a425d 100644 --- a/testing/devtest/get_pp_sofar.py +++ b/testing/devtest/get_pp_sofar.py @@ -1,3 +1,5 @@ +# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. +# import seed RV.write(seed.pp_sofar) diff --git a/testing/devtest/nvram.py b/testing/devtest/nvram.py index 9c7d7ad0..2e25a29a 100644 --- a/testing/devtest/nvram.py +++ b/testing/devtest/nvram.py @@ -1,3 +1,5 @@ +# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. +# # Unit test for shared/nvstore.py # # this will run on the simulator diff --git a/testing/devtest/segwit_addr.py b/testing/devtest/segwit_addr.py index 4af7811c..dbed2d52 100644 --- a/testing/devtest/segwit_addr.py +++ b/testing/devtest/segwit_addr.py @@ -1,3 +1,5 @@ +# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. +# # this will run on the simulator # run manually with: # execfile('../../testing/devtest/segwit_addr.py') diff --git a/testing/devtest/set_encoded_secret.py b/testing/devtest/set_encoded_secret.py index 4d09b668..75d73479 100644 --- a/testing/devtest/set_encoded_secret.py +++ b/testing/devtest/set_encoded_secret.py @@ -1,3 +1,5 @@ +# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. +# # load up the simulator w/ indicated encoded secret. could be xprv/words/etc. import tcc, main from sim_settings import sim_defaults diff --git a/testing/devtest/set_raw_secret.py b/testing/devtest/set_raw_secret.py index b2aa4285..60f5ee34 100644 --- a/testing/devtest/set_raw_secret.py +++ b/testing/devtest/set_raw_secret.py @@ -1,3 +1,5 @@ +# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. +# # load up the simulator w/ indicated test master key import tcc, main from sim_settings import sim_defaults diff --git a/testing/devtest/set_seed.py b/testing/devtest/set_seed.py index 09815666..299913c0 100644 --- a/testing/devtest/set_seed.py +++ b/testing/devtest/set_seed.py @@ -1,3 +1,5 @@ +# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. +# # load up the simulator w/ indicated list of seed words import tcc, main from sim_settings import sim_defaults diff --git a/testing/devtest/set_tprv.py b/testing/devtest/set_tprv.py index dfb97450..a37bf362 100644 --- a/testing/devtest/set_tprv.py +++ b/testing/devtest/set_tprv.py @@ -1,3 +1,5 @@ +# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. +# # load up the simulator w/ indicated test master key import tcc, main from sim_settings import sim_defaults diff --git a/testing/devtest/unit_addrs.py b/testing/devtest/unit_addrs.py index f02f0577..52906d75 100644 --- a/testing/devtest/unit_addrs.py +++ b/testing/devtest/unit_addrs.py @@ -1,3 +1,5 @@ +# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. +# # unit test for address decoding from various types of CTxOuts from h import a2b_hex, b2a_hex from psbt import psbtObject diff --git a/testing/devtest/unit_bip143.py b/testing/devtest/unit_bip143.py index 84b0f446..d832ba8d 100644 --- a/testing/devtest/unit_bip143.py +++ b/testing/devtest/unit_bip143.py @@ -1,3 +1,5 @@ +# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. +# # work thru the first example given in BIP-143 from h import a2b_hex, b2a_hex from psbt import psbtObject, psbtInputProxy, psbtOutputProxy diff --git a/testing/devtest/unit_decoding.py b/testing/devtest/unit_decoding.py index 07a764f0..56d9d63e 100644 --- a/testing/devtest/unit_decoding.py +++ b/testing/devtest/unit_decoding.py @@ -1,3 +1,5 @@ +# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. +# from utils import HexStreamer, Base64Streamer from ubinascii import unhexlify as a2b_hex from ubinascii import hexlify as b2a_hex diff --git a/testing/devtest/unit_multisig.py b/testing/devtest/unit_multisig.py index ec51d126..d73886b8 100644 --- a/testing/devtest/unit_multisig.py +++ b/testing/devtest/unit_multisig.py @@ -1,3 +1,5 @@ +# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. +# # unit test for address decoding for multisig from h import a2b_hex, b2a_hex from chains import BitcoinMain, BitcoinTestnet diff --git a/testing/devtest/unit_psbt.py b/testing/devtest/unit_psbt.py index 7580bb0c..d42a459a 100644 --- a/testing/devtest/unit_psbt.py +++ b/testing/devtest/unit_psbt.py @@ -1,3 +1,5 @@ +# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. +# # unit test for code in shared/psbt.py # # this will run on the simulator diff --git a/testing/devtest/unit_slip132.py b/testing/devtest/unit_slip132.py index b6e3a474..641c11ea 100644 --- a/testing/devtest/unit_slip132.py +++ b/testing/devtest/unit_slip132.py @@ -1,3 +1,5 @@ +# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. +# # work thru examples given in SLIP-132 # in simulator # diff --git a/testing/devtest/wipe_ms.py b/testing/devtest/wipe_ms.py index 9e10ff1d..fcfc3599 100644 --- a/testing/devtest/wipe_ms.py +++ b/testing/devtest/wipe_ms.py @@ -1,3 +1,5 @@ +# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. +# # quickly clear all multisig wallets installed from main import settings from ux import restore_menu diff --git a/testing/helpers.py b/testing/helpers.py index a192804e..a1fc885f 100644 --- a/testing/helpers.py +++ b/testing/helpers.py @@ -1,5 +1,4 @@ -# (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard -# and is covered by GPLv3 license found in COPYING. +# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. # # stuff I need sometimes from io import BytesIO diff --git a/testing/objstruct.py b/testing/objstruct.py index e5edf2cd..e4b460d1 100644 --- a/testing/objstruct.py +++ b/testing/objstruct.py @@ -1,5 +1,4 @@ -# (c) Copyright 2020 by Coinkite Inc. This file is part of Coldcard -# and is covered by GPLv3 license found in COPYING. +# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. # # objstruct.py # diff --git a/testing/psbt.py b/testing/psbt.py index c4b0ec74..c185dd6e 100644 --- a/testing/psbt.py +++ b/testing/psbt.py @@ -1,5 +1,4 @@ -# (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard -# and is covered by GPLv3 license found in COPYING. +# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. # # psbt.py - yet another PSBT parser/serializer but used only for test cases. # diff --git a/testing/test_addr.py b/testing/test_addr.py index 5772033c..85510083 100644 --- a/testing/test_addr.py +++ b/testing/test_addr.py @@ -1,5 +1,4 @@ -# (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard -# and is covered by GPLv3 license found in COPYING. +# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. # # test "show address" feature # diff --git a/testing/test_address_explorer.py b/testing/test_address_explorer.py index f341f7af..ca594c87 100644 --- a/testing/test_address_explorer.py +++ b/testing/test_address_explorer.py @@ -1,5 +1,4 @@ -# (c) Copyright 2019 by Coinkite Inc. This file is part of Coldcard -# and is covered by GPLv3 license found in COPYING. +# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. # import pytest, time, os from ckcc_protocol.constants import * diff --git a/testing/test_attended.py b/testing/test_attended.py index d78fc03b..6f7dd8e5 100644 --- a/testing/test_attended.py +++ b/testing/test_attended.py @@ -1,5 +1,4 @@ -# (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard -# and is covered by GPLv3 license found in COPYING. +# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. # # Tests that need a person there... mostly when not run on simulator # diff --git a/testing/test_bip39pw.py b/testing/test_bip39pw.py index 35fcb494..f5041ff8 100644 --- a/testing/test_bip39pw.py +++ b/testing/test_bip39pw.py @@ -1,5 +1,4 @@ -# (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard -# and is covered by GPLv3 license found in COPYING. +# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. # # BIP39 seed word encryption # diff --git a/testing/test_change_pins.py b/testing/test_change_pins.py index 2f400080..3c386380 100644 --- a/testing/test_change_pins.py +++ b/testing/test_change_pins.py @@ -1,5 +1,4 @@ -# (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard -# and is covered by GPLv3 license found in COPYING. +# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. # # UX and interactions related to Settings > Pin Options # diff --git a/testing/test_drv_entro.py b/testing/test_drv_entro.py index 4aa2e2a9..16fa44cb 100644 --- a/testing/test_drv_entro.py +++ b/testing/test_drv_entro.py @@ -1,5 +1,4 @@ -# (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard -# and is covered by GPLv3 license found in COPYING. +# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. # # test drv_entro.py features # diff --git a/testing/test_export.py b/testing/test_export.py index d342a603..0c8815c7 100644 --- a/testing/test_export.py +++ b/testing/test_export.py @@ -1,5 +1,4 @@ -# (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard -# and is covered by GPLv3 license found in COPYING. +# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. # # Exporting of wallet files and similar things. # diff --git a/testing/test_hsm.py b/testing/test_hsm.py index af600c72..f4b538cb 100644 --- a/testing/test_hsm.py +++ b/testing/test_hsm.py @@ -1,5 +1,4 @@ -# (c) Copyright 2020 by Coinkite Inc. This file is part of Coldcard -# and is covered by GPLv3 license found in COPYING. +# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. # # Test HSM and its policy file. # diff --git a/testing/test_msg.py b/testing/test_msg.py index 6cbaedd2..81e2f035 100644 --- a/testing/test_msg.py +++ b/testing/test_msg.py @@ -1,5 +1,4 @@ -# (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard -# and is covered by GPLv3 license found in COPYING. +# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. # # Message signing. # diff --git a/testing/test_multisig.py b/testing/test_multisig.py index 97fdede9..a64d726f 100644 --- a/testing/test_multisig.py +++ b/testing/test_multisig.py @@ -1,5 +1,4 @@ -# (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard -# and is covered by GPLv3 license found in COPYING. +# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. # # Multisig-related tests. # @@ -69,9 +68,10 @@ def clear_ms(unit_test): def make_multisig(): # make a multsig wallet, always with simulator as an element - # always BIP45: m/45'/... (but no co-signer idx) + # default is BIP45: m/45'/... (but no co-signer idx) + # - but can provide str format for deriviation, use {idx} for cosigner idx - def doit(M, N, unique=0): + def doit(M, N, unique=0, deriv=None): keys = [] for i in range(N-1): @@ -79,11 +79,31 @@ def make_multisig(): xfp = unpack(" -# and is covered by GPLv3 license found in COPYING. +# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. # # Tests for paper-wallet feature # diff --git a/testing/test_pincodes.py b/testing/test_pincodes.py index 3069ee61..9f8447ef 100644 --- a/testing/test_pincodes.py +++ b/testing/test_pincodes.py @@ -1,5 +1,4 @@ -# (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard -# and is covered by GPLv3 license found in COPYING. +# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. # # Test PIN code management. Requires real device, emulator is useless for this. # diff --git a/testing/test_pwsave.py b/testing/test_pwsave.py index 38da6bb9..e70d8050 100644 --- a/testing/test_pwsave.py +++ b/testing/test_pwsave.py @@ -1,5 +1,4 @@ -# (c) Copyright 2020 by Coinkite Inc. This file is part of Coldcard -# and is covered by GPLv3 license found in COPYING. +# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. # # tests for ../shared/pwsave.py # diff --git a/testing/test_sign.py b/testing/test_sign.py index 92fb712c..af4362de 100644 --- a/testing/test_sign.py +++ b/testing/test_sign.py @@ -1,5 +1,4 @@ -# (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard -# and is covered by GPLv3 license found in COPYING. +# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. # # Transaction Signing. Important. # @@ -313,7 +312,6 @@ def test_vs_bitcoind(match_key, check_against_bitcoind, bitcoind, start_sign, en open('debug/finalized-by-btcd.txn', 'wb').write(network) # try to send it - assert 0 txed = bitcoind.sendrawtransaction(B2A(network)) print("Final txn hash: %r" % txed) @@ -322,7 +320,6 @@ def test_vs_bitcoind(match_key, check_against_bitcoind, bitcoind, start_sign, en #print("Final txn: %s" % B2A(signed)) open('debug/finalized-by-cc.txn', 'wb').write(signed) - assert 0 txed = bitcoind.sendrawtransaction(B2A(signed)) print("Final txn hash: %r" % txed) @@ -1201,7 +1198,7 @@ def test_payjoin_signing(num_ins, num_outs, fake_txn, try_sign, start_sign, end_ assert 'warning below' in story assert 'Limited Signing' in story - assert 'Some inputs are signed already' in story + assert 'because we do not know the key' in story assert ': %s' % (num_ins-1) in story txn = end_sign(True, finalize=False) diff --git a/testing/test_unit.py b/testing/test_unit.py index a1b60c8e..203f064c 100644 --- a/testing/test_unit.py +++ b/testing/test_unit.py @@ -1,5 +1,4 @@ -# (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard -# and is covered by GPLv3 license found in COPYING. +# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. # # Run tests on the simulator itself, not here... these are basically "unit tests" # diff --git a/testing/test_upgrades.py b/testing/test_upgrades.py index db4ec9e7..6298dc64 100644 --- a/testing/test_upgrades.py +++ b/testing/test_upgrades.py @@ -1,5 +1,4 @@ -# (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard -# and is covered by GPLv3 license found in COPYING. +# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. # # Various firmware upgrade things. # diff --git a/testing/test_usb.py b/testing/test_usb.py index c7d898bb..59f27b42 100644 --- a/testing/test_usb.py +++ b/testing/test_usb.py @@ -1,5 +1,4 @@ -# (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard -# and is covered by GPLv3 license found in COPYING. +# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. # # A few USB link layer tests. # diff --git a/testing/test_ux.py b/testing/test_ux.py index 24247210..dc4f3897 100644 --- a/testing/test_ux.py +++ b/testing/test_ux.py @@ -1,5 +1,4 @@ -# (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard -# and is covered by GPLv3 license found in COPYING. +# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. # import pytest, time, os from helpers import xfp2str diff --git a/testing/txn.py b/testing/txn.py index 966489d1..16049976 100644 --- a/testing/txn.py +++ b/testing/txn.py @@ -1,5 +1,4 @@ -# (c) Copyright 2020 by Coinkite Inc. This file is part of Coldcard -# and is covered by GPLv3 license found in COPYING. +# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. # # Creating fake transactions. Not simple. # diff --git a/testing/xfp-miner.py b/testing/xfp-miner.py index 298615ce..e777038e 100755 --- a/testing/xfp-miner.py +++ b/testing/xfp-miner.py @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# Search for an XFP collision. +# (c) Copyright 2020 by Coinkite Inc. This file is covered by license found in COPYING-CC. +# +# Search for an XFP collision. Needs to be much faster. # import os, hmac, hashlib from pycoin.key.BIP32Node import BIP32Node diff --git a/unix/Makefile b/unix/Makefile index a7ccb363..4720819a 100644 --- a/unix/Makefile +++ b/unix/Makefile @@ -1,5 +1,4 @@ -# (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard -# and is covered by GPLv3 license found in COPYING. +# (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC. # # Use this to build the simulator. # diff --git a/unix/headless.py b/unix/headless.py index 55db8435..0460943c 100755 --- a/unix/headless.py +++ b/unix/headless.py @@ -1,7 +1,6 @@ #!/usr/bin/env python # -# (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard -# and is covered by GPLv3 license found in COPYING. +# (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC. # # Simulate the hardware of a Coldcard.. except not: be headless. # - does simulate USB (altho that's not here, but part of mpy code for simulator) diff --git a/unix/simulator.py b/unix/simulator.py index 3482c247..b869f5e7 100755 --- a/unix/simulator.py +++ b/unix/simulator.py @@ -1,7 +1,6 @@ #!/usr/bin/env python # -# (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard -# and is covered by GPLv3 license found in COPYING. +# (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC. # # Simulate the hardware of a Coldcard. Particularly the OLED display (128x32) and # the numberpad.