Add five companion flow docs
- flows/receive-resource.md: inverse of send-resource. ADV
ingestion, accept/reject decision, request_next loop,
receive_part insertion, assemble + decrypt + hash-validate,
RESOURCE_PRF emission, multi-segment continuation.
- flows/receive-link-lxmf.md: responder side of the link
handshake plus inbound LXMF DATA handling. validate_request
-> handshake -> prove (LRPROOF emission) -> link_established
callback wires delivery_packet. PACKET-form inbound runs
delivery_packet directly; RESOURCE-form inbound runs through
delivery_resource_advertised + delivery_resource_concluded
pipeline.
- flows/send-announce.md: random_hash construction (5B random +
5B BE-uint40 timestamp), optional ratchet rotation, signed_data
assembly, sign + pack, the broadcast emission. Notes that
ANNOUNCE packets are NOT encrypted (Packet.pack special-cases
line 189-191) and the periodic re-announce loop drives 5-15min
cadence.
- flows/forward-announce.md: relay-side rebroadcast for
transport-mode nodes. Eligibility checks (transport_enabled,
not PATH_RESPONSE, not rate_blocked), announce_table queue,
Transport.jobs drain with PATH_REQUEST_GRACE = 0.4s,
per-interface announce_queue with ANNOUNCE_CAP = 2.0% airtime
enforcement, lowest-hop-count-first emission order, hops byte
increment, local-rebroadcast counter for loop break.
- flows/send-propagated-lxmf.md: PROPAGATED method end to end.
LXMessage.pack with body encrypted to recipient (propagation
node never decrypts), Link establishment to the propagation
node, optional propagation stamp (1000 PoW rounds vs 3000 for
regular stamps), submission via Link DATA or Resource,
state goes to SENT (not DELIVERED — recipient pulls via /get
later per §5.8.3).
flows/README.md status table updated; receive-propagated-lxmf.md
added as the only remaining ⏳ flow.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 12:21:05 -04:00
# Flow: receive an LXMF message over a Reticulum Link
Re-anchor against RNS 1.2.4 / LXMF 0.9.7 + track upstream distribution shift
Upstream RNS 1.2.4 (2026-05-07) announces it is "probably the last
release that is also published to GitHub" — pip continues until rnpkg
is complete and RNS is self-hosting. All 13 verifiers pass against
1.2.4 / 0.9.7; no wire-format, signing, or protocol behavior changed
between 1.2.0 and 1.2.4, so the changes here are purely currency:
- Pin tools/requirements.txt to rns==1.2.4 / lxmf==0.9.7 so the
verifier stays reproducible if upstream stops mirroring to PyPI
before the migration is ready.
- Add an "Upstream distribution shift" watch-list to todo.md (local
Reticulum node, repo destination hash, rnpkg install/upgrade
commands, rsg signature verification, mirroring source citations).
- Bump SPEC.md frontmatter and re-anchor ~50 line citations across
Identity.py, Transport.py, Resource.py, Link.py, Reticulum.py,
Packet.py, and LXMF/* (Identity.py drift was the heaviest at +13
to +31 lines; Transport.py was variable). Fix one numeric
(MAX_RANDOM_BLOBS = 32 → 64) and one semantic (§6.6.3 LRPROOF MTU
clamp citation pointed at the wrong location — corrected to point
at the transit-relay clamp at Transport.py:1539-1556).
- Update §10.4 decompression-bomb hazard to note upstream's 1.1.9 cap
adoption, with citations to Resource.py:686-691 and Buffer.py:95-97
plus a "do not use one-shot bz2.decompress()" warning.
- Re-anchor 11 flows/ files (version pins + ~30 line citations).
- Bump version labels in tools/README.md, test-vectors/README.md, and
4 verifier docstrings + 2 hardcoded print strings.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 07:42:25 -04:00
The inverse of [`send-link-lxmf.md` ](send-link-lxmf.md ), covering both halves of the responder side: accepting the inbound LINKREQUEST, sending the LRPROOF, then handling LXMF DATA on the established link. Pinned against **RNS 1.2.4 / LXMF 0.9.7 ** ; cross-references [`../SPEC.md` ](../SPEC.md ) §6 (Link), §6.5 (PROOF), §6.6 (signalling), §6.7 (KEEPALIVE/teardown), §10 (Resource).
Add five companion flow docs
- flows/receive-resource.md: inverse of send-resource. ADV
ingestion, accept/reject decision, request_next loop,
receive_part insertion, assemble + decrypt + hash-validate,
RESOURCE_PRF emission, multi-segment continuation.
- flows/receive-link-lxmf.md: responder side of the link
handshake plus inbound LXMF DATA handling. validate_request
-> handshake -> prove (LRPROOF emission) -> link_established
callback wires delivery_packet. PACKET-form inbound runs
delivery_packet directly; RESOURCE-form inbound runs through
delivery_resource_advertised + delivery_resource_concluded
pipeline.
- flows/send-announce.md: random_hash construction (5B random +
5B BE-uint40 timestamp), optional ratchet rotation, signed_data
assembly, sign + pack, the broadcast emission. Notes that
ANNOUNCE packets are NOT encrypted (Packet.pack special-cases
line 189-191) and the periodic re-announce loop drives 5-15min
cadence.
- flows/forward-announce.md: relay-side rebroadcast for
transport-mode nodes. Eligibility checks (transport_enabled,
not PATH_RESPONSE, not rate_blocked), announce_table queue,
Transport.jobs drain with PATH_REQUEST_GRACE = 0.4s,
per-interface announce_queue with ANNOUNCE_CAP = 2.0% airtime
enforcement, lowest-hop-count-first emission order, hops byte
increment, local-rebroadcast counter for loop break.
- flows/send-propagated-lxmf.md: PROPAGATED method end to end.
LXMessage.pack with body encrypted to recipient (propagation
node never decrypts), Link establishment to the propagation
node, optional propagation stamp (1000 PoW rounds vs 3000 for
regular stamps), submission via Link DATA or Resource,
state goes to SENT (not DELIVERED — recipient pulls via /get
later per §5.8.3).
flows/README.md status table updated; receive-propagated-lxmf.md
added as the only remaining ⏳ flow.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 12:21:05 -04:00
---
## Sequence
### 1. LINKREQUEST arrives
A Reticulum DATA packet with `packet_type = LINKREQUEST (2)` , addressed to the responder's `lxmf.delivery` dest_hash. Body (§6.1):
```
initiator_X25519_pub(32) || initiator_Ed25519_pub(32) || [signalling(3)]
```
Re-anchor against RNS 1.2.4 / LXMF 0.9.7 + track upstream distribution shift
Upstream RNS 1.2.4 (2026-05-07) announces it is "probably the last
release that is also published to GitHub" — pip continues until rnpkg
is complete and RNS is self-hosting. All 13 verifiers pass against
1.2.4 / 0.9.7; no wire-format, signing, or protocol behavior changed
between 1.2.0 and 1.2.4, so the changes here are purely currency:
- Pin tools/requirements.txt to rns==1.2.4 / lxmf==0.9.7 so the
verifier stays reproducible if upstream stops mirroring to PyPI
before the migration is ready.
- Add an "Upstream distribution shift" watch-list to todo.md (local
Reticulum node, repo destination hash, rnpkg install/upgrade
commands, rsg signature verification, mirroring source citations).
- Bump SPEC.md frontmatter and re-anchor ~50 line citations across
Identity.py, Transport.py, Resource.py, Link.py, Reticulum.py,
Packet.py, and LXMF/* (Identity.py drift was the heaviest at +13
to +31 lines; Transport.py was variable). Fix one numeric
(MAX_RANDOM_BLOBS = 32 → 64) and one semantic (§6.6.3 LRPROOF MTU
clamp citation pointed at the wrong location — corrected to point
at the transit-relay clamp at Transport.py:1539-1556).
- Update §10.4 decompression-bomb hazard to note upstream's 1.1.9 cap
adoption, with citations to Resource.py:686-691 and Buffer.py:95-97
plus a "do not use one-shot bz2.decompress()" warning.
- Re-anchor 11 flows/ files (version pins + ~30 line citations).
- Bump version labels in tools/README.md, test-vectors/README.md, and
4 verifier docstrings + 2 hardcoded print strings.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 07:42:25 -04:00
`Transport.inbound` (`RNS/Transport.py:2030-2060` ) recognizes `packet_type == LINKREQUEST + destination_type == SINGLE` , looks up the destination in `destinations_map` , and calls `Destination.receive(packet)` which routes to `Destination.incoming_link_request(data, packet)` per `RNS/Destination.py:403-450` (`receive` at 403, dispatches to `incoming_link_request` at 420):
Add five companion flow docs
- flows/receive-resource.md: inverse of send-resource. ADV
ingestion, accept/reject decision, request_next loop,
receive_part insertion, assemble + decrypt + hash-validate,
RESOURCE_PRF emission, multi-segment continuation.
- flows/receive-link-lxmf.md: responder side of the link
handshake plus inbound LXMF DATA handling. validate_request
-> handshake -> prove (LRPROOF emission) -> link_established
callback wires delivery_packet. PACKET-form inbound runs
delivery_packet directly; RESOURCE-form inbound runs through
delivery_resource_advertised + delivery_resource_concluded
pipeline.
- flows/send-announce.md: random_hash construction (5B random +
5B BE-uint40 timestamp), optional ratchet rotation, signed_data
assembly, sign + pack, the broadcast emission. Notes that
ANNOUNCE packets are NOT encrypted (Packet.pack special-cases
line 189-191) and the periodic re-announce loop drives 5-15min
cadence.
- flows/forward-announce.md: relay-side rebroadcast for
transport-mode nodes. Eligibility checks (transport_enabled,
not PATH_RESPONSE, not rate_blocked), announce_table queue,
Transport.jobs drain with PATH_REQUEST_GRACE = 0.4s,
per-interface announce_queue with ANNOUNCE_CAP = 2.0% airtime
enforcement, lowest-hop-count-first emission order, hops byte
increment, local-rebroadcast counter for loop break.
- flows/send-propagated-lxmf.md: PROPAGATED method end to end.
LXMessage.pack with body encrypted to recipient (propagation
node never decrypts), Link establishment to the propagation
node, optional propagation stamp (1000 PoW rounds vs 3000 for
regular stamps), submission via Link DATA or Resource,
state goes to SENT (not DELIVERED — recipient pulls via /get
later per §5.8.3).
flows/README.md status table updated; receive-propagated-lxmf.md
added as the only remaining ⏳ flow.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 12:21:05 -04:00
```python
def receive(self, packet):
if packet.packet_type == LINKREQUEST:
self.incoming_link_request(packet.data, packet)
```
### 2. Responder builds Link state via `Link.validate_request`
Re-anchor against RNS 1.2.4 / LXMF 0.9.7 + track upstream distribution shift
Upstream RNS 1.2.4 (2026-05-07) announces it is "probably the last
release that is also published to GitHub" — pip continues until rnpkg
is complete and RNS is self-hosting. All 13 verifiers pass against
1.2.4 / 0.9.7; no wire-format, signing, or protocol behavior changed
between 1.2.0 and 1.2.4, so the changes here are purely currency:
- Pin tools/requirements.txt to rns==1.2.4 / lxmf==0.9.7 so the
verifier stays reproducible if upstream stops mirroring to PyPI
before the migration is ready.
- Add an "Upstream distribution shift" watch-list to todo.md (local
Reticulum node, repo destination hash, rnpkg install/upgrade
commands, rsg signature verification, mirroring source citations).
- Bump SPEC.md frontmatter and re-anchor ~50 line citations across
Identity.py, Transport.py, Resource.py, Link.py, Reticulum.py,
Packet.py, and LXMF/* (Identity.py drift was the heaviest at +13
to +31 lines; Transport.py was variable). Fix one numeric
(MAX_RANDOM_BLOBS = 32 → 64) and one semantic (§6.6.3 LRPROOF MTU
clamp citation pointed at the wrong location — corrected to point
at the transit-relay clamp at Transport.py:1539-1556).
- Update §10.4 decompression-bomb hazard to note upstream's 1.1.9 cap
adoption, with citations to Resource.py:686-691 and Buffer.py:95-97
plus a "do not use one-shot bz2.decompress()" warning.
- Re-anchor 11 flows/ files (version pins + ~30 line citations).
- Bump version labels in tools/README.md, test-vectors/README.md, and
4 verifier docstrings + 2 hardcoded print strings.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 07:42:25 -04:00
`RNS/Link.py:186-230` . Length-checks the body (`ECPUBSIZE` or `ECPUBSIZE + LINK_MTU_SIZE` ), rejects otherwise. On success:
Add five companion flow docs
- flows/receive-resource.md: inverse of send-resource. ADV
ingestion, accept/reject decision, request_next loop,
receive_part insertion, assemble + decrypt + hash-validate,
RESOURCE_PRF emission, multi-segment continuation.
- flows/receive-link-lxmf.md: responder side of the link
handshake plus inbound LXMF DATA handling. validate_request
-> handshake -> prove (LRPROOF emission) -> link_established
callback wires delivery_packet. PACKET-form inbound runs
delivery_packet directly; RESOURCE-form inbound runs through
delivery_resource_advertised + delivery_resource_concluded
pipeline.
- flows/send-announce.md: random_hash construction (5B random +
5B BE-uint40 timestamp), optional ratchet rotation, signed_data
assembly, sign + pack, the broadcast emission. Notes that
ANNOUNCE packets are NOT encrypted (Packet.pack special-cases
line 189-191) and the periodic re-announce loop drives 5-15min
cadence.
- flows/forward-announce.md: relay-side rebroadcast for
transport-mode nodes. Eligibility checks (transport_enabled,
not PATH_RESPONSE, not rate_blocked), announce_table queue,
Transport.jobs drain with PATH_REQUEST_GRACE = 0.4s,
per-interface announce_queue with ANNOUNCE_CAP = 2.0% airtime
enforcement, lowest-hop-count-first emission order, hops byte
increment, local-rebroadcast counter for loop break.
- flows/send-propagated-lxmf.md: PROPAGATED method end to end.
LXMessage.pack with body encrypted to recipient (propagation
node never decrypts), Link establishment to the propagation
node, optional propagation stamp (1000 PoW rounds vs 3000 for
regular stamps), submission via Link DATA or Resource,
state goes to SENT (not DELIVERED — recipient pulls via /get
later per §5.8.3).
flows/README.md status table updated; receive-propagated-lxmf.md
added as the only remaining ⏳ flow.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 12:21:05 -04:00
1. Build a `Link` object with `peer_pub_bytes = data[:32]` and `peer_sig_pub_bytes = data[32:64]` .
2. `set_link_id(packet)` per §6.3 — the link_id derives from `Packet.get_hashable_part` , invariant under HEADER_1↔HEADER_2 conversion.
3. If signalling present, parse MTU and mode per §6.6.
4. Call `link.handshake()` — ECDH with the initiator's X25519 ephemeral pub, HKDF over the shared secret with `salt=link_id` , derives `signing_key || encrypt_key` . Status `PENDING → HANDSHAKE` .
5. Call `link.prove()` to emit the LRPROOF.
6. Register the link in `Transport.active_links` and append to the destination's `links` list.
### 3. Responder emits LRPROOF
`RNS/Link.py:371-381` . Body per §6.2:
```
proof_data = signature(64) || responder_X25519_pub(32) || [signalling(3)]
```
where `signature = sign(link_id || responder_X25519_pub || responder_long_term_Ed25519_pub || [signalling])` . Wire packet: `packet_type = PROOF (3)` , `context = LRPROOF (0xFF)` , `dest_hash` field carries the link_id.
### 4. RTT measurement (LRRTT round trip)
After the initiator validates the LRPROOF and sends `Link.LRRTT (0xFE)` carrying its measured RTT, the responder receives it at `Link.receive` line 1056-1059 and calls `rtt_packet` . The responder's RTT cache updates and `Link.STATUS = ACTIVE` triggers the `link_established_callback` registered via `Destination.set_link_established_callback` .
Re-anchor against RNS 1.2.4 / LXMF 0.9.7 + track upstream distribution shift
Upstream RNS 1.2.4 (2026-05-07) announces it is "probably the last
release that is also published to GitHub" — pip continues until rnpkg
is complete and RNS is self-hosting. All 13 verifiers pass against
1.2.4 / 0.9.7; no wire-format, signing, or protocol behavior changed
between 1.2.0 and 1.2.4, so the changes here are purely currency:
- Pin tools/requirements.txt to rns==1.2.4 / lxmf==0.9.7 so the
verifier stays reproducible if upstream stops mirroring to PyPI
before the migration is ready.
- Add an "Upstream distribution shift" watch-list to todo.md (local
Reticulum node, repo destination hash, rnpkg install/upgrade
commands, rsg signature verification, mirroring source citations).
- Bump SPEC.md frontmatter and re-anchor ~50 line citations across
Identity.py, Transport.py, Resource.py, Link.py, Reticulum.py,
Packet.py, and LXMF/* (Identity.py drift was the heaviest at +13
to +31 lines; Transport.py was variable). Fix one numeric
(MAX_RANDOM_BLOBS = 32 → 64) and one semantic (§6.6.3 LRPROOF MTU
clamp citation pointed at the wrong location — corrected to point
at the transit-relay clamp at Transport.py:1539-1556).
- Update §10.4 decompression-bomb hazard to note upstream's 1.1.9 cap
adoption, with citations to Resource.py:686-691 and Buffer.py:95-97
plus a "do not use one-shot bz2.decompress()" warning.
- Re-anchor 11 flows/ files (version pins + ~30 line citations).
- Bump version labels in tools/README.md, test-vectors/README.md, and
4 verifier docstrings + 2 hardcoded print strings.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 07:42:25 -04:00
For LXMF, that callback is `LXMRouter.delivery_link_established` (`LXMF/LXMRouter.py:1852-1858` ):
Add five companion flow docs
- flows/receive-resource.md: inverse of send-resource. ADV
ingestion, accept/reject decision, request_next loop,
receive_part insertion, assemble + decrypt + hash-validate,
RESOURCE_PRF emission, multi-segment continuation.
- flows/receive-link-lxmf.md: responder side of the link
handshake plus inbound LXMF DATA handling. validate_request
-> handshake -> prove (LRPROOF emission) -> link_established
callback wires delivery_packet. PACKET-form inbound runs
delivery_packet directly; RESOURCE-form inbound runs through
delivery_resource_advertised + delivery_resource_concluded
pipeline.
- flows/send-announce.md: random_hash construction (5B random +
5B BE-uint40 timestamp), optional ratchet rotation, signed_data
assembly, sign + pack, the broadcast emission. Notes that
ANNOUNCE packets are NOT encrypted (Packet.pack special-cases
line 189-191) and the periodic re-announce loop drives 5-15min
cadence.
- flows/forward-announce.md: relay-side rebroadcast for
transport-mode nodes. Eligibility checks (transport_enabled,
not PATH_RESPONSE, not rate_blocked), announce_table queue,
Transport.jobs drain with PATH_REQUEST_GRACE = 0.4s,
per-interface announce_queue with ANNOUNCE_CAP = 2.0% airtime
enforcement, lowest-hop-count-first emission order, hops byte
increment, local-rebroadcast counter for loop break.
- flows/send-propagated-lxmf.md: PROPAGATED method end to end.
LXMessage.pack with body encrypted to recipient (propagation
node never decrypts), Link establishment to the propagation
node, optional propagation stamp (1000 PoW rounds vs 3000 for
regular stamps), submission via Link DATA or Resource,
state goes to SENT (not DELIVERED — recipient pulls via /get
later per §5.8.3).
flows/README.md status table updated; receive-propagated-lxmf.md
added as the only remaining ⏳ flow.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 12:21:05 -04:00
```python
link.track_phy_stats(True)
link.set_packet_callback(self.delivery_packet) # ← inbound LXMF flows here
link.set_resource_strategy(RNS.Link.ACCEPT_APP)
link.set_resource_callback(self.delivery_resource_advertised)
link.set_resource_started_callback(self.resource_transfer_began)
link.set_resource_concluded_callback(self.delivery_resource_concluded)
link.set_remote_identified_callback(self.delivery_remote_identified)
```
This is what makes inbound DATA on this link route into LXMF processing.
### 5. Inbound LXMF DATA — single-packet (PACKET representation)
Re-anchor against RNS 1.2.4 / LXMF 0.9.7 + track upstream distribution shift
Upstream RNS 1.2.4 (2026-05-07) announces it is "probably the last
release that is also published to GitHub" — pip continues until rnpkg
is complete and RNS is self-hosting. All 13 verifiers pass against
1.2.4 / 0.9.7; no wire-format, signing, or protocol behavior changed
between 1.2.0 and 1.2.4, so the changes here are purely currency:
- Pin tools/requirements.txt to rns==1.2.4 / lxmf==0.9.7 so the
verifier stays reproducible if upstream stops mirroring to PyPI
before the migration is ready.
- Add an "Upstream distribution shift" watch-list to todo.md (local
Reticulum node, repo destination hash, rnpkg install/upgrade
commands, rsg signature verification, mirroring source citations).
- Bump SPEC.md frontmatter and re-anchor ~50 line citations across
Identity.py, Transport.py, Resource.py, Link.py, Reticulum.py,
Packet.py, and LXMF/* (Identity.py drift was the heaviest at +13
to +31 lines; Transport.py was variable). Fix one numeric
(MAX_RANDOM_BLOBS = 32 → 64) and one semantic (§6.6.3 LRPROOF MTU
clamp citation pointed at the wrong location — corrected to point
at the transit-relay clamp at Transport.py:1539-1556).
- Update §10.4 decompression-bomb hazard to note upstream's 1.1.9 cap
adoption, with citations to Resource.py:686-691 and Buffer.py:95-97
plus a "do not use one-shot bz2.decompress()" warning.
- Re-anchor 11 flows/ files (version pins + ~30 line citations).
- Bump version labels in tools/README.md, test-vectors/README.md, and
4 verifier docstrings + 2 hardcoded print strings.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 07:42:25 -04:00
A regular DATA packet on the link (`context = NONE` , Token-encrypted with link session key per §3.1). `Link.receive` decrypts and passes the plaintext to `delivery_packet(data, packet)` (`LXMF/LXMRouter.py:1822-1850` ) — the same handler used by opportunistic delivery. Differences:
Add five companion flow docs
- flows/receive-resource.md: inverse of send-resource. ADV
ingestion, accept/reject decision, request_next loop,
receive_part insertion, assemble + decrypt + hash-validate,
RESOURCE_PRF emission, multi-segment continuation.
- flows/receive-link-lxmf.md: responder side of the link
handshake plus inbound LXMF DATA handling. validate_request
-> handshake -> prove (LRPROOF emission) -> link_established
callback wires delivery_packet. PACKET-form inbound runs
delivery_packet directly; RESOURCE-form inbound runs through
delivery_resource_advertised + delivery_resource_concluded
pipeline.
- flows/send-announce.md: random_hash construction (5B random +
5B BE-uint40 timestamp), optional ratchet rotation, signed_data
assembly, sign + pack, the broadcast emission. Notes that
ANNOUNCE packets are NOT encrypted (Packet.pack special-cases
line 189-191) and the periodic re-announce loop drives 5-15min
cadence.
- flows/forward-announce.md: relay-side rebroadcast for
transport-mode nodes. Eligibility checks (transport_enabled,
not PATH_RESPONSE, not rate_blocked), announce_table queue,
Transport.jobs drain with PATH_REQUEST_GRACE = 0.4s,
per-interface announce_queue with ANNOUNCE_CAP = 2.0% airtime
enforcement, lowest-hop-count-first emission order, hops byte
increment, local-rebroadcast counter for loop break.
- flows/send-propagated-lxmf.md: PROPAGATED method end to end.
LXMessage.pack with body encrypted to recipient (propagation
node never decrypts), Link establishment to the propagation
node, optional propagation stamp (1000 PoW rounds vs 3000 for
regular stamps), submission via Link DATA or Resource,
state goes to SENT (not DELIVERED — recipient pulls via /get
later per §5.8.3).
flows/README.md status table updated; receive-propagated-lxmf.md
added as the only remaining ⏳ flow.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 12:21:05 -04:00
- `packet.destination_type == LINK` so `method = DIRECT` .
- The LXMF body arrives **with ** the recipient's dest_hash (§5.2), so no re-prepend like the opportunistic path does at step 9 of `receive-opportunistic-lxmf.md` .
The handler calls `packet.prove()` immediately (mandatory PROOF receipt per §6.5), then dispatches the body to `LXMessage.unpack_from_bytes` and `lxmf_delivery` exactly like the opportunistic flow's steps 10-12.
### 6. Inbound LXMF DATA — Resource representation
Re-anchor against RNS 1.2.4 / LXMF 0.9.7 + track upstream distribution shift
Upstream RNS 1.2.4 (2026-05-07) announces it is "probably the last
release that is also published to GitHub" — pip continues until rnpkg
is complete and RNS is self-hosting. All 13 verifiers pass against
1.2.4 / 0.9.7; no wire-format, signing, or protocol behavior changed
between 1.2.0 and 1.2.4, so the changes here are purely currency:
- Pin tools/requirements.txt to rns==1.2.4 / lxmf==0.9.7 so the
verifier stays reproducible if upstream stops mirroring to PyPI
before the migration is ready.
- Add an "Upstream distribution shift" watch-list to todo.md (local
Reticulum node, repo destination hash, rnpkg install/upgrade
commands, rsg signature verification, mirroring source citations).
- Bump SPEC.md frontmatter and re-anchor ~50 line citations across
Identity.py, Transport.py, Resource.py, Link.py, Reticulum.py,
Packet.py, and LXMF/* (Identity.py drift was the heaviest at +13
to +31 lines; Transport.py was variable). Fix one numeric
(MAX_RANDOM_BLOBS = 32 → 64) and one semantic (§6.6.3 LRPROOF MTU
clamp citation pointed at the wrong location — corrected to point
at the transit-relay clamp at Transport.py:1539-1556).
- Update §10.4 decompression-bomb hazard to note upstream's 1.1.9 cap
adoption, with citations to Resource.py:686-691 and Buffer.py:95-97
plus a "do not use one-shot bz2.decompress()" warning.
- Re-anchor 11 flows/ files (version pins + ~30 line citations).
- Bump version labels in tools/README.md, test-vectors/README.md, and
4 verifier docstrings + 2 hardcoded print strings.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 07:42:25 -04:00
A larger LXMF body arrives as a Resource transfer per `flows/receive-resource.md` . The Link's `resource_strategy = ACCEPT_APP` triggers `delivery_resource_advertised(resource)` (`LXMF/LXMRouter.py:1867-1874` ):
Add five companion flow docs
- flows/receive-resource.md: inverse of send-resource. ADV
ingestion, accept/reject decision, request_next loop,
receive_part insertion, assemble + decrypt + hash-validate,
RESOURCE_PRF emission, multi-segment continuation.
- flows/receive-link-lxmf.md: responder side of the link
handshake plus inbound LXMF DATA handling. validate_request
-> handshake -> prove (LRPROOF emission) -> link_established
callback wires delivery_packet. PACKET-form inbound runs
delivery_packet directly; RESOURCE-form inbound runs through
delivery_resource_advertised + delivery_resource_concluded
pipeline.
- flows/send-announce.md: random_hash construction (5B random +
5B BE-uint40 timestamp), optional ratchet rotation, signed_data
assembly, sign + pack, the broadcast emission. Notes that
ANNOUNCE packets are NOT encrypted (Packet.pack special-cases
line 189-191) and the periodic re-announce loop drives 5-15min
cadence.
- flows/forward-announce.md: relay-side rebroadcast for
transport-mode nodes. Eligibility checks (transport_enabled,
not PATH_RESPONSE, not rate_blocked), announce_table queue,
Transport.jobs drain with PATH_REQUEST_GRACE = 0.4s,
per-interface announce_queue with ANNOUNCE_CAP = 2.0% airtime
enforcement, lowest-hop-count-first emission order, hops byte
increment, local-rebroadcast counter for loop break.
- flows/send-propagated-lxmf.md: PROPAGATED method end to end.
LXMessage.pack with body encrypted to recipient (propagation
node never decrypts), Link establishment to the propagation
node, optional propagation stamp (1000 PoW rounds vs 3000 for
regular stamps), submission via Link DATA or Resource,
state goes to SENT (not DELIVERED — recipient pulls via /get
later per §5.8.3).
flows/README.md status table updated; receive-propagated-lxmf.md
added as the only remaining ⏳ flow.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 12:21:05 -04:00
```python
def delivery_resource_advertised(self, resource):
size = resource.get_data_size()
if self.delivery_per_transfer_limit and size > self.delivery_per_transfer_limit*1000:
return False # reject — over limit
return True # accept
```
If accepted, `Resource.accept` runs and the receiver state machine in `flows/receive-resource.md` takes over. On completion, `delivery_resource_concluded(resource)` fires, reads the assembled file, and feeds it through `lxmf_delivery` exactly like the single-packet path.
### 7. KEEPALIVE / teardown
Standard §6.7 protocol. The responder reflects every `0xFF` ping with a `0xFE` pong, emits its own KEEPALIVE-driven STALE→CLOSED transition if `last_inbound + 2*keepalive` elapses, and accepts inbound LINKCLOSE packets (validating that `decrypt(body) == link_id` ).
### 8. Backchannel-identify (post-first-delivery)
After a successful inbound LXMF delivery, the LXMRouter on the **initiator ** side may emit a `LINKIDENTIFY (context = 0xFB)` proof so the responder can record the initiator's long-term identity for backchannel use (`flows/send-link-lxmf.md` step 9). On the responder side, this triggers `delivery_remote_identified` which lets the responder send LXMF replies back over the same link without opening its own.
---
## Source map
| Step | File | Function / line |
|---|---|---|
| 1 | `RNS/Transport.py` | LINKREQUEST dispatch, line 2027 |
| 1 | `RNS/Destination.py` | `receive` LINKREQUEST branch, line 403 |
| 2 | `RNS/Link.py` | `validate_request` , line 186 |
| 2 | `RNS/Link.py` | `handshake` , line 353 |
| 3 | `RNS/Link.py` | `prove` (LRPROOF emission), line 371 |
| 4 | `RNS/Link.py` | `rtt_packet` , line 534 |
| 4 | `LXMF/LXMRouter.py` | `delivery_link_established` , line 1849 |
| 5 | `LXMF/LXMRouter.py` | `delivery_packet` , line 1819 |
| 6 | `LXMF/LXMRouter.py` | `delivery_resource_advertised` / `_concluded` , lines 1864-1900 |
| 7 | `RNS/Link.py` | KEEPALIVE handling, line 1149 |
| 8 | `LXMF/LXMRouter.py` | `delivery_remote_identified` , line 1849+ |