Files
mantra-kmp/docs
Kgothatso Ngako 670f87a609 docs: record what phase 3 turned out to require
Phase 3 is implemented in the fork on claude/jvm-target-actuals (ce49657).
The security analysis in the plan held up; three practical constraints
around it did not appear until the code was written.

**A passphrase-derived KEK is not a drop-in.** The plan treated the choice
between a passphrase, an OS keychain and a key file as the whole decision.
But keyStoreEncryption(keyName, plainText) takes no context and no secret
-- on android the OS holds the key, so none is needed -- which means any
passphrase scheme needs an out-of-band unlock the expect cannot express.
That is a change to application startup, not just to the actual, so it is
now called out against phase 5: the desktop entry point has to prompt and
unlock before the wallet starts.

**The iv must be 16 bytes.** EncryptedSeed.V2.serialize in commonMain
throws on anything else, which rules out a conventional 96-bit GCM nonce
-- worth knowing before designing around one. It turns out to help: with
randomly generated nonces the risk is a repeat under one key, and 128 bits
makes that vanishingly unlikely where 96 merely makes it unlikely.

**Argon2id costs a dependency.** The jdk has PBKDF2 and no memory-hard
KDF at all, so it means bouncycastle. Recorded with the reason to pay it:
if the build is dev-only because it lacks hardware backing, weakening the
KDF too gets the trade backwards.

Also recorded: wrap a per-name data key under the KEK rather than
encrypting the seed with it directly, so a passphrase change rewraps 32
bytes; throw java.security.KeyStoreException when locked, since the
graceful* wrappers already map it to
DecryptSeedResult.Failure.KeyStoreFailure; and a verification section
naming the properties that fail quietly, plus the two limits worth writing
down rather than fixing -- the first unlock on a new store accepts any
passphrase, and zeroing the key is best effort.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-06 01:13:07 +02:00
..

mantra docs

Notes on the parts of this app whose behaviour is not recoverable by reading the code alone — where the reasoning lives in a protocol, a failure mode that is silent, or a decision that looked arbitrary and was not.

document covers
shared-key-ceremony.md ChillDKG over NIP-17: the rounds, the approval gates, the chat transcript, participant ordering
shared-key-derivation.md deriving further keys from the group's threshold key with FROST tweaks — why not BIP32, why no chain code, and the one rule that must not be broken
marmot-membership.md how members join an MLS group, and the epoch race that makes a missing member look like a successful invite
mls-skipped-keys.md why a group event that arrives a moment late is dropped for good, which flows trigger it, the quartz fix, and the partial mitigation in this app
jvm-target.md what desktop support would cost, phased — why the native chain is already done, why an empty source set in our phoenix fork is the real blocker, and why DAO tests do not need any of it

Start with the ceremony if you are new to this area; the other two both assume it. Read the skipped-keys note before debugging any "the other device never got it" report — it is silent, and it looks like every other kind of delivery failure.