kanmanimonad mainnet · 143

Account

One passkey ceremony gives three independent keys: the account you sign in with, the identity that signs verification receipts and the key that encrypts anything private. Nothing is stored on this device and nothing secret reaches the server, so clearing local storage loses nothing and a second device reproduces the same keys exactly.

Creating is one prompt on most authenticators. On ones that do not evaluate PRF during creation it is two, because a second assertion has to run. That depends on your authenticator rather than on this site, so it is stated rather than promised. Signing in afterwards is always exactly one.

what this site has stored about you

Live readout of this origin, not a claim. Clear it and nothing here changes, because nothing about your identity was ever in it.

reading

localStorage

reading

sessionStorage

reading

cookies

The passkey is created as a discoverable credential, so the browser offers it with nothing from us. There is no cached credential ID and no returning-user path, which is why there is no returning-user path that can break. Sign in on a second device and the address above will be identical, because it is a deterministic function of the PRF output and nothing else.

how the three keys are derived

One WebAuthn assertion returns a 32-byte PRF output. That output is run through HKDF-SHA256 with a distinct info string per key, so the three are independent: holding one tells you nothing about the others.

prfOutput  = getPasskeyPrfOutput({ rpId })        one ceremony, one prompt

account    = HKDF(prfOutput, info="kanmani.iris.v1")       -> secp256k1 -> EVM address
attestation= HKDF(prfOutput, info="kanmani.optic.v1")      -> ed25519   -> signs receipts
content    = HKDF(prfOutput, info="kanmani.vitreous.v1")   -> AES-256-GCM key

The honest limit: HKDF makes the three keys independent of each other, not independent of the PRF output. Anyone holding those 32 bytes holds all three. That is equally true of deriving from three separate salts, at a different point in the flow and saying so beats implying a compartmentalisation that does not exist.

A salt costs a ceremony and a ceremony costs a prompt. Three namespaces as three salts would be three prompts. Category Labs, who build Mera, confirmed on 2026-09-18 that HKDF namespacing counts as genuinely namespaced. It is also their own pattern: Mera's secret vault derives its AES key from the same PRF output with fixed HKDF info, explicitly so it is separated from other keys derived from that output.

authenticators, tested rather than assumed

PRF is not universal and you pick the authenticator, not us. Published here so nothing about this is a surprise mid-demo.

authenticatorwhereprf
Google Password ManagerChrome, Edgeyes
iCloud KeychainmacOS 15+, iOS 18+yes
1Passwordextension and appyes
Windows Password ManagerWindows 11 25H2+yes
YubiKey 5C Nanohardwareyes
Proton Passextensionyes
Chrome local profileno Google Password Managerno
Bitwardenextensionno
Dashlaneextensionno

On desktop Chrome only passkeys saved to Google Password Manager carry PRF, because the local profile authenticator lacks hmac-secret. A password-manager extension that intercepts WebAuthn can produce a passkey that exists and returns no PRF output at all. When that happens this page names the cause and the fix rather than throwing.

what the server never gets

  • no session cookie carrying authority. A cookie may cache. It may never authorise.
  • no private key, ever. All three are derived in the tab and stay there.
  • no credential ID cached anywhere. The passkey is discoverable, so the browser offers it unprompted.
  • no recovery path. Losing the passkey loses the keys. Said plainly rather than implying a recovery that does not exist.

A database breach here exposes no key material, because there is none to expose. That is a stronger property than most applications have and it falls out of the constraint rather than being bolted on. How the rest of it is decided →