trust-tasks-tsp 0.17.8

ToIP Trust Spanning Protocol (TSP) transport binding for the Trust Tasks framework, built on affinidi-tsp. Provides pack/unpack helpers and a TransportHandler that maps the authenticated VID sender into the framework's §4.8.1 precedence.
Documentation

ToIP Trust Spanning Protocol (TSP) transport binding for the Trust Tasks framework.

Wraps affinidi-tsp so a Trust Task document can ride as the authenticated, encrypted payload of a TSP message — sealed with HPKE authenticated encryption and signed from the producer's Verifiable Identifier (VID) to the recipient's VID. On unwrap, the authenticated sender VID becomes the framework's transport-authenticated sender for SPEC §4.8.1 precedence.

Binding URI

https://trusttasks.org/binding/tsp/0.1

Wire shape

The TSP message payload (the plaintext TSP seals) is the JSON serialisation of the binding envelope object:

{
  "type": "https://trusttasks.org/binding/tsp/0.1/envelope",
  "document": { /* the full TrustTask<P> */ }
}

Unlike the DIDComm binding — which normalises a sender_kid to its bare DID — a TSP VID is the framework VID, so no transformation is applied: the authenticated VID_sndr is surfaced verbatim as the transport-authenticated issuer. TSP has no anonymous/unauthenticated sender mode, so every envelope this binding accepts carries a verified sender.

The producer can ship a plain Direct message ([pack_trust_task], sealed straight to the consumer) or relay it through intermediaries (SPEC binding §5): a Nested envelope sealed to a single intermediary for metadata privacy ([pack_trust_task_nested]), or a Routed envelope relayed through one or more hops ([pack_trust_task_routed]). Routed/Nested relaying — where the messaging mediator unwraps its outer layer and forwards the sealed inner — is the mediator's job on the wire; the consumer always opens the innermost Direct message, which [unpack_trust_task] handles regardless of how it was carried.

The guarded inbound path

[unpack_trust_task] opens the seal and stops there. The consumer obligations of SPEC §7.2 still have to run over the document it returns, and two of them are stateful: item 11's duplicate-execution record and the freshness bound that lets that record be dropped.

[TspConsumer] is that path with both wired, on by default. Binding §7 records that TSP data messages "do not inherently prevent replay", and under §5's routed and nested carriage an intermediary may re-send the sealed inner message — so an ordinary re-forward, with no attacker involved, executes a consequential task twice unless the consumer keeps the record. The record is keyed on the document id and never on the envelope, which is resealed with fresh material on every send.

Sketch

use affinidi_tsp::PrivateVid;
use trust_tasks_tsp::{pack_trust_task, unpack_trust_task};

// alice (producer) seals a document for bob:
let wire = pack_trust_task(&doc, &alice_private, &bob_resolved)?;

// bob (consumer) opens it (alice's VID resolved for verification):
let (doc, handler) = unpack_trust_task::<MyPayload>(&wire, &bob_private, &alice_resolved)?;

Versioning

This crate exposes trust-tasks-rs types in its own public API, so a breaking change there breaks this crate's callers even when nothing here changes. cargo-semver-checks cannot catch that: it compares each crate's rustdoc against that crate's own published baseline, and does not track type identity across dependency versions. The crates that share trust-tasks-rs in their public API are therefore released as one compatibility unit with a single shared version — see version_group in release-plz.toml.