Proof first, story second: Consent registry on Solana devnet · A capture recorded on Thru · Source
Inspiration
Hack the North puts a couple thousand people in a few rooms with a camera pointed at nearly all of them, nearly all the time. Nobody asks, and there is no way to say no. Consent to being filmed is a checkbox you never saw.
The spark was the badge. This year's badge is an ESP32 with a screen, a small computer you're already wearing. It can show a machine-readable key, and a camera can read that key and respect your choice, frame by frame. Your consent stops being a form and becomes something you carry, show, and revoke.
What it does
People wear the badge, which displays a coded optical key. A camera, either a webcam or Ray-Ban Meta glasses through our iPhone relay, films the scene and, in near-real time:
- Reads the key to recover each badge's ID.
- Detects faces and binds each badge to the face directly above it.
- Enforces consent from your on-chain record: blurs you, or covers you with an icon of your choosing.
- Tells you. If you were filmed while opted out, you get an email within about a second, and the chain records both that you were captured and that you were told.
Consent is a signed, revocable record you own on Solana. The camera reads your consent from that record, never from your face.
Two properties carry the design:
- No biometric database. We never identify anyone by their face. Identity comes from the optical key; the face is only used to know where to cover, and that box is discarded every frame.
- Every claim is earned. The notice on-chain says how you were told (email, badge radio, voice), and a channel is only claimed when the delivery actually happened. An email sets its bit only on the provider's confirmation. A silent failure never becomes a receipt.
How we built it
The badge. A sandboxed Lua app on the ESP32-C3 draws a white ring around three 7-segment hex digits: the 12-bit payload id << 4 | crc4(id). It is static, so one frame decodes it and frame rate stops mattering. Digit colour (mint or rose) mirrors consent as a restrict-only hint: it can make a face stricter, never clear one. Pressing A flips it, and the camera relays that request to the chain through light, since the badge has no network of its own.
Vision. Two paths, one contract. In the browser: MediaPipe BlazeFace plus a classical decoder that finds the ring, samples 21 segments from a native-resolution crop, and CRC-checks the payload. On the laptop's GPU: a YOLOv8 sidecar running a face model and a 17-class badge-glyph model we trained ourselves, ~13 ms per frame, streamed over a local WebSocket. The browser keeps everything that decides; the sidecar only looks, and if it drops, the in-browser path takes over the next frame.
Binding is the only thing that can un-cover someone, so every rule refuses rather than guesses: a badge must sit within a few face-heights of a face, two near-equidistant faces bind to neither, one badge binds one face, and a binding expires a second after the badge was last seen. The badge is a heartbeat, not a login.
Consent on Solana. An Anchor program on devnet stores one owner-signed record per badge, with revocation, per-event overrides, and close. The badge holds no SOL, so it signs a 49-byte message with its own key and a relayer pays; the program verifies the signature with the Ed25519 precompile. Every capture is anchored in a hash-chained audit log, and every capture of an opted-out person files a notice account: record_capture when it happened, record_notice when, and how, they were told. The app reads a slot-ordered local cache; if the cache goes stale, everyone reads as unknown and the fail-safe blurs.
Evidence on Thru. Authorization and evidence are different problems. Consent is rare and owner-signed, which is Solana's job. Enforcement produces records at camera speed, so each film-event is committed to Thru Alphanet as its own account the moment it happens, in a few seconds, carrying only IDs, hashes and timestamps. Nothing visual is ever stored.
Observability with Sentry. One trace per second across the pipeline (detect, track, decode, bind, decide, cover) and a structured log on every consent decision and film-event. We deliberately don't use Session Replay: it would record faces, the one thing this app refuses to do.
The console wears the badge's own materials: badge IDs are drawn as the same seven-segment glyphs the camera reads, lit in the badge's own consent colours, on the PCB's purple.
Challenges we ran into
- Real footage broke our assumptions. Synthetic frames decoded perfectly; a real recording decoded nothing, because the display's blue read as "lit" under auto-exposure. A whiteness metric fixed it. Distance needed a native-resolution crop, then a trained detector.
- The badge fought us. No buzzer, no speaker, no Wi-Fi or BLE from Lua. "The badge buzzes" became a red-LED alarm and a banner, and "tell the person" became email and the chain.
- A tracker that swaps boxes hands one person's consent to another. That's the failure that exposes someone, so binding got a distance cap, an ambiguity refusal, one-to-one matching and a TTL.
- Where consent lives. The tempting shortcut is to put opt-in/opt-out in the light. We didn't: anyone could show your ID and flip you. Identity travels in the light; consent lives on-chain where only you can change it.
- A receipt is a promise. The first version claimed "told by voice" whenever a voice provider existed. We tightened every channel to claim only on confirmed delivery.
Accomplishments that we're proud of
- A working optical link from a screen to a camera, decoding a real badge at 35 fps with zero false IDs.
- A privacy tool that holds to its own ethics: no face database, a default-deny fail-safe, and an evidence trail that never stores an image.
- Consent you actually own, enforced locally, with a truthful, on-chain record that you were filmed and told.
- Two chains doing two honest jobs.
What we learned
- Reading data off a screen with a camera is signal processing first: exposure and colour matter more than clever code.
- Hardware never matches the datasheet. Leave calibration knobs.
- Detection is not recognition and identity is not consent. Keeping those separate is what makes this defensible.
- A shared wire-format file let three people build the badge, the decoder and the chain in parallel.
What's next
- A signed optical payload, so a spoofer can't even mislabel a face.
- The wearer countersigning their own notice, a two-sided record.
- Crowds, per-event consent, natural-language policy and audit.
Honest status
Solana devnet, Thru Alphanet and Sentry are live and linked above. Two enforcement policies ship behind one switch: default-deny (the repo default) and opt-out-only, which is what we run in a crowded room so bystanders aren't blurred. Emails send through Resend's sandbox sender, so for the demo every notice is delivered to one inbox while the record keeps the contact's own address. Badge decode through the glasses is our least-tested path. We'd rather say that than imply otherwise.
Log in or sign up for Devpost to join the conversation.