Test vectors

These are the golden vectors that prove the binary claims in this specification. They are the genuine output of the reference code, generated by vectors/gen_vectors.py and stored in machine-readable form in vectors/vectors.json.

Regenerate and verify (from the repository root):

PYTHONPATH=reference/Reticulum:reference/LXMF \
    python3 docs/src/appendix/lxmf/vectors/gen_vectors.py

Pinned to LXMF 795fdaa (1.1.0) and Reticulum d5e62d4 (RNS 1.3.5). Fixed inputs: source identity private = 00010203…3f, destination identity private = 404142…7f, message timestamp = 1700000000.0.

Vector kinds

  • frozen — deterministic; the hex is the proof; reproduces byte for byte.
  • roundtrip — encryption uses ephemeral key material. The fixture omits the random ciphertext and ciphertext-derived hashes, retaining deterministic lengths, structure, and decrypt assertions. The complete JSON therefore reproduces byte for byte.

VEC-MSG-1 (frozen) — minimal opportunistic message

title=b"Hi", content=b"Hello", fields={}. (LXMessage.py:355-388)

packed (118 B):
cf0b2a4a8d2a0b6978b71290da7cc80e   destination_hash(16)
fae321c442e3c9bdcd7a3e79d850e03c   source_hash(16)
fb321978105a4c709c3b86930ff15a9d
7b53b3485517ec19e2083b39f7661e6e
531c78fb71d932f0baf13794c42234ab
9320f1ab5b7688e93eaf5960810ece00   signature(64)
94cb41d954fc40000000c4024869c405
48656c6c6f80                       packed_payload (msgpack)

message_id = 9aec506b63deab21d8fa4954d9f743cf20f5adeeb1abd1c7429bb3f832dc287b
signature_valid = true

VEC-MSG-2 (frozen) — fields dict with integer key

title=b"", content=b"body text", fields={0x0F: 0x02}. (LXMessage.py:355)

packed_payload: 94cb41d954fc40000000c400c409626f64792074657874810f02
  94                      array(4)
  cb 41d954fc40000000     timestamp 1700000000.0
  c4 00                   title bin(0) = ""
  c4 09 626f6479...       content bin(9) = "body text"
  81 0f 02                fields {0x0F: 0x02}

VEC-MSG-NEGATIVE-FIELD (frozen) — negative-fixint field key

fields={-1: b"negative field"} proves that unknown signed integer keys retain their MessagePack type. The 0xff byte below is negative fixint -1, not an unsigned field ID or a string key. (LXMessage.py:215-219,355-387)

packed_payload:
94cb41d954fc40000000c40c6e65676174697665206b6579c404626f6479
81ffc40e6e65676174697665206669656c64
                                                      ^^ key = -1

VEC-MSG-TICKET (frozen) — ticket-stamped message, five-element payload

The only deterministic stamped message: an outbound ticket yields truncated_hash(ticket || message_id) instead of a mined proof of work, and the carried FIELD_TICKET value is the [expires, ticket] list generate_ticket returns. outbound_ticket = 101112…1f, carried ticket secret 202122…2f, expires = 1700000000.0 + TICKET_EXPIRY. (LXMessage.py:355-388,293-302; LXMRouter.py:1096-1100,1770-1772)

packed_payload:
95cb41d954fc40000000c40154c4087469636b65746564
810c92cb41d95be820000000c410202122232425262728292a2b2c2d2e2f
c41054f9096872188db445566721224cca74
  95                      array(5)  <- stamp present
  cb 41d954fc40000000     timestamp 1700000000.0
  c4 01 54                title bin(1) = "T"
  c4 08 7469636b65746564  content bin(8) = "ticketed"
  81 0c 92 …              fields {FIELD_TICKET: [expires, ticket]}
     92                     array(2)
     cb 41d95be820000000   expires 1701814400.0
     c4 10 202122…2f       ticket bin(16)
  c4 10 54f909…a74        stamp bin(16) = truncated_hash(ticket || message_id)

message_id  = 190d522017c991b7e74bd958faadfc780dced409514904e6f7fd514b4a84d974
stamp_value = 256 (COST_TICKET)

The message ID and the signature are computed over the four-element payload; the stamp is appended afterwards and is covered by neither.

VEC-MSG-3 (frozen) — unpack + verify of VEC-MSG-1

After making the source identity recallable, unpack_from_bytes of VEC-MSG-1 yields signature_validated = true, matches_source = true, recovered title="Hi", content="Hello". (LXMessage.py:747-822)

VEC-MSG-FOREIGN-* (frozen) — reader tolerance for payload[0]

