DEOS Anchor Format — v1 Specification
Status: v1.0 — published 2026-05-02
Spec URI: https://projectmaya.deoscomputing.io/anchor/v1
Maintainer: DEOS Computing (did:web:deos.computing)
Companion: /anchor/bitcoin/v1
Receipts are signed and inclusion-proofed by the substrate, but "the substrate said it" is a weak time claim. An anchor binds a log root to one or more external timestamp authorities so that "this root existed by time T" is verifiable without trusting the substrate.
v1 supports OpenTimestamps (OTS) anchors. The substrate submits the log root to public OTS calendars; the calendars return pending proofs that, once aggregated and committed to Bitcoin, upgrade to Bitcoin-block-confirmed proofs.
This document is normative for v1.
1. Anchor record
An anchor is a JSON object stored under <data-dir>/anchors/<root_hex>.json
and served by GET /attestation/v1/anchor/{root_hex}:
{
"schema": "deos_anchor_v1",
"root": "<hex of log root>",
"leaf_count": 5,
"anchored_at_ns": 1730419200000000000,
"ots_proofs": [
{
"calendar_url": "https://alice.btc.calendar.opentimestamps.org",
"proof_b64": "<base64url-nopad of OTS pending-proof bytes>",
"proof_size_bytes": 172,
"submitted_at_ns": 1730419200000000000,
"calendars_in_proof": [
"https://alice.btc.calendar.opentimestamps.org"
]
},
{
"calendar_url": "https://bob.btc.calendar.opentimestamps.org",
"proof_b64": "...",
...
}
]
}
| Field | Required | Notes |
|---|---|---|
schema |
yes | MUST equal "deos_anchor_v1". |
root |
yes | The log root the anchor binds, lowercase hex. |
leaf_count |
yes | Log leaf-count at time of anchor. |
anchored_at_ns |
yes | Substrate's wall-clock estimate (NOT trusted by verifiers). |
ots_proofs |
yes | Array (may be empty if no calendars were configured / reachable). |
ots_proofs[].calendar_url |
yes | URL the substrate POSTed the digest to. |
ots_proofs[].proof_b64 |
yes | base64url-nopad of the calendar's response bytes (opaque pending-proof). |
ots_proofs[].proof_size_bytes |
yes | Byte length of the decoded proof. |
ots_proofs[].submitted_at_ns |
yes | When the substrate received the proof. |
ots_proofs[].calendars_in_proof |
yes | Calendar URLs extracted from the proof bytes (heuristic v1; see §4.1). |
An empty ots_proofs array is valid — it means the substrate was running
in offline mode (no calendars configured) or every configured calendar was
unreachable when the anchor was created.
2. OTS submission protocol
For each newly committed log root, the substrate:
- Takes the 32-byte raw root (as bytes — NOT hex).
- For each configured calendar URL, executes:
POST <calendar_url>/digest Content-Type: application/vnd.opentimestamps.v1 Accept: application/vnd.opentimestamps.v1 <body: 32 raw bytes> - On HTTP 2xx, stores the response body bytes as one entry in
ots_proofs. - On non-2xx or transport error, logs a warning and continues with the next calendar.
The OTS proof bytes are stored opaquely in v1. The substrate does not parse them beyond the URL-extraction heuristic in §4.1. v1.1 adds a full OTS-binary parser.
2.1 BLAKE3 vs SHA-256
OTS calendars accept any 32-byte digest. The DEOS substrate's log root is BLAKE3-256. The OTS calendar treats it as opaque 32 bytes — its eventual Bitcoin commitment binds the input bytes regardless of which hash function produced them. A verifier's interpretation: "the byte sequence equal to log root R existed before the Bitcoin block referenced in the upgraded proof." That binding is exactly what the substrate needs.
3. Anchoring policy
v1 anchors after every POST /attestation/v1/append (i.e., once per leaf).
Production substrates SHOULD batch anchors by time or leaf count to avoid
overloading public calendars.
The anchoring runs synchronously inside the append handler in v1 (simplicity over latency). v1.1 moves anchoring to a background thread.
4. Verification
A verifier examining an anchor record performs the following checks; any failure yields a soft warning, not a hard rejection. (Anchors strengthen "existed by time T" — a receipt without a verifying anchor is still authentic, just less time-bound.)
4.1 v1: extraction + presence
The v1 verifier:
- Fetches
GET /attestation/v1/anchor/{root_hex}. - Parses the anchor record per §1.
- For each entry in
ots_proofs, base64-decodesproof_b64and runs the URL-extraction heuristic — scan forhttp:///https://substrings, collect the embedded calendar URL(s). - Reports the set of calendars the proof attests to.
This proves: (a) the substrate did call calendars, (b) the proof bytes are well-formed at the URL level, (c) which calendars to ask for the upgraded (Bitcoin-confirmed) proof later.
This does NOT yet prove: that the substrate didn't fabricate the proof bytes. (It would, however, be exposed when an honest verifier later upgrades the proof and the calendar replies with a different — or nonexistent — proof for that input.)
4.2 v1.1: full OTS proof + Bitcoin upgrade
v1.1 introduces:
- A proper OTS binary-format parser that walks the operation stream, applies hash ops to the starting digest, and identifies attestation tags.
- A separate
upgradejob that periodically re-fetches each pending proof's URL (calendars expose the upgrade endpoint), replacing the pending proof with the Bitcoin-confirmed one once the calendar's batch is mined. - Bitcoin block-header verification (see
/anchor/bitcoin/v1) — supported header sources include blockstream.info SPV, a locally synced bitcoind, or a header-only LN node. - The verifier output upgrades from
anchor=presenttoanchor=bitcoin_confirmed block=<height> ts=<unix>.
The wire format of the anchor record DOES NOT change between v1 and v1.1 — v1 records continue to verify under v1.1 with the additional Bitcoin checks.
5. Trust model
What you trust by relying on a v1 anchor:
- The substrate honestly forwarded its log root to the named calendars.
- The OTS calendar(s) honestly returned a real pending proof and will honestly aggregate it into a Bitcoin commitment.
What you do not need to trust to verify a v1 anchor post-upgrade:
- The substrate (the cryptographic chain runs from the log root through the OTS proof to a Bitcoin block — DEOS is not in that chain).
- Any single calendar (multiple submissions = redundant anchors; an attacker would need to compromise all of them to forge a timestamp).
What v1.1 adds:
- The verifier can independently confirm the binding without trusting the calendar (verifies against Bitcoin consensus via block headers).
6. Endpoint
GET /attestation/v1/anchor/{root_hex}
200 -> the anchor record JSON (§1)
404 -> "no anchor for this root"
500 -> read/parse error
7. Server CLI
attestation-api --bind 127.0.0.1:8088 \
--data-dir /var/lib/deos-attestation \
--ots-calendars https://alice.btc.calendar.opentimestamps.org,https://bob.btc.calendar.opentimestamps.org
If --ots-calendars is absent or empty, the server runs in offline
mode: anchors are still created (with ots_proofs: []) but no network
calls are made. This mode is the default for tests and CI.
8. Anchor scheme registry
The anchor_record JSON object carries third-party timestamp evidence. v1 ships with one scheme — OpenTimestamps + Bitcoin — but additional schemes are planned (multi-rail anchors). To prevent ad-hoc field naming and enable verifier-side scheme dispatch, every anchor scheme MUST be registered here.
Scheme record shape
Every scheme is identified by a short ASCII ID (lowercase, hyphens-allowed, ≤32 chars) and registered with:
| Field | Type | Notes |
|---|---|---|
scheme_id |
string | Unique registry key; appears as the JSON field name in anchor_record. |
version |
integer | Bumped on any breaking change to the field contract. |
value_type |
string | One of array<object>, object, array<string>. Tells the verifier the shape to parse. |
time_source |
string | bitcoin / ethereum-l1 / private-tsa / internal — the trust authority. |
verifier_required |
boolean | True if a verifier MUST validate this scheme's proofs (vs. SHOULD). |
Registry
scheme_id |
version | value_type | time_source | verifier_required | spec |
|---|---|---|---|---|---|
ots_proofs |
1 | array<object> |
bitcoin |
true | this spec §1, /anchor/bitcoin/v1 |
eth_l1_timestamp |
1 | object |
ethereum-l1 |
false | anchor-eth v1.2 (planned) |
private_tsa |
1 | array<object> |
private-tsa |
false | anchor-tsa v1.2 (planned) |
A new scheme MUST update this table BEFORE shipping verifier code that emits the scheme's field. Implementations encountering an unregistered scheme_id MUST treat the anchor record as containing evidence they don't understand: log a warning, skip the unknown evidence, and continue verification with whatever registered schemes are present.
Scheme-version negotiation
anchor_record MAY carry multiple schemes simultaneously. Verifiers SHOULD prefer schemes with verifier_required = true; if none of the required schemes verify, the anchor is invalid even if optional schemes verify. This pattern lets v1.2 substrates emit private_tsa evidence alongside ots_proofs without weakening the ots_proofs requirement.
9. Anchor revocation / replacement [v1.3]
If an OTS calendar (or any registered anchor scheme) is later found to have been compromised — e.g. the calendar operator was malicious, or its signing key was leaked — DEOS needs a way to invalidate that calendar's proofs across ALL anchors that referenced it.
Status: design specified; implementation deferred to v1.3.
9.1 Revocation entry (proposed)
A new deos_anchor_revocation_v1 entry shape:
{
"schema": "deos_anchor_revocation_v1",
"scheme_id": "ots_proofs",
"anchor_authority": "https://alice.btc.calendar.opentimestamps.org",
"compromised_at_ns": 1730000000000000000,
"reason": "calendar key leaked per public disclosure",
"evidence_uri": "https://calendar-incident.example.com/2026-05-04",
"issuer": "<substrate DID or curated DEOS-Computing-signed root>",
"signature": { "alg": "ed25519", "kid": "...", "sig": "..." }
}
Two issuers are normative:
- Substrate-side: a substrate operator can revoke an anchor authority for receipts they emitted. Other substrates' receipts are unaffected.
- Curated: DEOS Computing publishes a signed list of compromised authorities at
https://anchors.deos.computing/revocations.json. Substrates SHOULD subscribe and treat revoked authorities as untrusted across all anchors.
9.2 Verifier behavior
A verifier with a fresh anchor revocation list MUST:
- Identify each anchor's
scheme_id+ authority (e.g. for OTS, the calendar URL). - If any (scheme_id, authority) is on the revocation list with
compromised_at_ns ≤ anchor.submitted_at_ns, treat that anchor proof as untrusted. - If after filtering, no trusted anchor remains AND
--require-third-party-anchoris set (operator policy), reject the receipt. - If after filtering, no trusted anchor remains AND
--require-third-party-anchoris not set, accept the receipt with an explicit "no third-party timestamp evidence" annotation.
9.3 Why deferred
OTS calendar compromise is rare with no known historical incident. v1.1 accepts the residual risk in exchange for a simpler implementation surface. v1.3 ships when either a real OTS or alternative-anchor compromise is observed, or an operator deployment requires the curated revocation feed.
Operators SHOULD subscribe to the OpenTimestamps mailing list and monitor the anchor scheme registry (§8) for incident reports.
10. Open questions deferred
- Full OTS binary-format parser — v1's URL-extraction heuristic surfaces "which calendars to ask later" but doesn't cryptographically verify the proof structure. v1.1.
- Bitcoin block-header verification — header source choice (SPV API, Electrum, bitcoind). v1.1.
- Upgrade job — periodic re-fetch of each pending proof, swapping in the Bitcoin-confirmed version. v1.1.
- Background anchoring — production anchors in a background thread, batched by time or leaf count. v1.1.
- Multi-rail anchors — non-OTS authorities (L2 timestamp service, private TSA, Ethereum L1 timestamp via oracle). The anchor schema admits these as parallel fields. v1.2.
11. Maintainer
DEOS Computing — design questions and conformance reports to github.com/DEOS-Computing.
License: CC BY 4.0 (text), Apache-2.0 (reference code).