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>
This commit is contained in:
parent
1e375e52ea
commit
038e39401f
9 changed files with 1028 additions and 55 deletions
|
|
@ -4,12 +4,14 @@ Known-good byte sequences that any Reticulum-compatible implementation should be
|
|||
|
||||
## Status
|
||||
|
||||
Partially populated against RNS 1.2.0:
|
||||
Populated against RNS 1.2.0 / LXMF 0.9.6:
|
||||
|
||||
- ✅ `identities.json` — Alice + Bob identity vectors (regenerator: `../tools/regen_identities.py`, verifier: `../tools/verify_destination_hash.py`).
|
||||
- ⏳ `announces.json` — not yet populated.
|
||||
- ⏳ `lxmf.json` — not yet populated.
|
||||
- ⏳ `links.json` — not yet populated.
|
||||
- ✅ `announces.json` — two announce vectors (no-ratchet + with-ratchet) signed by Alice (regenerator: `../tools/regen_announces.py`, verifier: `../tools/verify_announce_roundtrip.py`).
|
||||
- ✅ `lxmf.json` — two opportunistic-LXMF vectors Alice → Bob (regenerator: `../tools/regen_lxmf.py`, verifier: `../tools/verify_lxmf_opportunistic.py`).
|
||||
- ✅ `links.json` — full Link handshake vector (LINKREQUEST + LRPROOF + derived session key) Alice → Bob (regenerator: `../tools/regen_links.py`, verifier: `../tools/verify_link_handshake.py`).
|
||||
|
||||
All four files are byte-deterministic across runs: regenerators pin every random source (ephemeral keys, IVs, `random_hash` prefix + timestamp, LXMF timestamp) so the output is reproducible against a fixed upstream RNS / LXMF version.
|
||||
|
||||
See [`../agent.md`](../agent.md) §5 and [`../todo.md`](../todo.md) for the remaining bootstrap task list.
|
||||
|
||||
|
|
|
|||
88
test-vectors/announces.json
Normal file
88
test-vectors/announces.json
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
{
|
||||
"_about": "Announce test vectors. Each entry's `expected.wire_bytes_hex` is the full packed announce bytes (header + body). Drop them into a fresh RNS.Packet via the inbound path and call RNS.Identity.validate_announce; it MUST accept. The `expected.fields` block decomposes the wire bytes into named slices per SPEC.md S4.1 for human inspection. Regenerate with the script in `generator_script`.",
|
||||
"vectors": [
|
||||
{
|
||||
"label": "alice_lxmf_no_ratchet",
|
||||
"context_flag": 0,
|
||||
"with_ratchet": false,
|
||||
"inputs": {
|
||||
"identity_label": "alice",
|
||||
"destination_full_name": "vectors.alice_announce_no_ratchet",
|
||||
"random_hash_prefix_hex": "a1a2a3a4a5",
|
||||
"random_hash_timestamp": 1700000000,
|
||||
"ratchet_priv_hex": null,
|
||||
"app_data_msgpack_hex": "92c409416c6963655465737400",
|
||||
"app_data_decoded": [
|
||||
"AliceTest",
|
||||
0
|
||||
]
|
||||
},
|
||||
"expected": {
|
||||
"destination_hash_hex": "d9587f0be518490591c181755404d851",
|
||||
"wire_bytes_hex": "0100d9587f0be518490591c181755404d8510076fce269b2356a51b6a832a1a25099155acb20733b453f9538aaa8069e854d5a780708b44424373474ee1607c3f2b4a1cd5643de508e106e6b8cf4a10f00ec7c8b5739ff0fe7afaf7157a1a2a3a4a5006553f1009b0f121c51fda21cbce043b5b9d89b09817f29d320d2027c0f6c67144ace9d577722791e9ca1c5d24678ced4166862d77650756a98369c48a8455865c279e20092c409416c6963655465737400",
|
||||
"fields": {
|
||||
"header_flags_hex": "01",
|
||||
"header_hops_hex": "00",
|
||||
"header_dest_hash_hex": "d9587f0be518490591c181755404d851",
|
||||
"header_context_hex": "00",
|
||||
"body_public_key_hex": "76fce269b2356a51b6a832a1a25099155acb20733b453f9538aaa8069e854d5a780708b44424373474ee1607c3f2b4a1cd5643de508e106e6b8cf4a10f00ec7c",
|
||||
"body_name_hash_hex": "8b5739ff0fe7afaf7157",
|
||||
"body_random_hash_hex": "a1a2a3a4a5006553f100",
|
||||
"body_signature_hex": "9b0f121c51fda21cbce043b5b9d89b09817f29d320d2027c0f6c67144ace9d577722791e9ca1c5d24678ced4166862d77650756a98369c48a8455865c279e200",
|
||||
"body_app_data_hex": "92c409416c6963655465737400"
|
||||
}
|
||||
},
|
||||
"rns_version_at_generation": "1.2.0",
|
||||
"generator_script": "tools/regen_announces.py",
|
||||
"verifies_spec_sections": [
|
||||
"2.1",
|
||||
"4.1",
|
||||
"4.2",
|
||||
"4.3",
|
||||
"4.5"
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "alice_lxmf_with_ratchet",
|
||||
"context_flag": 1,
|
||||
"with_ratchet": true,
|
||||
"inputs": {
|
||||
"identity_label": "alice",
|
||||
"destination_full_name": "vectors.alice_announce_with_ratchet",
|
||||
"random_hash_prefix_hex": "a1a2a3a4a5",
|
||||
"random_hash_timestamp": 1700000000,
|
||||
"ratchet_priv_hex": "b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0",
|
||||
"app_data_msgpack_hex": "92c409416c6963655465737400",
|
||||
"app_data_decoded": [
|
||||
"AliceTest",
|
||||
0
|
||||
]
|
||||
},
|
||||
"expected": {
|
||||
"destination_hash_hex": "141410d233872609cf7b9f075afb4ebb",
|
||||
"wire_bytes_hex": "2100141410d233872609cf7b9f075afb4ebb0076fce269b2356a51b6a832a1a25099155acb20733b453f9538aaa8069e854d5a780708b44424373474ee1607c3f2b4a1cd5643de508e106e6b8cf4a10f00ec7c5130f0a9b2e01f693bd0a1a2a3a4a5006553f100cd700e88f9e99b19c1a8a8dcd58182fd101e5e032a69ce317fde23e8ee265c51e4985b2edb0694b51ddcb9e1aa73f60acd297bf8dd087056f90c2c9ee1e47587feef3b5f6f18de160bad45e49abe5f8c7d74ccb893e207061136f5222434620392c409416c6963655465737400",
|
||||
"fields": {
|
||||
"header_flags_hex": "21",
|
||||
"header_hops_hex": "00",
|
||||
"header_dest_hash_hex": "141410d233872609cf7b9f075afb4ebb",
|
||||
"header_context_hex": "00",
|
||||
"body_public_key_hex": "76fce269b2356a51b6a832a1a25099155acb20733b453f9538aaa8069e854d5a780708b44424373474ee1607c3f2b4a1cd5643de508e106e6b8cf4a10f00ec7c",
|
||||
"body_name_hash_hex": "5130f0a9b2e01f693bd0",
|
||||
"body_random_hash_hex": "a1a2a3a4a5006553f100",
|
||||
"body_signature_hex": "e4985b2edb0694b51ddcb9e1aa73f60acd297bf8dd087056f90c2c9ee1e47587feef3b5f6f18de160bad45e49abe5f8c7d74ccb893e207061136f52224346203",
|
||||
"body_app_data_hex": "92c409416c6963655465737400",
|
||||
"body_ratchet_pub_hex": "cd700e88f9e99b19c1a8a8dcd58182fd101e5e032a69ce317fde23e8ee265c51"
|
||||
}
|
||||
},
|
||||
"rns_version_at_generation": "1.2.0",
|
||||
"generator_script": "tools/regen_announces.py",
|
||||
"verifies_spec_sections": [
|
||||
"2.1",
|
||||
"4.1",
|
||||
"4.2",
|
||||
"4.3",
|
||||
"4.5"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
46
test-vectors/links.json
Normal file
46
test-vectors/links.json
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
{
|
||||
"_about": "Link handshake test vectors. Each vector records a full Reticulum Link handshake: LINKREQUEST (initiator -> responder) and LRPROOF (responder -> initiator). The ephemeral X25519/Ed25519 keys are pinned via the `inputs.*_priv_hex` blobs; both Ed25519 signatures are RFC 8032 deterministic so the resulting wire bytes are reproducible. A clean-room implementation can verify by: (a) packing a LINKREQUEST from the recorded initiator ephemerals and confirming bytes match `linkrequest_raw_hex`; (b) computing `link_id` per SPEC.md S6.3 (N=2 for HEADER_1) and matching `link_id_hex`; (c) packing an LRPROOF as the responder, with bob's identity Ed25519 sig over `link_id || responder_X25519_pub || responder_long_term_Ed25519_pub || signalling`, and matching `lrproof_raw_hex`; (d) running ECDH+HKDF on either side and matching `derived_key_hex`. Regenerate with `generator_script`.",
|
||||
"vectors": [
|
||||
{
|
||||
"label": "alice_to_bob_aes256cbc",
|
||||
"inputs": {
|
||||
"initiator_identity_label": "alice",
|
||||
"responder_identity_label": "bob",
|
||||
"destination_full_name": "vectors.link",
|
||||
"initiator_x25519_priv_hex": "1111111111111111111111111111111111111111111111111111111111111111",
|
||||
"initiator_ed25519_priv_hex": "2222222222222222222222222222222222222222222222222222222222222222",
|
||||
"responder_x25519_priv_hex": "3333333333333333333333333333333333333333333333333333333333333333",
|
||||
"mode": "MODE_AES256_CBC (0x01)"
|
||||
},
|
||||
"expected": {
|
||||
"linkrequest_raw_hex": "02008c670c64308e0325ea0fd7c72787449d007b4e909bbe7ffe44c465a220037d608ee35897d31ef972f07f74892cb0f73f13a09aa5f47a6759802ff955f8dc2d2a14a5c99d23be97f864127ff9383455a4f02001f4",
|
||||
"linkrequest_body_hex": "7b4e909bbe7ffe44c465a220037d608ee35897d31ef972f07f74892cb0f73f13a09aa5f47a6759802ff955f8dc2d2a14a5c99d23be97f864127ff9383455a4f02001f4",
|
||||
"linkrequest_fields": {
|
||||
"initiator_x25519_pub_hex": "7b4e909bbe7ffe44c465a220037d608ee35897d31ef972f07f74892cb0f73f13",
|
||||
"initiator_ed25519_pub_hex": "a09aa5f47a6759802ff955f8dc2d2a14a5c99d23be97f864127ff9383455a4f0",
|
||||
"signalling_hex": "2001f4"
|
||||
},
|
||||
"link_id_hex": "7ee5fe3e4952c9ac4519b537f6278474",
|
||||
"lrproof_raw_hex": "0f007ee5fe3e4952c9ac4519b537f6278474ff1de2168a36a816163aec0bb0749ff6792f78eb4f7b39156f8ee5c8693e83ebd67439ac28d9e4603334428713154edd04395b0b8acec2f703c05c3d38af133e0c7b0d47d93427f8311160781c7c733fd89f88970aef490d8aa0ee19a4cb8a1b142001f4",
|
||||
"lrproof_body_hex": "1de2168a36a816163aec0bb0749ff6792f78eb4f7b39156f8ee5c8693e83ebd67439ac28d9e4603334428713154edd04395b0b8acec2f703c05c3d38af133e0c7b0d47d93427f8311160781c7c733fd89f88970aef490d8aa0ee19a4cb8a1b142001f4",
|
||||
"lrproof_fields": {
|
||||
"signature_hex": "1de2168a36a816163aec0bb0749ff6792f78eb4f7b39156f8ee5c8693e83ebd67439ac28d9e4603334428713154edd04395b0b8acec2f703c05c3d38af133e0c",
|
||||
"responder_x25519_pub_hex": "7b0d47d93427f8311160781c7c733fd89f88970aef490d8aa0ee19a4cb8a1b14",
|
||||
"signalling_hex": "2001f4"
|
||||
},
|
||||
"shared_secret_hex": "5bf22caf31c0316785b0b9bc60e56d48582ce59435ce5b3c028052be42631e0f",
|
||||
"derived_key_hex": "d4c8238d23a1810c3dbe4caec15253d5a86d7fe6afa8dfa76f915579723fd88cbcd2ab3a0cd96f5b6ffd8abec8307f05cd791dc9c4fca900f706b0313a51ab65",
|
||||
"mtu": 500,
|
||||
"mode": 1
|
||||
},
|
||||
"rns_version_at_generation": "1.2.0",
|
||||
"generator_script": "tools/regen_links.py",
|
||||
"verifies_spec_sections": [
|
||||
"6.1",
|
||||
"6.2",
|
||||
"6.3",
|
||||
"6.6"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
76
test-vectors/lxmf.json
Normal file
76
test-vectors/lxmf.json
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
{
|
||||
"_about": "Opportunistic LXMF test vectors. `expected.lxmf_packed_hex` is the full plaintext body per SPEC.md S5.2: dest(16) || src(16) || sig(64) || msgpack. `expected.opportunistic_plaintext_hex` is the same with the leading dest_hash stripped (S5.1 wire form). `expected.token_ciphertext_hex` is the deterministic Token encryption of the opportunistic plaintext (S3) using the fixed ephemeral X25519 priv + IV. To verify against upstream: decrypt with Bob's identity, re-prepend Bob's dest_hash, then call LXMessage.unpack_from_bytes \u2014 it MUST succeed with signature_validated == True and title/content/fields matching the `inputs` block. Regenerate with `generator_script`.",
|
||||
"vectors": [
|
||||
{
|
||||
"label": "alice_to_bob_simple",
|
||||
"inputs": {
|
||||
"src_identity_label": "alice",
|
||||
"dst_identity_label": "bob",
|
||||
"title_utf8": "hello",
|
||||
"content_utf8": "hi bob",
|
||||
"fields": {},
|
||||
"lxmf_timestamp": 1700000000.0,
|
||||
"ephemeral_x25519_priv_hex": "d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0",
|
||||
"token_iv_hex": "11223344556677889900aabbccddeeff"
|
||||
},
|
||||
"expected": {
|
||||
"lxmf_packed_hex": "9695d17f22fa6e45d2b0cd3439a7ca7ec33c40a5b030596d95617dc4ca163aaedc758d54b21a2ca01a8fcc3e21c45eb60918d2dc64508037ce640e000a295a81951e5a7d0f8fedb90ec4df0b0a05b437b43d6692c9dd7faa98c4b679935a940e94cb41d954fc40000000c40568656c6c6fc406686920626f6280",
|
||||
"opportunistic_plaintext_hex": "c33c40a5b030596d95617dc4ca163aaedc758d54b21a2ca01a8fcc3e21c45eb60918d2dc64508037ce640e000a295a81951e5a7d0f8fedb90ec4df0b0a05b437b43d6692c9dd7faa98c4b679935a940e94cb41d954fc40000000c40568656c6c6fc406686920626f6280",
|
||||
"token_ciphertext_hex": "21c3332b61be6a7b6ab8461e155651b17501b6e07532ecf9ab6661bd5a2ca57511223344556677889900aabbccddeeffefa9d24b76e1adf393cfd588214e236e219743697af96912b8eae84f3a1f28a3d68abd62f3e42c6944015c3d00e5e7aa8af732123d079ab10353597669c8cd3ba57cfae3a28ea1a99a44e0b492ba5deedd23232d2edab78fa037967757808c8578496aee7b21c70ce2476c54540d96d928e8ddf35c6bfb5d76261c07f1bb48af9d7bec8261cd30f3b03986614ba93173",
|
||||
"fields_layout": {
|
||||
"destination_hash_hex": "9695d17f22fa6e45d2b0cd3439a7ca7e",
|
||||
"source_hash_hex": "c33c40a5b030596d95617dc4ca163aae",
|
||||
"signature_hex": "dc758d54b21a2ca01a8fcc3e21c45eb60918d2dc64508037ce640e000a295a81951e5a7d0f8fedb90ec4df0b0a05b437b43d6692c9dd7faa98c4b679935a940e",
|
||||
"msgpack_payload_hex": "94cb41d954fc40000000c40568656c6c6fc406686920626f6280"
|
||||
}
|
||||
},
|
||||
"rns_version_at_generation": "1.2.0",
|
||||
"lxmf_version_at_generation": "0.9.6",
|
||||
"generator_script": "tools/regen_lxmf.py",
|
||||
"verifies_spec_sections": [
|
||||
"3",
|
||||
"5.1",
|
||||
"5.2",
|
||||
"5.5",
|
||||
"5.6"
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "alice_to_bob_with_fields",
|
||||
"inputs": {
|
||||
"src_identity_label": "alice",
|
||||
"dst_identity_label": "bob",
|
||||
"title_utf8": "meeting",
|
||||
"content_utf8": "see attached",
|
||||
"fields": {
|
||||
"1": "k1",
|
||||
"2": 42
|
||||
},
|
||||
"lxmf_timestamp": 1700000000.0,
|
||||
"ephemeral_x25519_priv_hex": "d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0",
|
||||
"token_iv_hex": "11223344556677889900aabbccddeeff"
|
||||
},
|
||||
"expected": {
|
||||
"lxmf_packed_hex": "9695d17f22fa6e45d2b0cd3439a7ca7ec33c40a5b030596d95617dc4ca163aaef23eb2c325e59493c187b8fa1cc0efb6306f3eeed159a33aeec954576cbd354451caaa176aff84b57cc154b4e4113197b5eb92f1ec6a0e7635fa3d0508c67e0194cb41d954fc40000000c4076d656574696e67c40c7365652061747461636865648201a26b31022a",
|
||||
"opportunistic_plaintext_hex": "c33c40a5b030596d95617dc4ca163aaef23eb2c325e59493c187b8fa1cc0efb6306f3eeed159a33aeec954576cbd354451caaa176aff84b57cc154b4e4113197b5eb92f1ec6a0e7635fa3d0508c67e0194cb41d954fc40000000c4076d656574696e67c40c7365652061747461636865648201a26b31022a",
|
||||
"token_ciphertext_hex": "21c3332b61be6a7b6ab8461e155651b17501b6e07532ecf9ab6661bd5a2ca57511223344556677889900aabbccddeeffefa9d24b76e1adf393cfd588214e236eac9dde2777640fdd62e86256d9ddac812eeda9277056b5652b9d83ca7d0da7203a5f51b69f7d35a58da4b6a13562a12145a98810d1b89fec9a70e947c50eee6482f3fda4165fd6eef25819fc5093d5f2aaaf7b8911689a3eeaf0131816bac4041923df9e64a807d9809c35cc7bed027de94dc42a7af10261f14053dc62d77d54e66f60dfb83763a6f66798c51eeabcd2",
|
||||
"fields_layout": {
|
||||
"destination_hash_hex": "9695d17f22fa6e45d2b0cd3439a7ca7e",
|
||||
"source_hash_hex": "c33c40a5b030596d95617dc4ca163aae",
|
||||
"signature_hex": "f23eb2c325e59493c187b8fa1cc0efb6306f3eeed159a33aeec954576cbd354451caaa176aff84b57cc154b4e4113197b5eb92f1ec6a0e7635fa3d0508c67e01",
|
||||
"msgpack_payload_hex": "94cb41d954fc40000000c4076d656574696e67c40c7365652061747461636865648201a26b31022a"
|
||||
}
|
||||
},
|
||||
"rns_version_at_generation": "1.2.0",
|
||||
"lxmf_version_at_generation": "0.9.6",
|
||||
"generator_script": "tools/regen_lxmf.py",
|
||||
"verifies_spec_sections": [
|
||||
"3",
|
||||
"5.1",
|
||||
"5.2",
|
||||
"5.5",
|
||||
"5.6"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue