Test vectors (v1 core)
This page answers one question: what do the Tieroute test vectors cover, and how do you regenerate and check them? They're byte-exact examples that any Tieroute implementation can check itself against. Section references (§) are to the Tieroute protocol specification.
Warning: every key in these files is public. Never use them for anything real.
| File | What it covers |
|---|---|
signed.json |
The signed envelope (§4.3): the body as text in the JSON Canonicalization Scheme (JCS), the signature input JCS(["tieroute/v1", t, b]), the signature, the whole envelope as JCS, and its hash. The example is a POST auth/session body, plus the same envelope with an extra member, which must be rejected. |
recovery.json |
A recovery code (16 bytes and 12 BIP-39 (Bitcoin Improvement Proposal 39) words), HMAC-based key derivation (HKDF) of recovery keys 1 and 2, their pre-rotation commitments, and recovery_wrap (§6.1, §6.3) |
chain.json |
A valid four-entry identity chain: genesis, add device, a recovery-signed removal with re-commitment, and a self-rotation. Includes the identifier derivation and the expected final state (§6.2 to §6.4). |
codes.json |
A contact verification-code round (§6.7) |
ed25519.json |
Ed25519 verification rules (§4.3): a valid signature, an unreduced S, and small-order keys and R points, including the all-zero signature that a plain cofactorless check accepts for any message |
fork.json |
The fork rule (§6.4.1, §6.5): a stolen device moves the identity to another homeserver, the recovery key forks it back, and seven cached-versus-candidate cases with the required outcome, including both orders of arrival for a late recovery entry |
vouch.json |
Who vouches for chain entries (§6.5): 11 cases covering previous-home confirmation, unreachable and 404 homes (a first fetch rejects while the previous home can't be reached), and recovery entries vouching for earlier ones |
s2s.json |
A server-to-server (S2S) request signed with a server key named by kid (§8.3) |
formatting.json |
Message formatting (§12.1): 30 bodies and the block trees they parse to, covering every span, escapes, links, quotes, code blocks, and the edge cases. A Go reference parser generates them and an independent JavaScript parser in check.mjs must agree |
sframe.json |
SFrame (Secure Frame) for calls (§15.2, RFC 9605): RFC 9605's own case for AES_128_GCM_SHA256_128, header encodings, and Tieroute's key IDs ((leaf_index << 4) + (epoch % 16)) with their keys and an encrypted frame. The Messaging Layer Security (MLS) exporter output is a stand-in, since it needs a real group. The reference client and check.mjs check it |
link.json |
Signing in with another device (§7.2, and the device-linking endpoints in the client API): the link code for a device key, accepted spellings, confirmation-code normalization, and a signed link proof |
account.json |
Account data (§7.4): the account key wrapped under recovery_wrap from recovery.json, and an account-data blob, each AES-128-GCM with its 12-byte nonce first and the associated data that binds it to its identity and purpose; and a recovery-code rotation's staged wrap (recovery-next), bound to its code by the commitment to the code's key 1. The reference client and check.mjs check it |
Raw bytes are hex, in fields ending in _hex. Signed objects and other signed or hashed inputs are given as their exact JCS text (body, sig_input, signed, input): sign and hash the UTF-8 bytes of that text. Inside it, byte strings are unpadded base64url, as on the wire (§4).
Generate the vectors
The vectors are produced by a Go program with fixed inputs, so the output is reproducible. From the spec/vectors/ directory:
cd gen
go run . -out ..
Regenerate them whenever the spec changes something they cover, and commit the result.
Check the vectors
check/check.mjs re-derives everything it can from the JSON using only the built-in crypto of Node.js and its own JCS: every signed object from its type and body, signatures, hashes, HKDF, identifiers, and codes. It's a second, independent implementation of the encoding and the crypto parts. From the spec/vectors/ directory:
node check/check.mjs .
Not covered yet
- MLS objects: key packages, commits,
app-messageinside MLS. These depend on the MLS library and suite (§3.1). Use the IETF MLS interop vectors for the MLS layer itself. - Link bundles, which use the hybrid post-quantum form of Hybrid Public Key Encryption (HPKE)
- Contact requests