§ 00 · STATUS

Where Wave 1 stands.

A live record of what's done, what's in motion, and what's next — so I can stay oriented, and anyone following the buildathon can see where Vero is at.

live last updated wave 1 of 3 11 of 11 milestones complete

Done

  • Product concept, mechanism and naming finalized
  • Competitive landscape, personas and risk notes documented
  • Local dev environment fully operational — Docker stack, wallet, and CLI tested
  • Compact contract — Merkle issuer registry, expiry enforcement
  • End-to-end proof flow on the local devnet
  • Automated checks — end-to-end and proof-forgery regression
  • Reader view — verified badge rendered from live ledger state
  • Contract tests that need no devnet — 30 of them, under a second
  • Multiple registrars — one per issuer type, appointed by governance
  • Demo video — three minutes, narrated, with the proof shown running
  • Wave 1 submitted

Now

  • Judging — September 16 to 27

Next

  • Wallet bridge — prove from the browser
  • Public-network deployment

Wave 1 is about proving the mechanism — not building the entire product.

Wave 1 deadline · September 16, 2026

§ 01 · LOG

What's been happening.

Newest first. Each entry is one step forward — finished, in progress, or blocked.

done

The demo, recorded — and the proving turned out to take twenty‑two seconds

Three minutes, narrated, cut from eight shots. It opens on the reader view rather than a title card, spends its longest stretch on the contract, and ends on the tests, because a system that refuses is more convincing than a system that approves.

The proof in it is real. A credential is proven against a local Midnight node, the transaction lands, and the reader view — reading live ledger state, not a fixture — shows the badge appear. The wait is trimmed, and the cut is marked on screen rather than hidden, because a viewer who later works out that a live proof was quietly accelerated is right to discount everything around it.

Writing the script had assumed the proving would take about a minute. Measured frame by frame in the recording, it took twenty‑two seconds — a better number than the one that had been guessed, and the narration was re-recorded to say so.

Watch the demo →
done

One registrar per issuer type — and why the subject stopped building its own credential

The contract held a single registrar, so one authority granted every kind of credential. The adoption model does not work that way: the body that grants a credential is the only one that can say whether it still holds. A press council can accredit journalists and has no standing to certify surgeons.

There are now three roles. Governance appoints registrars, a registrar grants credentials of its own issuer type, and a holder proves. Each has its own domain-separated commitment, so no secret can be replayed as another role's authority.

The part that mattered was not the map but who builds the credential. Earlier versions took a finished commitment from the subject, which meant the registrar signed off on thirty-two opaque bytes — survivable with one trusted registrar, and not with several, because a subject could take a commitment built as "accredited journalist" to whichever registrar was easiest to convince. The subject now hands over only a commitment to a secret it never reveals, and the contract builds the credential from what the registrar states.

Binding the granting registrar into the credential has a consequence worth being deliberate about: replacing a registrar invalidates everything it granted. That is intended. Governance replaces a registrar precisely when it should no longer be trusted, and the alternative would silently transfer its credentials to the replacement. There is a test for it.

Read the contract →
done

Thirty tests for the contract, and not one of them needs Docker

The only tests needed a running devnet — proof server, node, indexer and a funded wallet. That is the right test for the wiring and the wrong one for the contract's logic, and it meant anyone cloning the repository and running the test command was told there were no tests.

The suite now drives the compiled circuits directly through the Compact runtime. Circuit execution is real, so every assertion in the contract fires exactly as it would on-chain; only the proving is skipped. It runs in under a second, and compiles the contract itself when needed, so a fresh clone needs nothing but Node and the Compact compiler.

There is one test per rejection the contract can make, because a credential system that verifies valid credentials and also verifies invalid ones is worse than no system at all: it looks like it works. A genuine Merkle path belonging to somebody else. A path built against a different registry. A credential proven under an issuer type it was never granted for.

Running in process also makes block time a settable value, which a live devnet cannot offer. That bought two tests the devnet could not: the expiry boundary, checked one second either side, and a regression for the millisecond trap — an expiry given in milliseconds is accepted twenty years after it should have lapsed, silently, and nothing in the contract can catch it.

Read the tests →
done

A reader can now see the signal — and the wallet bridge is scoped for Wave 2

