Any of plates recover it.
Paste a descriptor or any other secret. It splits as you type.
Recovery
Select the plates you still have, scan them, or type their text. Any k plates of one set bring it back.
Type or paste share text
Split something in tab 1, scan plates with the camera, or type their text.
The descriptor is the backup
A multisig can only be spent through its witness script, and that script contains every cosigner's key. In a 3-of-5, three seeds can sign. They cannot rebuild the script without the other two xpubs.
The output descriptor records all five, so it is the one part of the wallet that must survive complete. It holds no private key. It should still be backed up on steel like the seeds.
SeedHammer today
SeedHammer II engraves the descriptor on a single plate with a fixed layout. Four cosigners with key origins fit. Five do not.
That plate is one more thing to lose. Whoever finds it reads every xpub, and with them every address the wallet will ever use.
What shaQR does
shaQR encrypts the secret with ChaCha20 under a one-time 32-byte key. It spreads the ciphertext over the plates with a Reed-Solomon code, so each plate holds 1/k of it, and splits the key with Shamir's scheme. The construction is Hugo Krawczyk's "Secret Sharing Made Short", CRYPTO 1993.
Any k plates rebuild the key and the ciphertext, and with them the secret. Fewer plates show only its length, to within k bytes. Derived sets, below, are the one exception. A share is about 1/k of the secret plus 55 bytes.
For a descriptor, k and n are the wallet's own, and share x goes on the plate of the x-th key. Whoever holds enough seeds to spend also holds enough plates to recover, so the backup is never weaker than the wallet.
Shares shorter than the secret cannot have perfect secrecy, so shaQR's secrecy rests on ChaCha20 and SHA-256. The wallet's own keys rest on assumptions of the same kind.
Sizes
| Quorum | Descriptor, bytes | Per plate, chars | QR version | Shamir share, QR version |
|---|---|---|---|---|
| 2-of-3 | 457 | 462 | 11 | 15 |
| 3-of-5 | 743 | 493 | 12 | 20 |
| 10-of-20 | 2889 | 558 | 13 | none |
The descriptors are wsh(sortedmulti(...)) with key origins and
/<0;1>/* children. The QR versions are for alphanumeric mode at
error level L. The Shamir share carries the same 9 bytes of type, terminator, header
and check as a shaQR share.
Plates grow slowly with the quorum, because each holds 1/k of the descriptor. Small secrets go the other way. A 20-byte TOTP seed split 2-of-3 makes 66-byte shares, against 29 for a Shamir share. Most of the difference is the 32-byte key part.
What every plate carries
A check. Four bytes of a SHA-256 hash over the rest of the share. A damaged or mistyped plate fails it the moment it is scanned, while its holder is still there to try again.
A set id. Sixteen bytes that commit to the key and the ciphertext. Recovery recomputes it and outputs nothing when it differs. Anyone can compute a check, so the check stops no forger. Someone who was present at an earlier recovery knows the key and the ciphertext. Without the id, they could make a plate that changes what a later recovery outputs. A recovery that uses such a plate fails the id, so the plate can stop a recovery and cannot change its result. With a spare plate, the receiver names the forged one.
A tag. The first two bytes of the id, in hex after a
#, as in #2714. It tells sets apart on a shelf and in a
scanner. A plate of another wallet lands in a set of its own and spoils nothing.
Derived sets. A descriptor backup draws its key from the canonical descriptor, so the same wallet always cuts the same plates, in any tool that follows the spec. A lost plate can be cut again from the descriptor alone. A derived set cannot be refreshed: splitting again gives the same plates, so a departed cosigner normally means a new wallet, a new descriptor and a new set. In exchange for the derivation, anyone who already holds every xpub can recognise the plates. They learn nothing new by it. Each xpub carries as many unknown bits as the seed behind it, about 128 for a 12-word seed, so someone missing even one xpub can no more guess the descriptor than guess that seed. Any other secret gets a session set, with a fresh random key each time.
An open spec. SPEC.md and DESCRIPTOR.md are CC0. There are two implementations, in Go and in JavaScript, and both pass the same test vectors. This page runs the JavaScript one.
Compared with the alternatives
| Per plate | Rebuilt from | One plate shows | |
|---|---|---|---|
| shaQR | 1/k of the secret, plus 55 bytes | any k of n plates | its length |
| SLIP-39 Shamir | the whole secret | any k of n plates | nothing |
| BBQr parity | 1/k of the descriptor, plain or compressed | any k of n plates | on a data plate, its part in the clear |
| UR fountain | 1/k, plus a header per part | only some sets of k plates | pieces of the descriptor |
| BIP-138 | the whole secret, encrypted | one plate and one xpub | everything, to anyone with one xpub |
Shamir shares as long as the secret
SLIP-39 splits a seed this way. Each share is as long as the secret, and in return the secrecy is perfect. For the 3-of-5 descriptor above that is a version 20 code on every plate. The 10-of-20 does not fit one QR code at all.
BBQr parity parts
An earlier version of this page proposed them. They cut the descriptor into k data parts and add parity parts, so any k plates rebuild it. In plain mode the data plates keep the descriptor readable. For the 3-of-5 descriptor above, a compressed part is 320 characters, a version 9 code, against shaQR's 493 and version 12. A part carries an 8-character header where a shaQR share carries 55 bytes of key, id, check and header, and shaQR compresses nothing. In hex, the mode a pen and a table can read, a part is 532 characters and version 12, the same version as shaQR's.
They carry no key, no check and no set id. A data plate holds its part of the descriptor in the clear. Damage to a part shows only after the whole descriptor is rebuilt, and nothing ties the parts of one set to each other.
UR fountain codes
On a screen, a fountain code keeps sending parts until the receiver has enough. On steel the set of plates is fixed. A fountain part is an XOR of slices chosen by a pseudo-random mixer, and decoding works only if the parts at hand happen to peel.
A fixed set of plates would need parts of which every k decode. XOR mixes of k fragments give only 2k − 1 distinct parts, and a set in which every k of them are independent has at most k + 1 members: the k fragments and their XOR. One part per plate therefore gives only n-of-n and (n−1)-of-n. A code in which every k of n parts decode is what Reed-Solomon gives, and it is the code shaQR spreads the ciphertext with.
A key derived from the xpubs
BIP-138 encrypts a descriptor under a key derived from its own public keys, so any cosigner opens it with an xpub and no other secret. That keeps the backup simple: one plate, one xpub. It also means anyone who ever held one of the xpubs can open it: a coordinator, a watch-only wallet, a laptop that once imported a key.
A shaQR set opens with k plates. For a descriptor backup the key also follows from the whole descriptor, which only someone who already has every xpub could supply. One xpub opens nothing.
Links
- Spec: shaQR, SPEC.md
- Profile: descriptor backups, DESCRIPTOR.md
- Code: Go package and the descbackup tool
- Code: JavaScript module
- Test vectors
- Paper: Krawczyk, Secret Sharing Made Short, CRYPTO 1993
- BIP-138: Compact Encryption Scheme for Non-seed Wallet Data
- Earlier proposal: BBQr parity parts
- SeedHammer: the original project
- SeedHammer: steel engraving