Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
339 commits
Select commit Hold shift + click to select a range
65d3a9f
allow multisig descriptor with root keys
scgbckbone Feb 12, 2025
5d15fe4
fix: id hint while displaying qr segwit address overlap QR
scgbckbone Feb 12, 2025
3124325
fix: busy bar after failed calc_qr
scgbckbone Feb 12, 2025
127f651
fix: multisg address display
scgbckbone Feb 12, 2025
97ee810
BBQr switch in QR File Share
scgbckbone Feb 12, 2025
1f72051
edits
doc-hex Feb 12, 2025
2e30c9d
Ownership success UX story title compat Mk4/Q
doc-hex Feb 13, 2025
b335d92
fixing tests
doc-hex Feb 13, 2025
3743151
update for new release
doc-hex Feb 13, 2025
9f31ed3
Signed for q1 release.
doc-hex Feb 13, 2025
16cf7ab
Signed for mk4 release.
doc-hex Feb 13, 2025
77dda12
version bump
doc-hex Feb 13, 2025
d95b1db
fixes after git magic
scgbckbone Feb 19, 2025
e6ac73b
fixes after git magic 1
scgbckbone Feb 19, 2025
d2ef212
fixes after git magic 2
scgbckbone Feb 19, 2025
ef2ff97
changelog clear
scgbckbone Feb 19, 2025
5c3be0c
miniscript: allow origin-less (blinded) keys for cosigners
scgbckbone Dec 29, 2024
d3d301f
taproot: static internal keys disallowed
scgbckbone Jan 2, 2025
3c01600
fixes & version bump
scgbckbone Feb 19, 2025
0427af8
Merge pull request #469 from scgbckbone/edge_feb2025
doc-hex Feb 19, 2025
a735a4c
For
doc-hex Feb 19, 2025
06a6796
Signed for q1 release.
doc-hex Feb 19, 2025
5a3b64e
New release: 2025-02-19T1940-v6.3.5QX
doc-hex Feb 19, 2025
706466a
For 2025-02-19T1941-v6.3.5X
doc-hex Feb 19, 2025
940aa32
Signed for mk4 release.
doc-hex Feb 19, 2025
c10aff8
New release: 2025-02-19T1941-v6.3.5X
doc-hex Feb 19, 2025
339b2bc
untested: skip making factory version for Edge
doc-hex Mar 10, 2025
e209980
improve taptree parser
scgbckbone May 23, 2025
e68123c
(slightly) faster tagged sha256
scgbckbone Jun 2, 2025
41b200b
nit
scgbckbone Jun 2, 2025
b6a3564
miniscript teleport init
scgbckbone Jun 2, 2025
a1d9652
bugfix: PSBT corner cases
scgbckbone May 27, 2025
2ebe376
word_wrap: if last character is double wide on Q move to next line
scgbckbone May 15, 2025
215357a
is None, not equals None
scgbckbone Apr 17, 2025
da80fd3
move shared modules from version manifests to default manifest.py
scgbckbone Jun 3, 2025
60a6777
sort manifest modules alphabetically
scgbckbone Jun 3, 2025
3075cd0
remove dup comment
scgbckbone Jun 3, 2025
6507856
QRs in txn output explorer
scgbckbone Apr 20, 2025
68792a7
move OP_RETURN ux rendition from chains to render_output
scgbckbone Jun 3, 2025
0dc88cc
CHANGE -> CHANGE BACK
scgbckbone Jun 3, 2025
ac472ab
fix word_wrap; adjust tests for new double wide policy
scgbckbone Jun 4, 2025
042b0ee
Bump requests from 2.32.3 to 2.32.4 in /testing
dependabot[bot] Jun 10, 2025
b9d8d8c
multiprocess simulator
scgbckbone Apr 25, 2025
b134cd9
update ckcc
scgbckbone Jun 11, 2025
93e1827
update libngu
scgbckbone Jun 11, 2025
e04d391
remove linux address patch
scgbckbone Jun 11, 2025
9d31349
fix miniscript test
scgbckbone Jun 11, 2025
ab91463
test fixes, multiproc for test_miniscript.py
scgbckbone Jun 13, 2025
7a94a6f
cc
scgbckbone Jun 13, 2025
6852ce3
remove teleport inaccurate complexity
scgbckbone Jun 13, 2025
4c6a6b8
miniscript teleport fixes
scgbckbone Jun 16, 2025
34b7152
more test cases regarding keys with same origin
scgbckbone Jun 16, 2025
f70b324
fe
scgbckbone Jun 16, 2025
9cd6043
move
scgbckbone Jun 17, 2025
1ff76f3
changelogs
scgbckbone Jun 17, 2025
cd344cb
nits
scgbckbone Jun 17, 2025
d4e9549
rework key derivation parsing
scgbckbone Jun 18, 2025
dc73bdf
allow spk generation from compiled script insteaad of self
scgbckbone Jun 18, 2025
24dccb6
test_minitapscript cut in half
scgbckbone Jun 18, 2025
4254fba
remove unused methods
scgbckbone Jun 18, 2025
7d84ba4
slightly optimized yield addresses for miniscript; remove derivations…
scgbckbone Jun 18, 2025
f6639e4
what
scgbckbone Jun 19, 2025
0ac8951
move move
scgbckbone Jun 21, 2025
68ffcec
further
scgbckbone Jun 25, 2025
d4e8dfb
further 21
scgbckbone Jun 25, 2025
32d28de
fixes
scgbckbone Jun 26, 2025
e9b04ff
key are only on descriptor level; improve tests
scgbckbone Jun 27, 2025
f7cb241
removed unused censor_address
scgbckbone Jun 27, 2025
0b20ef5
fixes + small speed up for multi/sortedmulti scripts
scgbckbone Jun 28, 2025
37a677e
bip388 import/export
scgbckbone Jun 30, 2025
3090d22
disjoint multipath test
scgbckbone Jul 1, 2025
638e7ac
remove MultisigWallet part 1
scgbckbone Jul 2, 2025
789b87c
multi-day commit dump
scgbckbone Jul 9, 2025
f8d32a8
better matching
scgbckbone Jul 10, 2025
6eb1ef2
a lot
scgbckbone Jul 15, 2025
f70b05b
a lot more fixes
scgbckbone Jul 16, 2025
54ccfe6
fat cut
scgbckbone Jul 16, 2025
754c4c3
optional full CSV export, default off
scgbckbone Jul 23, 2025
0ca4109
no need to calc scriptCode if we're not signing that input
scgbckbone Jul 23, 2025
8169ec0
sign with specific miniscript wallet + separate complex wallets from …
scgbckbone Jul 26, 2025
3a98641
fix
scgbckbone Jul 26, 2025
7029918
improve signing code
scgbckbone Jul 30, 2025
8223765
fix
scgbckbone Jul 30, 2025
962dd2e
cache taproot scriptPubKey for later use in sighash ops - no need to …
scgbckbone Jul 31, 2025
7d3c982
memory optimize PSBT inputs
scgbckbone Aug 1, 2025
a973c7e
p2wsh fix
scgbckbone Aug 2, 2025
e01e23a
optimize PSBT class (RAM)
scgbckbone Aug 4, 2025
ef92efe
move
scgbckbone Aug 5, 2025
7a0e0a2
versions
scgbckbone Aug 5, 2025
5a27fcc
more
scgbckbone Aug 5, 2025
4439f3d
optimize PSBT class
scgbckbone Aug 15, 2025
30457c9
optimize PSBT class more
scgbckbone Aug 19, 2025
20207f2
fix, do not resign if signature from us was already provided
scgbckbone Aug 25, 2025
c6a0ab9
more
scgbckbone Aug 25, 2025
bc6b5a2
edge simulator
scgbckbone Aug 26, 2025
6f6b245
reorder/rename exports and add Cove
nvk Jun 12, 2025
d2dce34
Bull Bitcoin export
scgbckbone Jul 24, 2025
9998b57
update documentation for multisig quorum constraints
cc-unchained Jun 6, 2025
c4c2ae8
restore note on 520 byte stack element limit
cc-unchained Jun 9, 2025
b1fdbae
bugfix: use full LCD display width (34) when displaying seed words; n…
scgbckbone Jul 30, 2025
a12ac4b
cleanups
doc-hex Jul 31, 2025
b8d702c
Key Teleport easier to access
doc-hex Aug 11, 2025
3d57e1f
narrower
nvk Aug 18, 2025
b09fde8
Clarify allowed usage of Seed XOR standard and name
kdmukai Aug 26, 2025
f3f3f1d
slip32 --> slip132
scgbckbone Sep 4, 2025
734bcc7
USB signtx miniscript wallet argument
scgbckbone Sep 8, 2025
c3a8941
bugfix: enter vfs after creating it
scgbckbone Sep 16, 2025
b4e4505
SSSP (squashed)
doc-hex Aug 11, 2025
4808ae4
bugfix: selftest MicroSD test
scgbckbone Sep 17, 2025
329c6c5
bugfix: premature wipe while exporting secret material via NFC - only…
scgbckbone Jun 24, 2025
e202ab9
decouple wiping NFC chip from `ux_animation` routine
scgbckbone Jun 24, 2025
b4d3e50
little bug
doc-hex Sep 17, 2025
5fd2ee9
lower Mk4 default wrap-around from 16 to 10 (same as Q)
scgbckbone Jun 25, 2025
5132051
rename files on SD card via List Files
scgbckbone Jun 19, 2025
4e77d38
edits
doc-hex Sep 18, 2025
5b7bee4
restore backup via USB
scgbckbone Aug 6, 2025
d2aeedb
edit
doc-hex Sep 18, 2025
2d5e123
bugfix: ownership check needed re-run for values near max
scgbckbone May 21, 2025
e01822c
ownership: search particular named wallet via BIP-21 wallet query param
scgbckbone May 22, 2025
8e90fe6
docs & nits
scgbckbone May 22, 2025
a70dd4e
txout explorer do not yikes on big QRs
scgbckbone Jun 5, 2025
e296bda
ownership
doc-hex Sep 18, 2025
dcc028f
nits
doc-hex Sep 19, 2025
2aa6c45
fix tests
scgbckbone Sep 19, 2025
ad3b1e4
update ckcc to latest master
scgbckbone Sep 19, 2025
d8210a2
SSSP settings shared across temporary seeds
scgbckbone Sep 21, 2025
e7f42cf
add "Restore from XOR" to Temporary Seed menu
scgbckbone Sep 12, 2025
78d5f2d
Q: brick into forever calculator
scgbckbone Aug 23, 2025
9c4257a
review
scgbckbone Sep 5, 2025
a7713e3
Q becomes calculator rather than e-waste
doc-hex Sep 22, 2025
6cb1173
nit
doc-hex Sep 22, 2025
e4eaaf1
seedxor allowed when hobbled
doc-hex Sep 22, 2025
56180d7
nits
doc-hex Sep 22, 2025
ec9d625
mk4 fix word entry after restore via USB
scgbckbone Sep 22, 2025
b9deed6
hide empty menu
doc-hex Sep 23, 2025
39d8767
multisig input/output address format
scgbckbone Sep 18, 2025
ee62d42
test hobbled Teleport
scgbckbone Sep 23, 2025
79dbfa9
comments
doc-hex Sep 23, 2025
1a10e11
edits
doc-hex Sep 23, 2025
e7f0a08
ckcc bump
scgbckbone Sep 23, 2025
5020ee5
reword
doc-hex Sep 23, 2025
47cc8ea
test fixes
scgbckbone Sep 23, 2025
8ac90d4
fix multisig test ms_sign_simple
scgbckbone Sep 24, 2025
bea721a
ownership improve UI
scgbckbone Sep 24, 2025
7da6d97
bump ccc_min_block (block height)
scgbckbone Sep 24, 2025
3cae633
fix SSSP test drive to actually enforce policy
scgbckbone Sep 24, 2025
76d4e53
fix SSSP unable to find unlock policy PIN
scgbckbone Sep 24, 2025
041f803
do not allow empty BIP-39 passphrase over USB
scgbckbone Sep 24, 2025
08df482
proper label for Web 2FA warning
scgbckbone Sep 25, 2025
437961c
disallow Type Passwords if not okeys in sssp
scgbckbone Sep 25, 2025
d2f4871
reload Trick Pins before deleting unlock pins
scgbckbone Sep 25, 2025
5f29751
Edits
doc-hex Sep 25, 2025
c3500f0
Signed for q1 release.
doc-hex Sep 25, 2025
b5d0535
Signed for mk4 release.
doc-hex Sep 25, 2025
edc5584
dont show "allow notes" on mk4
doc-hex Sep 25, 2025
5edc688
tweak
doc-hex Sep 26, 2025
c2f1041
add heartbeats, cleanups
doc-hex Sep 26, 2025
0bc4c4f
bugfix: only list files with proper extension delimited by dot; fix U…
scgbckbone Sep 25, 2025
32272b9
cleanups
doc-hex Sep 26, 2025
13888fd
undo-rc
doc-hex Sep 26, 2025
292e580
another day, another RC
doc-hex Sep 26, 2025
e22c6b6
Signed for q1 release.
doc-hex Sep 26, 2025
74c81c2
Signed for mk4 release.
doc-hex Sep 26, 2025
b30fc66
test_sssp.py more sleeps
scgbckbone Sep 28, 2025
6a47b29
spelling
doc-hex Sep 29, 2025
5bd7f4b
deltamode timing fix
doc-hex Sep 29, 2025
1ca5f2e
undo-gold-rc
doc-hex Sep 30, 2025
8f8b952
Signed for q1 release.
doc-hex Sep 30, 2025
f862202
Signed for mk4 release.
doc-hex Sep 30, 2025
65e7121
bump date
doc-hex Sep 30, 2025
ee39e91
after master cherry-pick fixes
scgbckbone Oct 5, 2025
b870f93
after master cherry-pick fixes 2
scgbckbone Oct 5, 2025
f316847
fix address explorer ownership for complex wallets
scgbckbone Oct 5, 2025
95a1b25
ownership UX
scgbckbone Oct 5, 2025
fe7244c
ownership fixes
scgbckbone Oct 6, 2025
d55a869
DER signature length verification
scgbckbone Oct 6, 2025
ba3bc33
test for same key set miniscript
scgbckbone Oct 6, 2025
c323d2f
nits
scgbckbone Oct 6, 2025
548c63b
BIP-388 fixes & tests
scgbckbone Oct 6, 2025
9a59217
save some flash space
scgbckbone Oct 6, 2025
0a0d937
extendable miniscript wallet serialization format
scgbckbone Oct 7, 2025
a1342ac
fixes & optimization of get_my_deriv
scgbckbone Oct 9, 2025
eb55a6d
invalidate descriptor cache when changing secret
scgbckbone Oct 9, 2025
5b67e2c
migrations 6.4.0
scgbckbone Oct 9, 2025
c72b77a
Changelog
scgbckbone Oct 9, 2025
aa4e259
Changelog
scgbckbone Oct 9, 2025
0ee23f5
test fix
scgbckbone Oct 10, 2025
4ea01f7
try_sign accept miniscript argument
scgbckbone Oct 10, 2025
89bdf2d
miniscript rename test
scgbckbone Oct 10, 2025
fa9bff5
do not allow miniscript in legacy P2SH
scgbckbone Oct 10, 2025
3b8930b
slip132 compat
scgbckbone Oct 17, 2025
64eb5cc
testing: cope with bitcoin core v30
scgbckbone Oct 13, 2025
edc8593
improve guessing address fmt and M of N
scgbckbone Oct 17, 2025
44701a3
remove in-object Trick Pin storage - always use settings
scgbckbone Sep 26, 2025
2784308
disallow non-consensus meaningful relative locktimes
scgbckbone Oct 20, 2025
3a1ad13
comment
scgbckbone Oct 20, 2025
785b8a4
nits
scgbckbone Oct 20, 2025
5f06e09
test miniscript & SSSP
scgbckbone Oct 20, 2025
8d0d9af
ChangeLog
scgbckbone Oct 20, 2025
9841af4
UI improvements
scgbckbone Oct 21, 2025
8081732
assert miniscript fragment wrapped by t is of type V
scgbckbone Oct 21, 2025
727beab
test cope
scgbckbone Oct 21, 2025
f34faaf
fix miniscript teleport & teleport UI
scgbckbone Oct 21, 2025
4abf8b7
store BBQRs in (unused) 3rd MB of PSRAM
scgbckbone Oct 21, 2025
8709817
Changelog
scgbckbone Oct 21, 2025
c0b9ea1
fixes
scgbckbone Oct 21, 2025
1349b73
fix miniscript rename after HW testing, broken code worked on simulator
scgbckbone Oct 21, 2025
b1b2edd
multisig -> miniscript
scgbckbone Oct 21, 2025
2dc1b97
typo
scgbckbone Oct 21, 2025
30946eb
remove SIGHASH_DEFAULT from PSBT input after signing
scgbckbone Oct 21, 2025
7c8aceb
env path for bitcoind for CC testing
scgbckbone Oct 21, 2025
6dd8237
drop sighash only after modifiable flags are properly set for v2 PSBT
scgbckbone Oct 22, 2025
512349b
cut sighash tests - too long
scgbckbone Oct 22, 2025
807e7a0
fix
scgbckbone Oct 22, 2025
cb539f6
typo
scgbckbone Oct 22, 2025
449e889
check
scgbckbone Oct 22, 2025
e3b2e49
more nits
scgbckbone Oct 22, 2025
ca1b7b6
modify --ms simulator flag to use miniscript
scgbckbone Oct 22, 2025
8d8b496
older miniscript fragment validation
scgbckbone Oct 23, 2025
a1eb3e9
bugfix: exiting custom backup password text form causes yikes
scgbckbone Oct 22, 2025
337ee8c
show fw version in hobbled mode
scgbckbone Sep 29, 2025
fc2bfe2
show backup filename during backup password entry (Q only)
scgbckbone Oct 23, 2025
ff3b385
UX confirm loading backup
scgbckbone Oct 20, 2025
e361408
re-fix: bugfix: exiting custom backup password text form causes yikes
scgbckbone Oct 29, 2025
30b1c04
test fixes
scgbckbone Oct 30, 2025
3f938c3
changelog compatibility warning
scgbckbone Oct 30, 2025
203c288
fin
scgbckbone Oct 30, 2025
fa6a361
fix name handling during migration
scgbckbone Oct 31, 2025
d055680
fix name tests after extending possible name size to 30
scgbckbone Oct 31, 2025
a5caa48
update ckcc submodule
scgbckbone Oct 31, 2025
52ae9f9
stxn USB cmd miniscript name lenght
scgbckbone Nov 3, 2025
514b1ae
update ckcc submodule
scgbckbone Nov 3, 2025
8552571
block bump
doc-hex Nov 3, 2025
fc4daa6
Signed for q1 release.
doc-hex Nov 3, 2025
a1e486a
Signed for mk4 release.
doc-hex Nov 3, 2025
b4a3304
update changelogs
doc-hex Nov 3, 2025
3550107
Merge pull request #568 from scgbckbone/edge_31_Oct_2025_1
doc-hex Nov 5, 2025
9259b03
For 2025-11-05T1533-v6.4.0QX
doc-hex Nov 5, 2025
eeabaef
Signed for q1 release.
doc-hex Nov 5, 2025
1d3be6d
New release: 2025-11-05T1533-v6.4.0QX
doc-hex Nov 5, 2025
5f38ae2
For 2025-11-05T1535-v6.4.0X
doc-hex Nov 5, 2025
e1cbe65
Signed for mk4 release.
doc-hex Nov 5, 2025
9d04ea8
New release: 2025-11-05T1535-v6.4.0X
doc-hex Nov 5, 2025
b0f4d8b
update embit<->firmware licensing
scgbckbone Nov 10, 2025
54fb9d6
unwrap static Number(s)
scgbckbone Nov 10, 2025
4974782
Merge pull request #569 from scgbckbone/edge_licensing
doc-hex Nov 11, 2025
d9c9098
Merge pull request #570 from scgbckbone/unwrap_static_nums
doc-hex Nov 11, 2025
c84eb79
renames Multisig/Miniscript
doc-hex Nov 11, 2025
37f4a1f
preserve old multisig wallets for downgrade; execute multisig migrati…
scgbckbone Nov 5, 2025
cc4034b
multi verbose detail
scgbckbone Nov 12, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,9 @@ git clone --recursive https://github.com/Coldcard/firmware.git
cd firmware
# Apply address patch
git apply unix/linux_addr.patch
# if unix/linux_addr.patch exists use below command
# not needed in current revision
# git apply unix/linux_addr.patch
# * below is needed for ubuntu 24.04
pushd external/micropython
Expand Down
5 changes: 3 additions & 2 deletions cli/signit.py
Original file line number Diff line number Diff line change
Expand Up @@ -319,13 +319,14 @@ def doit(keydir, outfn=None, build_dir=None, high_water=False,
pubkey_num=pubkey_num,
timestamp=timestamp(backdate) )

