Inspiration

Age and consent checks are becoming common in AI products, but the usual approach asks people to hand over a birth date, ID, selfie, or a persistent account identity. We wanted to explore a better default: prove that someone meets a policy such as “18+” without exposing the underlying personal data.

What it does

Guardian Rail is a privacy-preserving access gate for AI chat. A user holds a local credential and proves, through a Midnight Compact zero-knowledge circuit, that it meets the age policy. The chat service receives only a yes/no decision after the Midnight Indexer confirms an on-chain, session-specific nullifier. It does not receive the user’s date of birth, credential salt, issuer secret, holder secret, ID, or photo.

How we built it

We built Guardian Rail as an npm-workspace monorepo: 1) A Next.js frontend handles local credential selection, Lace wallet connection, local proof preparation, and access-state UI. 2) An Express backend creates chat sessions and unlocks access only after Indexer-backed verification. 3) A Compact contract stores the issuer commitment, policy cutoff, registered credential commitments, and spent nullifiers. 4) Lace connects the browser to Midnight Preprod, while a local Docker proof server supports local proving. 5) A local mock issuer creates test credentials and issuer keypairs for the hackathon flow. The contract has been compiled and deployed to Midnight Preprod. The frontend and backend use the deployed contract address and Preprod Indexer configuration.

Challenges we ran into

The hardest part was integrating multiple moving pieces: Compact artifacts, Lace’s wallet connector, local proof generation, transaction balancing, Preprod DUST availability, and asynchronous Indexer confirmation.

We also encountered SDK/version compatibility issues, wallet-channel shutdowns after signing, generated ZK asset loading problems, and a hosted Indexer issue involving default offset: null queries. We added explicit Indexer queries and made the UI distinguish between a wallet signature, transaction submission, and actual on-chain confirmation.

Another practical challenge was DUST: tDUST is generated gradually from registered tNIGHT and cannot simply be transferred. This made it important to show honest wallet-readiness and pending-confirmation states.

Accomplishments that we're proud of

1) A real Compact age-gate contract compiled and deployed to Midnight Preprod. 2) A browser-to-Lace path for issuer-authorized credential registration and proveAge transactions. 3) A design where sensitive witness data stays in the browser. 4) Context-specific nullifiers that prevent proof replay across chat sessions. 5) Backend access control that waits for Indexer-observed contract state instead of trusting a frontend claim. 6) Clear documentation, setup instructions, compile commands, and a demo walkthrough for reviewers.

What we learned

We learned that privacy is not only about cryptography—it is also about product boundaries, error states, and avoiding accidental data collection in the surrounding application.

Technically, we learned how Compact witnesses map local private inputs into ZK circuits, how public ledger state differs from private proof inputs, how Midnight transaction finality is asynchronous, and why the Indexer is essential for trustworthy application-level decisions.

We also learned to treat wallet approval as only one stage of a transaction lifecycle. A signed popup is not the same as a submitted, finalized, and Indexer-confirmed on-chain action.

What's next for Guardian-Rail

Next, we will complete the live credential-registration and proof demonstration once the wallet has sufficient Preprod tDUST. Beyond the hackathon prototype, we plan to: 1) Replace the mock issuer with a real, security-reviewed credential issuer. 2) Add credential expiry and revocation. 3) Consider Merkle-based credential membership for a stronger anonymity set. 4) Add durable sessions, authentication, rate limiting, monitoring, and recovery. 5) Perform security, privacy, and legal reviews before any production use.

Built With

Share this project:

Updates

Submission history