6.5 KiB
LXMF Implementation-Derived Specification
LXMessage Wire Format
This section describes behavior confirmed in the checked-in LXMF implementation
and by the reproducible vectors under examples/. It does not assign normative
requirements to independent implementations.
Evidence baseline:
- LXMF commit
d483d40d5cb994c6027802af1bf284dfeccc623b - Reticulum commit
2646f673ee061135d7c351ef44dce290ccd7e06e
Evidence status
- Source-confirmed means the behavior is directly implemented by the checked-in LXMF or Reticulum source.
- Vector-confirmed means
perl tools/verify_examples.plconfirms the behavior for the deterministic minimal and stamped vectors. - Behavior not covered by either form of evidence is marked Unresolved.
Core serialized message
LXMessage.pack() constructs lxmf_bytes by concatenating:
destination_hash || source_hash || signature || packed_payload
| Part | Position | Confirmed representation | Evidence |
|---|---|---|---|
destination_hash |
bytes 0..15 |
16 bytes | Source-confirmed: LXMF/LXMessage.py:40, LXMF/LXMessage.py:383; Vector-confirmed |
source_hash |
bytes 16..31 |
16 bytes | Source-confirmed: LXMF/LXMessage.py:384; Vector-confirmed |
signature |
bytes 32..95 |
64 bytes | Source-confirmed: LXMF/LXMessage.py:41, LXMF/LXMessage.py:385; Vector-confirmed position and length only |
packed_payload |
bytes 96..end |
MessagePack array | Source-confirmed: LXMF/LXMessage.py:362, LXMF/LXMessage.py:381-386; Vector-confirmed |
The 16-byte hash length derives from
RNS.Identity.TRUNCATED_HASHLENGTH // 8. The checked-in Reticulum source sets
the truncated hash length to 128 bits. The 64-byte signature length derives
from RNS.Identity.SIGLENGTH // 8. See RNS/Reticulum.py:146-147 and
RNS/Identity.py:80-83 in the evidence-baseline Reticulum checkout.
Payload
For messages generated by LXMessage.pack(), the payload is:
[
timestamp,
title,
content,
fields
]
If a message stamp is available when packing, it is appended:
[
timestamp,
title,
content,
fields,
stamp
]
| Index | Name | Confirmed behavior | Evidence |
|---|---|---|---|
0 |
timestamp |
Set from time.time() when not already set, then packed as the first payload value |
Source-confirmed: LXMF/LXMessage.py:357, LXMF/LXMessage.py:362; Vector-confirmed as MessagePack float64 for the deterministic vectors |
1 |
title |
Constructor string input is UTF-8 encoded to bytes; byte input is retained | Source-confirmed: LXMF/LXMessage.py:130-133, LXMF/LXMessage.py:193-197; Vector-confirmed as MessagePack binary |
2 |
content |
Constructor string input is UTF-8 encoded to bytes; byte input is retained | Source-confirmed: LXMF/LXMessage.py:135-136, LXMF/LXMessage.py:202-206; Vector-confirmed as MessagePack binary |
3 |
fields |
Constructor input must be a dictionary or None; None becomes an empty dictionary |
Source-confirmed: LXMF/LXMessage.py:138, LXMF/LXMessage.py:215-219; Vector-confirmed for an empty MessagePack map |
4 |
stamp |
Optional value appended after the four base payload values | Source-confirmed: LXMF/LXMessage.py:371-373; Vector-confirmed as MessagePack binary in the stamped vector |
The payload order above is source- and vector-confirmed. It differs from the
order stated in the upstream README.md, which lists content before title.
Message ID
The message ID, also stored as LXMessage.hash, is:
SHA-256(
destination_hash ||
source_hash ||
msgpack([timestamp, title, content, fields])
)
The optional stamp is excluded from the MessagePack payload used to calculate
the message ID. This is source-confirmed by both packing and unpacking behavior,
and vector-confirmed by the minimal and stamped vectors producing the same
message ID. See LXMF/LXMessage.py:362-369 and
LXMF/LXMessage.py:754-764. Reticulum defines full_hash() as SHA-256 at
RNS/Identity.py:238-246.
The message ID is not included in lxmf_bytes.
Signature input
LXMessage.pack() requests a signature over:
destination_hash ||
source_hash ||
msgpack([timestamp, title, content, fields]) ||
message_id
The optional stamp is excluded from the signature input. The construction of
the signature input is source-confirmed at LXMF/LXMessage.py:375-378 and
LXMF/LXMessage.py:762-764, and vector-confirmed.
The deterministic vectors contain placeholder signature bytes. They confirm the signature position and input bytes, but do not confirm signing or signature validation.
Delivery representations
The core lxmf_bytes representation is modified or wrapped for some delivery
methods:
| Delivery representation | Confirmed serialized data | Evidence |
|---|---|---|
| Direct packet or resource | Full lxmf_bytes |
Source-confirmed: LXMF/LXMessage.py:635-636, LXMF/LXMessage.py:653-654 |
| Opportunistic packet | lxmf_bytes without the leading destination hash |
Source-confirmed: LXMF/LXMessage.py:633-634 |
| Propagated message data | `destination_hash | |
| Propagation transfer wrapper | MessagePack [time.time(), [propagated_message_data]] |
Source-confirmed: LXMF/LXMessage.py:436 |
| Paper message data | `destination_hash | |
| Paper URI | URL-safe Base64 of paper message data, without = padding, prefixed by lxm:// |
Source-confirmed: LXMF/LXMessage.py:698-707 |
These delivery representations are not covered by the current deterministic test vectors.
Unresolved behavior
The following behavior is not established by the current source inspection and test-vector coverage:
- Normative requirements for independent LXMF implementations.
- Cross-implementation Ed25519 signature generation and validation.
- Accepted signature encodings beyond the fixed 64-byte position generated by the checked-in implementation.
- A universal MessagePack float width for timestamps on every supported platform. The deterministic vectors confirm float64 only for those vectors.
- Interoperable constraints on the contents, key types, value types, ordering,
and nesting depth of
fields. - Interoperable constraints on stamp length and encoding.
- Required handling of malformed, truncated, non-canonical, or payload arrays containing fewer than four or more than five entries.
- Byte-for-byte vectors for opportunistic, propagated, paper, URI, encrypted, or persisted-container representations.