This repo contains a NEAR contract (email-dkim-verifier-contract) that uses OutLayer to run a WASI worker in a TEE. The worker fetches DKIM DNS TXT records and verifies the DKIM signature inside the worker, returning a summarized VerificationResult back on‑chain.
Used for email-based account recovery for tatchi.xyz accounts; other contracts call this one as a stateless global verifier.
-
Run DKIM tests:
cd email-dkim-verifier-contract cargo test --features unit-testing # or just test
-
Configure environment:
cp env.example .env # edit .env to set CONTRACT_ID, NEAR_NETWORK_ID, keys, etc. -
Deploy / upgrade contract from repo root:
# dev (testnet, non-reproducible WASM) just deploy-dev just upgrade-dev # prod (reproducible WASM) just deploy just upgrade
For a fresh deploy to a new CONTRACT_ID (typical testnet setup):
cp env.example .env
# edit .env
just deploy-dev
just set-outlayer-contract
just set-secrets-owner
just set-outlayer-wasm
just set-outlayer-keysNotes:
- In WasmUrl mode, create
PROTECTED_OUTLAYER_WORKER_SK_SEED_HEX32under the WasmHash secrets scope for the worker hash you’re using (owner =SECRETS_OWNER_ID, profile =main).
After pushing a change to main:
- Wait for GitHub Actions to finish publishing the worker wasm bundle to R2 (workflow: “Publish Outlayer Worker (R2)”).
- Upgrade (or deploy) the contract:
just upgrade # existing contract # or: just deploy # new contract
- Set the Outlayer contract ID for your network:
just set-outlayer-contract
- Set which account “owns” the Outlayer secrets for this app:
just set-secrets-owner
- Point the contract at the latest worker build:
just set-outlayer-wasm
- Refresh the contract’s stored worker public key:
just set-outlayer-keys
The Outlayer worker is built and uploaded by CI. Each run uploads:
workers/email-dkim/<sha>.wasmworkers/email-dkim/<sha>.wasm.sha256workers/email-dkim/latest.wasmworkers/email-dkim/latest.wasm.sha256workers/email-dkim/latest.json(manifest with timestamp + commit)
To point the contract at a new worker build:
- Run:
This uses
just set-outlayer-wasm
OUTLAYER_WORKER_WASM_URLif set; otherwise it fetcheslatest.json. It downloads the wasm, computes SHA‑256, optionally verifies it against the.sha256file, and stores URL + hash in contract state.
The encrypted DKIM flow uses a KEM + AEAD scheme (X25519 + HKDF‑SHA256 + ChaCha20‑Poly1305). The worker derives a static X25519 keypair (sk_worker, pk_worker) from a protected seed:
PROTECTED_OUTLAYER_WORKER_SK_SEED_HEX32(private, protected): 64‑char hex string (32 bytes) stored as an Outlayer protected secret (“Hex 32 bytes (64 chars)”).sk_worker/pk_worker: derived inside the worker via HKDF‑SHA256 (info ="outlayer-email-dkim-x25519"). The private key never leaves the TEE.pk_workeris stored in contract state and exposed viaget_outlayer_encryption_public_key.
For local testing (outside Outlayer), the worker also accepts OUTLAYER_WORKER_SK_SEED_HEX32 with the same 64‑char hex seed.
- In the Outlayer Secrets Management page, create a protected secret
PROTECTED_OUTLAYER_WORKER_SK_SEED_HEX32with type "Hex 32 bytes (64 chars)". Outlayer will generate the value for you.
- Important: secrets are scoped to the worker code source:
- If you use
WasmUrlsource (URL+hash), create the secret under the WasmHash scope for the current worker WASM hash.
- If you use
- leave
Branchempty - set
profiletomain(or whatever is set inlib.rs:SECRETS_PROFILE = "main")
- Restart/redeploy the worker so it picks up the updated secret.
- Refresh the contract’s stored public key (owner‑only; triggers worker
get-public-key):just set-outlayer-keys # or: sh ./scripts/set_outlayer_keys.sh
If you want the secrets owner to be the contract account (common for Outlayer secrets), set it explicitly:
just set-secrets-owner
# or: sh ./scripts/set_secrets_owner_id.shAfter rotation:
- The worker decrypts using the new
sk_worker. - Relayers fetch the new
pk_workerviaget_outlayer_encryption_public_keyand encrypt to that key going forward.