Reference · OP Mainnet · updated 12 Oct 2026

CryoShield system map

How a secret goes from your browser to permanent storage and back, which pieces we run, and how code reaches production.

This page mirrors docs/system-design.md in the open-source repository.

Components and trust boundaries

CryoShield runs exactly one thing: a static website on Fly. Everything else is either on your device or third-party infrastructure that never sees a plaintext secret.

YOUR DEVICE THIRD-PARTY INFRASTRUCTURE PUBLIC AND PERMANENT Security keys (2+ YubiKeys) PRF secret + P-256 signer, UV required Web app (/app in browser) encrypts / decrypts locally AES-256-GCM, keys in memory only smart-account owner = each key cryoshield-recover (CLI) works if CryoShield is gone Fly.io · cryoshield.app static files only, the one thing we run Pimlico bundler + paymaster (we pay gas) Public RPCs 2+ must agree (recovery) Arweave gateway / Turbo free upload ≤105 KiB · GraphQL OP MAINNET (10) EntryPoint v0.6 CryoShield Smart Wallet VaultRegistry v2 no admin, no upgrades blob ≤1 KB · locator → vaultIds Arweave permaweb mirror tagged by vaultId + locator WebAuthn: PRF + signature serves HTML/JS signed userOp handleOps validates key signature createVault / updateVault eth_call reads mirror upload stores eth_call + logs GraphQL by tag CTAP2 hmac-secret over USB
Only the blue box is operated by CryoShield, and it serves static files. Writes go through Pimlico because we sponsor gas. Reads, unlocks and recovery never touch Pimlico or Fly: the recovery tool talks to the key over USB and reads the chain or Arweave directly.

From one key tap to your secret

Each tap returns one 32-byte PRF output for a fixed salt. Two separate keys are derived from it: one is public (the lookup), one never leaves memory (the wrap key).

PRF output 32 bytes, UV required HKDF-SHA256 info cryoshield/v1/locator HKDF-SHA256 salt = vault wrapSalt Locator bytes32, public Wrap key memory only, wiped Data key unwrapped Your secrets decrypted locally resolveLocator → vaultIds try each; keep the one that authenticates AES-GCM AES-GCM AAD binds the vault header and the 32-byte vaultId, so a copied blob fails anywhere else
Symmetric primitives only, so the ciphertext that sits in public forever has no elliptic-curve layer for a future quantum computer to strip. Every enrolled key holds its own wrapped copy of the data key: losing one key loses nothing, losing every key loses the vault.

What each flow touches

Create a vault

  1. Tap key 1, then key 2. Each creates a discoverable credential and returns its PRF output; their P-256 public keys become smart-account owners.
  2. The browser picks a random vaultId, encrypts the secret and wraps the data key once per key.
  3. One more tap signs the userOp. Pimlico sponsors it and EntryPoint calls createVault.
  4. The same blob is uploaded to Arweave with CryoShield-Vault-Id and CryoShield-Locator tags.

Unlock or recover

  1. Tap any enrolled key once. The PRF output gives the locator and, after the lookup, the wrap key.
  2. resolveLocator over public RPCs returns candidate vaultIds. No account and no gas needed.
  3. Each candidate is tried; only the genuine vault authenticates, so clones and junk are skipped.
  4. The recovery CLI does the same over USB, falls back to Arweave, and checks copies against the latest on-chain event hash.

How code reaches cryoshield.app

Nothing reaches main or production without a spec, a pull request and a green ci-ok. There is no bypass, including for admins.

OpenSpec change proposal → tasks Branch + PR feat/ fix/ ci/ docs/ pr-checks title · spec gate · gitleaks · osv Area jobs contracts · crypto · web · e2e · recover ci-ok required main squash only Fly deploy.sh clean tree · 2 identical builds · RP ID = host
Each deploy writes a release manifest with the commit and a deterministic tree hash, so anyone can rebuild the site and compare it with what Fly serves.

Live reference values

NetworkOP Mainnet, chain 10
VaultRegistry v20xA622c92d3D5b54aeA081Cf410224a8A2eCb08cB7
VaultRegistry v1none on this network
Deploy block158114294
Smart accountCryoShield Smart Wallet (Coinbase Smart Wallet v1.1 code that also requires the key's PIN and this RP ID on every signature) on EntryPoint v0.6, P-256 precompile at 0x100
Account factory0x775dc816594262274E78Ae75D97C8EdB0df5DfED
Account implementation0x8aA76FaA6629cA1EA8ccC3F9Edf0E8D98816Acd7
WebAuthn RP IDcryoshield.app (permanent)
HostingFly app cryoshield-web, org cryoshield, region sin; DNSSEC and CAA on
Vault limitsblob ≤ 1024 bytes · 2–8 keys · v2: vault ID derived from the owner account, no per-locator cap, paged lookups (v1: 16 vaults per locator)
Sourcegithub.com/prix0007/cryoshield (MIT, public)