Nhảy tới nội dung

Conformance & Security

Normative spec

The authoritative cross-implementation conformance discipline is Protocol · Conformance & parity; the blind serving model is Protocol · The blind host model. This page is the task-oriented node-operator contract.

The dig RPC is designed so that any node can join the network's read path by implementing one interface exactly. This page is the contract.

The blind serving model

A node stores, per hosted generation, the compiled .dig capsule — a self-defending WebAssembly module that is both the data and the code that gates access to it. To serve a resource, the node runs the capsule's own serve flow for the requested retrieval key inside a bounded host runtime. The capsule returns a ContentResponse envelope carrying the resource's ciphertext and a merkle inclusion proof rooted at the generation's content root. The node decodes the envelope framing host-side to split the two — which is not decryption, the ciphertext stays sealed — and returns ciphertext (base64) + proof (base64). The host runtime holds no URN and no key, so it never reads what it serves.

Decoys: no existence oracle

On any content miss — unknown store, unknown retrieval key, a root with no hosted capsule — the capsule returns a deterministic pseudo-random stream seeded by the requested key, byte-shaped identically to a hit. There is no decoy flag on the wire: the response is indistinguishable, so a passive observer (and the operator) cannot tell a hit from a miss by status, shape, or size. The client learns not-found only when the inclusion proof fails to verify or the GCM-SIV tag fails to decrypt. (A genuine infra failure — no host seed, module absent, a trap, an undecodable envelope — is the distinct error -32004, not a decoy.)

Root resolution

When root is an explicit 64-hex value, the node serves that exact generation. When root is "latest" or absent, the node resolves the store's newest confirmed generation from its capsule index and serves that; the resolved root is echoed back as root. Because a store's existence and its generation list are already public on-chain (and via dig.listCapsules), a "latest" request against a store with no confirmed generation returns an error, not a decoy — that is store-level discovery, not a private-resource oracle.

A trustless client pins an explicitly chain-verified root rather than relying on the node's "latest" resolution.

CORS and cross-origin use

The RPC is a public, credential-free service over public ciphertext, so it is fully cross-origin. A node must answer OPTIONS with 204 and set, on every response:

Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, OPTIONS
Access-Control-Allow-Headers: content-type
Access-Control-Max-Age: 86400

Cookies and credentials are never used or honored. This lets any web app, a sandboxed preview origin, or any third-party site call any node directly from the browser. A node must send a strict content-security and nosniff posture so its opaque JSON is never interpreted as an executable document.

Caching and immutability

RPC responses are not edge-cached: the body is a POST result and a single chunk request is cheap. Content is nonetheless effectively immutable when addressed by an explicit (store_id, root, retrieval_key, offset) tuple — the generation root pins the exact bytes — so a client may cache a verified, decrypted resource keyed by that tuple. A "latest" read is mutable by definition; clients that need stability pin the root echoed in the first chunk.

Rate limits and abuse

Rate limiting and request shaping are node-operator policy, not part of the wire contract. A node may reject or throttle abusive callers by IP or volume, and should do so without revealing content state (a throttle is an HTTP-level rejection, never a JSON-RPC error tied to a specific store or key). Because the interface is blind and read-only, the abuse surface is bandwidth, not data exposure.

Conformance checklist

A node is a conformant dig RPC endpoint if and only if it:

  • accepts JSON-RPC 2.0 single and batch requests over HTTPS POST at a single origin, and answers OPTIONS per the CORS rules above;
  • implements dig.getContent, dig.getProof, dig.getProofStatus, dig.getCapsule (and the dig.getModule alias), dig.getManifest, dig.getMetadata, dig.listCapsules, dig.health, and dig.methods with the documented parameters and results;
  • returns the REAL merkle inclusion proof synchronously and serves only REAL execution-proof receipts (a forgeable mock is never published as a proof);
  • streams byte methods with the chunk object, snapping to 64 KiB blocks and capping at the declared max chunk, with correct total_length, complete, and next_offset;
  • returns sealed ciphertext plus a root-anchored inclusion proof for real dig.getContent/dig.getManifest hits, and never returns a URN, a key, or plaintext;
  • answers every content miss with an indistinguishable decoy stream (no decoy flag on the wire), never a 404 or a distinguishing error, and never exposes an existence oracle for a private resource;
  • resolves "latest" to the newest confirmed generation and echoes the resolved root; and
  • uses the JSON-RPC error codes only for malformed or unroutable calls.
ghi chú

The full normative text is the Protocol · The dig RPC section — the network content interface — alongside the DIGHUb API Interface.