Skip to content

feat(identity): seed phrases and switchable sub-identities #353

Description

@kNoAPP

Problem or Motivation

A MeshCore identity today is a 64-byte Ed25519 key that exists in exactly one
place: the radio's flash. Lose the radio and the identity is gone — every
contact's address book entry for you is dead, and there is no way back. The only
mitigation is the passphrase-encrypted backup file from #299, which requires the
user to have taken one before the loss.

There is also no way to hold more than one identity. A single operator who wants
a public persona for open channels, an admin persona for repeater work, and a
throwaway persona for a field exercise has to own three radios.

Cryptocurrency solved the first problem with seed phrases and the second with
hierarchical deterministic subkeys. Both map onto MeshCore.

Proposed Solution

Two capabilities, delivered in phases:

  1. Seed-born identities. Generate an identity from a BIP-39 phrase, write it
    to the radio, and let the user keep the phrase offline. A lost radio is then
    recoverable onto a replacement with the same public key — every peer's
    contact entry keeps working.
  2. Sub-identities. Derive N unlinkable personas from one phrase via
    SLIP-0010 hardened derivation, and let the user switch the live one.

Research findings that shape the work

All verified before filing — see the linked tickets for detail.

  • The firmware supports it, on by default. ENABLE_PRIVATE_KEY_IMPORT=1 and
    ENABLE_PRIVATE_KEY_EXPORT=1 are set in [arduino_base] in the firmware's
    platformio.ini, which every platform base and every board variant inherits.
    The flags are opt-out ("comment these out for more secure firmware").
  • The derivation is one-way. ed25519_create_keypair stores
    clamp(SHA-512(seed)) — the expanded key, not the seed. So seed → radio
    works and radio → seed does not. An identity the radio generated can never be
    given a phrase retroactively; the user must deliberately regenerate.
  • The derivation math is verified. SHA-512(seed) + clamp matches RFC 8032
    test vector 1, and the derived public key matches. The app can predict the
    public key client-side before writing it, which makes a verify step possible.
  • Only the keypair changes on import. CMD_IMPORT_PRIVATE_KEY calls
    saveMainIdentityresetContacts()loadContacts() and touches nothing
    else. Contacts, channels, node name, lat/lon and radio params all survive.
    This is why a persona is more than a key — see the persona-blob ticket.
  • Contacts survive but go dead. Peers still hold the old public key, so
    their ECDH secret no longer matches. The contact list looks full and nothing
    works until every peer re-adds you.
  • MAX_CONTACTS is 100, so a full contact swap is ~6-20s over BLE — slow
    enough to need progress and cancel, not slow enough to rule out per-persona
    contact sets.
  • No upstream work exists. Zero results across issues, PRs and Discussions
    for mnemonic / seed phrase / bip39 / sub identity. We would be first.

Phases

Phase 0 — foundations. Hardware verification, the missing client wrappers,
a capability probe, and one real bug that blocks everything (preferences and
automation rules are lost across any public-key change).

Phase 1 — seed-born identity + recovery. The crypto core, a storage root
that no longer depends on public material, the vault, and the two user-facing
flows. Ships standalone value: recovery from paper.

Phase 2 — sub-identities. SLIP-0010 derivation, the persona blob, the switch
ceremony, and burner mode.

Phase 3 — persona hygiene. Making the live persona unmistakable.

Scope guards

  • Fully client-side. No backend, no change to output: 'export'.
  • One new dependency (@noble/ed25519) — WebCrypto cannot derive an Ed25519
    public key from an imported private key.
  • The seed vault is a documented exception to the per-radio encryption rule
    in AGENTS.md; that file is amended as part of the vault ticket.

Tickets

Phase 0 — foundations

Phase 1 — seed-born identity + recovery

Phase 2 — sub-identities

Phase 3 — persona hygiene

Ordering notes

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions