# Tier 1 Audit: Resource Fragmentation Question: Does `SPEC.md` §10 accurately describe the wire-visible Resource fragmentation behavior of upstream RNS 1.2.4? Evidence baseline: - RNS package: `rns==1.2.4` - Source: installed package paths `RNS/Resource.py`, `RNS/Packet.py`, `RNS/Link.py`, and `LXMF/LXMessage.py` - Audit date: 2026-06-08 This began as a Tier 1 source-analysis report. The completed Tier 2 checks live in `tools/verify_resource.py` and `test-vectors/resources.json`; the confirmed F1-F6 corrections were promoted into `SPEC.md` §10 on 2026-06-08. ## Confirmed Core Model The central §10 model matches RNS 1.2.4: - Resource prepends a throwaway 4-byte prefix, encrypts the complete stream once with the Link, then slices the ciphertext into parts (`Resource.py:404-428`, `453-472`; `Packet.py:201-204`). - Advertisement `r` is a distinct 4-byte salt used for the resource hash and per-part map hashes (`Resource.py:440-443`, `505-506`). - Resource integrity is `SHA256(uncompressed_segment_plaintext || r)`, and the expected proof is `SHA256(uncompressed_segment_plaintext || resource_hash)` (`Resource.py:440-443`, `681-695`, `752-758`). - RESOURCE_REQ may carry requested part hashes while also requesting a hashmap continuation; the sender fulfils parts before emitting RESOURCE_HMU (`Resource.py:994-1027`, `1027-1064`). - RESOURCE parts are matched only within the receiver's current window, while sender lookup is bounded by `COLLISION_GUARD_SIZE` (`Resource.py:863-890`, `999-1010`). ## Findings Requiring Correction or Clarification ### F1 — Direct LXMF threshold is 319 bytes, not approximately 360 `SPEC.md` §10 introduction says Resource carries an LXMF body larger than approximately 360 bytes. With default RNS 1.2.4 / LXMF 0.9.7 parameters: ```text RNS.Link.MDU = 431 LXMessage.LXMF_OVERHEAD = 112 LXMessage.LINK_PACKET_MAX_CONTENT = 319 ``` `LXMessage.pack()` selects Resource representation for DIRECT delivery when `content_size > 319` (`LXMF/LXMessage.py:80-89`, `414-421`). Recommended Tier 3 correction: say 319 bytes with default parameters, while noting that the threshold derives from Link MDU and may vary with protocol parameters. ### F2 — Resource is not the only possible way to carry larger application data The §10 introduction calls Resource "the only way" to carry payloads exceeding one Link packet. Resource is the standard RNS mechanism used by LXMF, Link REQUEST/RESPONSE, and `rncp`, but applications can also stream or sequence data over Channel or their own Link DATA protocol. Recommended Tier 3 correction: replace "the only way" with "the standard RNS mechanism used by LXMF, REQUEST/RESPONSE, and file-transfer utilities". ### F3 — Advertisement `d` is total logical-resource size For multi-segment resources, advertisement field `d` is `resource.total_size`, the total uncompressed logical transfer size including metadata, not the plaintext size of the advertised segment (`Resource.py:281-314`, `Resource.py:1281-1283`). Each segment still has its own: - `t`: encrypted transfer size for this segment - `n`: part count for this segment - `h`: integrity hash for this segment - `r`: salt for this segment Recommended Tier 3 correction: define `d` as total logical-resource size and explicitly distinguish it from the current segment's uncompressed plaintext length, which is not directly advertised. ### F4 — `RESOURCE_RCL` is not a general receiver-side cancel notification `Resource.reject(advertisement_packet)` sends `RESOURCE_RCL` (`Resource.py:154-163`). A corrupt receiver also calls `reject()` and tears down the Link (`Resource.py:1081-1084`). However, ordinary receiver-side `Resource.cancel()` only removes the incoming resource locally; it does not send `RESOURCE_RCL` (`Resource.py:1086-1097`). The current §10.9 wording implies either side can always notify cancellation on the wire. Recommended Tier 3 correction: describe `RESOURCE_RCL` as advertisement rejection / corrupt-resource rejection. Do not claim ordinary receiver cancel always emits it. ### F5 — Resource-part packet storage wording is imprecise `SPEC.md` §10.2 says packed wire bytes are stored in `parts[i]`. Upstream stores pre-packed `RNS.Packet` objects in `parts`; each packet's `data` is the raw ciphertext slice and its `raw` field is the packed Reticulum packet (`Resource.py:450-472`). Recommended Tier 3 clarification: distinguish the stored Packet object, its Resource body (`part.data`), and complete Reticulum wire packet (`part.raw`). ### F6 — Pinned-source mismatch in §10.7 citation The exhausted-REQ callout cites RNS 1.2.9 while this repository is pinned to RNS 1.2.4. The behavior is already present in RNS 1.2.4 (`Resource.py:994-1064`). Recommended Tier 3 correction: cite the pinned 1.2.4 behavior first; retain a later-version note only when documenting an actual version change. ## Tier 2 Verifier Scope The focused verifier is implemented in `tools/verify_resource.py` and avoids a live threaded transfer. It covers: 1. Construct a Resource with a deterministic fake Link encryption key, fixed throwaway prefix, and fixed advertisement `r`. 2. Verify whole-stream encryption occurs before slicing. 3. Verify Resource-part Packet bodies are raw slices and are not packet-level re-encrypted. 4. Verify advertisement dictionary fields, flags, and hashmap first segment. 5. Verify `hash`, `truncated_hash`, `expected_proof`, and map-hash formulas. 6. Verify RESOURCE_REQ parsing for both normal and exhausted-with-parts forms, including simultaneous part fulfilment and RESOURCE_HMU generation. 7. Verify receiver assembly strips the throwaway prefix, decrypts once, validates the hash, and emits the expected RESOURCE_PRF bytes. 8. Verify a multi-segment fixture proving `d` remains total logical size while `t`, `n`, `h`, and `r` describe the current segment. 9. Verify negative cases: malformed ADV, wrong `r`, corrupt part, invalid HMU boundary, and oversized decompression. The deterministic fixture is regenerated by `tools/regen_resources.py`. Tier 2 Resource work is complete for this audit scope; confirmed claims have been promoted into `SPEC.md` and the Resource flow documents.