assert FW_MIN_LENGTH <= hdr.firmware_length <= FW_MAX_LENGTH, hdr.firmware_length

if hw_compat & MK_3_OK:
# actual file length limited by size of SPI flash area reserved to txn data/uploads
assert FW_MIN_LENGTH <= hdr.firmware_length <= FW_MAX_LENGTH, hdr.firmware_length
USB_MAX_LEN = (786432-128)
else:
# new value for Mk4: limited only by final binary size, not SPI flash
# new value for Mk4 and later: limited only by final binary size, not SPI flash
assert FW_MIN_LENGTH <= hdr.firmware_length <= FW_MAX_LENGTH_MK4, hdr.firmware_length
USB_MAX_LEN = 1472 * 1024

assert hdr.firmware_length <= USB_MAX_LEN, \
Expand Down
15 changes: 15 additions & 0 deletions docs/bip-21-extensions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
## Multisig Ownership address check: "wallet"

If the name of the multisig wallet related to an address is provided, address search
can be greatly accelerated. Just provide `wallet=name` parameter in a standard
[BIP-21](https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki) URL
shown in QR code or NFC record. If omitted, search will continue across
all multisig wallets known by COLDCARD.

### Examples

```
tb1q4d67p7stxml3kdudrgkg5mgaxsrgzcqzjrrj4gg62nxtvnsnvqjsxjkej0?wallet=goldmine
bitcoin:mtHSVByP9EYZmB26jASDdPVm19gvpecb5R?label=coldcard_purchase&amount=50&wallet=Haystack%20Four
```
2 changes: 1 addition & 1 deletion docs/generic-wallet-export.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ to be the first (non-change) receive address for the wallet.
segregate funds into sub-wallets. Don't assume it's zero.

