Inspiration
AI on sensitive data hits a regulatory triple-bind. The EU AI Act (high-risk enforcement begins August 2026) mandates per-inference audit logs that an independent party can verify. GDPR / HIPAA / CCPA forbid those logs from retaining PII. And US courts only treat digital records as self-authenticating evidence when they're cryptographically signed (Federal Rules of Evidence 902(14)).
Today's logging satisfies none of these. Vendor-attested logs don't meet the EU AI Act's independent-verifiability bar. Plain-text storage breaks GDPR. Centralised logs require forensic experts to admit in court. Yet AI keeps shipping into compliance-critical workflows — robo-advisors, medical triage, customer support touching PII.
WITNESS is the protocol layer that closes the gap.
What it does
WITNESS turns every AI inference into a zero-knowledge receipt: cryptographic proof that the output satisfied a user-defined policy, with content kept encrypted until the user chooses to reveal it.
- Sign once, in your wallet. Users register output policies as Compact circuits — "AI must keep risk_score ≤ 50", "AI must not say bitcoin or leverage". Commitments live on Midnight; thresholds and keywords stay private.
- Every AI call mints receipts. The SDK extracts deterministic features from the response, generates ZK proofs that features satisfy each active policy, encrypts the request + response with a fresh AES-256-GCM key, and posts one receipt per passing policy to Midnight.
- Selective disclosure on demand. Owner clicks Reveal on a receipt. Auditor opens
/verify#<token>— no wallet needed. Three badges render: receipt exists on Midnight, SHA-256(plaintext) matches the on-chain commit, owner revealed on-chain (or amber if off-chain link only). The AES key travels in the URL fragment and never reaches a server.
How we built it
- Compact contract (Compact 0.23, compactc 0.31) — three exported circuits:
register_policy,submit_receipt,reveal_receipt.reveal_receiptis owner-only — checks the policy's stored owner pk against the caller's derived pk. - Policy library — two primitives live:
NumericThresholdandKeywordAbsence, both running through the samesubmit_receiptcircuit. The KeywordAbsence salt isSHA-256("witness:keywords:v1" || JSON(sorted_keywords))so the on-chainpolicy_idis cryptographically bound to the keyword set. - Client SDK — extractor registry pattern; each primitive ships a deterministic feature extractor;
chatMulti(prompt, {policyIds})runs one LLM call and mints N receipts sequentially. - UI — Next.js 16 + React 19, six pages. AES-256-GCM via Web Crypto. Keys persisted in IndexedDB; receipts cached in localStorage.
- Reveal flow — URL fragment encodes
{r, c, k, i, x}(receiptId, contract address, AES key, IV, ciphertext). Base64url. Never reaches the server.
Challenges we ran into
- Multi-policy nonce race. Minting N receipts increments
nonce_counterN times. We made the SDK await sequentially to avoid the race. - Next.js 16 Turbopack vs midnight-js ESM. Production build fails on Turbopack; switched to
next build --webpack. - Vercel framework detection. Monorepo root
package.jsondidn't declarenext; Vercel refused to recognise the framework. Addednextas a root devDep purely for the detector. - Reveal-key transport. AES key for decryption cannot touch the server. We landed on URL fragment (
#) which browsers never send in HTTP requests — auditor decrypts entirely client-side.
Accomplishments that we're proud of
- A single, composable on-chain primitive (
submit_receipt) that already supports two distinct policy primitives — and architecturally accepts more without recompiling the contract. - Selective-disclosure verification that works for any visitor — no wallet, no login, no API key.
- 27 unit tests + 3 e2e tests against a live local devnet round-trip; SDK + UI typecheck clean at submission.
- Apache 2.0, public from day one.
What we learned
- Compact's
disclose()semantics make selective-disclosure protocols feel natural; harder primitives (custom merkle proofs, set membership) become tractable. - ZK-ML for policy compliance isn't ready for production (15+ min proving for tiny classifiers). Deterministic feature extractors covering 80% of compliance use cases get the practical wins now.
- URL fragments are an underused primitive for "secret-that-server-must-not-see" flows.
What's next for WITNESS
- Hosted proof server so the live demo can run chat end-to-end without a local Docker stack.
ScopeMembershippolicy primitive — third extractor in the registry, topic-classifier-driven, for domain-restricted assistants.- Revocable reveal links — re-encrypt under a fresh key, post a superseding receipt, invalidate the old commit on-chain.
- On-chain policy enumeration so the UI no longer relies on localStorage to remember registered policies. ## What it does
How we built it
Challenges we ran into
Accomplishments that we're proud of
What we learned
What's next for WITNESS
Built With
- compact
- midnight-network
- nextjs
- openrouter
- react
- tailwindcss
- typescript
- vercel
- web-crypto
- zero-knowledge
Log in or sign up for Devpost to join the conversation.