Skip to content

Watch-only public key derivation for third-party apps (so read-only apps don't have to ask for a seed phrase) #18

Description

@tobyjaguar

Environment: Foundation SDK 1.0.0 (foundation 1.0.0 (039881500da0)), KeyOS 1.4.0-beta3, retail Passport Prime, third-party publisher.

Summary

A third-party app currently has no way to learn any address derived from the device's master seed. That forces read-only "show me my assets" apps into one of two bad options, and I'd like to propose a third that gives them what they need without giving them signing power.

The gap, as gated today

message gating third-party
GetSeed (id 6) ungrouped — so Foundation-only despite approval = "autoAllow"
GetAppSeed (id 8) device-secrets.app-scoped-seed, grantOnFirstUse

GetAppSeed is the right primitive for an app's own secrets, and I'm using it happily elsewhere. But it is hmac256(app_id, master_seed) — a different key. The addresses it derives hold none of the user's assets, so it cannot answer "what does this user own?".

That leaves a read-only app two choices, and both are bad:

  1. Ask the user to type an address. 42 hex characters on a touchscreen, per address, and it has to be re-entered on every device.
  2. Ask the user to type their seed phrase. This is the one I want to argue against, and it's why I'm filing rather than just building it. On a device whose entire purpose is that the seed never leaves it, a third-party app prompting for the seed is the exact phishing pattern the product exists to defeat — and worse, "this app cannot sign" would be a promise rather than a property. Any app holding seed bytes can sign; nothing structurally prevents it. I don't want to ship that, and I don't think you want third-party apps on Prime training users to do it.

What I'd like

A watch-only public derivation message — public keys only, no private material, no signing:

DerivePublicKey { path: "m/44'/60'/0'/0/0" } -> compressed pubkey (33 bytes)

or an extended-public-key form (GetXpub { path }) if that's a better fit for how the seed is held, so an app can derive a range of addresses itself without a round trip per index.

Gated exactly like GetAppSeed: a permissionGroup (something like device-secrets.watch-only-derivation) plus grantOnFirstUse, so the user sees and consents to a distinct prompt.

Why this shape

  • No private key material crosses the boundary. The seed stays in os/security; the app receives public keys it could have derived from an xpub anyway.
  • "Cannot sign" becomes a structural property, not something the app promises. That's the whole point — it's the difference between a design I'd ship and one I won't.
  • It's the familiar watch-only pattern. Exporting an xpub to a watch-only wallet is well-understood in Bitcoin tooling; this is the same idea, and the privacy trade-off (an xpub reveals a whole address range) is one users and reviewers already reason about. Per-path DerivePublicKey is the tighter variant if you'd rather not hand out an xpub at all.
  • It's strictly weaker than something you already grant. GetAppSeed hands third-party apps real secret material behind a group and a consent prompt. This asks for public keys behind the same machinery.

Concrete use case

passport-nft-viewer — an offline, read-only NFT gallery (public repo, gui-app + removable-read only, no crypto permissions at all today). Images are fetched host-side and staged onto a USB drive; the device only reads files. The one thing it cannot do is know which addresses to show without the user typing them. With watch-only derivation it becomes "your Passport's own assets" with no address entry and no key exposure.

What I'm explicitly not asking for

Not GetSeed, and not a third-party signing path. If the answer is "public derivation is fine but only for Foundation-signed apps", that's useful to know too — I'd rather design against a clear no than guess.

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

    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