3. When making your PSBT files to spend these amounts, remember that the XFP of the master
(`0F056943` in this example) is is the root of the subkey paths found in the file, and
(`0F056943` in this example) is the root of the subkey paths found in the file, and
you must include the full derivation path from master. So based on this example,
to spend a UTXO on `tb1qc58ys2dphtphg6yuugdf3d0kufmk0tye044g3l`, the input section
of your PSBT would need to specify `(m=0F056943)/84'/1'/123'/0/0`.
Expand Down
224 changes: 224 additions & 0 deletions docs/key-teleport.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@

# Key Teleport

Purpose: Send a small quantity of very secret data between two COLDCARD Q systems, with
no risk of anything in the middle learning the secret.

Method: ECDH and AES-256-CTR plus an extra wrapping layer, transmitted over a mixture of
NFC, passive websites, and QR/BBQr codes.

# Protocol Overview

## Steps

- Receiver picks an EC keypair, stores it in settings, and publishes the pubkey via a QR/NFC
- The pubkey is encrypted by a short 8-digit numeric code, which should be
sent by a different channel.
- Sender gets QR and numeric code, picks own keypair, and does ECDH to arrive at a
shared session key
- Sender picks a human-readable secret which is independent of anything else (P key)
- The secret data (perhaps a seed phrase, XPRV, secure note, full backup, etc) is
AES-256-CTR encrypted with P key, then encrypted + MAC added with session key
- Data packet is sent to receiver (via BBQr), who can reconstruct the session key via ECDH
- Prompt user for the P key to finish decoding
- Decoded secret value is saved to Seed Vault or secure notes as appropriate
- Receiver destroys EC keypair used in transfer

### When used for PSBT Multisig

- No action required on receiver
- Sender uses the pubkey derived from pre-shared XPUB involved in the multisig wallet.
- Same steps, but drops immediately into signing process when decoded correctly

## Notes and Limitations

- max 4k (after encoding) of data is possible due to HTTP limitations
- all transfers are "data typed" and decode only on COLDCARD
- Q model is required due to the use of QR codes to ultimately get data into the COLDCARD


# Details

## Data Type Codes

The first byte encodes what the package contents (under all the encryption).

- `s` - 12/18/24 words/raw master/xprv - 17-72 bytes follow, encoded in an internal format
- `x` - XPRV mode, full details - 4 bytes (XPRV) + base58 *decoded* binary-XPRV follows
- `n` - one or many notes export (JSON array)
- `v` - seed vault export (JSON: one secret key but includes name, source of key)
- `p` - binary PSBT to be signed, perhaps multisig but not required.
- `b` - complete system backup file (text lines, internal format)

## QR details

BBQr is always used for the QR's involved in this process, even if
they are short enough for a normal QR code. Because the BBQr is
being generated by the COLDCARD embedded firmware, it will not be
compressed and will always be Base32 encoded.

New type codes for BBQr are defined for the purposes of this application:

- `R` contains `(pubkey)` ... begins the process from receiver; compressed pubkey is 33 bytes
- `S` contains `(pubkey)(data)` ... data from sender; first 33 bytes are sender's pubkey
- `E` for Multisig PSBT: `(randint)(data)` ... randint (4 byte nonce) indicates which
derived subkey from pre-shared xpub associated with receiver

