ALL SYSTEMS LIVE·67 INSTRUMENTS · 18 VERTICALS
ED25519 · BITCOIN-ANCHORED·--:--:-- UTC
OPEN STANDARD · DF-VERIFY/1

The verification standard for AI that acts.

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, optional Bitcoin timestamping. Free to implement. Verifiable by anyone, in any language, even against us.

1Why a standard

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 timestamp the record on a public blockchain. 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.

2The signed envelope

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-4cb32e72f333",
    "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.

3Canonicalization — json-sorted-compact

To 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.

4Verification anyone, independently

  1. Parse the response. Lift out its signature block; keep the rest as the payload.
  2. Canonicalize the payload per §3.
  3. Fetch the public key set: GET /.well-known/keys (§5). Look up signature.key_id.
  4. Verify 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.

5Public keys (JWKS-style)

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-4cb32e72f333": "base64url( 32-byte Ed25519 public key )" }

Issuers SHOULD use a stable, long-lived signing key so historical records keep verifying. (An issuer with no configured key MAY sign with an ephemeral key for demos; such signatures carry an ephemeral_key flag and will not verify after a restart.)

An issuer's capabilities — keys, profiles, endpoints, reference verifiers, conformance vectors — are machine-discoverable at /.well-known/df-verify.json.

6Anchoring to Bitcoin optional

A signature proves who said it and that it is unaltered. To also prove when — independently, against the issuer — a record's hash MAY be committed to the Bitcoin blockchain via OpenTimestamps.

POST /v1/anchor   { "snapshot": { ...the signed record... } }  →
{ "chain": "bitcoin", "status": "pending",
  "digest_sha256": "…", "proof_ots_b64": "…" }

Only the SHA-256 of the canonical record goes on-chain — never the data itself. Once confirmed (~one block), the .ots proof shows the record existed no later than that block, verifiable with any standard OpenTimestamps client. It is free, wallet-less, and never on the request hot path.

7Attestation profiles

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).

Receipt — wrap any claim in a signed, timestamped record receipt/v1

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. Anchor a receipt's hash to Bitcoin via POST /v1/anchor 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.

Provenance envelope — every datapoint is sourced

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 trigger receipt — the dispute-proof settlement artifact trigger-receipt/v1

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 (anchorable to Bitcoin 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.

Intensity-at-location — the reading a trigger evaluates intensity/v1

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.

8Conformance

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.

9Status & versioning

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).

10Implement it in minutes

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.

Display it — the “Verified by Dynamic Feed” badge

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:

[![DF-VERIFY/1](https://dynamicfeed.ai/badge.svg)](https://dynamicfeed.ai/standard)

Renders as: DF-VERIFY/1 — verifiable grounding