Any of plates recover it.
On: encrypted plates. Fewer than k of them show nothing of the secret but its length. Off: open plates, 32 bytes smaller. Each one shows part of the secret.
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
A shaQR share is a Shamir share of a key and a parity part of the secret. shaQR encrypts the secret with ChaCha20 under a one-time 32-byte key, cuts the ciphertext into k parts and extends them to n with a Reed-Solomon code, so that any k parts rebuild it. It splits the key with Shamir's scheme, and share x carries key share x and part x. 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 and open sets, below, are the exceptions. A share is about 1/k of the secret plus 55 bytes.
For a descriptor, k and n default to the wallet's own quorum. Each cosigner can then keep one plate beside the seed, and whoever holds enough seeds to spend also holds enough plates to recover, so the backup is never weaker than the wallet.
The quorum of the plates can be changed. A 3-of-5 wallet can go on 2-of-3 plates where steel is short, or on more plates than it has keys. A plate carries the set tag, its number and the quorum, and no key, so who keeps which plate is up to the owner. Any group that has to recover the wallet needs k of them.
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.
Encrypted or open
The Encrypt switch on the Split tab picks the kind of set. SPEC.md calls the two kinds sealed and open.
Encrypted, the default, is the scheme above. Fewer than k plates show nothing of the secret but its length. A descriptor gets a derived set, and any other secret a session set.
Open leaves out the key and the encryption. A share is then the parity part alone, 32 bytes shorter, which for the descriptors below is one QR version. The first k plates hold slices of the secret in the clear, and the others hold mixes of it. Any k plates still rebuild it, the check still catches a damaged plate and the set id still stops a forged one. An open set is for data that must survive lost plates and need not stay private.
A finder of one open plate of a descriptor learns some of its xpubs, or parts of them, and that they belong to a multisig wallet. Below k plates the wallet's addresses stay hidden, since its script needs every key. This page refuses to cut an open set of anything that holds a private key, an xprv, a tprv, a zprv or a WIF key, or a key that starts like one.
Packed descriptors
A descriptor is mostly keys in base58 and paths in decimal. Before a descriptor is
split it is packed, as DESCRIPTOR.md describes. Each key origin, extended key, hex key
and /<0;1>/* becomes a binary token, and the checksum is dropped,
since unpacking computes it again. Every other character stays as it is. A key with
its origin and children is 142 characters of text and packs to 75 bytes, or 80 for the
first key, whose origin path is written out.
Packing is exact. A receiver unpacks the payload, packs the text again and rejects the payload when the bytes differ, so one wallet has one packed form and every tool cuts the same plates from it. For the wallets below it makes the shares about a third smaller, two or three QR versions.
Sizes
| Wallet | Descriptor, bytes | Packed, bytes | Encrypted plate | Open plate | Unpacked, encrypted | Shamir share |
|---|---|---|---|---|---|---|
| 2-of-3 | 457 | 252 | 298 · v9 | 246 · v8 | 462 · v11 | 424 · v11 |
| 3-of-5 | 743 | 404 | 312 · v9 | 261 · v8 | 493 · v12 | 667 · v14 |
| 10-of-20 | 2889 | 1545 | 342 · v10 | 291 · v9 | 558 · v13 | 2493 · v30 |
The wallets are wsh(sortedmulti(...)) of keys derived from seeds, with key
origins and /<0;1>/* children, each split at its own quorum, the
default. A plate cell gives the characters of
the share text and its QR version, in alphanumeric mode at error level L. The Shamir
share holds the packed descriptor and 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, and an open set, which has none, makes 34-byte shares.
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, or in an open set to the secret itself. 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 #7B63. 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, and
so does an open plate among encrypted ones.
Derived sets. A descriptor backup draws its key from the canonical descriptor and k, so the same wallet and k always cut 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 set has no key, so it too comes out the same every 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, encrypted | 1/k of the secret, plus 55 bytes | any k of n plates | its length |
| shaQR, open | 1/k of the secret, plus 23 bytes | any k of n plates | part of it in the clear, on every plate |
| 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, packed, that is a version 14 code on every plate, and for the 10-of-20 a version 30. As text the 3-of-5 needs version 20, and 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.
Compressed, a part comes out about as long as an encrypted shaQR share. For the 3-of-5 above a compressed data part is 320 characters and a parity part 328, both version 9 codes. An encrypted shaQR share of the packed descriptor is 312 characters, also version 9, and an open one 261 characters, version 8. For the 10-of-20 a compressed part is version 9, one below an encrypted shaQR share and level with an open one. A part carries an 8-character header where a shaQR share carries 55 bytes of key, id, check and header, or 23 in an open set. In hex, the mode a pen and a table can read, a data part of the 3-of-5 is 532 characters, version 12.
They carry no check and no set id. Damage to a part shows only after the whole descriptor is rebuilt, and nothing ties the parts of one set to each other. An open shaQR set shows as much as a BBQr set and carries both.
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 of shaQR's parity parts.
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.
An encrypted 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