All the data is encrypted with the exception randint. Keep in mind
this is a nonce value picked uniquely for each transfer. The
receiver's pubkey is only weakly encrypted by the 8-digit numeric
password, but is also a nonce effectively.

### PSBT Key Selection

When sending PSBT data, a nonce is picked at random by the sender
in range: `0..(2^28)`

This nonce is called `randint`. The receiver's pubkey will be

.../20250317/(randint)

where `...` is the derivation used in the multisig wallet for the co-signer who will
receive the package. The sender's keypair has the same sub key path assuming all
co-signers have same derivation path from root (not required).

Because both the sender and receiver already have each other's XPUB they can derive
the appropriate pubkeys (and privkey for their side) without communicating
more than `randint`. The sending COLDCARD will pick a new random value each time.

When receiving a multisig PSBT encrypted this way, the receiver does not need
to do any setup (nor numeric password) and can receive a QR code at any time.
This works because the shared multisig wallet is already setup. Receiver will
take the nonce value (randint) and seach all pre-defined multisig wallets for
any pubkey that can decrypt the package successfully (based on checksum inside
first layer of ECDH encryption).

The next layer of encryption (paranoid password) is unchanged.

## Encryption Details

AES-256-CTR is used exclusively. Session key is picked via ECDH with final
key value being the SHA256 over 64 bytes of coordinate X (concat) Y.

