Key custody options
| Option | Posture | Trust |
|---|---|---|
| Platform keychain | Default | macOS Keychain, Windows Credential Manager, Gnome Keyring. OS-isolated. |
| Hardware wallet | Recommended for high-value | Ledger / Trezor. Requires physical confirmation per signature — not suitable for per-MB voucher signing at scale. |
| Safe (1-of-1 or multi-owner) | Recommended for high-value + high-frequency | Smart-account. Signs via ERC-1271. Holds a hot session key for voucher signing. |
| File-based key | Discouraged | Plaintext keys in filesystem leak to any process that reads your home directory. |
Why Safe is the recommended path
Vouchers are signed per MB. A 1 GiB download at 1 MB cadence requires 1024 signatures. You do not want to tap a hardware wallet 1024 times. Safe + session keys (ERC-7579smartsessions) give you:
- A long-lived owner key held in high-security storage (hardware wallet, platform keychain).
- A short-lived session key the Safe authorizes for a bounded window and bounded scope.
- Spending caps — session key can sign vouchers totalling at most X USDC.
- Selector scoping — session key can only sign this contract function (e.g., voucher EIP-712) for this channel.
- Time-bounded — session key auto-expires at T.
- Revocable — the owner can revoke the session key at any time on-chain.
Safe + session keys
- Signs only voucher-format EIP-712 payloads for the scoped channel.
- Expires at the configured time.
- Can be revoked early:
decdn client session revoke <id>.
SignatureChecker everywhere
All contract signature checks use OpenZeppelin’s SignatureChecker.isValidSignatureNow rather than ECDSA.recover. This means:
- EOA signatures (raw
ecrecover) — fully supported, ~5.6k gas. - ERC-1271 signatures (Safe, other smart accounts) — supported uniformly, ~12–15k gas.
- EIP-712 domains and voucher formats — unchanged regardless of wallet type.
counterparty field, from the NodeInfo binding, etc.) — it validates the signature against that address rather than recovering it from the signature.
Key rotation
- Session key — create a new one, revoke the old one. No protocol-level migration needed.
- Safe owner — use Safe’s native
swapOwnergovernance. All outstanding channels survive; the Safe address doesn’t change. - EOA key — create a new address, open new channels from it. Existing channels belong to the old address and settle to the old address on close.
Clients-side gas considerations
Every channel open and close is on-chain. At Arbitrum gas prices:openChannel: ~80–120k gascloseChannel(happy path): ~90k gasdisputeChannel: ~150k gas (rare)
What the CDN never sees
- Your Ethereum private keys — all signatures happen on-device.
- Your plaintext content for encrypted blobs — the app server delivers keys directly to you over
cdn/keys/v1(encryption). - Your OAuth / session tokens with the content provider — those exchange only with the provider’s app server.