Verify your signing library against ground truth.
Eight known-good Platform Contract HMAC vectors. Run each through your signRequest implementation. If your output doesn't match the expected signature byte-for-byte, your library is broken — fix it locally before pointing the manifest validator at your live URL.
How to use these vectors
For each vector, your signRequest(path, secret, timestamp) must return a signature equal to the expected hex string. The timestamp is provided so this is reproducible — production code uses Date.now(), but for testing you pin the timestamp to match.
for vector in vectors: got = sign_request(vector.path, vector.secret, vector.ts) assert got["X-Meridian-Signature"] == vector.sig, vector.name
The vectors deliberately exercise edge cases: query strings, colon characters in paths (which collide with the payload separator), epoch-zero timestamps, very large timestamps, Unicode in secrets, and Base64-shaped secrets. Pass all eight and your library is conformant.
The vectors
simple-path
The smallest possible case. Plain ASCII secret, plain ASCII path, no query string.
- secret
- shared-secret-do-not-leak
- timestamp
- 1714248000000
- path
- /api/meridian/health
- payload
- 1714248000000:/api/meridian/health
- expected
- 919f998d621d36c60c21d28900b75938c42bb98b76cc3c0ab875c5741b2dbf74
path-with-query
Query string is part of the signed path. If your library strips it before signing, this fails.
- secret
- shared-secret-do-not-leak
- timestamp
- 1714248000000
- path
- /api/meridian/metrics?since=1714247000000
- payload
- 1714248000000:/api/meridian/metrics?since=1714247000000
- expected
- ad2525729303da420dad91fe2536f67a88c31e626e34f98c6cf9b27d24fe56cc
install-post-path
POST endpoint. Method is NOT in the signature; only path. Same hash as a GET to the same path.
- secret
- shared-secret-do-not-leak
- timestamp
- 1714248000000
- path
- /api/meridian/install
- payload
- 1714248000000:/api/meridian/install
- expected
- 9e80440a403ecaf14bdd2281a3e3acc192921bc963591f470a56e44dc3315c85
longer-secret
Base64-shaped secret (the kind real deployments use). Confirms your library doesn't trim padding or treat the trailing equals sign specially.
- secret
- aGRrZmpsa2FzZGY7bGtqYXNkO2xramFzZDtsa2phc2Q7bGtqYXNkZjtsamFzZGZsa2pkc2Y=
- timestamp
- 1714248000000
- path
- /api/meridian/events?since=0
- payload
- 1714248000000:/api/meridian/events?since=0
- expected
- 04b1b1fdc901b081e0ff1832d52d03fe96693277dfabfc3d1d2b6056b03ecf31
unicode-in-secret
Secret contains non-ASCII characters (UTF-8 encoded). Confirms your library passes raw UTF-8 bytes to HMAC, not a re-encoded form.
- secret
- sécret-with-é-and-中-test
- timestamp
- 1714248000000
- path
- /api/meridian/manifest
- payload
- 1714248000000:/api/meridian/manifest
- expected
- 7952e5baca0940ccac713b7aa9f432ad987ffbe6537e1025c91f0ce08b4fb4da
epoch-zero-timestamp
Timestamp = 0. If your library skips signing when the timestamp is falsy, this is the failure mode that catches it.
- secret
- shared-secret-do-not-leak
- timestamp
- 0
- path
- /api/meridian/health
- payload
- 0:/api/meridian/health
- expected
- fde65c41209ad0f592e971598d273185d4b27692d9c4f05de2c605c2356a610b
large-timestamp
Timestamp near the int64 max. Confirms your library doesn't overflow when serializing large integers.
- secret
- shared-secret-do-not-leak
- timestamp
- 9999999999999
- path
- /api/meridian/billing?tenant_id=t_abc
- payload
- 9999999999999:/api/meridian/billing?tenant_id=t_abc
- expected
- 2198e4bfafb81e0e7ac606e5a425de27b5909fdb50a19627881d0b1b8257412d
path-with-colon
Colon in the path collides with the payload separator. The signature treats the entire path as opaque — your library should not split or re-escape on the first colon.
- secret
- shared-secret-do-not-leak
- timestamp
- 1714248000000
- path
- /api/meridian/install/ins_abc123:revoke
- payload
- 1714248000000:/api/meridian/install/ins_abc123:revoke
- expected
- e5ae8a2bd9945bf73debee31ca76a885a699c907a16b772aaecf8b701e211334
JSON form (for automated tests)
Same vectors as a single JSON array. Drop into your test fixtures.
[
{"name":"simple-path", "secret":"shared-secret-do-not-leak", "ts":1714248000000, "path":"/api/meridian/health", "sig":"919f998d621d36c60c21d28900b75938c42bb98b76cc3c0ab875c5741b2dbf74"},
{"name":"path-with-query", "secret":"shared-secret-do-not-leak", "ts":1714248000000, "path":"/api/meridian/metrics?since=1714247000000", "sig":"ad2525729303da420dad91fe2536f67a88c31e626e34f98c6cf9b27d24fe56cc"},
{"name":"install-post-path", "secret":"shared-secret-do-not-leak", "ts":1714248000000, "path":"/api/meridian/install", "sig":"9e80440a403ecaf14bdd2281a3e3acc192921bc963591f470a56e44dc3315c85"},
{"name":"longer-secret", "secret":"aGRrZmpsa2FzZGY7bGtqYXNkO2xramFzZDtsa2phc2Q7bGtqYXNkZjtsamFzZGZsa2pkc2Y=", "ts":1714248000000, "path":"/api/meridian/events?since=0", "sig":"04b1b1fdc901b081e0ff1832d52d03fe96693277dfabfc3d1d2b6056b03ecf31"},
{"name":"unicode-in-secret", "secret":"sécret-with-é-and-中-test", "ts":1714248000000, "path":"/api/meridian/manifest", "sig":"7952e5baca0940ccac713b7aa9f432ad987ffbe6537e1025c91f0ce08b4fb4da"},
{"name":"epoch-zero-timestamp", "secret":"shared-secret-do-not-leak", "ts":0, "path":"/api/meridian/health", "sig":"fde65c41209ad0f592e971598d273185d4b27692d9c4f05de2c605c2356a610b"},
{"name":"large-timestamp", "secret":"shared-secret-do-not-leak", "ts":9999999999999, "path":"/api/meridian/billing?tenant_id=t_abc", "sig":"2198e4bfafb81e0e7ac606e5a425de27b5909fdb50a19627881d0b1b8257412d"},
{"name":"path-with-colon", "secret":"shared-secret-do-not-leak", "ts":1714248000000, "path":"/api/meridian/install/ins_abc123:revoke", "sig":"e5ae8a2bd9945bf73debee31ca76a885a699c907a16b772aaecf8b701e211334"}
]
Test vectors — questions, plainly answered.
What are HMAC test vectors and why do I need them?
Known-good (input → expected signature) pairs that let you verify your signing library is correct without deploying. Each vector lists method, path, body, timestamp, secret, and the exact hex signature. If your signRequest function produces the same hex string for the same inputs, your implementation is byte-correct against Merkava Core.
How do I run these vectors against my library?
For each vector: feed the inputs (method, path, body, timestamp, secret) into your signRequest function, compare your output to the published expected signature. Match = correct. Mismatch = look at canonicalization, encoding, digest algorithm. The JSON form on this page can be loaded directly by automated tests.
What are the most common bugs these vectors catch?
Wrong digest algorithm (using SHA1 or SHA512 instead of SHA256). Wrong encoding (base64 instead of hex). Wrong newline handling (\r\n vs \n). Body normalization (trimming whitespace that shouldn't be trimmed). Off-by-one in the canonicalization order (timestamp before body, or method missing). All five fail loudly against the test vectors.
Are these vectors stable across Platform Contract versions?
These vectors are bound to Platform Contract v1. If v2 ever ships with a different signing canonicalization, new vectors will be published alongside. v1 vectors will keep working for v1-implementing Drives during the deprecation overlap window. Vectors are versioned in the JSON form.
Can I add my own vectors?
For your private CI: yes — generate them locally with a known-correct library and use them as regression tests. For contribution back to the published set: open an issue at the Merkava-HQ GitHub describing the edge case. Common asks (UTF-8 in body, very long bodies, empty paths) get prioritized if multiple authors hit them.
What's next
- HMAC cookbook (5 languages) → — ready-made signRequest + verifyRequest in Node, Python, Go, Ruby, PHP.
- Drive Quickstart tutorial → — end-to-end build of an Echo Drive in an afternoon.
- Manifest examples gallery → — five fully-worked Drive archetypes.
- Platform Contract reference → — canonical signing scheme, error semantics.