Verify an Ethereum signature and recover the signer
When someone signs a message with MetaMask, a hardware wallet or any Ethereum library, the signature contains enough information to recover the address that made it. This Ethereum signature verifier performs that recovery (the same ecrecover the EVM uses) and tells you whether the signer is the address you expected.
It handles the three forms you meet in practice: personal_sign messages (EIP-191, the “Sign this message” prompt used for log-ins, proofs of ownership and airdrop claims), EIP-712 typed data (permits, orders and gasless approvals) and a raw 32-byte hash signed directly. It accepts 65-byte signatures with v = 27/28 or 0/1 and 64-byte EIP-2098 compact signatures.
Everything runs offline in your browser with a built-in implementation of Keccak-256 and secp256k1, so the message you are checking never leaves your device. You only need public data: the message, the signature and, optionally, the claimed address. No private key is ever required to verify a signature.
How to use the Ethereum Signature Verifier
- Choose the signature type: personal_sign (EIP-191), EIP-712 typed data or Raw 32-byte hash.
- Paste the Message exactly as it was signed (or the typed data JSON, or the hash). For a 0x… message choose whether it was signed as text or as hex bytes.
- Paste the Signature and, optionally, the Expected signer address.
- Read the badge: Valid when the recovered signer equals the expected address, Does not match otherwise.
- Check the details — digest, r, s, v and the signer’s public key — or press Copy result.
Ethereum Signature Verifier features
EIP-191 and EIP-712
Applies the “\x19Ethereum Signed Message” prefix with the byte length, or builds the EIP-712 domain separator and struct hash for nested types and arrays.
Every signature form
65-byte r‖s‖v with v of 27, 28, 0 or 1, and 64-byte EIP-2098 compact signatures.
Explains mismatches
Spots a 0x… message signed as bytes instead of text, an expected address with a broken EIP-55 checksum, and high-s signatures that some contracts reject.
Shows its working
Digest, domain separator, encoded type, r, s, v, recovery id and the signer’s public key — useful when debugging your own signing code.
JSON import
Load the common {"address", "msg", "sig"} JSON that wallets and explorers export.
How the verification works
For personal_sign the wallet does not sign your text directly. It signs keccak256("\x19Ethereum Signed Message:\n" + length + message), where the length is the number of bytes in decimal — so “Some data” becomes a 9-byte message and “₹100” a 6-byte one. The prefix stops a signed message from ever being a valid transaction. EIP-712 instead signs keccak256(0x19 0x01 ‖ domainSeparator ‖ hashStruct(message)), which binds the signature to one app, version, chain ID and contract.
A signature is the pair (r, s) plus a recovery id v. Public-key recovery finds the point R with x-coordinate r, then computes the signer’s public key Q = r⁻¹(s·R − e·G), where e is the digest. The address is the last 20 bytes of Keccak-256 of Q. If that address equals the expected one, the holder of that address’s private key signed this exact message.
Worked example: the web3.js documentation signs “Some data” with a published test key. The digest is 0x1da44b58…871655 and recovery gives 0x2c7536E3605D9C16a7a3D7b1898e529396a65c23 — the default shown above.
Why a signature might not match
- The message differs by one character — a trailing space, a missing line break, curly instead of straight quotes or a different nonce changes the digest completely.
- Text versus bytes. Some wallets treat a 0x… string as raw bytes, others as text. The tool tries the other reading and tells you if it matches.
- Wrong EIP-712 domain. The chain ID, contract address, name or version must be exactly what the app used.
- Smart-contract wallets. Safe and other EIP-1271 wallets validate signatures in a contract; recovering an address offline will not give the wallet address.
Related checks
To confirm that a public key belongs to an address use the public key to address converter; to tidy an address’s capitalisation use the EIP-55 checksum converter; to decode what a transaction would do before you sign it, try the contract ABI decoder.
Ethereum Signature Verifier FAQ
How do I verify an Ethereum signature?
Paste the message, the signature and the claimed address into this Ethereum signature verifier. It recovers the signer with ecrecover and shows “Valid” when it equals the claimed address.
Do I need a private key to verify a signature?
No. Verification uses only public data: the message, the signature and the address. Never give anyone your private key or recovery phrase — no verification needs it.
What is the difference between personal_sign and eth_signTypedData?
personal_sign (EIP-191) signs a plain message with the “Ethereum Signed Message” prefix. eth_signTypedData_v4 (EIP-712) signs structured data bound to a domain, so wallets can show each field and the signature cannot be replayed in another app.
What do v = 27 and v = 28 mean?
v tells the verifier which of two possible points R was used. 27 and 28 are the Ethereum convention; some libraries write 0 and 1. EIP-2098 packs this bit into the top of s to make a 64-byte signature.
Can a valid signature be faked?
Not without the private key. But a signature only proves who signed this message — check that the message itself (domain, nonce, date) is what you expect, since an old signature can be replayed where the app does not prevent it.
Is my message sent to a server?
No. The page works offline; the hashing and curve maths run in your browser.