The demo had been a command line. There is now a frontend, and the reader view works: it queries the indexer, decodes the ledger with the contract's own decoder, and renders the verified badge beside a post. It deliberately needs no wallet, no account and nothing installed — checking a source should cost the reader nothing, and that asymmetry is the product.

The publisher view — proving a credential inside the browser — connects to a wallet and holds a credential, but stops short of a proof. Browser wallets implement the DApp Connector API v4, which passes transactions as serialized strings and returns nothing from submit; the midnight-js version this contract is built on expects objects and a transaction id. An official bridge exists for the proving half of that gap, and none for the wallet half.

Writing that adapter is Wave 2 work, and deliberately so. The Wave 1 criterion asks whether the frontend connects to the contract as part of a functional end-to-end experience, and the reader view does. Spending the remaining days on an undocumented bridge written blind is worth less than the testing work carrying the same weight. It is also a clean piece of engineering to show next Wave, with a visible before and after: a demo that reads verifications becomes one where a source produces them.

Read the technical specification →
done

Closing a privacy leak in the disclosed expiry

Verification discloses the credential's expiry, and an exact per-credential timestamp behaves like a serial number: two posts verified by the same credential share it, so an observer could group a pseudonymous source's posts together without ever identifying them — undoing much of what the membership proof is for. Expiries are now issued rounded up to a shared quarter boundary, so everyone credentialed in the same quarter discloses the same value. Removing the disclosure entirely is designed and deferred; it depends on knowing how large the registry will be.

done

Credential registry — prove membership without revealing which credential

The contract now holds a Merkle tree of credential commitments rather than one accepted credential. A source proves that one of the registered credentials is theirs, without revealing which: a reader learns that an accredited journalist verified the post, not which journalist, nor which newsroom credentialed them. Registration is gated on a registrar secret, and the subject derives its own commitment off-chain — so the credential secret never reaches the registrar.

One line carries the security: the circuit binds the Merkle path to the commitment derived from the prover's own secret. The tree's leaves are public, so without it anyone could take a valid path for someone else's credential and prove with it. A regression test plays that attacker — unregistered secret, genuine path — and fails if it is ever accepted.

done

Issuer type and expiry bound into the credential

The signal stopped being binary. The commitment now binds the secret, the issuer type and the expiry together, so a source cannot re-badge itself as a different kind of issuer, or quietly extend its own validity, while reusing the same secret. The ledger records the issuer type per post rather than a bare flag — which is the signal a reader actually needs. Expiry is enforced on-chain against Midnight's block time: a past-dated credential is refused.

done

Contract wired end-to-end — first real proof on the devnet

Until now the deploy and CLI scripts still targeted the scaffold contract that came with the project template, which set verified = true unconditionally. They are now wired to the real Vero circuit, with its constructor argument and its witness. A dependency fix that had only ever existed in the original working copy was also committed, so a clean clone finally runs: npm install, npm run setup, npm run test:e2e from scratch.

done

Local dev environment fully operational — Docker stack, wallet, and CLI tested

The local Midnight dev stack (node + indexer + proof server) is running successfully via Docker. A wallet has been created with test tokens (tNight and DUST), a contract has been deployed, and the CLI plumbing — deploy, transaction submission, ledger reads and balance checking — works end to end. The contract at this point was still the project template's placeholder circuit, so nothing was being verified yet; what this unblocked was the ability to build and test the real mechanism locally.

done

Minimal Compact contract — compiling

The credential-verification circuit is being written in Compact. Currently working through the validity checks (issuer allowlist, expiry, scope) and getting the contract to compile cleanly against the local Midnight dev stack.

done

Product concept and positioning refined

Vero is now positioned as a verifiable credibility layer — not just identity verification. The core distinction: credibility is the product value, privacy/selective disclosure is a capability. Identity is optional: a source can be fully identified, associated with an organisation, or pseudonymous. The architecture — source → Compact circuit → selective disclosure → frontend — is settled, and the name "Vero" is chosen.

done

Competitive landscape, personas and risk notes documented

Comparison against platform verification, Community Notes, fact-checking, C2PA/Content Credentials, and professional credentials; three personas (reader, credentialed professional, organisation); and risk notes captured in the repo README. This is the foundation the rest of Wave 1 builds on.