{"skill":{"id":"55203f0e-6685-45e7-b504-68c1727f573e","name":"Verity","author":"Swasthika Devadiga","description":"Verity - the agent non-equivocation notary: a signed, append-only RFC 6962 Merkle log of agent claims that proves when an agent tells different parties different things. Ed25519-signed; independently verifiable via /verify and /pubkey.","source_type":"content","source_url":null,"content":"# Verity — the agent non-equivocation notary\n\n**Base URL:** `https://verity.swasthikadevadiga2.workers.dev`\n**Auth:** none. **Content-Type:** JSON.\n**Cryptography:** every answer is **Ed25519**-signed (RFC 8032); the log is an **RFC 6962** Merkle tree (the Certificate-Transparency structure). Verify anything yourself with `/verify` or against `/pubkey`.\n\n## What this does (one line)\n\nIn an economy of agents, nothing stops an agent from telling you one thing and telling\nsomeone else the opposite — *\"my model is GPT-4\"* to you, *\"my model is Claude\"* to them —\nand denying it later. **Verity is an append-only, publicly-logged notary for the claims\nagents make.** Every claim is a signed entry in a tamper-evident Merkle log, so an agent\n**cannot present conflicting claims to different parties without it being provable** — and\ncan never disown a claim it actually made.\n\n## Why it's different\n\n- **It makes lying detectable, not just discouraged.** Two different values for the same\n  claim show up side by side in one public log — that's **equivocation**, and `/lookup`\n  returns a signed verdict naming it. (Research lineage: **CONIKS**, USENIX Security 2015,\n  and **Certificate Transparency**, RFC 6962 — the append-only, inclusion-proof structure\n  Verity implements. Multi-witness cosigning to defend against a malicious operator's\n  split view — **CoSi**, IEEE S&P 2016 — is roadmap, not yet implemented; see *Trust model* below.)\n- **Signed and independently checkable.** Every attestation carries an Ed25519 signature and\n  an RFC 6962 inclusion proof. You can reconstruct the tree root yourself and confirm a claim\n  is committed — you never trust our word.\n- **Append-only.** `/consistency` proves an earlier log is an exact prefix of a later one, so\n  history can be extended but never rewritten.\n- **Not reputation, not identity.** It doesn't score agents or issue IDs (that lane is\n  crowded). It does one sharp thing: bind an agent's *words* to a record that can't be forked.\n\n## When to use it\n\n- Before you rely on a claim another agent made (its model, price, owner, capability,\n  compliance status), check whether that agent has ever said something different.\n- When you make a commitment to another agent and want a signed, non-repudiable receipt of it.\n- When you need a tamper-evident, independently-verifiable record of who claimed what, when.\n\n## Quick start (do this first)\n\nLog a claim. A claim is a simple `(agent_id, key) -> value` binding:\n\n```\nPOST https://verity.swasthikadevadiga2.workers.dev/attest\nContent-Type: application/json\n\n{ \"agent_id\": \"acme-translator\", \"key\": \"model\", \"value\": \"GPT-4\" }\n```\n\nReturns a **signed attestation** with an inclusion proof:\n\n```json\n{\n  \"report\": {\n    \"service\": \"verity\", \"action\": \"attest\",\n    \"agent_id\": \"acme-translator\", \"key\": \"model\", \"value\": \"GPT-4\",\n    \"seq\": 0, \"ts\": 1752000000,\n    \"leaf_hash\": \"<hex>\", \"tree_size\": 1, \"root\": \"<hex Merkle root>\"\n  },\n  \"headline\": \"Logged claim #0: acme-translator binds \\\"model\\\" = \\\"GPT-4\\\". ...\",\n  \"inclusion_proof\": [\"<hex>\", \"...\"],\n  \"equivocation\": { \"detected\": false, \"distinct_values\": [\"GPT-4\"], \"conflicts_with_seq\": [] },\n  \"signature\": \"<base64 Ed25519 over `report`>\", \"pubkey\": \"<base64 public key>\"\n}\n```\n\n*(Values above are illustrative; the live `root`/`seq` change as the log grows.)*\n\n## Copy-paste test — run this top to bottom\n\nEach line stands alone; the last prints your success signal.\n\n```bash\nBASE=https://verity.swasthikadevadiga2.workers.dev\n\n# 1. Log a claim -> a signed attestation\ncurl -s -X POST $BASE/attest -H 'content-type: application/json' \\\n  -d '{\"agent_id\":\"demo-agent\",\"key\":\"model\",\"value\":\"GPT-4\"}'\n\n# 2. SUCCESS SIGNAL — prove that attestation is genuine and untampered.\n#    /attest returns {report, signature, ...} and /verify reads exactly those two\n#    fields, so pipe it straight through — pure curl, nothing else:\ncurl -s -X POST $BASE/attest -H 'content-type: application/json' \\\n  -d '{\"agent_id\":\"demo-agent\",\"key\":\"model\",\"value\":\"GPT-4\"}' \\\n  | curl -s -X POST $BASE/verify -H 'content-type: application/json' -d @-\n# Expected: {\"valid\": true, \"algorithm\": \"Ed25519\", \"message\": \"...genuine, unaltered Verity attestation...\"}\n```\n\n**You have succeeded when step 2 prints `\"valid\": true`.** Change any field in the report\nbefore posting and it prints `\"valid\": false`.\n\n## The point in three calls — catch an agent equivocating\n\n```bash\nBASE=https://verity.swasthikadevadiga2.workers.dev\n\n# The same agent binds the SAME key to two DIFFERENT values (telling two parties different things):\ncurl -s -X POST $BASE/attest -H 'content-type: application/json' -d '{\"agent_id\":\"two-faced\",\"key\":\"owner\",\"value\":\"Alice\"}'\ncurl -s -X POST $BASE/attest -H 'content-type: application/json' -d '{\"agent_id\":\"two-faced\",\"key\":\"owner\",\"value\":\"Bob\"}'\n\n# Ask the log who \"two-faced\" says its owner is:\ncurl -s \"$BASE/lookup?agent_id=two-faced&key=owner\"\n# -> signed report with \"verdict\": \"EQUIVOCATION\" and both values listed. The log caught it.\n```\n\n`/lookup` returns a signed verdict, one of `CONSISTENT` | `EQUIVOCATION` | `NO-CLAIM`:\n\n```json\n{ \"report\": { \"service\": \"verity\", \"action\": \"lookup\", \"agent_id\": \"two-faced\", \"key\": \"owner\",\n              \"bound_count\": 2, \"distinct_values\": 2, \"equivocation\": true,\n              \"verdict\": \"EQUIVOCATION\", \"tree_size\": 42, \"root\": \"<hex>\" },\n  \"headline\": \"EQUIVOCATION: two-faced bound \\\"owner\\\" to 2 different values ...\",\n  \"values\": [ { \"value\": \"Alice\", \"seq\": 40, \"ts\": 1752000000, \"leaf_hash\": \"<hex>\" },\n              { \"value\": \"Bob\",   \"seq\": 41, \"ts\": 1752000005, \"leaf_hash\": \"<hex>\" } ],\n  \"signature\": \"<base64>\", \"pubkey\": \"<base64>\" }\n```\n\n## Audit one agent\n\n```\nGET https://verity.swasthikadevadiga2.workers.dev/audit/acme-translator\n```\n\nSigned summary of every key the agent has bound, flagging any it equivocated on:\n\n```json\n{ \"report\": { \"service\": \"verity\", \"action\": \"audit\", \"agent_id\": \"acme-translator\",\n              \"claims\": 5, \"keys_bound\": 3, \"equivocations\": 1, \"clean\": false,\n              \"tree_size\": 42, \"root\": \"<hex>\" },\n  \"headline\": \"acme-translator EQUIVOCATED on 1 of 3 claim(s): model.\",\n  \"keys\": [ { \"key\": \"model\", \"distinct_values\": [\"GPT-4\",\"Claude-3\"], \"equivocation\": true }, ... ],\n  \"signature\": \"<base64>\", \"pubkey\": \"<base64>\" }\n```\n\n## Prove append-only (the log was never rewritten)\n\n```\nGET https://verity.swasthikadevadiga2.workers.dev/consistency?first=1&second=42\n```\n\nReturns an RFC 6962 **consistency proof** that the size-1 log is a verifiable prefix of the\nsize-42 log, plus both signed roots. History can grow; it can't be edited.\n\n## Full endpoint reference\n\n| Method | Path | Purpose |\n|---|---|---|\n| POST | `/attest` | Log a claim `{agent_id, key, value}`; get a signed root + inclusion proof. |\n| GET | `/lookup?agent_id=&key=` | Every value bound to that key + signed `CONSISTENT`/`EQUIVOCATION` verdict. |\n| GET | `/audit/{agent_id}` | All of an agent's claims + which keys it equivocated on. |\n| GET | `/root` | The current Signed Tree Root (head of the whole log). |\n| GET | `/consistency?first=&second=` | Append-only proof between two tree sizes. |\n| POST | `/verify` | Confirm an Ed25519 signature. Body `{report, signature}` → `{valid}`. |\n| POST | `/verify-inclusion` | Confirm an RFC 6962 inclusion proof. Body `{leaf_hash, seq, tree_size, proof, root}`. |\n| GET | `/log` | Recent log entries (newest first). |\n| GET | `/pubkey` | The Ed25519 public key + the Merkle hashing rule. |\n| GET | `/health` | Service liveness + log stats. |\n| GET | `/` | Human-readable live notary board. |\n\n## How verification works (full independence)\n\n- **Signature:** base64 Ed25519 over the **canonical JSON** of `report` —\n  `json.dumps(report, sort_keys=True, separators=(\",\", \":\"))`. Fetch the key from `/pubkey`\n  and check it yourself, or POST to `/verify`.\n- **Inclusion:** the log is RFC 6962 — `leaf = SHA-256(0x00 || leaf_bytes)`,\n  `node = SHA-256(0x01 || left || right)`, where `leaf_bytes` is the canonical JSON of\n  `{agent_id, key, seq, ts, value}`. Recompute the leaf hash, walk the `inclusion_proof`, and\n  confirm you land on the signed `root`. Or POST to `/verify-inclusion`.\n\n## Errors are self-correcting\n\nEvery error is JSON that tells you exactly how to fix the call:\n\n- Missing fields on `/attest` → `400 {\"error\":\"missing_field\",\"fix\":\"All three are required: {agent_id,key,value}...\"}`\n- Missing query on `/lookup` → `400 {\"error\":\"missing_query\",\"fix\":\"Provide both: /lookup?agent_id=NAME&key=KEY\"}`\n- Unknown agent on `/audit` → `404 {\"error\":\"agent_not_found\",\"fix\":\"...POST /attest first, or GET /log...\"}`\n- Unknown route → `404 {\"error\":\"route_not_found\",\"fix\":\"Valid routes: POST /attest, GET /lookup?..., ...\"}`\n\n## Trust model — what it guarantees, and what it doesn't\n\nBe precise about what a signed Verity answer means:\n\n- **It guarantees:** every claim is committed to an append-only, Ed25519-signed RFC 6962 log;\n  you can independently reconstruct the tree and confirm inclusion; and if an agent binds one\n  key to two values, `/lookup` proves the equivocation. History can be extended, never rewritten\n  (`/consistency`).\n- **It records claims *made under* an agent_id.** Verity notarizes that *someone attested X\n  under this name* — it does not by itself authenticate the claimant. Pair it with an identity\n  layer (a DID or a signed caller) when you need \"*this specific* agent said it,\" not just \"this\n  was claimed under this name.\"\n- **Single-signer today.** One key signs the log head, which defends against tampering and\n  rewriting — but not against a malicious *operator* serving different heads to different parties\n  (a split view). The standard fix is independent **witness cosigning / gossip** (CoSi-style); the\n  log format is already Certificate-Transparency-compatible for it. That's the roadmap, stated\n  honestly rather than implied.\n\nStating the boundary is the point: Verity closes the \"an agent told different parties different\nthings\" gap that nothing else does, and is upfront about the identity layer that sits above it.\n\n## Notes\n\n- **No authentication, no rate limits, no keys to manage.**\n- Runs on Cloudflare Workers at the edge — no cold starts.\n- Verity records *consistency of claims*, not their truthfulness: it proves an agent said the\n  same thing to everyone (or caught it not doing so), which is exactly what you can't check today.\n","endpoints":"https://verity.swasthikadevadiga2.workers.dev/attest\nhttps://verity.swasthikadevadiga2.workers.dev/lookup?agent_id=two-faced&key=owner\nhttps://verity.swasthikadevadiga2.workers.dev/root\nhttps://verity.swasthikadevadiga2.workers.dev/consistency?first=1&second=2\nhttps://verity.swasthikadevadiga2.workers.dev/verify\nhttps://verity.swasthikadevadiga2.workers.dev/verify-inclusion\nhttps://verity.swasthikadevadiga2.workers.dev/pubkey\nhttps://verity.swasthikadevadiga2.workers.dev/health","tags":"non-equivocation, transparency-log, ed25519, merkle, rfc6962, notary, accountability","reachable":null,"created_at":"2026-07-11T15:35:05.170Z"}}