Offline verification
The reason the Data Exchange verifies trust the way it does is a single hard requirement: an organization must be able to accept a listing on a disconnected, sovereign, air-gapped cell, with no shared secret and no coordinator to phone. That is a verification problem, and it is solved locally.
Verify-only, and why the boundary sits there
Accepting a listing is a verification problem, offline, per-cell, judged against a clock the caller supplies. The market that produced the listing is a connectivity problem, and that stays where connectivity is. So the roles split cleanly:
- Signing, minting, settlement, and the live request/approve lifecycle are the publishing side's acts and run on a full cell.
- Verifying a listing you did not mint, and reading from a cell, is what the edge does in isolation.
The Edge Agent is a consumer and verifier: it verifies cross-org listings offline and pins peer-org keys with validity windows. It does not serve data across the org boundary, data never crosses that boundary at all, only the signed listing does, and it does not mint listings or run the exchange lifecycle.
The Edge Agent is verify-only in isolation, but an edge deployment can run a cell at the site. With a cell on the device, the complete data platform and the exchange, serving, marketplace, and settlement, run locally, sovereign and air-gapped. The agent is the on-device verify-and-operate layer; the site cell is the local data plane. The edge device itself never becomes a data-serving plane on its own.
Pinned peer-org keys
A listing is verified against a peer-org key pin the operator provisioned out of band, the manual trust edge that stands in for a shared secret. A pin carries the peer's raw Ed25519 public key and, for a hybrid pin, its independently pinned ML-DSA-65 public key; a validity window; a status (active or revoked); and an optional attenuation ceiling for that peer's listings. The pin's fingerprint is recomputed from the key at load and never trusted from the wire, so a corrupt entry cannot pin a key under the wrong identity.
The gate cascade: deny-closed, in order
Verification is stateless, pure, offline, and fail-closed. It runs a fixed cascade and only reports success if every gate passes:
- Known, active publisher: the listing's signer must resolve to a pin that
is
active. An unknown or revoked org is refused, and no cryptography is run for it. - Pin validity window: the pin itself must be within its own validity window, checked against the caller's clock before any cryptography.
- Content-hash integrity: the listing's record hash must equal the hash of its canonical bytes, so a tampered field reads as a hash mismatch.
- Fingerprint match: the carried signer fingerprint must name the key being checked against.
- Signature: the hybrid (or classical) signature must verify over the domain-separated message; a downgrade against a hybrid pin is refused here.
- Reach: the listing's reach must be the cross-org value.
- Validity window: the caller-supplied clock must fall inside the listing's
[issued, expires)window. - Attenuation: the listing's scope must be a subset of the importer's pinned ceiling.
- Content: if an expected content hash was supplied out of band, it must match.
The verifier returns an error only on a programming fault (a wrong-length key, an encoding failure), never on a policy or listing mismatch. Those are captured as a verdict with the first failing gate named, so a refusal is an answer, not a crash.
A clock the caller supplies
An air-gapped cell has no trustworthy wall clock to reach for, so the caller supplies the time anchor. Validity windows are judged against that caller-provided clock, which lets a disconnected cell reason about "is this listing still valid" using its own anchor-corrected time rather than a network time source.
Two-runtime parity
The edge verifier and the core mint the same canonical bytes and run the same verdict cascade, pinned by cross-language fixtures so both runtimes make the same decision for the same listing. Where a capability can land on only one side first live cross-org key discovery and the live request/approve flow are core-side, it is recorded as owed work rather than allowed to drift.
Across the deployment matrix
- Single-cell: one cell verifies against its pinned peer keys.
- Multi-cell: each cell verifies independently; there is no shared verifier to coordinate.
- Sovereign / air-gapped: the whole point: verification runs with outbound network access denied.
- Cloud-enabled: the same verifier, with online key provisioning as a convenience rather than a requirement.
Run it at the edge
The gate has a production entry point on the Edge Agent, s9 exchange verify-listing. It verifies a hand-carried listing against the pinned peer-org
keys, deny-closed, and mints a signed deny-receipt on refusal:
# Verify a couriered listing against your out-of-band pins
s9 exchange verify-listing \
--listing /media/usb/peer-offer.json \
--pins ./peer-org-pins.json
# Optionally bind the offer to the exact payload you are about to pull
s9 exchange verify-listing \
--listing /media/usb/peer-offer.json \
--pins ./peer-org-pins.json \
--content-hash "$EXPECTED_SHA256"
The pins default ships empty, so a device with no pins deny-closes every listing. For the full walkthrough, including the refusal path, see the tutorial Verify a Data Exchange listing offline.