Three payloads built with payload[0] spliced in as a non-float64 msgpack number — uint32, float32 and a negative fixint — and signed over the bytes the writer packed. Each vector records the reference decoder's own verdict: reference_signature_validated = true and reference_message_id_matches = true in all three cases, with reference_timestamp_type showing int or float as packed. They exist because LXMF's writer cannot produce these forms (time.time() is always a Python float) while its reader accepts them, so nothing generated from the reference's writer covers the case. See Reader tolerance. (LXMessage.py:747-766)

VEC-DLV-OPP (frozen) — opportunistic on-air payload

on_air = packed[16:] (destination hash omitted). (LXMessage.py:633-634)

VEC-DLV-DIRECT (frozen) — direct on-air payload

on_air = packed (full bytes over a link). (LXMessage.py:635-636)

VEC-PROP-ENVELOPE (roundtrip) — propagation envelope

Structure destination_hash(16) || destination.encrypt(packed[16:]); envelope msgpack([timestamp, [lxmf_data]]); transient_id = full_hash(lxmf_data); destination.decrypt(pn_encrypted) == packed[16:] holds. The random transient ID itself is intentionally not stored. (LXMessage.py:426-436)

VEC-PAPER-URI (roundtrip) — paper URI

lxm://base64url(destination_hash(16) || destination.encrypt(packed[16:])) with = padding stripped; prefix lxm://; decoding and decrypting recovers packed[16:]. Random URI body bytes are intentionally not stored. (LXMessage.py:446-451,698-713)

VEC-STAMP-1 (frozen) — stamp workblock, validity, value

material = full_hash(b"lxmf-spec-stamp-material") = 1c91877ffb9797aa6f33064586b47a3c41f6dfa75e10aa17bc24bf0ac6833712, expand_rounds=4, target_cost=8, workblock 1024 B. Deterministic search stamp = full_hash(material || counter_be8) finds counter=377:

stamp  = 9b79689af899049accea13624a3c59221603117e81086a86a3249ce278acc35e
target = 0100000000000000000000000000000000000000000000000000000000000000   (1 << 248)
valid  = true
value  = 8

(LXStamper.py:49-77)

VEC-STAMP-PN (frozen) — propagation-node stamp

This vector pins the full propagation-node workblock rather than only the common stamp algorithm: material 00..1f, expand_rounds=1000, and target_cost=8 produce a 256000-byte workblock whose SHA-256 is 36224067c2ebd1a40b0dc8908bd34dc4b7cd84be57f68a765dbaf3298bcd9719. Searching counter_be32 finds counter 17:

stamp  = 0000000000000000000000000000000000000000000000000000000000000011
digest = 00420981fc866c09cb2f28e7503147d56bae0b3a6fc69f00478cb247f8d95b91
valid  = true
value  = 9

(LXStamper.py:13,53-63,122-155)

Propagation mailbox /get vectors (frozen)

These are the complete client-only exchange at /get (LXMPeer.MESSAGE_GET_PATH): initial list, selected download, acknowledgement/purge, and both response shapes. The implementation does not expose /offer.

VEC-PROP-GET-LIST

[None, None] (LXMRouter.py:511-520):

request: 92c0c0

VEC-PROP-GET-DOWNLOAD

One wanted ID (20..3f), one already-held ID (40..5f), transfer limit 1000 KB (LXMRouter.py:1577-1595):

request:
9391c420202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f
91c420404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f
cd03e8

VEC-PROP-GET-ACK

[None, [transient_id]], which asks the node to purge the acknowledged entry (LXMRouter.py:1625-1637):

request: 92c091c420000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f

VEC-PROP-LIST-RESPONSE

response:
92c420202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f
c420404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f

VEC-PROP-GET-RESPONSE

Two binary downloaded entries, b"one" and b"two"; error responses are ccf0 (NO_IDENTITY) and ccf1 (NO_ACCESS).

response: 92c4036f6e65c40374776f

VEC-ANN-DELIVERY (frozen) — delivery announce app_data

LXMF 1.0.1 advertises Resource compression in the third element: msgpack([b"Alice", 8, [SF_COMPRESSION]]).

app_data: 93c405416c696365089100
  93                array(3)
  c4 05 416c696365  display_name bin(5) = "Alice"
  08                stamp_cost = 8
  91 00             supported functionality = [SF_COMPRESSION]
first_byte = 0x93  (new-format sniff)
decoded: display_name="Alice", stamp_cost=8, compression_supported=true

(LXMRouter.py:1034-1050; LXMF.py:151-200)

VEC-ANN-PROPAGATION (frozen) — propagation node announce app_data

7-element list, metadata={PN_META_NAME: b"Node"}, stamp_costs=[16,3,18], fixed timebase:

app_data: 97c2ce6553f100c3cd0100cd2800931003128101c4044e6f6465
valid = true; pn_name = "Node"; pn_stamp_cost = 16

(LXMRouter.py:324-336; LXMF.py:202-250)