Introduction
Need to sign a message with an elliptic curve private key and verify it with the public key? This tool generates ECDSA key pairs on NIST P-256, P-384, and secp256k1 (the Bitcoin curve), signs messages, and verifies signatures, all in your browser. P-256 and P-384 use the native Web Crypto API. secp256k1 uses the @noble/curves library with RFC 6979 deterministic nonce generation. Paste a message, click Sign, and the signature appears as hex. Change one character and verification fails. This is the same algorithm that secures TLS certificates, Apple's Secure Enclave, and Ethereum transactions.
What this tool does
- Generate ECDSA key pairs on NIST P-256 (secp256r1, ES256), P-384 (secp384r1, ES384), or secp256k1 (the Bitcoin and Ethereum curve), with public keys in SPKI/PEM format
- Sign arbitrary text messages with the private key, producing a signature in hex (DER-encoded ASN.1 for P-256/P-384, compact r||s for secp256k1)
- Verify a signature against the original message and public key, returning a clear valid or invalid result
- Use SHA-256 as the hash for P-256 and secp256k1, and SHA-384 for P-384, matching the JOSE algorithm identifiers ES256 and ES384
- Apply RFC 6979 deterministic nonce generation for secp256k1 via @noble/curves, eliminating the catastrophic k-reuse vulnerability that drained early Bitcoin wallets
- Run entirely client-side: private keys are generated in your browser and never sent anywhere
How this tool works
For P-256 and P-384, the tool uses the Web Crypto API. Key generation calls `crypto.subtle.generateKey` with the `ECDSA` algorithm and the selected named curve. The resulting `CryptoKey` pair is exported to SPKI (public) and PKCS#8 (private) PEM format. Signing calls `crypto.subtle.sign` with the curve-appropriate hash (SHA-256 for P-256, SHA-384 for P-384) and returns a DER-encoded ASN.1 signature (a SEQUENCE of two INTEGERs, r and s). The tool displays this as hex.
For secp256k1, the Web Crypto API does not support the curve, so the tool uses the `@noble/curves` library. Key generation calls `secp256k1.utils.randomSecretKey()` to produce a 32-byte private key, then `secp256k1.getPublicKey(priv)` to derive the 65-byte uncompressed public key (04 || x || y). Signing calls `secp256k1.sign(data, privKey)`, which uses RFC 6979 to derive the nonce k deterministically from the message hash and private key. The signature is returned in compact format (r || s, 64 bytes) and displayed as hex.
Verification for P-256/P-384 calls `crypto.subtle.verify` with the public key, signature, and message. For secp256k1, it calls `secp256k1.verify(sigBytes, data, pubKeyBytes)`. Both return a boolean. The tool displays a green badge for valid signatures and a red badge for invalid ones.
The tool clears the signature and verification result when you change the message, so you always know the displayed signature corresponds to the current input. If you modify the message after signing and click Verify, the result will be invalid, demonstrating that ECDSA signatures are tied to the exact message content.
How ECDSA works (FIPS 186-5, SEC 1)
ECDSA (Elliptic Curve Digital Signature Algorithm) is specified in FIPS 186-5 and SEC 1. It operates on an elliptic curve over a finite field, where the group of points has a known order n. Each curve has a base point G (a generator of the group). The private key d is a random integer in [1, n-1]. The public key Q is the point Q = d * G (scalar multiplication on the curve).
Signing a message m works as follows. Pick a random nonce k in [1, n-1]. Compute the point R = k * G. Set r = R_x mod n (the x-coordinate of R, reduced mod n). If r is 0, pick a new k. Compute s = k^(-1) * (H(m) + r * d) mod n, where H(m) is the hash of the message and k^(-1) is the modular inverse of k mod n. The signature is the pair (r, s).
Verification takes the message m, the signature (r, s), and the public key Q. Compute w = s^(-1) mod n. Compute u1 = H(m) * w mod n and u2 = r * w mod n. Compute the point R' = u1 * G + u2 * Q. If R' is the point at infinity, the signature is invalid. Otherwise, check that R'_x mod n equals r. If it does, the signature is valid.
The security relies on the elliptic curve discrete logarithm problem (ECDLP): given G and Q = d * G, finding d is infeasible for properly chosen curves. NIST P-256 provides ~128-bit security, P-384 provides ~192-bit, and P-521 provides ~256-bit. secp256k1 provides ~128-bit security. These are all far stronger than RSA for equivalent key sizes: a 256-bit ECDSA key matches a 3072-bit RSA key.
The nonce k is the most critical parameter. If k is reused for two different messages with the same private key, the private key can be recovered algebraically. This is how the PlayStation 3 signing key was extracted in 2010 (the fail0verflow team showed that Sony reused k across all signatures) and how Android Bitcoin wallets were drained in 2013 (a Java RNG bug produced repeated k values). RFC 6979 solves this by deriving k deterministically from H(m) and d using HMAC, so the same message always produces the same signature but different messages always use different k values. The @noble/curves library uses RFC 6979 by default for secp256k1.
ECDSA public keys are encoded in RFC 5480 format for X.509 certificates. The JOSE profile (RFC 7518) defines ES256 (P-256 with SHA-256), ES384 (P-384 with SHA-384), and ES512 (P-521 with SHA-512) for JWT signing.
How to use this tool
- Select a curve: P-256 (ES256, most common in TLS and JWT), P-384 (ES384, higher security), or secp256k1 (Bitcoin and Ethereum)
- Click Generate key pair. The tool creates the private and public keys and displays them in PEM format (P-256/P-384) or hex (secp256k1)
- Type or paste your message in the input field. The message is encoded as UTF-8 before hashing
- Click Sign. The tool hashes the message with the curve-appropriate hash function, applies the ECDSA signing algorithm, and displays the signature as hex
- To verify, keep the same message and signature, then click Verify. The badge shows Valid or Invalid
- Try modifying a single character in the message and click Verify again. The result will be Invalid, demonstrating that signatures are bound to the exact message
- Copy the public key and signature to share them. The private key should never leave your device
Real-world examples
Signing and verifying a message on P-256
Select P-256, generate a key pair, and type `Transfer $100 to Alice`. Click Sign. The tool hashes the message with SHA-256, picks a nonce k, computes r and s, and outputs a DER-encoded signature (typically 70-72 bytes, shown as hex). Click Verify without changing anything: the badge shows Valid. Now change the message to `Transfer $100 to Bob` and click Verify: the badge shows Invalid. The signature is tied to the exact message content.
Signing with secp256k1 (the Bitcoin curve)
Select secp256k1 and generate a key pair. The private key is a 32-byte hex string and the public key is a 65-byte uncompressed point (04 || x || y). Sign the message `Hello secp256k1`. The signature is 64 bytes of hex (r || s in compact form, not DER). Because @noble/curves uses RFC 6979, signing the same message with the same key always produces the same signature. This is deterministic ECDSA, and it is what Bitcoin and Ethereum use.
Why deterministic nonces matter (RFC 6979)
Sign `Message A` with secp256k1 twice. Both signatures are identical because RFC 6979 derives k from H(m) and d deterministically. Now sign `Message B`: the signature is different because k changes with the message. This prevents the k-reuse attack that extracted Sony's PS3 signing key in 2010 and drained Android Bitcoin wallets in 2013. With random k, a PRNG failure could reuse k across messages, leaking the private key. With deterministic k, that cannot happen.
Signature format differences between curves
P-256 and P-384 produce DER-encoded ASN.1 signatures (a SEQUENCE of two INTEGERs). The hex starts with `30` (SEQUENCE tag) and varies in length (70-72 bytes) because the INTEGER encoding depends on the leading byte of r and s. secp256k1 produces compact 64-byte signatures (r || s concatenated, no DER wrapper). If you need to convert between formats, use a DER parser or the JWK Converter which handles both.
Verifying a tampered signature
Sign a message on P-256, copy the signature hex, then flip one hex digit (e.g. change the first character from `3` to `4`). Paste the modified signature and click Verify. The result is Invalid. ECDSA verification checks that R'_x mod n equals r, so any change to r or s produces a different R' and fails the check. This is the integrity guarantee: a valid signature proves the message was not modified after signing.
Comparison with similar methods
| Method | Complexity | Typical use |
|---|---|---|
| ECDSA P-256 (ES256) | 256-bit curve, ~128-bit security | TLS 1.3, JWT, Apple Secure Enclave |
| ECDSA P-384 (ES384) | 384-bit curve, ~192-bit security | High-assurance TLS, government systems |
| ECDSA secp256k1 | 256-bit curve, ~128-bit security | Bitcoin, Ethereum, cryptocurrency wallets |
| ECDSA P-521 (ES512) | 521-bit curve, ~256-bit security | Highest security, rare in practice (not in this tool) |
| RSA-PSS 2048 | 2048-bit modulus, ~112-bit security | Legacy TLS, X.509 certificates |
| Ed25519 | 255-bit Edwards curve, ~128-bit security | SSH, Signal, modern signatures (not in this tool) |
Limitations or considerations
ECDSA signatures are non-deterministic unless RFC 6979 is used. This tool applies RFC 6979 for secp256k1 via @noble/curves, but the Web Crypto API does not guarantee deterministic signatures for P-256 and P-384. Signing the same message twice on P-256 may produce different signatures. This is not a security problem (both signatures verify), but it means you cannot use the signature as a unique identifier.
The tool does not support P-521. The Web Crypto API supports it, but it was excluded to keep the UI focused on the three most common curves. For P-521 signatures, use OpenSSL or a library like node-webcrypto-ossl.
The tool does not support Ed25519 or Ed448 (Edwards-curve signatures). Ed25519 is simpler, faster, and deterministic by design, and is the recommended signature scheme for new applications (SSH, Signal, age). The Web Crypto API does not expose Ed25519 in most browsers. Use the `@noble/curves` library or libsodium for Ed25519.
ECDSA is not post-quantum secure. Shor's algorithm on a quantum computer breaks the elliptic curve discrete logarithm problem, exposing the private key from the public key. NIST's post-quantum signature standard ML-DSA (FIPS 204) is being deployed to replace ECDSA in the coming years. For now, ECDSA remains secure against classical computers.
The tool signs text messages only. For signing binary data or files, use a command-line tool like `openssl dgst -sign` or a library. The same ECDSA algorithm applies, but the tool's UI is designed for text input.
Frequently asked questions
What is the difference between ECDSA and RSA signatures?
ECDSA uses elliptic curve cryptography; RSA uses integer factorization. A 256-bit ECDSA key provides the same security as a 3072-bit RSA key, so ECDSA signatures are much smaller (64 bytes vs 256 bytes for P-256 vs RSA-2048) and faster to compute. ECDSA is preferred in TLS 1.3 and modern systems. RSA signatures are still common in legacy X.509 certificates. See the RSA Encrypt / Decrypt tool for RSA key generation.
What happens if the nonce k is reused?
If the same k is used to sign two different messages with the same private key, the private key can be recovered algebraically. Given two signatures (r, s1) and (r, s2) for messages m1 and m2 with the same r (hence same k), you can compute k = (H(m1) - H(m2)) / (s1 - s2) mod n, then d = (s1 * k - H(m1)) / r mod n. This is how Sony's PS3 key was extracted in 2010 and how Android Bitcoin wallets were drained in 2013. RFC 6979 prevents this by deriving k deterministically.
Why does secp256k1 produce 64-byte signatures but P-256 produces variable-length ones?
secp256k1 via @noble/curves outputs compact signatures (r || s, 64 bytes fixed). P-256 and P-384 via the Web Crypto API output DER-encoded ASN.1 signatures (a SEQUENCE of two INTEGERs), which vary in length (typically 70-72 bytes) because DER INTEGER encoding adds a padding byte when the high bit is set. Both formats contain the same r and s values. Use a DER parser to convert between them.
Is secp256k1 safe to use?
secp256k1 has ~128-bit security, the same as P-256. It was chosen by Satoshi Nakamoto for Bitcoin, likely because it was untainted by NIST's Dual_EC_DRBG backdoor concerns. The curve has no known vulnerabilities, and its parameters are transparent (unlike NIST curves, whose origin is questioned by some). It is widely used in cryptocurrency. For non-cryptocurrency applications, P-256 is more common and better supported by hardware and APIs.
What is RFC 6979 and why does this tool use it?
RFC 6979 specifies deterministic ECDSA: instead of picking a random nonce k, it derives k from HMAC(d, H(m)). This means the same message and private key always produce the same signature, and different messages always produce different k values. This eliminates the k-reuse vulnerability without relying on a random number generator. The tool uses RFC 6979 for secp256k1 via @noble/curves. The Web Crypto API does not expose whether it uses RFC 6979 for P-256/P-384.
Can I use this tool to sign cryptocurrency transactions?
No. This tool is for education and testing. It signs text messages, not transaction payloads, and does not implement the encoding and hashing that Bitcoin or Ethereum require (e.g. double SHA-256 for Bitcoin, keccak256 for Ethereum). For real cryptocurrency signing, use a hardware wallet (Ledger, Trezor) or a dedicated library. Never paste a real private key into a web tool.
Conclusion
ECDSA is the dominant signature algorithm in modern cryptography, used in TLS 1.3, JWT, Apple's Secure Enclave, and every Bitcoin and Ethereum transaction. This tool shows the full cycle on P-256, P-384, and secp256k1, with RFC 6979 deterministic nonces for secp256k1 to prevent the k-reuse attacks that have caused real-world key compromises. For the RSA counterpart, see the RSA Encrypt / Decrypt tool. For key agreement rather than signatures, see the Diffie-Hellman Key Exchange. To convert between key formats (PEM, JWK, DER), see the JWK Converter.