IETF DTN Working Group · for discussion
Who can prove they held a bundle, and when: evidence that travels with the bundle and anyone can check later, offline. Written up as an individual Internet-Draft, with an open reference implementation tested through four independent BPv7 stacks.
The problem
Ground stations, relays and lunar networks run by different parties hold data for minutes to hours.
Another party cannot verify an operator’s log without trusting the operator that wrote it.
Custody transfer asks who must retransmit now. Receipts answer who can prove they held it, and when.
How it works
Nodes that choose to act as custodians each append one signed receipt to an extension block carried in the bundle. Forwarders that do not implement the draft keep the block unchanged: it is replicated in every fragment and never asks a node to delete the bundle or discard the block. A verifier checks every receipt against the custodian’s key and reports any stretch of the route that nobody signed, using the Previous Node block.
| The receipts are not | Instead |
|---|---|
| Custody transfer | They complement BIBE and carry no retransmission duty |
| Administrative records | Signed objects in an extension block |
| A reason to parse payloads | No custodian interprets the ADU; it hashes the bytes it holds |
| Required of every node | Opt-in per node; forwarders need not implement the draft |
| Proof the claims are true | Each custodian is bound to its signed claims; gaps are reported, never inferred |
The receipt (version 2)
EdDSA (Ed25519) in the protected header; the key is pinned by the custodian’s node ID.
Bundle identity and a SHA-256 of the payload bytes held, so any verifier checks the binding with no application knowledge.
A whole-bundle receipt covers each fragment; a custodian holding a fragment signs for that fragment.
Evidence
| Path, held across a scheduled gap | Block on arrival | Payload BIB | Gap audit |
|---|---|---|---|
| µD3TN, two nodes | byte-identical | verifies | with Previous Node option on |
| NASA HDTN | byte-identical | verifies | names the unsigned node |
| JPL ION | byte-identical | verifies | names the unsigned node |
| Hardy | byte-identical | verifies | names the unsigned node |
| µD3TN then HDTN, one path | byte-identical | verifies | names the unsigned node |
| Two JPL ION nodes over LTP, Earth-Moon light time on the link | byte-identical | verifies | names the unsigned node |
Aalyria's Hardy, built with a prototype custody-receipt filter (a Rust Egress Rewriter), now signs receipts itself. Its receipts verify with our reference code, our receipts pass through it byte-identical and gain a second valid one, and the Rust and JavaScript encoders agree byte for byte on shared test vectors. It also signs each fragment of a fragmented bundle for exactly the bytes it holds, leaves encrypted payloads unsigned rather than sign bytes it cannot see, and can be set to sign only bundles that already carry receipts: 31 of 31 live checks (RESULTS.md section 7). The filter is local and not yet proposed upstream.
Along the way, interop testing found that JPL ION builds its BIB input differently from RFC 9173 §3.7 (reported as ION-DTN #130), and our implementation independently reproduces the corrected Appendix A.3 vector of RFC 9173 erratum 9192. Commands and outputs: transport/bpv7/RESULTS.md.
Lunar and laser links
Mapped onto NASA's LunaNet Interoperability Specification v5: BPv7, LTP and IP convergence layers, BPSec. A three-provider lunar relay run checks every receipt against the Moon's actual distance at the moment of contact, so a backdated receipt is caught even when its signature is genuine (profile).
Modeled on public optical inter-satellite link parameters at 2.5, 10 and 100 Gbps, with fades, pointing and acquisition outages and cross-plane handoffs. An unsigned relay is reported as a gap and a tampered bundle is caught. Across a 4,032-satellite constellation with laser crosslinks, 10,000 of 10,000 bundles verify, including with 30% of crosslinks failing (results).
Signing every bundle at every hop does not scale to laser rates; signing once per contact does, with nothing added to the forwarding path. Per-bundle stamping now adds 0.13 to 0.16 ms per hop for a 1 MiB bundle, down from 10 ms. Batch carriage is proposed for -02 (proposals).
New, 2026-10-21
BPSec leaves key management out of scope. For custody receipts it is now built, tested through all four stacks, and in the npm package (0.5.0).
Key and revocation records, COSE_Sign1 like the receipts, chain to each operator's root key and ride in a Key Record Block (type 225). A destination holding only the root key verified the chain through µD3TN, HDTN, ION, Hardy and the mixed path (spec).
Receipt field 9 commits each receipt to the ones before it, so a later custodian witnesses that they existed. A backdated signature from a revoked key is refused unless an honest node or the verifier saw it in time. Self-revocation needs no operator.
Receipt field 8 records the Hop Count block. All four stacks add exactly one per node, so an unsigned stretch is reported as a number of forwarders, including on uD3TN, which leaves no Previous Node (results, sections 8 and 9).
Onboard, the same rules run in C with no heap, about 3 KB on an ARM Cortex-M4. Both fields are optional; receipts without them are unchanged. Proposed for -02 as proposals 4 and 5 (proposals).
Where it fits
| Work | Relation to custody receipts |
|---|---|
| BIBE custody transfer | Who must retransmit; receipts record who held it |
| Traceroute Extension Block | Unsigned hop records for diagnostics; a proposed optional signature would make them evidence (sketch) |
| SBAM | Audits dropped security operations; receipts evidence custody that did happen |
| DTN Peering Protocol | Routes between domains; receipts are the accounting between them, with custodian keys endorsed by a domain’s peering key |
| BPSec COSE context | Same COSE building blocks |
How these fit together is set out in a discussion draft, accountability between administrative domains, and the block is offered as a case for the per-hop block discussion in a short case study.
For the group
Get involved
Comments are welcome on the dtn@ietf.org list or directly. We will run any stack’s build against the interoperability suite.