While ECDH is enough to assure privacy from men in the middle, we
add an additional layer of encryption. We call this the "paranoid key" internally
and in the UX it is called "Teleport Password".

The user sees a random 8-character password, generated as a random 40-bit value, but
shown in Base32 (8 chars) for the human to enter. We apply PBKDF2-SHA512 with
an iteration count of 5000 to stretch that to 512 bits, of which we use half.
The session key is used as the key for the KDF, and the entered value as salt.

- ECDH arrives at session key
- decrypt (AES-256-CTR) the binary body of message
- verify checksum:
- final 2 bytes should be `== SHA256(decrypted body[0:-2])[-2:]`
- if not, corruption, truncation, or wrong keys
- if that decryption is correct, then prompt user for the paranoid key (8 chars)
- stretch that value using session key and 5000 iterations of PBKDF2-SHA512
- use upper 256 bits and run AES-256-CTR again
- same checksum of 2 bytes of SHA256 are found inside after decryption

Encryption adds 4 bytes of overhead because of these MAC values,
but should catch truncation and bitrot. There are no other
protections against truncation as length data is not transmitted.

# Receiver Password

When the teleport process is started, the receiver shares his pubkey
as QR. However, we also show an 8-digit numeric password. The
purpose of this is force the receiver to share this separately from
the pubkey QR on another channel. The code is randomly picked, but
only represents about 26 bits of entropy and is stretched with
a single round of SHA256 before being used as a AES-256-CTR key
to decrypt the pubkey. No checksum verifies correct
decryption, so any code is accepted, and will with near-50% odds,
decrypt to a valid pubkey.

