Skip to content

proof-of-concept(wallet): opt in to kv-store encryption-at-rest#18

Open
mverzilli wants to merge 1 commit intomartin/sqlite-opfs-wiringfrom
martin/sqlite-opfs-encryption-at-rest
Open

proof-of-concept(wallet): opt in to kv-store encryption-at-rest#18
mverzilli wants to merge 1 commit intomartin/sqlite-opfs-wiringfrom
martin/sqlite-opfs-encryption-at-rest

Conversation

@mverzilli
Copy link
Copy Markdown
Contributor

Wires the new AesGcmCipher from @aztec/kv-store/sqlite-opfs into the PXE + walletDB stores. A 32-byte master seed is generated once and persisted in localStorage under aztec-kv-cipher-seed-v1; subsequent loads reuse it so the encrypted OPFS data remains readable across reloads.

Changes

  • walletService.ts: build a shared AesGcmCipher (RawKeyProvider over the persisted seed) and pass it to both AztecSQLiteOPFSStore.open calls. The wallet + PXE get the same HKDF-derived sub-keys.
  • walletService.ts: VITE_KV_ENCRYPT=0 (or "false") disables the cipher — useful for A/B diagnosis and as a safety escape hatch. Default is on.
  • walletService.ts: registerSqliteInspectors runs BEFORE EmbeddedWallet.create so the DevTools helpers are reachable even if wallet init hangs or throws.
  • sqliteInspector.ts: new peekEncryption() reports per-container valueEncrypted / keyLooksHmacd flags at a glance, so you can visually confirm the cipher is active and opaque-keys containers actually HMAC their keys on disk. Fixed summarize()'s reliance on SQLite's rowid — the data table is WITHOUT ROWID, so the old query syntax failed.

Key provider caveat
This is a dev-grade key source: the seed survives page reloads (localStorage) but not device loss or same-origin XSS. A proper IndexedDB-backed unextractable CryptoKey provider — or WebAuthn-PRF — is follow-up work.

Validated end-to-end
Ran a full swap + claim on testnet with encryption on, then confirmed via peekEncryption() that every audit-flagged container is HMAC'd (32-byte keys): map:notes, map:note_nullifiers_by_contract, map:note_block_number_to_nullifier, map:pending_indexes, map:last_finalized_indexes, map:highest_aged_index, map:highest_finalized_index, map:complete_address_index, map:accounts, map:account_aliases. All 22 populated containers show valueEncrypted: true.

Depends on aztec-packages martin/sqlite-with-encryption-at-rest (PR AztecProtocol/aztec-packages#22683).

Wires the new AesGcmCipher from @aztec/kv-store/sqlite-opfs into the PXE +
walletDB stores. A 32-byte master seed is generated once and persisted in
localStorage under `aztec-kv-cipher-seed-v1`; subsequent loads reuse it so
the encrypted OPFS data remains readable across reloads.

Changes
- walletService.ts: build a shared AesGcmCipher (RawKeyProvider over the
  persisted seed) and pass it to both AztecSQLiteOPFSStore.open calls. The
  wallet + PXE get the same HKDF-derived sub-keys.
- walletService.ts: VITE_KV_ENCRYPT=0 (or "false") disables the cipher —
  useful for A/B diagnosis and as a safety escape hatch. Default is on.
- walletService.ts: registerSqliteInspectors runs BEFORE EmbeddedWallet.create
  so the DevTools helpers are reachable even if wallet init hangs or throws.
- sqliteInspector.ts: new peekEncryption() reports per-container
  valueEncrypted / keyLooksHmacd flags at a glance, so you can visually
  confirm the cipher is active and opaque-keys containers actually HMAC
  their keys on disk. Fixed summarize()'s reliance on SQLite's `rowid` —
  the data table is WITHOUT ROWID, so the old query syntax failed.

Key provider caveat
This is a dev-grade key source: the seed survives page reloads (localStorage)
but not device loss or same-origin XSS. A proper IndexedDB-backed unextractable
CryptoKey provider — or WebAuthn-PRF — is follow-up work.

Validated end-to-end
Ran a full swap + claim on testnet with encryption on, then confirmed via
peekEncryption() that every audit-flagged container is HMAC'd (32-byte keys):
map:notes, map:note_nullifiers_by_contract, map:note_block_number_to_nullifier,
map:pending_indexes, map:last_finalized_indexes, map:highest_aged_index,
map:highest_finalized_index, map:complete_address_index, map:accounts,
map:account_aliases. All 22 populated containers show valueEncrypted: true.

Depends on aztec-packages martin/sqlite-with-encryption-at-rest
(PR AztecProtocol/aztec-packages#22683).

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
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