DEVELOPERS · HMAC TEST VECTORS

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.

Pseudocode for the round-trip:
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

Vector 1

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
Vector 2

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
Vector 3

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
Vector 4

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
Vector 5

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
Vector 6

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
Vector 7

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
Vector 8

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"}
]
QUESTIONS

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