Inspiration
Credit and reputation systems today force an impossible tradeoff: to prove you're trustworthy — a good tenant, a reliable borrower, a dependable gig worker — you have to hand over your entire financial history to whoever's asking. A landlord doesn't need your bank balance; they need to know you won't default. A lender doesn't need your full credit history; they need to know your score clears a bar. Every existing system leaks far more data than the question actually requires.
Midnight's combination of a public ledger with private, provable state felt like the first real answer to this. We wanted to build something concrete: a "credit passport" where a Holder can prove specific claims about their financial reputation — "my score is above 700," "I've never defaulted," "my score is between X and Y" — without ever revealing the underlying number to anyone, including the verifier.
What it does
CreditProof lets an Issuer (a bank or gig platform) commit a Holder's reputation score to the Midnight blockchain as a cryptographic commitment — the raw score never touches the chain. The Holder can then generate zero-knowledge proofs against that commitment to answer specific yes/no questions for a Verifier (a lender, a landlord):
prove_score_above(threshold)— proves the score clears a bar, reveals nothing elseprove_no_default()— proves zero defaults, reveals nothing elseprove_score_range(min, max)— proves the score falls in a band, reveals nothing else
Every proof is verified on-chain and the verification result (pass/fail only) is recorded publicly, so a Verifier has an auditable, tamper-proof answer — without ever seeing the number behind it. Credentials can also be revoked by the Issuer if reputation data changes.
How we built it
The core is a Compact smart contract (credit_passport.compact) that defines the public ledger state (commitment, issuer identity, revocation flag, verification maps) and a set of ZK circuits that recompute a Holder's private witnesses — score, default count, issuance timestamp, and a nonce — hash them, and check the result against the on-chain commitment before disclosing only a boolean.
On top of the contract, we built:
- A Node/Express backend that acts as a proof relay and credential signing service, orchestrating requests between Holder, Issuer, and Verifier flows.
- A React + Vite frontend (React Router, TypeScript) giving each actor role — Issuer, Holder, Verifier — its own interface to issue credentials, generate proofs, and verify claims.
- Deploy tooling to compile the Compact contract, spin up a local Midnight network (node, indexer, proof server) via Docker, and push the contract on-chain.
Because the @midnight-ntwrk SDK packages are still evolving in preview, we also built a simulation layer that mirrors the exact behavior, delays, and cryptographic hashes of the real SDK, so the full user flow — issuing a credential, proving a claim, verifying it — can be demoed end-to-end even while wallet/network infrastructure catches up.
Challenges we ran into
The biggest challenge was infrastructure instability at the edges of a very new ecosystem. The public Preprod faucet's ZK prover was crashing server-side on every request and imposing 24-hour IP rate limits, which meant we couldn't reliably get tNIGHT/DUST to pay gas for a real on-chain deploy. We pivoted to running Midnight's own local "undeployed" network via Docker, which ships with a pre-funded genesis wallet — no faucet required.
That surfaced a second challenge: the @midnight-ntwrk JS/TS SDK is moving fast, and package versions in active development diverge quickly from documentation and examples — provider constructors became factory functions, config shapes changed, and the contract execution layer moved to an Effect-based API requiring compiled contracts to be wrapped with explicit witness implementations. Chasing a moving-target SDK under a hackathon clock was the real test of the weekend.
What we learned
We came away with a much deeper appreciation for the mechanics of ZK proof systems — specifically how a single commitment plus a set of private witnesses can support many different disclosure circuits, each revealing exactly one bit of information and nothing more. We also learned a lot about designing for infrastructure that's still stabilizing: building a faithful simulation layer alongside the real integration turned out to be essential, not just for demos under time pressure, but for iterating on the app's UX independently of network/tooling flakiness.
What's next for CreditProof
- Complete the real on-chain deployment against Midnight's SDK as the Effect-based contract execution APIs stabilize.
- Add issuer attestation chains, so multiple issuers (bank, gig platform, utility provider) can contribute to one Holder's passport.
- Expand the proof vocabulary (income bands, employment tenure, rental history) beyond credit score and default status.
- Explore selective credential revocation and expiry, so passports age out gracefully without a full re-issuance.
Built With
- blockchain
- compact
- docker
- express.js
- midnight
- node.js
- react
- react-router
- typescript
- vite
- zero-knowledge-proofs
- zk-snarks
Log in or sign up for Devpost to join the conversation.