Mechanics

Three keys.
None of them leave you.

Cenotaph replaces the master password with two hardware-bound factors you already carry. Together they derive a single cryptographic key that seals and unseals everything.
1

Wallet signature

When you unlock, the extension asks your wallet (MetaMask, Rainbow, or any EVM wallet) to sign a fixed, human-readable challenge string. This isn't a transaction — no gas, no on-chain footprint. The resulting 65-byte personal_sign signature becomes half of your master key material.

Because the signature is deterministic for a given private key + message, you get the same output every time. Move to a new device, import your seed phrase, sign the same challenge — identical result.


2

Passkey PRF

Next, the extension triggers a WebAuthn authentication with the prf extension. Your OS prompts for Touch ID, Face ID, or a hardware security key. The authenticator returns a 32-byte pseudo-random output bound to the credential and a salt we provide.

This is the second half. It never leaves the secure enclave — no server sees it, no JavaScript can extract it, and it can't be phished because WebAuthn enforces origin binding.


3

Key derivation

The two halves meet inside the background service worker. HKDF-SHA256(walletSignature, passkeyPRF) produces your 32-byte master key. A second HKDF pass derives a domain-ID salt used to hash site identifiers before they hit the chain.

The master key lives only in the service worker's memory. When Chrome suspends the worker (or you lock the vault), it's gone. Session persistence uses chrome.storage.session — encrypted, scoped to the browser profile, wiped on exit.


4

Per-entry encryption

Each password entry gets its own AES-GCM key derived from masterKey + domainHash + version. The plaintext (username, password, notes) is encrypted into an opaque envelope, then written to the smart contract as raw bytes keyed by the domain hash.

Rotating a single entry doesn't re-encrypt the vault — only that entry's version increments, producing a new per-entry key. The rest of your data is untouched.


5

Recovery

Optionally, you can set a BIP-39 recovery phrase. The extension wraps your master key with AES-GCM(HKDF(mnemonic, walletSig)) and writes the wrapped blob on-chain via setRecoveryWrap. If you lose your passkey, you can restore with phrase + wallet.

The recovery phrase itself is never stored anywhere — not on chain, not in the extension. You write it down, like a seed phrase.

Cenotaph

A vault with no secrets to steal.

Install for Chromium