Skip to main content

ProofExt

Trait ProofExt 

Source
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§

Source

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 proof member. An existing proof is replaced, never nested and never signed over.
  • The document MUST already carry an in-band issuer equal to the DID of the signer’s verificationMethod (the part before #). Otherwise the call fails with SignError::MissingIssuer / SignError::IssuerMismatch before a signature is produced, rather than emitting a document no conforming verifier could accept.
  • proofPurpose defaults to assertionMethod and the cryptosuite to eddsa-jcs-2022 unless SignOptions says 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).

Source

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".

Implementations on Foreign Types§

Source§

impl<P> ProofExt for TrustTask<P>
where P: Serialize + Send + Sync,

Source§

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,

Source§

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,

Implementors§