Expand description
The browser content-VERIFICATION contract — how a blind client turns opaque gateway bytes into verified plaintext, fail-closed, over INJECTED crypto primitives.
§Trust model
On the blind (rpc/gateway) tier a client fetches opaque ciphertext + an inclusion proof from an UNTRUSTED public gateway. The gateway can lie about anything except what the chain anchors, so the client MUST verify every byte against the URN’s PINNED root (obtained from the chain, NEVER from the gateway) before trusting it. The node tier does NOT use this contract — a loopback node decrypts + verifies server-side and returns plaintext under a loopback trust boundary.
§The normative rules (all enforced here, fail-closed)
- Rootless-URN rejection. A rootless URN cannot be verified on the blind tier (there is no
trusted root) →
ResolveError::RootRequired. Userequire_blind_root. - Leaf binding.
leaf == SHA-256(ciphertext)— the served ciphertext MUST be the proof’s declared leaf. (This crate owns this SHA-256 check; seeresource_leaf.) - Path fold. The proof’s merkle path MUST fold consistently to
proof.root— enforced by the injectedContentCrypto::decode_and_fold(returnsNoneon any inconsistency). - Root anchoring.
proof.root == trusted_root— the folded root MUST equal the chain-anchored root pinned by the URN. A decoy / wrong-store / tampered response can never chain to the real root. - Gate-then-decrypt. Decryption happens ONLY after 1–4 pass; the AEAD tag is the final gate.
- u64-bounded chunk split. The gateway-supplied
chunk_lensis NOT covered by the proof, so it is UNTRUSTED: it is accumulated and bounded inu64and sliced against the remaining buffer so a crafted length can never wrapusizeon wasm32 and slice out of bounds (→panic=abort, a wallet crash). Any inconsistency fails closed asResolveError::DecryptFailed.
The merkle-fold and AES primitives are supplied by the caller (digstore_core) via
ContentCrypto — this crate reimplements NO merkle or AES crypto, so it can never skew from
the canonical read-crypto.
Structs§
- Folded
Proof - A decoded, folded inclusion proof: its declared leaf and the root its merkle path folds to.
Traits§
- Content
Crypto - The crypto primitives this contract INJECTS from
digstore_core(never reimplemented here).
Functions§
- chunk_
ranges - Rule 6: split concatenated chunk ciphertexts into byte ranges under a u64-bounded plan.
- decrypt
- Rule 5 (confidentiality half): decrypt the verified ciphertext. Splits by
chunk_rangesand AES-opens each chunk in order via the injectedContentCrypto::decrypt_chunk. A tag failure on any chunk fails closed withResolveError::DecryptFailed. - require_
blind_ root - Rule 1: obtain the trusted root for a BLIND-tier verify, rejecting a rootless URN.
- resource_
leaf - The content leaf:
SHA-256(ciphertext)(rule 2). This is the only crypto this leaf crate performs directly; it matchesdigstore_core::resource_leaf. - verify_
and_ decrypt - The full blind-tier pipeline: gate-then-decrypt (rules 1–6). Rejects a rootless URN, verifies
inclusion against
trusted_root, then decrypts — decryption is reached ONLY after verification passes. - verify_
inclusion - Rules 2–4: the integrity gate. The served
ciphertextmust be the proof’s leaf, the path must fold to a root (via the injected decoder), and that root must equaltrusted_root. Any failure is a hard fail-closedResolveError::VerifyFailed.