pub trait ProofExt {
// Required methods
fn sign<'life0, 'life1, 'async_trait>(
&'life0 mut self,
signer: &'life1 dyn AffinidiSigner,
options: SignOptions,
) -> Pin<Box<dyn Future<Output = Result<(), SignError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait;
fn verify<'life0, 'life1, 'async_trait, V>(
&'life0 self,
verifier: &'life1 V,
) -> Pin<Box<dyn Future<Output = Result<(), VerificationError>> + Send + 'async_trait>>
where V: ProofVerifier + ?Sized + 'async_trait,
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait;
}Expand description
Extension trait adding sign and
verify to the framework’s TrustTask<P>, for
every payload type P a producer can serialise.
§Why this trait exists
sign_trust_task operates on a
serde_json::Value, because a W3C Data Integrity proof is computed
over the document’s JSON form and the framework’s document type is
generic over its payload. That is the right shape for the primitive
and the wrong shape for a producer, who holds a TrustTask<P> and
wants a signed TrustTask<P> back. Without this trait, signing is a
five-step ritual — serialise, call, check, deserialise, reassign —
that every producer writes out by hand and can get subtly wrong (most
often by mutating the document after signing it).
ProofExt is a thin typed wrapper over the free functions, not a
replacement for them. It reuses
sign_trust_task verbatim, so the
canonicalisation contract, the deterministic eddsa-jcs-2022 default,
the replace-don’t-nest rule for an existing proof, and the SPEC.md
§4.7/§4.8 issuer↔verificationMethod pre-flight are all exactly what
that function already implements. A document signed through this trait
and one signed through the free function are byte-identical.
use trust_tasks_proof::{affinidi::{SignOptions, Verifier}, ProofExt};
use trust_tasks_rs::{specs::acl::grant::v0_1 as grant, TrustTask};
let mut req = TrustTask::for_payload(new_id(), grant::Payload { /* … */ });
req.issuer = Some(my_did.clone()); // set every member first …
req.recipient = Some(server_did.clone());
req.sign(&secret, SignOptions::new()).await?; // … then sign.
// Consumer side, same trait:
req.verify(&Verifier::for_did_key()).await?;§⚠ Sign last
The proof covers the document as it stands at the moment
sign is called. Mutating any member afterwards
invalidates the signature, and nothing in the type system stops you —
sign takes &mut self precisely so the call reads as the final step
of composing the document. Re-signing after a change is always safe:
the existing proof is discarded and a fresh one minted over the
current content.
Required Methods§
Sourcefn sign<'life0, 'life1, 'async_trait>(
&'life0 mut self,
signer: &'life1 dyn AffinidiSigner,
options: SignOptions,
) -> Pin<Box<dyn Future<Output = Result<(), SignError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn sign<'life0, 'life1, 'async_trait>(
&'life0 mut self,
signer: &'life1 dyn AffinidiSigner,
options: SignOptions,
) -> Pin<Box<dyn Future<Output = Result<(), SignError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Sign this document in place, attaching the resulting Data
Integrity proof to its proof member.
Equivalent to serialising the document, calling
sign_trust_task, and
deserialising the result — the round-trip through
serde_json::Value happens inside, over exactly the same
unsigned bytes, so the emitted proof is identical to the free
function’s.
Every rule the free function applies applies here:
- The signature is computed over the document minus its
proofmember. An existing proof is replaced, never nested and never signed over. - The document MUST already carry an in-band
issuerequal to the DID of the signer’sverificationMethod(the part before#). Otherwise the call fails withSignError::MissingIssuer/SignError::IssuerMismatchbefore a signature is produced, rather than emitting a document no conforming verifier could accept. proofPurposedefaults toassertionMethodand the cryptosuite toeddsa-jcs-2022unlessSignOptionssays otherwise.
On error, self is left untouched — a failed sign never leaves a
half-signed document behind.
Available with the affinidi feature (on by default).
Sourcefn verify<'life0, 'life1, 'async_trait, V>(
&'life0 self,
verifier: &'life1 V,
) -> Pin<Box<dyn Future<Output = Result<(), VerificationError>> + Send + 'async_trait>>where
V: ProofVerifier + ?Sized + 'async_trait,
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn verify<'life0, 'life1, 'async_trait, V>(
&'life0 self,
verifier: &'life1 V,
) -> Pin<Box<dyn Future<Output = Result<(), VerificationError>> + Send + 'async_trait>>where
V: ProofVerifier + ?Sized + 'async_trait,
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Verify this document’s proof with verifier.
The mirror of sign, and the argument-order flip of
ProofVerifier::verify — the same check, spelled from the
document’s point of view so a consumer holding a TrustTask<P>
does not have to reach for the verifier first.
Returns VerificationError on every failure mode, including a
document that carries no proof at all (the framework’s
proofRequired check is a separate, earlier concern — see
TrustTask::enforce_spec_policy).
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".