ecdsa.com

ECDSA Test Vector Generator

Pick a curve, a hash and a seed — get key pairs, messages, digests and signatures in every encoding your test suite might need, as JSON plus ready-to-run Node.js, Python and Go code. The same seed always produces the same vectors.

100% local — everything runs in your browser, nothing is sent to any server

Signatures use RFC 6979 deterministic nonces — no randomness in the signing step.

How it works

A test vector is a frozen example: a known key, a known message and the exact signature that belongs to them. Your test feeds those bytes to your code and asserts the answer. That is how you find out whether your verifier really works — without it, a test that signs and then verifies with the same library only proves the library agrees with itself, and would happily pass even if both halves were wrong in the same way. Each vector here ships in every encoding a real code path might expect: the public key as uncompressed and compressed SEC1 points, PEM SubjectPublicKeyInfo and JWK; the signature as ASN.1 DER, as raw r‖s and as the base64url form JWTs use.

Deterministic seeds make those vectors reproducible. In seed mode each private key is derived by hashing seed/index/counter with SHA-256 and folding the result into the valid scalar range [1, n−1], and the signatures use RFC 6979 deterministic nonces — the nonce comes from an HMAC-DRBG over the private key and the digest, not from a random number generator. So the same seed, curve and hash always produce byte-identical vectors: you can hard-code them in a test file, regenerate them years later, or hand the seed to a colleague instead of a blob of hex. Random mode uses crypto.getRandomValues instead, which is what you want when you need fresh keys rather than repeatable ones — but then only what you copy or download survives.

Negative vectors matter more than positive ones. A verifier that returns true for everything passes every happy-path test you will ever write. The invalid vectors here are the failures that actually happen in production code: one flipped bit in s (corruption), a genuine signature replayed over a different message (code that verifies but forgets to bind the payload), r = 0 (a missing range check), the malleable twin (r, n − s) that low-S enforcing stacks like Bitcoin must reject, and a real signature made on a different curve of the same size — P-256 versus secp256k1 produce byte-identical shapes, so only the curve math tells them apart. Each carries expected: "invalid" and a short reason, so a table-driven test can assert the rejection and print something useful when it does not happen.

Everything is computed in your browser with the audited @noble/curves library — no key, seed or message is ever sent anywhere, and every generated signature is re-verified locally before it is shown. Nothing here is a substitute for the official NIST CAVP or Wycheproof suites when you need certification-grade coverage; this is the quick, reproducible set you paste into your own repository.