Expand description
RFC 0008 — sealed payloads: carriage without readership. The reference implementation, spec/aph-0.2.md §§1-4 (v0.2, cut 2026-08-29).
RFC 0008 is Accepted onto the v0.2 line and implemented here: the
WIRE types live in aph-core
(re-exported below) so the envelope can carry them, the wire-version
rule (sealed_payload_is_declared) keeps them off any aphVersion-0.1
envelope, and THIS crate holds the cryptography plus the
envelope-level operations — seal_into_envelope /
unseal_from_envelope — that RFC 0008 §§3-4 specify. v0.1.0 itself is
untouched: a v0.1-only verifier still refuses the member at strict
parse, correctly.
Two scenarios, one mechanism (RFC 0008 §“The problem”):
- sealed TO THE RECEIVER: intermediate agents verify the envelope and carry what they cannot read;
- sealed TO THE SENDER (or any designated third key): the counterparty carries and proves receipt of what it cannot open.
The cryptography is RFC 9180 HPKE single-shot, one pinned suite
(X25519-HKDF-SHA256 / HKDF-SHA256 / ChaCha20-Poly1305), through the
pure-Rust hpke crate — this repository writes no cryptography. The
load-bearing choice is the AAD: a canonical CONTEXT — suite, reader id,
reader kid, envelope id — authenticates every seal, so a ciphertext
lifted into a different envelope OR relabeled about itself (a different
claimed reader, a different claimed suite) fails open even for its
rightful key. The audit probe that forced the widening is kept as a
test. Errors are this crate’s own type, deliberately
NOT APH_E-prefixed: the §11 set is closed, and RFC 0008 §5 assigns
codes when a version exists that can declare them.
Structs§
- Sealed
Payload - The wire types are
aph-core’s — the envelope carries them — and this crate re-exports them so a sealing caller needs one import path. A payload the envelope authorizes but onlySealedReadercan read (spec/aph-0.2.md §1, RFC 0008): verification and readership as independent capabilities. Every hop runs §8.3 in full — the signature covers this ciphertext,bodySha256MAY bind its raw decoded octets — and none but the reader learns the plaintext. - Sealed
Reader - The wire types are
aph-core’s — the envelope carries them — and this crate re-exports them so a sealing caller needs one import path. Who may open a sealed payload: a DID and which of itskeyAgreementkeys (spec/aph-0.2.md §1, RFC 0008 §2). Signing keys are never converted to encryption keys; the reader publishes a distinctkeyAgreemententry through the §8.4 surfaces.
Enums§
- Envelope
Seal Error - Why an envelope-level unseal can fail — three DIFFERENT kinds of failure with three different repairs, kept as distinct as the codes that carry two of them.
- Seal
Error - This crate’s own refusals — deliberately NOT
APH_Ecodes (RFC 0008 §5: the §11 set is closed, and names are minted by the version that can declare them, not by a draft).
Constants§
- SUITE
- The one suite this draft compiles. A wire member exists so a future version CAN move; an unseal of any other value refuses. Closed-set discipline applied to ciphersuites from birth (RFC 0008 §1).
Functions§
- seal
- Seals
plaintextso that ONLY the holder ofreader’s private key can open it, bound to the full seal CONTEXT — suite, reader, envelope id — as HPKE additional authenticated data (RFC 0008 §3). Sealing happens BEFORE the envelope is signed, so the signature covers the ciphertext and every hop verifies blind. - seal_
into_ envelope - Seals
plaintextINTO an envelope (RFC 0008 §3): binds the seal to the envelope’s ownidand claimed context, then places it oncredentialSubject.sealedPayload. Call this BEFORE signing — the signature must cover the ciphertext — and only on an envelope whoseaphVersiondeclares the member; anything else refuses up front rather than minting a wire no conformant verifier admits. - unseal
- Opens a seal with the reader’s private key, under the SAME context it
was sealed to — with
suiteandreadertaken from the sealed payload’s OWN claims, so a payload relabeled about itself refuses. Any mismatch — key, bytes, envelope, or claimed context — refuses with one indistinguishableSealError::OpenRefused, and RFC 0008 §4 tells a reader-verifier what that refusal means: refuse the ENVELOPE, because an unopenable seal addressed to you is evidence, not an inconvenience. - unseal_
from_ envelope - Opens the seal an envelope carries, for the reader holding the private
key (RFC 0008 §4): run AFTER the envelope itself verifies, and treat a
EnvelopeSealError::Refusedas a refusal of the ENVELOPE — an unopenable seal addressed to you is evidence, never a shrug. The wire-version rule runs first, so a mis-versioned envelope refuses before any cryptography.