When the sender is given the receiver's pubkey via QR code, it
prompts for the numeric code and uses it to decrypt the pubkey.
Thus a MiTM who injects their pubkey will be detected and blocked.

The "paranoid key" serves the same role in the other direction but
it is Base32 character set, so it will not look similar or be
confusing as to its purpose.

# Web Component

In order to "teleport" the contents of a QR code over NFC, we will
publish a static website directly from an open Github repository.
The single-page website contains javascript code which looks at the
"hash" part of the incoming URL (`window.location.hash`) and if it
meets the requirements, renders a large QR. The QR data must look like
a correctly-encoded BBQr with one of the 3 type-codes above (`R` `S` or `E`).
Otherwise the website could render any QR, which we don't want to
support.

The page will offer "copy to clipboard" features for the data inside
the QR as a URL (ie. same URL as shown) and as an image and of course,
the COLDCARD Q can scan from the web browser screen itself.

When the BBQr data is larger than comfortable for a single QR, the
website can split into a multi-frame BBQr. The website can
do this without understanding the contents of the BBQr data (all
of which is encrypted). Download options will be provided for
single-frame QR, animated PNG, and "stacked BBQr" (a single tall
PNG with each QR frame stacked).

On the COLDCARD side, when NFC is tapped, it will offer a long URL
to this site with the data to be transferred "after the hash". This
is optional since the QR can be shown on the Q itself, and would
pass the same data.

Since the website is running on Github, Coinkite does not have
access to IP addresses or other access log details. Because the data for
teleport is "after the hash" it is never sent to Github's servers
but remains in the browser only. All JS resources referenced by the
webpage will have content hashes applied to prevent interference,
and the site will be served over SSL.

