Gated Attestation¶
Attestation is CivicOS's defense against spam, bot armies, and coordinated manipulation. It converts a digital problem (unlimited key generation) into a physical one (you must show up in person).
The Problem¶
Generating a cryptographic key pair is free and instant. A single laptop can produce a million "citizens" in an hour. Without a gate, any coordination system is vulnerable to Sybil attacks — one entity pretending to be many.
The attack (without attestation):
1. Generate 10,000 key pairs (< 1 second)
2. Sign 10,000 "support" voices (< 1 second)
3. Send to relay (< 1 second)
Result: "10,023 residents support this initiative!"
Reality: 23 real people, 10,000 fake keys
This problem has gotten worse with autonomous AI agents, which can generate realistic engagement histories, produce human-sounding comments, and operate at scale for pennies.
The Gate¶
CivicOS uses a hard gate: to voice or comment, you must present a valid attestation proof. No proof, no participation. Browsing, reading, and subscribing remain open to everyone.
To get attested, you must physically attend a community event (farmer's market, city council meeting, library pop-up) and receive a single-use code from a volunteer. The volunteer uses human judgment — "this is a person" — not bureaucratic verification. No government ID is checked. No name is recorded.
| Attack vector | Cost without gate | Cost with gate |
|---|---|---|
| Generate 10,000 fake keys | Free | Irrelevant (no attestation = can't voice) |
| Build fake history over months | Automated | Irrelevant (history doesn't bypass gate) |
| Get 10,000 attestations | N/A | 10,000 physical appearances at events |
How It Works¶
Step 1: Community Event¶
A volunteer distributes single-use attestation codes — one per person. Codes are printed on cards or displayed as QR codes.
Step 2: Redeem in Extension¶
The resident opens the CivicOS browser extension, enters the code, and clicks "Verify." The extension signs a Nostr event binding the code to the resident's public key.
Step 3: Relay Issues Attestation¶
The relay checks: - Code exists and hasn't been used - Code hasn't expired - This pubkey isn't already attested for this jurisdiction
If all checks pass, the relay signs a kind 30850 Nostr event — an attestation that this pubkey is verified for the jurisdiction.
Step 4: Stored Locally¶
The signed attestation is stored in the browser's local storage. From then on, every voice and comment the resident submits includes this attestation as embedded proof.
The Attestation Event¶
{
"kind": 30850,
"pubkey": "jurisdiction_issuer_pubkey",
"tags": [
["d", "attest:city-san-rafael:user_pubkey"],
["p", "user_pubkey"],
["j", "city-san-rafael"],
["type", "physical"]
],
"content": "civicos:attestation:v1:city-san-rafael:physical:1739520000",
"sig": "schnorr_signature_by_issuer"
}
Key observations:
- Signed by the issuer, not the user. The
pubkeyfield is the jurisdiction's issuer key. This is what makes it an authority-issued credential. - Addressable. The d-tag ensures one attestation per user per jurisdiction.
- Self-contained. Any relay can verify the attestation by checking the issuer's signature — no database lookup required.
Verification: The Six Checks¶
When a voice arrives at the relay with an attestation proof, the relay runs six checks:
| Check | Validates | Defends Against |
|---|---|---|
| Kind | Proof is a kind 30850 event | Attaching a random Nostr event as "proof" |
| Issuer | Signed by the jurisdiction's official issuer keypair | Self-attestation |
| D-tag | Matches attest:{jurisdiction}:{your_pubkey} | Using someone else's attestation |
| Required tags | Has ["p", your_pubkey] and ["j", jurisdiction] | Cross-jurisdiction or cross-user misuse |
| Event ID | Hash of event contents matches claimed ID | Post-signing tampering |
| Schnorr signature | Valid against the issuer's public key | Forgery |
Why Embed, Not Look Up¶
The attestation proof is embedded on each voice, not looked up in a separate table. This is deliberate:
- Self-contained — The voice carries its own proof
- Portable — Works on any relay without database access
- Fast reads — No JOIN required
- Federation-ready — A receiving relay can verify independently
Think of it like a passport: you don't call the issuing country every time someone shows you their passport. The document itself is the proof.
What Attestation Is Not¶
Not identity verification¶
Attestation proves you physically attended a community event. It does not prove your name, address, citizenship, or residency status. This is deliberate — CivicOS is inclusive by design. The gate is "you're a real person who cares enough to show up," not "you can produce government ID."
Not surveillance¶
The system has intentional privacy gaps:
- The volunteer knows: A person showed up and got a code. They don't know the person's key or how they vote.
- The relay knows: A key is attested. It doesn't know who the person is or where they got the code.
- No single party knows both who the person is and how they participate.
Not foolproof¶
A determined person can get multiple codes across multiple events. This is acceptable noise — it doesn't scale. What gated attestation does prevent is the existential threat: bot armies, autonomous agents, and casual Sybil attacks.