pub struct VerifiedContext { /* private fields */ }Expand description
A retrieved context that has been cryptographically verified.
Every value of this type is the output of one of the
VerifiedContext::fetch* pipelines, each of which independently
recomputes content_hash (RFC-ACDP-0001 §5.11) and verifies the
producer signature before the value is constructed. The fields are
private precisely so this “cryptographically verified” invariant
cannot be forged: there is no way to construct a VerifiedContext
around an unverified FullContext. Downstream code can therefore
trust the accessors below without re-deriving anything.
Implementations§
Source§impl VerifiedContext
impl VerifiedContext
Sourcepub async fn fetch(
client: &RegistryClient,
resolver: &WebResolver,
ctx_id: &CtxId,
) -> Result<Self, AcdpError>
pub async fn fetch( client: &RegistryClient, resolver: &WebResolver, ctx_id: &CtxId, ) -> Result<Self, AcdpError>
Retrieve a context and verify its signature using the strict
default VerificationPolicy.
Sourcepub async fn fetch_with_policy(
client: &RegistryClient,
resolver: &WebResolver,
ctx_id: &CtxId,
policy: &VerificationPolicy,
) -> Result<Self, AcdpError>
pub async fn fetch_with_policy( client: &RegistryClient, resolver: &WebResolver, ctx_id: &CtxId, policy: &VerificationPolicy, ) -> Result<Self, AcdpError>
Retrieve a context and verify its signature with caller-controlled strictness.
- Fetches
body + registry_statefrom the registry. - Refuses a served body whose
ctx_iddiffers from the one requested (AcdpError::ContextIdMismatch) — this implements RFC-ACDP-0006 §4.1 step 7 (NORMATIVE, “Bind the resolved identity”): neither the signature check (step 5) nor thecontent_hashrecomputation (step 6) can supply this binding, becausectx_idsits in the RFC-ACDP-0001 §5.7 registry-assigned exclusion set and is therefore stripped from ProducerContent before hashing. See RFC-ACDP-0008 §9.1 for the threat this closes: without it, a registry can serve any other validly-signed body by the same producer under the requested context’s URL, and both preceding checks still pass. Step 7 permits a consumer to surface “an equivalent typed error” in place of the registry-sidecross_registry_resolution_failedwire code —ContextIdMismatchis that typed error. This generalizes the receipt-path analogue at RFC-ACDP-0010 §8 step 3 to the receipt-less core-profile path, where it is the only binding available. It does not close §9.1 in full: a registry that genuinely republishes the same content under a newctx_idstill passes; only serve-time substitution — a different id claimed to be the one requested — is caught. - Optionally runs
validate_body— structural schema checks plus embedded-DataRefhash verification (policy-controlled). - Recomputes
content_hashover ProducerContent. - Resolves the producer’s DID document.
did:webis required unconditionally for v0.1.0 (RFC-ACDP-0001 §5.4). - Verifies the Ed25519 signature (or other supported algorithm).
- Optionally verifies the
registry_receiptplaceholder. - Optionally rejects unknown statuses.
Sourcepub async fn fetch_current(
client: &RegistryClient,
resolver: &WebResolver,
lineage_id: &LineageId,
) -> Result<Self, AcdpError>
pub async fn fetch_current( client: &RegistryClient, resolver: &WebResolver, lineage_id: &LineageId, ) -> Result<Self, AcdpError>
Retrieve the current head of a lineage
(GET /lineages/{lineage_id}/current) and verify it with the
strict default VerificationPolicy — including the
lineage-head receipt when the registry minted one (ACDP 0.3,
RFC-ACDP-0011).
Sourcepub async fn fetch_current_with_policy(
client: &RegistryClient,
resolver: &WebResolver,
lineage_id: &LineageId,
policy: &VerificationPolicy,
) -> Result<Self, AcdpError>
pub async fn fetch_current_with_policy( client: &RegistryClient, resolver: &WebResolver, lineage_id: &LineageId, policy: &VerificationPolicy, ) -> Result<Self, AcdpError>
Retrieve + verify the current head of a lineage with caller-controlled strictness.
Runs the same pipeline as Self::fetch_with_policy against
the /current response (the expected ctx_id is the served
body’s own — there is no requested identifier on this endpoint;
the head receipt’s §7 step 5 byte-match is what binds it), then
applies policy.lineage_head to the response’s
lineage_head_receipt per RFC-ACDP-0011 §7:
ReceiptPolicy::Ignore— the raw value is preserved verbatim, unverified.ReceiptPolicy::VerifyIfPresent— verified when present (absence is fine: the registry may not advertiseacdp-registry-head-receipts).ReceiptPolicy::Require— fail closed withinvalid_receiptunless present AND verified.
Verification fetches the registry’s capabilities document for
the §7 step 3 capabilities.registry_did binding. Staleness
beyond policy.lineage_head.max_age_seconds is a freshness
verdict reported via Self::head_receipt_stale, never a
verification failure (§6).
Self::fetch_with_policy now additionally refuses a served body
whose ctx_id is not the one requested (RFC-ACDP-0008 §9.1). This
endpoint has no requested identifier to compare against — the
served head’s ctx_id is trivially “the one requested” — so on a
receipt-less registry the served head’s identity rests entirely on
registry honesty (RFC-ACDP-0008 §9.1). Use ReceiptPolicy::Require
where that matters.
Sourcepub async fn fetch_report(
client: &RegistryClient,
resolver: &WebResolver,
ctx_id: &CtxId,
policy: &VerificationPolicy,
) -> Result<(Self, VerificationReport), AcdpError>
pub async fn fetch_report( client: &RegistryClient, resolver: &WebResolver, ctx_id: &CtxId, policy: &VerificationPolicy, ) -> Result<(Self, VerificationReport), AcdpError>
Retrieve + verify, returning a structured VerificationReport
alongside the verified context. Does NOT attempt external
DataRef fetches — use Self::fetch_report_with_fetcher for
that. Each data_ref_external slot in the returned report is
None.
Unlike Self::fetch_with_policy, per-DataRef embedded-hash
failures are recorded in the report instead of aborting the
verification. The top-level checks (schema, body hash,
signature) remain hard-fail: if any of them fails, the method
returns an AcdpError and produces no report.
For diagnostic callers that want a populated report even when
a top-level check fails (e.g. an audit walker that needs to
distinguish “wrong hash” from “wrong signature”), use
Self::fetch_report_diagnose instead.
Sourcepub async fn fetch_report_diagnose(
client: &RegistryClient,
resolver: &WebResolver,
ctx_id: &CtxId,
policy: &VerificationPolicy,
) -> Result<(Option<Self>, VerificationReport), AcdpError>
pub async fn fetch_report_diagnose( client: &RegistryClient, resolver: &WebResolver, ctx_id: &CtxId, policy: &VerificationPolicy, ) -> Result<(Option<Self>, VerificationReport), AcdpError>
Diagnostic variant of Self::fetch_report that never
short-circuits on a top-level failure — schema, body-hash, and
signature outcomes are each recorded individually in the
returned VerificationReport. Returns Ok((None, report))
when any top-level probe failed (the report shows which one);
Ok((Some(verified), report)) only when every check passed
(FEAT-05) — and “every check” now genuinely means every
authorization phase (receipt, revocation, signature/
historical-key, unknown-status), not just the top-level probes:
once the probes pass, this method additionally runs the same
verify_retrieved phase fetch_with_policy does, and withholds
the handle — recording the cause in
VerificationReport::policy_phase_error — if that phase fails
too. Either way the method still returns Ok; it never converts
a policy-phase failure into an Err.
Use cases:
- Audit walkers that need to classify failures by stage.
- Admin tooling that wants to distinguish “hash mismatch” (probable tampering / encoding drift) from “signature verification failed” (key compromise / DID resolution problem).
Network errors from the initial retrieval still propagate as
Err — there’s no body to inspect when the registry is
unreachable. But network/DID-resolution errors that occur
inside the verify_retrieved phase (e.g. resolving the
fingerprint for a receipt cross-check, or the historical-key
fallback) are caught there and land in
VerificationReport::policy_phase_error instead of Err,
same as any other phase failure — this method never
short-circuits once retrieval has succeeded. That means a
transient network flake at that stage can read as a policy
rejection (Ok((None, report))) rather than an Err. A caller
that needs to tell a flake from a genuine rejection should
inspect policy_phase_error’s AcdpError::is_transient.
Stage-classification caveat: verify_retrieved (and therefore the
receipt/revocation/signature/historical-key phases it runs) is only
attempted once ALL top-level probes pass, ctx_id_ok included — see
all_top_level_pass below. So when ctx_id_ok is false,
policy_phase_error stays None even if the served body also
carries a receipt that would independently fail its own cross-check
(e.g. a receipt genuinely bound to the served, substituted body —
RFC-ACDP-0010 §8 step 3 — rather than the requested one). A caller
classifying a ctx_id_ok: false report should not read a None
policy_phase_error as “the receipt/signature phases passed” — they
were never attempted.
Sourcepub async fn fetch_report_with_fetcher<F: DataRefFetcher>(
client: &RegistryClient,
resolver: &WebResolver,
ctx_id: &CtxId,
policy: &VerificationPolicy,
fetcher: &F,
) -> Result<(Self, VerificationReport), AcdpError>
pub async fn fetch_report_with_fetcher<F: DataRefFetcher>( client: &RegistryClient, resolver: &WebResolver, ctx_id: &CtxId, policy: &VerificationPolicy, fetcher: &F, ) -> Result<(Self, VerificationReport), AcdpError>
Retrieve + verify like Self::fetch_report, and additionally
fetch every DataRef whose location resolves through fetcher.
Each external fetch outcome is recorded in report.data_ref_external.
pub fn body(&self) -> &Body
pub fn registry_state(&self) -> &RegistryState
Sourcepub fn full_context(&self) -> &FullContext
pub fn full_context(&self) -> &FullContext
The verified FullContext (body + registry state + any
receipts) in its retrieval shape. Every field was reached only
after this context’s hash + signature were verified.
Sourcepub fn key_status(&self) -> KeyAuthorization
pub fn key_status(&self) -> KeyAuthorization
Whether the body verified against a currently authorized key, a
receipt-attested historical one, or a receipt-attested
pre-compromise one (ACDP 0.2 WS-B / RFC-ACDP-0014 §7). This is
the real verdict regardless of which fetch*/fetch_report*
entry point produced this VerifiedContext — every construction
path runs the same verify_retrieved phase to derive it.
Sourcepub fn verified_receipt(&self) -> Option<&RegistryReceipt>
pub fn verified_receipt(&self) -> Option<&RegistryReceipt>
The verified registry receipt (RFC-ACDP-0010), when one was
present and the policy verified it. None under
ReceiptPolicy::Ignore or when the registry minted none — this
is exhaustive; there is no additional “or you used a report path”
carve-out, since fetch_report/fetch_report_with_fetcher/
fetch_report_diagnose verify the receipt exactly like
fetch_with_policy does. For the raw on-wire value see
Self::receipt.
Sourcepub fn receipt_key_status(&self) -> Option<ReceiptKeyStatus>
pub fn receipt_key_status(&self) -> Option<ReceiptKeyStatus>
RFC-ACDP-0010 §8 step 1 status of the key that signed the
verified receipt (0.5.0): ReceiptKeyStatus::Current when it is
in the registry DID document’s assertionMethod,
ReceiptKeyStatus::Historical when it is in verificationMethod
only. A historical receipt is not a currently-authorized registry
attestation and, under the strict profile, cannot place a
revoked-key context before its boundary. None exactly when
Self::verified_receipt is None.
Sourcepub fn receipt_registry_key_fingerprint(&self) -> Option<&str>
pub fn receipt_registry_key_fingerprint(&self) -> Option<&str>
The RFC-ACDP-0010 §6 fingerprint of the registry key that signed
Self::verified_receipt — the receipt input of RFC-ACDP-0020
§6.1, which is not the receipt’s key_fingerprint member (that
names the producer’s key). None exactly when no receipt verified.
Sourcepub fn receipt_verdict(&self) -> Option<&Result<(), AcdpError>>
pub fn receipt_verdict(&self) -> Option<&Result<(), AcdpError>>
The registry-receipt verdict, reported separately from the body
verdict (RFC-ACDP-0010 §8, 0.5.0). None when no receipt was
evaluated (none served, or ReceiptPolicy::Ignore);
Some(Ok(())) when it verified; Some(Err(_)) only under
ReceiptPolicy::VerifyAndReport — the other policies turn a
failing receipt into the call’s Err.
Sourcepub fn lineage_binding(&self) -> LineageBinding
pub fn lineage_binding(&self) -> LineageBinding
How body.lineage_id is bound (RFC-ACDP-0004 §2.1, 0.5.0):
derived offline for a first version, attested by the verified
receipt for a later one, or registry-asserted only (Unbound).
Sourcepub fn head_receipt_verdict(&self) -> Option<&Result<(), AcdpError>>
pub fn head_receipt_verdict(&self) -> Option<&Result<(), AcdpError>>
The lineage-head receipt verdict (RFC-ACDP-0011 §7), reported
separately; Some(Err(_)) only under
ReceiptPolicy::VerifyAndReport on LineageHeadPolicy::receipts.
Sourcepub fn verified_head_receipt(&self) -> Option<&LineageHeadReceipt>
pub fn verified_head_receipt(&self) -> Option<&LineageHeadReceipt>
The verified lineage-head receipt (ACDP 0.3, RFC-ACDP-0011),
populated only by Self::fetch_current /
Self::fetch_current_with_policy when one was present and the
policy verified it. For the raw on-wire value see
Self::lineage_head_receipt.
Sourcepub fn head_receipt_stale(&self) -> Option<bool>
pub fn head_receipt_stale(&self) -> Option<bool>
RFC-ACDP-0011 §6 freshness verdict for the verified head
receipt: Some(true) when the (genuine, verified) receipt’s
as_of is older than LineageHeadPolicy::max_age_seconds;
Some(false) when within policy; None when there is no
verified head receipt or the max-age knob is disabled.
Sourcepub fn revocation_discovery_failure(&self) -> Option<&AcdpError>
pub fn revocation_discovery_failure(&self) -> Option<&AcdpError>
RFC-ACDP-0014 §8 auto-discovery failure that
DiscoveryFailurePolicy::ProceedWithKnown swallowed to let
this VerifiedContext exist at all. None when discovery was
off (RevocationPolicy::discover is None), succeeded, or
was never attempted — a DiscoveryFailurePolicy::FailClosed
failure turns into this call’s Err instead, so there is no
VerifiedContext to carry it in that case. See
VerificationReport::revocation_discovery for the twin
surface on the report family, populated from the same event on
the fetch_report* paths.
Sourcepub fn revocation_verdict(&self) -> &RevocationVerdict
pub fn revocation_verdict(&self) -> &RevocationVerdict
The typed revocation verdict for this context’s signing key
(RFC-ACDP-0014 §7/§8, 0.5.0): RevocationVerdict::Revoked with
RevocationEffect::PreCompromise
(a refusal never yields a VerifiedContext — it is
AcdpError::KeyRevoked), RevocationVerdict::NotRevoked, or —
only under DiscoveryFailurePolicy::ProceedWithKnown —
RevocationVerdict::Unknown.
Sourcepub fn revocation_hints(&self) -> &[SourcedRevocation]
pub fn revocation_hints(&self) -> &[SourcedRevocation]
Verified revocations that do not speak for this context’s producer (RFC-ACDP-0014 §7 “Producer scope”, 0.5.0) — reported as hints, never applied to the verdict.
Sourcepub fn log_inclusion_verdict(&self) -> Option<&LogInclusionVerdict>
pub fn log_inclusion_verdict(&self) -> Option<&LogInclusionVerdict>
The RFC-ACDP-0012 §9 transparency-log inclusion verdict, reported separately from the body, receipt and revocation verdicts (§9.3: log-proof failure “invalidates nothing else”).
None: not evaluated. Either the policy isLogInclusionPolicy::Ignorewith no witness policy, or the response carried nolog_inclusion.LogInclusionVerdict::Included: the proof verified. The context is included in the log the registry committed to; seeSelf::verified_log_inclusion.LogInclusionVerdict::CannotVerify: no verified receipt to rebuild the leaf from. Not logged, and not a log failure.LogInclusionVerdict::Invalid: the proof was checked and failed (invalid_log_proof).
Under the default policy, no verdict fails verification.
Sourcepub fn verified_log_inclusion(&self) -> Option<&LogInclusion>
pub fn verified_log_inclusion(&self) -> Option<&LogInclusion>
The verified inclusion proof, including the signed checkpoint, when
Self::log_inclusion_verdict is
LogInclusionVerdict::Included. Keep the checkpoint to check
consistency with later ones (RFC-ACDP-0012 §9.2).
Sourcepub fn witness_quorum(&self) -> Option<&Result<WitnessQuorumReport, AcdpError>>
pub fn witness_quorum(&self) -> Option<&Result<WitnessQuorumReport, AcdpError>>
The RFC-ACDP-0015 §8 witness-quorum verdict over the verified checkpoint.
None:VerificationPolicy::witness_quorumwas unset.Some(Err(_)): there was no verified checkpoint to corroborate (invalid_log_proof). The checkpoint is verified on its own, so a cannot-verify inclusion still has a quorum when its checkpoint verifies.Some(Ok(report)): the quorum was evaluated.
Read the quorum from the report:
WitnessQuorumReport::meets_quorumis the split-view and anti-rewrite quorum;WitnessQuorumReport::meets_fresh_quorumis the quorum for decisions that need a current checkpoint.
Sourcepub fn receipt(&self) -> Option<&Value>
pub fn receipt(&self) -> Option<&Value>
Raw registry receipt value as served on the wire
(RFC-ACDP-0010), preserved verbatim. For the verified, typed
form see Self::verified_receipt.
Sourcepub fn lineage_head_receipt(&self) -> Option<&Value>
pub fn lineage_head_receipt(&self) -> Option<&Value>
Raw lineage-head receipt value as served on the wire
(RFC-ACDP-0011), preserved verbatim. For the verified, typed
form see Self::verified_head_receipt.
Sourcepub async fn verify_receipt(
&self,
resolver: &WebResolver,
) -> Result<Option<RegistryReceipt>, AcdpError>
pub async fn verify_receipt( &self, resolver: &WebResolver, ) -> Result<Option<RegistryReceipt>, AcdpError>
Verify the registry receipt, when one is present (RFC-ACDP-0010).
Standalone variant for contexts obtained via the report paths;
fetch_with_policy already does this under
ReceiptPolicy::VerifyIfPresent/Require. The serving
authority is taken from the context’s own ctx_id — this method
performs no requested-id binding of its own (it has no requested
id to compare against; it only ever sees self.inner.body.ctx_id),
so deriving the serving authority this way is sound only for a
VerifiedContext obtained through a pipeline that already bound
the served ctx_id to the one requested. Every construction path
does: fetch_with_policy and CrossRegistryResolver::resolve
check it directly; fetch_current_with_policy does too,
tautologically, since /current has no requested id to diverge
from; fetch_report/fetch_report_with_fetcher check it and
return ContextIdMismatch on failure; and fetch_report_diagnose
folds it into its all_top_level_pass gate, so it only ever
hands back Some(VerifiedContext) when ctx_id_ok held. All of
these implement RFC-ACDP-0006 §4.1 step 7, so the type invariant
— every VerifiedContext was bound to its requested ctx_id —
holds unconditionally.
Returns Ok(None) when no receipt is present, Ok(Some(_))
with the verified receipt otherwise.
The receipt cross-check (RFC-ACDP-0010 §8 step 4) relies on
body.content_hash being the independently recomputed value.
That is guaranteed by the type invariant — every
VerifiedContext is built only after its constructing pipeline
verified the body hash (Verifier::verify_body_hash /
verify_body_signed), and the fields are private so no caller
can substitute an unverified body — so no re-derivation is
needed here.
Sourcepub async fn recheck_revocation(
&self,
client: &RegistryClient,
resolver: &WebResolver,
policy: &RevocationPolicy,
) -> Result<RevocationAssessment, AcdpError>
pub async fn recheck_revocation( &self, client: &RegistryClient, resolver: &WebResolver, policy: &RevocationPolicy, ) -> Result<RevocationAssessment, AcdpError>
Re-assess this context’s revocation status under policy without
refetching the context (RFC-ACDP-0014 §7/§8) — for a long-lived
holder of a VerifiedContext that must notice a revocation
published after it verified.
Derives the two inputs of
find_revocations_verdict from
this context: the signing key’s RFC-ACDP-0010 §6 fingerprint
(resolved through resolver, normally a DID-cache hit) and the
placement fixed at verification time
(Self::verified_receipt’s created_at with
Self::receipt_key_status). Never fails on a verdict; call
RevocationAssessment::enforce
to turn a refusal or a fail-closed unknown into an error. Err
only when the signing key can no longer be resolved.