Proof, not promises. An open, vendor-neutral way to sign, publish, and independently verify exactly what an AI system was told the moment it acted — Ed25519 over a canonical envelope, keys published as JWKS and optional RFC 3161 timestamp artifacts. Free to implement. Verifiable by anyone, in any language, even against us.
When an AI only writes text, a wrong answer is a bad sentence. When an AI acts — a robot moves, a trade fires, a filing is submitted — you need a tamper-evident record of exactly what it was told at the moment it acted, and you need it to be checkable by a third party who doesn't trust the source. "Trust me" is not an audit trail.
DF-VERIFY/1 defines a minimal way to attach a cryptographic signature to any JSON data response, publish the verifying key openly, and optionally request a third-party timestamp artifact for the record. It is the grounding-and-audit layer for agentic and embodied AI — and it is deliberately small, open, and implementable in a few lines on any platform.
The keywords MUST, SHOULD and MAY are used per RFC 2119.
A signed response is any JSON object that carries a top-level signature block. The signature is detached: it covers the entire object except its own signature field.
{
"snapshot_id": "1644aefdefbb43e7b540b8716b526e78",
"issued_at": "2026-06-09T20:47:52Z",
"issuer": "dynamicfeed.ai",
"schema": "awareness/v1",
"... any payload fields ...": "...",
"signature": {
"alg": "Ed25519",
"key_id": "df-ed25519-6ca0de29113b",
"canonicalization": "json-sorted-compact",
"sig": "base64url( Ed25519 signature, 64 bytes )"
}
}
The signature block MUST contain alg, key_id, canonicalization and sig. sig is the base64url (unpadded-tolerant) encoding of the raw 64-byte Ed25519 signature. key_id binds the signature to one published key (see §5), so keys can rotate without breaking old records.
json-sorted-compactTo get the exact bytes that were signed, a verifier MUST: (a) remove the signature field from the object; (b) serialize the remainder as JSON with all object keys sorted recursively, compact separators (, between items and : between key and value, no spaces), and non-ASCII escaped as \uXXXX (astral characters as UTF-16 surrogate pairs); (c) encode as UTF-8.
This is exactly Python's:
import json
canonical = json.dumps(payload_without_signature,
sort_keys=True,
separators=(",", ":")).encode("utf-8")
Numbers are emitted verbatim as they appear in the source JSON — a conformant verifier MUST NOT reparse them through a lossy float, or re-canonicalization will not match byte-for-byte.
signature block; keep the rest as the payload.GET /.well-known/keys (§5). Look up signature.key_id.Ed25519( sig, canonical_bytes, public_key ). If it passes, the record is authentic and unaltered. Change a single byte of the payload and it fails.# 1) fetch a signed verdict (keyless)
curl -X POST https://dynamicfeed.ai/v1/awareness -H "Content-Type: application/json" \
-d '{"robot":{"class":"aerial"},"location":{"lat":51.5,"lon":-0.12}}'
# 2) fetch the public key, then verify the Ed25519 signature over the canonical payload
curl https://dynamicfeed.ai/.well-known/keys
Reference implementations (all share this exact canonical form, byte-for-byte):
Python — scripts/verify_awareness.py; in-browser JavaScript — /verify.js (powers the live check at /proof); C# — clients/csharp/AwarenessClient.cs.
GET /.well-known/keys returns a map of key_id → base64url-encoded raw 32-byte Ed25519 public key. A verifier MUST select the key whose id matches the signature's key_id; if no such id is present (e.g. the key has rotated), verification MUST fail closed.
GET /.well-known/keys →
{ "df-ed25519-6ca0de29113b": "base64url( 32-byte active Ed25519 public key )" }
The compatibility endpoint publishes only the active key and is served with Cache-Control: no-store. Historical key bytes and lifecycle state live at /.well-known/signing-key-registry.json. A verifier MUST apply that lifecycle policy: the former key df-ed25519-4cb32e72f333 is compromised from 2026-07-11T00:00:00Z, and an untrusted receipt timestamp cannot make a former-key receipt acceptable.
Production issuers MUST use a configured persistent key. Dynamic Feed does not permit ephemeral signing in production.
An issuer's capabilities — keys, profiles, endpoints, reference verifiers, conformance vectors — are machine-discoverable at /.well-known/df-verify.json.
A signature proves who signed the bytes and that they are unaltered. A record's SHA-256 hash MAY be submitted to an RFC 3161 Time-Stamping Authority, which returns a signed CMS timestamp token. RFC 3161 is not OpenTimestamps and does not commit the hash to Bitcoin.
POST /v1/anchor { "snapshot": { ...the signed record... } } →
{ "backend": "rfc3161", "status": "confirmed",
"digest_sha256": "…", "gen_time": "…", "token_b64": "…" }
Only the SHA-256 digest is submitted — never the record itself. Token presence alone is not independent verification. Before accepting an existed-by time claim, a verifier must validate the complete CMS token signature, message imprint and digest, TSA certificate chain, timestamping EKU, revocation status, trust anchor and claimed time. Dynamic Feed does not currently claim that every issued or stored RFC 3161 artifact has completed that full independent validation.
The envelope (§2–§6) is generic. A profile fixes the payload shape for a use case; the schema field names it.
awareness/v1 — a go / caution / no-go verdict for an acting system{ "schema": "awareness/v1", "issuer": "dynamicfeed.ai",
"snapshot_id": "…", "issued_at": "…Z",
"robot": { "class": "aerial" }, "location": { "lat": 51.5, "lon": -0.12 },
"verdict": { "status": "caution", "advisory": "…" },
"facts": [ { "id": "wx.wind_kmh", "value": 21, "unit": "km/h",
"source": "Open-Meteo", "age_s": 240, "stale": false } ],
"degraded": false,
"signature": { "alg": "Ed25519", "key_id": "…", "canonicalization": "json-sorted-compact", "sig": "…" } }
A verdict MUST NOT be go when degraded is true — missing or stale safety inputs floor it to caution. A physical system never gets a falsely-confident answer.
Machine-readable schema: /schemas/awareness-v1.json (JSON Schema 2020-12; the degraded → not go safety floor is encoded as an if/then constraint, so a conformant validator rejects a degraded go).
POST /v1/receipt with {"claim":"…"} (or {"data":…}) returns a signed receipt/v1 envelope — provable evidence of what an AI was told or asserted, and when. It is the audit artifact a regulated workflow keeps, and it verifies with the exact same procedure as §4 (drop signature, canonicalize, check the Ed25519 signature).
{ "schema": "receipt/v1", "issuer": "dynamicfeed.ai",
"issued_at": "2026-06-09T20:47:52Z",
"data": { "claim": "unit price was 19 USD at quote time" },
"signature": { "alg": "Ed25519", "key_id": "…", "canonicalization": "json-sorted-compact", "sig": "…" } }
Machine-readable schema: /schemas/receipt-v1.json. Timestamp a receipt's hash via POST /v1/anchor (RFC 3161) for independent proof of when.
Grounded receipts. Because data is arbitrary JSON, a receipt can carry not just the claim but the evidence behind it — the live datapoints, each with source, licence and timestamp, that the AI was told when it acted. That is the artifact a regulated workflow keeps: not "the model said $19," but "the model said $19 because these signed sources reported it at time T" — a tamper-evident, independently-checkable record of the grounding behind a decision.
Every value Dynamic Feed serves carries source, licence, measured_at and age_seconds, so a grounded claim can be traced to its publisher and its freshness checked.
Parametric catastrophe policies pay out when a measured trigger is crossed — wind above X, rainfall above Y, quake above M. The recurring friction is the settlement dispute: was that the official reading, at the right place and time, unaltered, and judged by a neutral party? GET /v1/trigger-receipt answers it with a signed trigger-receipt/v1 envelope built as the neutral calculation-agent-of-record — Dynamic Feed underwrites nothing, so its determination is structurally independent.
{ "schema": "trigger-receipt/v1", "issuer": "dynamicfeed.ai", "peril": "weather",
"trigger_definition": { "metric": "wind_kmh", "operator": "gte", "threshold": 150,
"source_of_authority": "Open-Meteo (open-meteo.com)",
"methodology": "Trigger MET iff observed wind_kmh ≥ 150 km/h …",
"methodology_hash": "sha256:…" },
"observation": { "measured_value": 162.4, "unit": "km/h", "source": "Open-Meteo",
"source_url": "https://api.open-meteo.com/v1/forecast?…",
"raw_reading_hash": "sha256:…" },
"determination": { "triggered": true, "payout_factor": 1.0, "rationale": "…" },
"signature": { "alg": "Ed25519", "key_id": "…", "canonicalization": "json-sorted-compact", "sig": "…" } }
Four properties make it dispute-proof, and each is independently checkable: (1) a methodology_hash pins the determination function so nobody can move the goalposts after the event; (2) a re-fetchable source_url + a raw_reading_hash — with the exact, reproducible hashing recipe named in the receipt (hash_method), so per-request timing noise can't break reproduction — let any party re-pull the official source and confirm the reading was not altered: verifiability, not "trust us"; (3) the determination is a deterministic function of the pinned methodology and the reading, so any party re-computes the same triggered + payout_factor; (4) the Ed25519 signature (timestampable via POST /v1/anchor) proves the receipt existed at time T and that no byte was changed.
Scope. The receipt attests that the cited official source reported a reading at a time, and what the pinned methodology implies from it. It does not attest to ground-truth physical loss — that boundary is what keeps the role neutral and the determination reproducible. Machine-readable schema: /schemas/trigger-receipt-v1.json. v0.1 covers weather metrics (wind, temperature, precipitation); location-resolved intensity layers for more perils are rolling in.
A parametric trigger needs the intensity of the parameter at the insured coordinate, not just that an event occurred. GET /v1/intensity?peril=&lat=&lon= returns that point reading as a signed intensity/v1 envelope — value + unit, the resolution method (interpolation_method), a latency tier (detection / provisional / operational / authoritative), and a re-fetchable source_url + reproducible raw_reading_hash. v1 covers flood (nearest USGS NWIS stream gauge — gage height / discharge, point-resolved, no interpolation); drought, wildfire and earthquake (ShakeMap, with a kept-forever version archive) intensity are rolling in. Schema: /schemas/intensity-v1.json. It is the reading layer beneath trigger-receipt/v1.
A family of receipt/v1 profiles — the same signed envelope, verifiable under §3–§5 — for the things AI systems do. The caller hashes the sensitive parts locally; only hashes + non-PII labels are witnessed.
txn-receipt/v1 — a neutral witness of a machine-to-machine / agent-to-agent transaction (POST /v1/witness). A witness BESIDE the deal, never the money path.inference-receipt/v1 — ProofOfModel: which model actually answered vs the one requested, plus the provider's own fallback flag (POST /v1/inference-receipt). Prompt + response hashed locally.robot-receipt/v1 — the embodied “black box”: the go / caution / no-go a robot acted on + which model decided (POST /v1/robot-receipt). Advisory evidence — not a safety system, not the actuator.eval-receipt/v1 — a Verified Eval: a benchmark score against a sealed test set committed before the run, so the set stays private and the score is un-retunable (POST /v1/eval-receipt).Each is advisory evidence — Dynamic Feed witnesses that the record existed and is intact (tamper-evident); it does not re-run, adjudicate, or certify. Schemas: txn · inference · robot · eval. One-call minting via the dynamicfeed-witness package; live demos at /receipts and /a2ui.
A response is DF-VERIFY/1 conformant if its signature block verifies against the published key under §3–§5. "Verified by Dynamic Feed" means exactly that — checked client-side, against the open key, with the open reference verifier. The standard is free to implement and imposes no dependency on Dynamic Feed: anyone can issue, and anyone can verify, including against us. That independence is the point.
Conformance vectors. The repo ships language-agnostic test vectors at tests/vectors/ — canonicalization cases (recursive key sorting, ensure_ascii \uXXXX escaping including astral surrogate pairs, and signature-stripping) plus a real signed envelope and a tampered twin. A conformant verifier reproduces every canonical byte, accepts the authentic record, and rejects the tampered one. Run python3 tests/verify_vectors.py to check an implementation; the Python and JavaScript reference verifiers both pass byte-for-byte.
This is DF-VERIFY/1, the live form that signer and all reference verifiers share today. The canonicalization field names the algorithm so future forms are unambiguous; a strict RFC 8785 (JCS) profile is a planned refinement and will ship under a new canonicalization name, leaving existing records verifiable. Profiles are versioned by their schema string (e.g. awareness/v1).
The entire verifier is a dozen lines. Copy this — it needs only a standard Ed25519 library and works against any DF-VERIFY/1 issuer, including us:
import base64, json, urllib.request
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
def b64(s): return base64.urlsafe_b64decode(s + "=" * (-len(s) % 4))
def verify(env, base="https://dynamicfeed.ai"):
sig = env["signature"]
payload = {k: v for k, v in env.items() if k != "signature"}
canon = json.dumps(payload, sort_keys=True, separators=(",", ":")).encode()
jwks = json.load(urllib.request.urlopen(base + "/.well-known/keys"))
Ed25519PublicKey.from_public_bytes(b64(jwks[sig["key_id"]])).verify(b64(sig["sig"]), canon)
return True # raises on any tampering, or if the signing key isn't published
Or don't write it at all. Clone the runnable example agent — it grounds on a live feed and refuses to act on data it can't verify — and have it running in under five minutes:
git clone https://github.com/dynamicfeed/df-verify
cd df-verify/examples/verified-agent
pip install cryptography
python agent.py # verify a live verdict, then act
python agent.py --tamper # altered after signing -> the agent refuses to act
Reference implementations in the repo: clients/python (the dynamicfeed-verify package), examples/verified-agent (the demo above), in-browser /verify.js, and C# clients/csharp — all sharing the §3 canonical form byte-for-byte.
If your product grounds on DF-VERIFY and checks signatures before it acts, show it. This badge is self-contained (inline styles, no script) and links back to this standard — paste it anywhere:
<a href="https://dynamicfeed.ai/standard"
style="display:inline-flex;align-items:center;gap:7px;text-decoration:none;
font:600 13px/1 ui-sans-serif,system-ui,sans-serif;color:#cfe9ff;background:#0a0e16;
border:1px solid #1c2740;border-radius:999px;padding:8px 14px">
<span style="color:#46e6da">✓</span> Verified by Dynamic Feed
</a>
Renders as: ✓ Verified by Dynamic Feed
For a README or repo, use the SVG badge:
[](https://dynamicfeed.ai/standard)