The access rule
A canister on the Internet Computer derives a decryption key if and only if a public EVM balance meets a stated threshold. Nothing else participates.
A lock its operator cannot open is a lock its operator cannot close either.
What the access check does
Access checks run in canister dciac-uaaaa-aaaad-qlzuq-cai, deployed on the Internet Computer mainnet, written in Motoko. It accepts a signed request from a reader, verifies that the reader holds a sufficient balance on a public EVM chain, and — only then — derives a decryption key from the network’s own threshold material via VetKD.
There is no account, no password, and no session to steal. The entire authorisation model is a single eth_call to balanceOf (selector 0x70a08231) or ownerOf on a public contract.
The request lifecycle
- The reader signs an EIP-712 typed struct —
GateRequestV3in the current version:
GateRequestV3(address evmAddress, bytes transportPublicKey, uint256 epoch, uint256 nonce)
-
The canister recovers the signer via
secp256k1ecrecover(implemented in pure Motoko — no precompile available on ICP). -
The canister calls the target EVM chain through the
ic/evm_rpccanister, checking that the recovered address satisfies the threshold. -
If the balance is sufficient, VetKD derives key material under context
accessol_v3with the preimage:
SHA-256("accessol_v3:" + chain + ":" + token + ":" + threshold + ":" + effectiveEpoch)
- The derived ciphertext is returned to the caller’s
transportPublicKey. Only the reader’s local client can unwrap it.
Epochs and caching
The V3 derivation is scoped to an epoch of 2,592,000 seconds (30 days). Within one epoch, a single derivation unlocks an entire corpus published against the same (chain, token, threshold) tuple. This is the design’s central efficiency gain over V1, where every CID required a separate derivation and a separate balance check.
The canister maintains an approval cache keyed on (chain, token, threshold, epoch, wallet). A reader who has already proven balance in the current epoch can derive additional keys without a second eth_call. The cache entry expires at epoch rollover — 30 days, or immediately via evictExpiredApprovals (controller-only).
A zero threshold is a special case: it bypasses both the cache and the balance check, but still validates the epoch. This allows content to be gated by signature alone — useful for free-tier archives that want authentication without payment.
Why ICP
The access check needs three properties that conventional smart-contract platforms do not provide together:
- Threshold key derivation — VetKD is native to ICP’s subnet architecture. No Ethereum precompile offers this today.
- Outbound HTTPS calls — the canister must call EVM RPCs to check balances. ICP canisters can make HTTP outcalls; Ethereum contracts cannot.
- Sub-second query latency — a reader should not wait for block confirmation to learn whether they hold. ICP query calls return in ~200ms.
The tradeoff is a trust assumption on ICP subnet honesty. A supermajority of replicas colluding could reconstruct derived keys. The protocol accepts this because the economic cost of such collusion exceeds the value of any individual locked archive.
The contract surface
The canister exposes exactly ten Candid methods. No other IPC channel exists between surfaces.
| Method | Kind | Purpose |
|---|---|---|
requestDecryptionKey |
update | V1: per-CID derivation |
batchRequestDecryptionKey |
update | V1: up to 20 CIDs, N derivations |
requestDecryptionKeyV3 |
update | V3: epoch-scoped derivation |
batchRequestDecryptionKeyV3 |
update | V3: up to 20 CIDs, one derivation replicated |
getVetKDPublicKey |
query | Cached V1 public key |
getVetKDPublicKeyV3 |
query | Distinct V3 public key |
warmupVetKDPublicKey |
update | Populate V1 cache |
warmupVetKDPublicKeyV3 |
update | Populate V3 cache |
getCurrentEpoch |
query | floor(unix / 2_592_000) |
evictExpiredApprovals |
update | Controller-only janitor |
No frontend, no upload pipeline, no storage logic. The canister knows only how to derive — and only when the chain says it should.