5.3 KiB
No, I don’t need SPEC.md or SOURCES.md for this first report. I used the checked-out LXMF source directly. I did not edit SPEC.md or any other file.
LXMessage Serialized Structure
Source inspected: LXMF commit fab12ad9bf9f997797034950f289fe41a79dcf5a
Core lxmf_bytes layout:
destination_hash || source_hash || signature || msgpack_payload
Where msgpack_payload is:
[
timestamp,
title,
content,
fields,
optional_stamp
]
The fifth element is only present when a normal message stamp is generated and appended.
| Field | Serialized position | Type / size | Source origin | Test vector confirmed |
|---|---|---|---|---|
destination_hash |
bytes 0..15 |
16 bytes | LXMessage.py, length from LXMessage.py and RNS 128-bit truncated hashes in Reticulum.py | No |
source_hash |
bytes 16..31 |
16 bytes | LXMessage.py | No |
signature |
bytes 32..95 |
64 bytes | LXMessage.py, LXMessage.py; RNS signature length from Identity.py and Identity.py | No |
msgpack_payload |
bytes 96..end |
msgpack list | LXMessage.py, packed at LXMessage.py | No |
timestamp |
payload index 0 |
Python float, normally msgpack float64 on this RNS umsgpack | LXMessage.py, LXMessage.py; float64 behavior from umsgpack.py and umsgpack.py | No |
title |
payload index 1 |
bytes | LXMessage.py, LXMessage.py, LXMessage.py | No |
content |
payload index 2 |
bytes | LXMessage.py, LXMessage.py, LXMessage.py | No |
fields |
payload index 3 |
dict, default {} |
LXMessage.py, LXMessage.py | No |
stamp |
payload index 4, optional |
bytes, only if generated | LXMessage.py, LXMessage.py; extracted on unpack at LXMessage.py | No |
Hash And Signature
message_id / hash is:
SHA256(destination_hash || source_hash || msgpack([timestamp, title, content, fields]))
Source: LXMessage.py, LXMessage.py, RNS SHA-256 at Identity.py.
The signature is over:
destination_hash || source_hash || msgpack([timestamp, title, content, fields]) || message_id
Source: LXMessage.py, LXMessage.py, RNS signing at Identity.py.
Important: the optional normal stamp is excluded from both message_id and signature. Unpack removes payload index 4 before recomputing hash/signature material: LXMessage.py.
Outer Representations
Direct/link/resource delivery uses full self.packed unchanged: LXMessage.py, LXMessage.py.
Opportunistic packet delivery omits the destination hash from the packet payload because the RNS packet destination already implies it:
source_hash || signature || msgpack_payload
Source: LXMessage.py.
Propagated and paper messages wrap/encrypt everything after the destination hash:
destination_hash || encrypted(source_hash || signature || msgpack_payload)
Source: propagated LXMessage.py, paper LXMessage.py. Propagation transit additionally msgpacks [time.time(), [lxmf_data]]: LXMessage.py.
Notes
The README is not authoritative here: it describes payload order as timestamp, content, title, fields, but current code serializes timestamp, title, content, fields.
No test vector confirmation exists in this checkout. There is no tools/ directory and no tracked SPEC.md or SOURCES.md, so every “Test vector confirmed” entry above is marked No.