Inspiration

Verifying a degree today means one of two bad options.

Send the whole document. To prove you hold a computer science degree, you email a PDF transcript containing your student number, every grade you ever received, and your date of birth. The employer keeps that file. So does their applicant tracking system.

Or call the university. Slow, manual, and only works while someone answers the phone.

Both leak far more than the question required. The question was "does this person hold this degree." The answer given is an entire academic history.

The case that stuck with us was the nursing diploma scandals. Thousands of forged credentials circulated for years without detection. When institutions finally started checking, the people who suffered were the nurses with real degrees — suspended without pay, "pending verification," while small schools were slow to answer the phone. A system that couldn't spot thousands of fakes also couldn't confirm one real credential in under a month.

What it does

A university issues a degree. The graduate decides who sees what. An employer verifies it in about a tenth of a second and learns only what the graduate chose to share.

Nothing about the student goes on the chain — not their name, not their student number, not their grades, not even a hash of any of it. And a forged credential isn't caught after the fact. It simply cannot produce a proof at all.

Beyond the degree, a university can attest individual courses, honors, extracurriculars and certifications. Each becomes its own credential on the chain, so a graduate can prove they took one specific course to one specific employer without revealing the rest of their transcript.

How we built it

  • Compact contract — 4 circuits: authorizeIssuer, issue, revokeCredential, proveCredential
  • chain-service — Node 22 + Midnight.js, holding private state and driving the proof server
  • Backend — FastAPI, with an off-chain index that deliberately stores no grades and no student identity
  • Frontend — Next.js, with the Lace wallet as the university's identity
  • Observability — Prometheus, Loki, Grafana, and an anomaly detector that correlates verification logs

The privacy design lives in two structs. CredentialData is a witness — a private input to the proof, never written to the chain. DisclosedClaim is what a verification returns, and it has four fields, none of which is studentId.

That absence is the whole design. Hiding the holder's identity isn't a runtime check someone could forget or a setting an admin could misconfigure. There is no field to put it in.

Challenges we ran into

The verifier had a toggle it should never have had. Our verify page shipped a "show GPA" button any visitor could click. We had described that as consent. It wasn't — asking is not consent. We deleted it and rebuilt disclosure around share links the graduate mints, so a verifier has no way to request more.

The student had no surface at all. The university issued, the employer verified, and the graduate — the person the product is about — was the row in between. We built them a portal reached by a secret link, with no account and no password for us to store.

A grade of zero isn't the absence of a grade. The chain stores gpaTimes100 as a non-nullable integer, so an ungraded honor arrives as 0. Rendering that as "0.00" would libel the graduate, so attestations read it as absent — while a degree keeps the strict reading, because a 0.00 GPA there is real data.

Our logging pipeline silently dropped everything. The proof server writes log lines over 256KB while proving. Loki rejected them, and Promtail drops the entire batch when one entry is rejected — so every service's logs vanished. It only appeared once we switched from the mock adapter to real proofs.

Accomplishments we're proud of

The privacy guarantee is enforced by the compiler, not by our discipline. Add one line writing the student's ID to the ledger and the build fails — Compact names the witness, the ledger operation, and the exact path the value would have taken.

We ship a script that demonstrates this in 13 seconds.

What we learned

Zero-knowledge changes what a failure means. In a normal system a bad credential is caught by comparison. In a circuit, assert failing doesn't throw an error you can catch — no proof exists. There is nothing to submit.

We also learned that privacy is mostly a design discipline about what you don't store. The hardest decisions weren't cryptographic; they were about refusing convenient fields. There is no "resend access link" because we keep only a one-way hash, and the student's email is used once and discarded.

What's next

Deploy to a public Midnight network, address the credential-ID linkability we document as a known limitation, and let a graduate hold credentials from multiple institutions behind one access link.

Tested

121 backend tests · 66 chain-service tests · 4 browser tests · contract compiles to 4 circuits with prover and verifier keys.

Built With

  • compact
  • docker
  • dynamodb
  • fastapi
  • github-actions
  • grafana
  • loki
  • midnight
  • midnight.js
  • next.js
  • node.js
  • playwright
  • plonk
  • prometheus
  • pytest
  • python
  • react
  • s3
  • tailwindcss
  • terraform
  • typescript
  • zero-knowledge-proofs
  • zk-snarks
Share this project:

Updates

posted an update —

Hello Everyone, As the project initiator, I proposed the idea for AcadVerify and helped translate it into an executable architecture by organizing the project into five parallel workstreams. I led the SRE/DevOps effort, establishing the GitHub repository structure, branch strategy, access controls, and development workflows. I implemented the project's observability stack using Prometheus, Grafana, and Loki, supported CI/CD and integration, and built end-to-end automated testing to improve reliability and operational readiness. My focus was on ensuring AcadVerify was not only functional but also deployable, observable, and maintainable using production-grade engineering practices. Kudos to all of my team members and thanks to Midnight for providing this opportunity without which I wouldn't have met my teammates.

Log in or sign up for Devpost to join the conversation.

posted an update —

We are beginner track focused. We originally planned the project on conventional Ethereum-style design, but after talking to midnight team while development, and going through their docs and tools they provided especially as claude skills, we locked in on midnight blockchain, and finished the project faster than we hoped to, thanks to Midnight team and mentors for guiding our team throughout the Hackathon.

Log in or sign up for Devpost to join the conversation.

Submission history