Visit [keyteleport.com](https://keyteleport.com/), or an
[example small QR](https://keyteleport.com/#B$2R0100VHT2AGUUH7KUZUUSTOWOIWHJX3XM7GA2N4BHQOXDFHXLVHVA7K6ZO)
and [view source code](https://github.com/coinkite/keyteleport.com).

# UX Details

- When the receive process is started by the user, a pubkey is picked
and stored, so that they can come back later (after a power cycle)
and make use of the data encoded by the sender. However once a package
is decoded successfully, that key is deleted.

- Sender must start by scanning the QR from a receiver. Then can pick what
to send, from secure notes to seeds and so on.

- For PSBT multisig, user must pick a single co-signer (who hasn't already
signed) and the QR is prepared for that receiver. Because we
cannot do arbitary combining, it's best if the next signer continues
to teleport the updated PSBT to further signers. In other words,
a daisy-chain pattern is prefered to a star pattern. The signer
who completes the Mth (of N) signature will be able to finalize
the transaction, and ideally with PushTx feature, broadcast it.

# Security Comments

## Such short passwords?

We are using 8-character passwords because we want them to be
practical to share over non-digital channels such as a voice phone
call, or hand-written note.

It is very important to remind users that the passwords should be sent
by a different channel from the QR itself. Best is to call up your
other party and say the letters to them directly.

## Is it safe to save image of QR to cloud?

Yes, this seems safe. Of course, if you can control it, perhaps not
a risk to accept... but the QR is encrypted via ECDH using a key
that is forgotten after the transfer, so forward privacy is protected.
Also your cloud service (or photo roll, chat app log, etc) will not
have the 8-character password which is also required unpack the secrets.

The QR codes themselves are fully random and do not reveal the
identity of your COLDCARD, your on chain funds or anything linked
to you.
34 changes: 29 additions & 5 deletions docs/limitations.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@
# PIN Codes

- 2-2 through 6-6 in size, numeric digits only
- pin code 999999-999999 is reserved (means 'clear pin')
- pin code 999999-999999 was reserved (meaning 'clear pin'), but now available again

# Backup Files

- we don't know what day it is, so meta data on files will not have correct date/time
- release date of the firmware version that made the file is used instead of true date
- encrypted files produced cannot be changed, and we don't support other tools making them

# Micro SD
Expand Down Expand Up @@ -55,14 +56,18 @@

- only one signature will be added per input. However, if needed the partly-signed
PSBT can be given again, and the "next" leg will be signed.
- we do not support PSBT combining or finalizing of transactions involving
P2SH signatures (so the combine step must be off-device)
- finalizing of multisig transactions involving P2SH signatures:
* SD/Vdisk signing exports both signed PSBT and finalized txn ready for broadcast (if txn is complete)
* QR/NFC outputs finalized txn ready for broadcast if txn is complete otherwise signed PSBT only
* USB signing requires `--finalize` parameter (as for standard single signature wallets)

- we can sign for P2SH and P2WSH addresses that represent multisig (M of N) but
we cannot sign for non-standard scripts because we don't know how to present
that to the user for approval.
- during USB "show address" for multisig, we limit subkey paths to
16 levels deep (including master fingerprint)
- max of 15 co-signers due to 520 byte script limitation in consensus layer with classic P2SH (same limit applies to segwit even though consensus allows up to 20 co-signers)
- max of 15 co-signers due to 1650 byte `scriptSig` limitation in policy with classic P2SH (same limit applies to segwit even though consensus allows up to 20 co-signers).
note: the consensus layer sets an upper bound of 520 bytes for the length of each stack element
- (mk3) we have space for up to 8 M-of-3 wallets, or a single M-of-15 wallet. YMMV
- only a single multisig wallet can be involved in a PSBT; can't sign inputs from two different
multisig wallets at the same time.
Expand All @@ -74,6 +79,7 @@
- multisig wallet `name` can only contain printable ASCII characters `range(32, 127)`

### BIP-67

- importing multisig from PSBT can ONLY create `sortedmulti(...)` multisig according to BIP-67, DO NOT use with `multi(...)`
- creating airgapped multisig using COLDCARD as coordinator always produces `sortedmulti(...)` multisig according to BIP-67
- COLDCARD import/export [format](https://coldcard.com/docs/multisig/#configuration-text-file-for-multisig) only supports `sortedmulti(...)` multisig according to BIP-67. To import multisig wallet with `multi(...)` use descriptor import [format](https://github.com/bitcoin/bips/blob/master/bip-0383.mediawiki)
Expand Down Expand Up @@ -128,12 +134,17 @@ We will summarize transaction outputs as "change" back into same wallet, however
- `p2wsh-p2sh`: _redeemScript_ (which is: `0x00 + 0x20 + sha256(witnessScript)`), and
_witnessScript_ (which contains the multisig script)
- `p2wsh`: only _witnessScript_ (which contains the actual multisig script)

- `p2tr`(keypath singlesig): no _redeemScript_, no _witnessScript_ and output key MUST commit to an unspendable script path as follows `Q = P + int(hashTapTweak(bytes(P)))G`
- `p2tr`(scriptpath multisig): _taproot_merkle_root_ and _leaf_script_ more info in docs/taproot.md

# Derivation Paths

- key derivatation paths must be 12 or less in depth (`MAX_PATH_DEPTH`)

# Pay-to-Pubkey

- although we have some code for "pay to pubkey" (P2PK not P2PKH), it is untested
and unused since this style of payment address is obsolete and largely unused today

# NFC Feature

Expand Down Expand Up @@ -198,3 +209,16 @@ We will summarize transaction outputs as "change" back into same wallet, however
- if you have an XFP collision between multiple wallets in SeedVault (ie. two wallets
with same descriptors, but different seeds) you will get false negatives

# Spending Policy

- (Cosign mode) only 12 or 24 word seeds (not XPRV) are accepted for "key C"
- velocity limit:
- based on a max magnitude per txn, and a required minimum block height
gap, based on previous `nLockTime` value in last-signed PSBT.
- if you sign a transaction, but never broadcast it, you will still have to wait out
the velocity policy.
- PSBT creator must put in `nLockTime` block heights (most already do to avoid fee sniping)
- maximum of 25 whitelisted addresses can be stored
- Web2FA: any number of mobile devices can be enrolled, but all will have the same shared secret
- any warning from the PSBT, such as huge fees, will cause the transaction to be rejected

Loading