When someone signs a message with MetaMask, they produce a cryptographic signature that proves ownership of their Ethereum address — without exposing their private key.
keccak256("\x19Ethereum Signed Message:\n" + len + message)
r, s, and vv to recover the public key from the signature and message hashkeccak256(pubKey)[-20:]
This is possible because of the elliptic curve digital signature algorithm (ECDSA) and the fact that Ethereum signatures include a recovery ID (v).
const recovered = ethers.utils.verifyMessage(message, signature);
if (recovered.toLowerCase() === expectedAddress.toLowerCase()) {
console.log("✅ Valid signature");
}
keccak256 and Why Ethereum Uses ItKeccak-256 is the hashing function used in Ethereum to securely compress data into a fixed-size fingerprint. It's used for:
Although both come from the same family, they differ in internal padding and are not interchangeable.
import { keccak256, toUtf8Bytes } from "ethers";
const message = "Hello Ethereum";
const hash = keccak256(toUtf8Bytes(message));
console.log("Message hash:", hash);
When you verify a signature, you're not just checking a hash — you're actually reconstructing the public key that signed a message, and converting it into the Ethereum address.
M): e.g. "Login to MyApp"r, s, v)A)H = keccak256("\x19Ethereum Signed Message:\n" + len + M)
publicKey = ecrecover(H, r, s, v)
A_recovered = keccak256(publicKey)[-20:]
A_recovered === A ? ✅ valid : ❌ invalid
The signature is never hashed itself. The signature is used to recover the public key, which proves ownership of the address.
const recovered = ethers.utils.verifyMessage(message, signature);
if (recovered.toLowerCase() === claimedAddress.toLowerCase()) {
console.log("✅ Valid signature");
}