Skip to content

Recover EncryptedMasterSecrets from arbitrary sequences of Mnemonics - #51

Open
pjkundert wants to merge 22 commits into
trezor:masterfrom
pjkundert:feature/group_ems_mnemonics
Open

pjkundert wants to merge 22 commits into
trezor:masterfrom
pjkundert:feature/group_ems_mnemonics

Conversation

@pjkundert

@pjkundert pjkundert commented Nov 15, 2024

Copy link
Copy Markdown

Recovering SLIP-39 EncryptedMasterSecrets from (possibly corrupted or otherwise attacked) sets of Mnemonics is the sole purpose of the SLIP-39 standard.

Verifying, grouping and vetting sets of mnemonics requires at least partial decoding of the mnemonic to extract identifier, extendable flag, group counts, thresholds, etc., so that only compatible mnemonics are considered. This is difficult to do "externally" to the SLIP-39 implementation.

Therefore, a robust API to recover one or more SLIP-39-encoded encrypted master secrets from a pool of collected mnemonics is not just useful, but critical to the proper operation of a SLIP-39 based recovery system.

Thus: I propose shamir_mnemonic.group_ems_mnemonics, which takes a sequence of Mnemonics (as either str or Share), and produces a sequence of EncryptedMasterSecrets and a dict of group indices and the list of Mnemonics used to recover the secret. It does so in a manner resilient to various corruptions or attacks, ignoring invalid, unrelated/incompatible or redundant Mnemonics.

Fixes #44

Furthermore, group_ems_mnemonics provides the ability to optionally expand 1 or more groups with additional mnemonics, or even replace a failed mnemonic group with a single-Share mnemonic. This allows recovery from SLIP-39 group failures (too many lost mnemonics), by:

  • recovering the group using existing mnemonics (if sufficient) and re-generating the missing ones, or
  • producing new ones compatible with the existing mnemonics to issue to new group participants, or
  • replacing (or augmenting) the failed group with a new single-Share (1 of 1) mnemonic for the group.

All of these approaches are supported by the existing underlying cryptography of SLIP-39, assume no new extensions to the protocol, and will work with any set of existing SLIP-39 mnemonics.

@andrewkozlik
andrewkozlik requested a review from matejcik July 29, 2025 10:57
pjkundert added a commit to pjkundert/python-shamir-mnemonic that referenced this pull request Aug 26, 2026
Rewrite the ceremony checklists onto the public group_one_mnemonics API:
C1 lost-card and C2 revealed-card are single group-local calls (C2 gains a
READ THE REPORT step for the revocation's destruction requirement), C3 puts
the resize in the same call, C4 composes the two public APIs to rebuild a
lost group's full structure, C6 notes that revoke on a threshold-1 group is
refused with an escalation pointer here.

Add 'Structural notes for whoever carries this on': the two-level Shamir
structure (groups as points on the master polynomial, members as points on
per-group polynomials, threshold points determine the WHOLE polynomial);
what the digest verifies and at which level; which metadata must be pinned
for cross-group compatibility and why; regenerate-identical vs re-randomize
and their different security consequences; augment vs revoke as identical
cryptography with different organizational commitments; and the per-API
RAM-reconstruction hazard windows.

Replace the PR trezor#51 gaps section with the two-API surface (group_ems owns
master-quorum ceremonies, group_one owns single-group ones), the shared
internals both consume, the status of the four gaps (all closed, one by
composition), and the remaining open items (CLI surface; unknowable original
member count; C5/C6 are master-level by construction).  Update the test map
for the 7 new API-surface tests.
pjkundert added a commit to pjkundert/python-shamir-mnemonic that referenced this pull request Aug 26, 2026
Rewrite the ceremony checklists onto the public group_one_mnemonics API:
C1 lost-card and C2 revealed-card are single group-local calls (C2 gains a
READ THE REPORT step for the revocation's destruction requirement), C3 puts
the resize in the same call, C4 composes the two public APIs to rebuild a
lost group's full structure, C6 notes that revoke on a threshold-1 group is
refused with an escalation pointer here.

Add 'Structural notes for whoever carries this on': the two-level Shamir
structure (groups as points on the master polynomial, members as points on
per-group polynomials, threshold points determine the WHOLE polynomial);
what the digest verifies and at which level; which metadata must be pinned
for cross-group compatibility and why; regenerate-identical vs re-randomize
and their different security consequences; augment vs revoke as identical
cryptography with different organizational commitments; and the per-API
RAM-reconstruction hazard windows.

Replace the PR trezor#51 gaps section with the two-API surface (group_ems owns
master-quorum ceremonies, group_one owns single-group ones), the shared
internals both consume, the status of the four gaps (all closed, one by
composition), and the remaining open items (CLI surface; unknowable original
member count; C5/C6 are master-level by construction).  Update the test map
for the 7 new API-surface tests.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Group member check seems too restrictive when combining mnemonics

1 participant