Skip to content

Provision a locker with a mint's note subtree - #69

Merged
TheCryptoDonkey merged 1 commit into
mainfrom
feat/provision-vault-cash
Sep 6, 2026
Merged

Provision a locker with a mint's note subtree#69
TheCryptoDonkey merged 1 commit into
mainfrom
feat/provision-vault-cash

Conversation

@TheCryptoDonkey

Copy link
Copy Markdown
Member

The wallet half of forgesworn/heartwood-esp32#105..#108 and forgesworn/notelocker#1. A locker can now hold notes this seed phrase can find again.

LUD-25 derives note secrets under m/139'/d1/d2/d3/d4/i', but that path hangs off the BIP-32 master and a locker keeps no seed — it stores a tree root from a different branch, and the recovery phrase only ever exists on the owner's screen. So this wallet derives one mint's domain node and hands it over. Beneath that node only i' remains, which is why it works on hardware with no elliptic curve at all.

cashDomainNodeFor goes through mintEntry, not a raw string

Two reasons, both about things that fail silently:

  • The host is then spelled the way serverOf spells it. One byte of difference is a different tree, whose notes neither side can see.
  • A mint this wallet does not track is one whose counter it cannot keep in step with the device's — which is how an index gets handed out twice, and two notes end up answering to one k1.

It returns the next index alongside the node, so the device can be raised to meet this wallet rather than re-issuing a secret already minted at.

device-node needs --force, and the refusal says why

This is the only command that prints key material the holder did not ask to spend, and unlike a note it is not bounded by an amount: whoever reads it can derive every note this wallet ever mints at that mint, forever, with no way to revoke.

The warning goes to stderr and the node to stdout, so a deliberate pipe still works.

Also

VaultClient gains provisionCashNode (gated — it waits on the button), forgetCashNode, listCashMints and setCashIndex. newSecret/newSecretPair take an optional host and derive when given one; the device refuses a host it has no subtree for rather than quietly drawing at random, which is the answer this wallet wants.

328 tests.

The wallet half. A locker can now hold notes this seed phrase can find again.

LUD-25 derives note secrets under m/139'/d1/d2/d3/d4/i', but that path hangs
off the BIP-32 master and a locker keeps no seed: it stores a tree root from a
different branch, and the recovery phrase only ever exists on the owner's
screen. So this wallet derives one mint's domain node and hands it over.
Beneath that node only i' remains, which is why it works on hardware with no
elliptic curve at all.

cashDomainNodeFor goes through mintEntry rather than taking a raw string, for
two reasons. The host is then spelled the way serverOf spells it, and one byte
of difference is a different tree whose notes neither side can see. And a mint
this wallet does not track is one whose counter it cannot keep in step with
the device's, which is how an index gets handed out twice. It returns the next
index alongside the node so the device can be raised to meet this wallet
rather than re-issuing a secret already minted at.

device-node needs --force, and the refusal says why rather than being coy.
This is the only command that prints key material the holder did not ask to
spend, and unlike a note it is not bounded by an amount: whoever reads it can
derive every note this wallet ever mints at that mint, forever, with no way to
revoke. The warning goes to stderr and the node to stdout, so a deliberate
pipe still works.

328 tests.
@TheCryptoDonkey
TheCryptoDonkey merged commit f177c0d into main Sep 6, 2026
2 checks passed
@TheCryptoDonkey
TheCryptoDonkey deleted the feat/provision-vault-cash branch September 6, 2026 11:53
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.

1 participant