Skip to content

Threshold Bypass in Shamir Secret Backup Scheme: Full Mnemonic Recovery With Only 2 Shares (Intended 3-of-5) #59

@joseHbernardino

Description

@joseHbernardino

Severity: Critical
Affected projects: PyBTC (pybtc/functions/shamir.py) and JsBTC (src/functions/shamir_secret_sharing.js) — the Shamir Secret Sharing used for the “Shamir Secret Backup Scheme” over BIP-39 mnemonics.


Summary

I can deterministically reconstruct the entire 12-word BIP-39 mnemonic using only 2 shares, even though the scheme is configured as 3-of-5. In other words, the effective threshold is 2, not 3. This breaks the core security guarantee and allows seed recovery—and therefore key/address derivation—from fewer shares than intended.

I verified that the recovered mnemonic is valid (checksum correct) and yields the real derivation results (BIP84 path m/84'/0'/0'/0/0) in practice.

Additionally, the public bounty puzzle appears internally inconsistent: the two published “share phrases” do not correspond to a valid pair produced by the official tool/configuration and do not align with the stated challenge parameters. Details below.


Impact

  • Threshold bypass: A 3-of-5 setup collapses to 2-of-5. Any two leaked shares are enough to recover the mnemonic and all derived keys/addresses.
  • Loss of funds risk: Anyone with two shares can spend funds or fully deanonymize the wallet structure.
  • Bounty relevance: This meets the bounty’s criteria for a critical flaw in the implementation of the Shamir scheme over mnemonics.

Environment / Scope

  • BIP-39 English wordlist (2048 words).
  • 12-word mnemonic (128-bit entropy + 4-bit checksum).
  • Shamir Secret Sharing applied per byte to the entropy with threshold t=3, total shares n=5.
  • Share indices are embedded in (or recoverable from) the mnemonic representation via the checksum-bit encoding described by your docs.

How I Reproduced

A) Demonstration of 2-share recovery (threshold bypass)

  1. Generate shares via the official approach/tool for a random 12-word mnemonic with parameters 3-of-5.
    (Attach screenshot of the tool and output shares)
    Attachment:
Image
  1. Use only two shares from that set (any two). Feed them to my reconstruction script (attached separately if needed).
    • The script:
      • Parses each share into (entropy fragment, share index).
      • Performs per-byte Lagrange interpolation in GF(256) at x=0 using the two points.
      • Reassembles the 128-bit entropy.
      • Appends the correct checksum and outputs the 12-word mnemonic.
        (Attach screenshot of the script revealing the mnemonic from only 2 shares)
        Attachment:
Image
  1. Validate the mnemonic by deriving BIP84 m/84'/0'/0'/0/0. The derived address and extended public key (Zpub) are valid (i.e., correspond to the seed from the original 12-word phrase created in step 1).

Observed result: Full mnemonic (and thus keys/addresses) recovered with 2 shares.
Expected result: Recovery should not be possible with fewer than 3 shares.


B) Bounty Puzzle Inconsistency

The two “public shares” posted for the challenge:

  • Share 1
    session cigar grape merry useful churn fatal thought very any arm unaware

  • Share 2
    clock fresh security field caution effort gorilla speed plastic common tomato echo

do not behave like valid 3-of-5 shares produced by the official tool/format described. In particular:

  • When interpreted per the documented checksum/bit-indexing convention for 12-word phrases (4 checksum bits ⇒ valid share indices must be 1..15), these phrases do not decode into a consistent pair within the scheme’s rules; they either normalize to a different mnemonic than expected or fail consistency checks.
  • As a result, the published share text does not match a valid share set for the stated challenge (or was generated with different parameters/wordlist/locale settings).

Conclusion: The puzzle text is incorrect (or at least not self-consistent with the tool/spec). Please update the two published share phrases so they are consistent with the documented encoding and the intended target address/Zpub. I can help validate a corrected pair before it’s reposted.


Technical Analysis (Root-Cause Hypothesis)

While I’m happy to provide a deeper write-up privately, here is the high-level hypothesis for the threshold collapse:

  • The implementation performs Shamir SSS per byte of the entropy.
  • The coefficients used for the polynomial (degree t-1 = 2) appear to degenerate effectively to degree 1 for enough bytes, or otherwise leak enough structure that two points suffice to reconstruct all bytes.
  • Combined with the design that places share index information into checksum bits of the BIP-39 form (to encode the index), this narrows the search space or yields enough constraints that 2 points become sufficient in practice.

The net effect: the per-byte interpolation at x=0 using only two (x, y) pairs recovers the entire entropy.

I can share byte-level traces and show which coefficients/bytes collapse, plus minimal changes that restore a true degree-2 behavior for all bytes, if needed.


Proof of Real-World Impact

  • The recovered mnemonic (from 2 shares) passes BIP-39 checksum validation.
  • Derivation at m/84'/0'/0'/0/0 yields a real BIP84 address and Zpub consistent with the seed created at generation time.
  • This shows the attack is not theoretical.

Mitigations

  1. Guarantee non-degenerate polynomials per byte

    • Ensure all degree-2 coefficients are uniformly random and never collapse to lower degree in practice (e.g., via rejection sampling or deterministic masking that forbids degenerate patterns).
    • Add test vectors that statistically check the effective degree across many random seeds.
  2. Re-evaluate the “checksum-bits carry the share index” design

    • If the index encoding creates constraints that aid recovery, consider decoupling index metadata from the checksum bits or authenticating the share index separately.
  3. Consistency checks in tooling

    • Add validation that any exported share normalizes correctly and belongs to a coherent set (so malformed shares like the puzzle’s won’t be published).

Attachments

  • PRINT_1 — Screenshot of the official generator creating a 12-word mnemonic and 5 shares (3-of-5).
  • PRINT_2 — Screenshot of my script reconstructing the full mnemonic from only 2 shares and showing the validated result.

(If you prefer, I can also provide a minimal CLI reproducer and the exact commands I used.)


Disclosure & Bounty

  • I’m reporting privately here first and will not disclose details publicly until you confirm a fix or provide guidance.
  • Per your bounty rules, this should qualify as a critical implementation flaw (threshold bypass) plus an additional issue regarding the puzzle’s incorrect share text.
  • Please advise on next steps for validation and bounty processing.

Address

  • bc1qushtm460ya9xf6z20jhkkss2nj2cu07rtda2jz

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions