1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-12-24 23:38:09 +00:00

core: add documentation for SLIP-39 handling in Trezor

This commit is contained in:
matejcik 2019-12-12 13:29:14 +01:00 committed by matejcik
parent 81a2476a45
commit f491239c26

105
docs/core/misc/slip0039.md Normal file
View File

@ -0,0 +1,105 @@
# Use of SLIP-39 in trezor-core
[SLIP-39](https://github.com/satoshilabs/slips/blob/master/slip-0039.md) describes a way
to securely back up a secret value using Shamir's Secret Sharing scheme.
The secret value, called a Master Secret (**MS**) in SLIP-39 terminology, is first
encrypted by a passphrase, producing an Encrypted Master Secret (**EMS**). The EMS is
then split into a number of shares, which are encoded as a set of mnemonic words.
Afterwards, it is possible to recombine some or all of the shares to obtain back the
EMS, and when the correct passphrase is provided, decrypt the original Master Secret.
This does not quite match Trezor's use of the "passphrase protection" feature, namely
that any passphrase is valid, and using any passphrase will yield a working wallet.
SLIP-39 enables this usage by specifying that passphrases are not validated in any way.
Decrypting an EMS with any passphrase will produce data usable as the Master Secret,
regardless of whether it is the original data or not.
## Seed handling in Trezor
Trezor stores a _mnemonic secret_ in a storage field `_MNEMONIC_SECRET`. This is the
input for the root node derivation process: `mnemonic.get_seed(passphrase)` takes the
user-provided passphrase as an argument, and derives the appropriate root node from the
mnemonic secret.
With BIP-39, the recovery phrase itself is the mnemonic secret. During device
initialization, the raw recovery phrase is given to the user, and also directly stored
in the `_MNEMONIC_SECRET` field. Whenever the root node is required, it is derived by
applying PBKDF2 to the mnemonic secret plus passphrase.
For SLIP-39 it is not practical to store the raw data of the recovery shares. During
device initialization, a random Encrypted Master Secret is generated and stored as
`_MNEMONIC_SECRET`. SLIP-39 encryption parameters (a random identifier and an iteration
exponent) are stored alongside the mnemonic secret in their own storage fields. Whenever
the root node is required, it is derived by "decrypting" the stored mnemonic secret with
the provided passphrase.
## SLIP-39 implementation
The [reference implementation](https://github.com/trezor/python-shamir-mnemonic) of
SLIP-39 provides the following high-level API:
* `generate_mnemonics(group parameters, master_secret, passphrase)`: Encrypt Master
Secret with the provided passphrase, and split into a number of shares defined via
the group parameters.
Implemented using the following:
- `encrypt(master_secret, passphrase, iteration_exponent, identifier)`: Encrypt the
Master Secret with the given passphrase and parameters.
- **`split_ems(group parameters, identifier, iteration_exponent, encrypted_master_secret)`**:
Split the encrypted secret and encode the metadata into a set of shares defined via
the group parameters.
* `combine_mnemonics(set of shares, passphrase)`: Combine the given set of shares to
reconstruct the secret, then decrypt it with the provided passphrase.
Implemented using the following:
- **`recover_ems(set of shares)`**: Combine the given set of shares to obtain the
encrypted master secret, identifier and iteration exponent.
- **`decrypt(encrypted_master_secret, passphrase, iteration_exponent, identifier)`**:
Decrypt the secret with the given passphrase and parameters, to obtain the original
Master Secret.
Only the functions denoted in **bold** are implemented in trezor-core. Recovery shares
are generated with `split_ems` and combined with `recover_ems`. Passphrase decryption is
done with `decrypt`. There is never an original "master secret" to be encrypted, so the
`encrypt` function is also omitted.
## Step-by-step
### Device initialization
This process does not use passphrase.
1. Generate the required number of random bits (128 or 256), and store as
`_MNEMONIC_SECRET`.
2. Generate a random identifier and store as `_SLIP39_IDENTIFIER`.
3. Store the default iteration exponent `1` as `_SLIP39_ITERATION_EXPONENT`.
4. The storage now contains all parameters required for seed derivation.
### Seed derivation
This is the only process that uses passphrase.
1. If passphrase is enabled, prompt user for passphrase. Otherwise use empty string.
2. Use `slip39.decrypt(_MNEMONIC_SECRET, passphrase, _SLIP39_ITERATION_EXPONENT, _SLIP39_IDENTIFIER)`
to "decrypt" the root node that matches the provided passphrase.
### Seed backup
This process does not use passphrase.
1. Prompt user for group parameters (number of groups, number of shares per group, etc.).
2. Use `slip39.split_ems(group parameters, _SLIP39_IDENTIFIER, _SLIP39_ITERATION_EXPONENT, _MNEMONIC_SECRET)` to split the secret into the given number of shares.
### Seed recovery
This process does not use passphrase.
1. Prompt the user to enter enough shares.
2. Use `slip39.recover_ems(shares)` to combine the shares and get metadata.
3. Store the Encrypted Master Secret as `_MNEMONIC_SECRET`.
4. Store the identifier as `_SLIP39_IDENTIFIER`.
5. Store the iteration exponent as `_SLIP39_ITERATION_EXPONENT`.
6. The storage now contains all parameters required for seed derivation.