Commit graph

2 commits

Author SHA1 Message Date
Rob
073203abae Resolve issue #6 — LRRTT and HEADER_1 for link-addressed DATA (§6.4.2, §6.4.3)
Upstream RNS enforces two requirements in code that SPEC.md left implicit;
both caused silent message loss in a clean-room Go LXMF service against
upstream Python rns 1.2.4 / lxmf 0.9.7.

§6.4.2 LRRTT — initiator's link-activation packet
  - HEADER_1, DATA, dest_type=LINK (0x03), ctx=0xfe; body is
    `umsgpack.packb(rtt_seconds)` encrypted with the link's session keys.
  - The responder transitions HANDSHAKE→ACTIVE only on LRRTT receipt
    (Link.py:534-553), which is also what fires the link_established
    callback. LXMF's set_resource_strategy(ACCEPT_APP) is installed
    from that callback; without it, every RESOURCE_ADV the initiator
    sends hits the silent ACCEPT_NONE branch at Link.py:1087.

§6.4.3 Header type for post-handshake DATA and Resource
  - Link-addressed packets are routed via link_table, which forwards
    header bytes verbatim (Transport.py:1587-1622). HEADER_2 with a
    relay's transport_id therefore arrives at the destination intact
    and is dropped by packet_filter (Transport.py:1283-1285) as
    "for another transport instance".
  - Mandates HEADER_1 with no transport_id for all post-handshake
    link DATA / Resource / control packets regardless of hop count.
  - Asymmetry with LINKREQUEST (which IS path_table-routed and so
    HEADER_2-eligible) is spelled out.

Companion changes:
  - §6.4 renamed to "Session keys and link activation"; existing
    HKDF content moved into §6.4.1.
  - §2.5 LRRTT context-byte entry points at §6.4.2.
  - §12.5.2 (Link DATA forwarding) cross-references §6.4.3.
  - §14 failure-modes table: two new entries for the silent-drop
    chains documented above.
  - flows/send-link-lxmf.md step 4 strengthened (LRRTT is mandatory,
    not informational); step 6 corrected (Transport.outbound does NOT
    apply HEADER_1→HEADER_2 for link DATA — that conversion is
    path_table-keyed, link DATA is link_table-keyed).
  - test-vectors/links.json extended with an LRRTT entry: pinned
    rtt_seconds=0.05 + pinned 16-byte IV produces deterministic
    wire bytes for the encrypted body.
  - tools/regen_links.py drives the LRRTT generation with an
    os.urandom patch for the Token IV.
  - tools/verify_link_lrrtt.py (new) locks the wire claims:
    HEADER_1, ctx=0xfe, dest=link_id, body decrypts under
    derived_key to msgpack float64 matching rtt_seconds.

Citations all verified against installed RNS 1.2.4 / LXMF 0.9.7.
All 14 verifiers PASS.
2026-05-10 14:35:56 -04:00
Rob
038e39401f Bootstrap test-vectors/{announces,lxmf,links}.json + regenerators
Three deterministic vector files complete the test-vectors/ bootstrap.
Each regenerator pins every random source so output is byte-identical
across runs against a fixed upstream RNS / LXMF version.

- announces.json: two vectors (no-ratchet + with-ratchet) signed by
  Alice. Determinism via patched Identity.get_random_hash + module-
  local time.time shim inside RNS.Destination.

- lxmf.json: two opportunistic-LXMF vectors Alice -> Bob, captures
  full plaintext (S5.2 layout) plus Token-encrypted ciphertext (S3).
  Determinism via fixed LXMessage.timestamp, ephemeral X25519 priv,
  and Token CBC IV.

- links.json: full Link handshake — LINKREQUEST + LRPROOF wire bytes,
  derived link_id, ECDH shared secret, and HKDF-derived session key
  that both initiator and responder MUST agree on. Determinism via
  three queued ephemeral priv-key blobs (initiator X25519, initiator
  Ed25519, responder X25519) consumed in source-call order at
  RNS/Link.py:285, :286, :278.

Status table in test-vectors/README.md and tools/README.md updated to
reflect the completed bootstrap. todo.md cleaned up to reflect actual
state (the previous "Open ⚠️ items needing a runtime verifier" section
was stale — all three verifiers were completed earlier).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 21:56:44 -04:00