These JSON fixtures lock down the wire format and signature behavior of the VectorPin protocol. Every language implementation (Python, Rust, TypeScript) consumes them in CI.
-
v2.json— positive fixtures. Each has an input (source, model, vector bytes, dtype, dim, timestamp, optional model_hash / extra) and the produced pin JSON, expected canonical bytes (with thevectorpin/v2\x00domain tag prepended), and component hashes. Seven entries: small f32, small f64, pin withmodel_hash, pin withextracontaining avectorpin.record_idreplay-protection key, f32 IEEE-754 edge cases (signed zeros, subnormals, max, 1 + ulp), f64 edge cases, and an f64 input pinned as f32 whose values are exact round-to-nearest-even ties. That last entry carriesinput.vec_native_dtype: "f64":vec_b64holds the f64 input bytes, the signer casts at sign time, and consumers verify with the f32 cast (what an f32 store persists) — verifying with the f64 input itself is a SHAPE_MISMATCH under the §3.2 precision rule. -
negative_v2.json— negative fixtures covering every failure mode in spec §5: VECTOR_TAMPERED, SOURCE_MISMATCH, MODEL_MISMATCH (wrong model, wrong / missing model_hash), SIGNATURE_INVALID (bit-flip, vec_dim tamper), UNSUPPORTED_VERSION, UNKNOWN_KEY, KEY_EXPIRED (ts after valid_until; backdated ts caught by a trusted time), SHAPE_MISMATCH (truncated vector; f64 vector with low-bit perturbation against an f32 pin; f32-exact f64 vector against an f32 pin), PARSE_ERROR (wrong sig length, padded sig, non-canonical trailing bits, unknown top-level field, non-string extra,extra: null,v: 2.0, NaN at verify, NFD string, lone surrogate, malformed and calendar-invalid timestamps, oversize pin, kid / model over the field caps), RECORD_MISMATCH, COLLECTION_MISMATCH, and TENANT_MISMATCH. Each entry carries adescriptionand anexpected_failurecode matching a v2 VerifyError enum value.Optional per-entry inputs consumers must honor:
tampered_vec_b64/nan_vec_b64withvec_dtype(the dtype of the supplied bytes, which may be wider than the pin's) andvec_dim;tampered_source;expected_model;expected_model_hash;expected_record_id/expected_collection_id/expected_tenant_id;key_valid_from/key_valid_until(register the key with that window); andtrusted_time(pass as the verifier-trusted instant).
-
v1.json— positive fixtures from the v1 protocol. These verify ONLY undervectorpin.LegacyV1Verifier(the opt-in migration verifier). The strict v2 verifier rejects them as UNSUPPORTED_VERSION. -
negative_v1.json— one v1 negative fixture (tampered vector). Retained for migration regression testing.
These v1 files are frozen — do NOT regenerate them. The v1 wire format is closed and the existing signatures must remain byte-for-byte verifiable.
The v2 signing key is deterministic:
- seed:
AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8(bytes 0x00..0x1f in URL-safe base64, no padding) - key id:
test-vectors-v2-2026-05
The v1 fixtures used the same seed under key id
test-vectors-2026-05.
Re-running scripts/generate_test_vectors.py regenerates v2.json
and negative_v2.json byte-for-byte from the deterministic seed. If
your port disagrees, the canonicalization or signing algorithm is off.
The deterministic seed contract is load-bearing for cross-language parity: every Rust/TypeScript test that consumes these fixtures re-derives the signature from the same seed and compares against the published bytes. Do not change the seed without coordinating with every implementation and bumping the cross-language compat-test expectations.
The seeds are published intentionally — these fixtures are public test data, not production keys.
v2 pins are signed over DOMAIN_TAG || canonical_json(header) where
DOMAIN_TAG = b"vectorpin/v2\x00" (13 bytes — 12 ASCII characters
"vectorpin/v2" plus one NUL terminator). Ports MUST match those exact
bytes. See src/vectorpin/attestation.py for the canonical constant.