Saltar al contenido
ecdsa.com

Verificador de mensajes de Bitcoin online

Pega una dirección, el mensaje exacto y su firma. El verificador detecta el formato (una firma compacta BIP-137 o una BIP-322 simple o completa) y la comprueba igual que se validaría un gasto desde esa dirección, todo en tu navegador.

100 % local: todo se ejecuta en tu navegador y nada se envía a ningún servidor

Cargando el verificador…

Completa la dirección, el mensaje y la firma, o carga un ejemplo. La firma se comprueba en esta página mientras escribes.

Qué no evalúa este verificador

  • Bloqueos temporales: una firma completa cuyo script necesita un tiempo de bloqueo o un número de secuencia (CLTV, CSV) se indica como no compatible, ni válida ni no válida.
  • Rutas de script de Taproot: solo se comprueban las firmas por la ruta de clave; un gasto por una ruta de script se indica como no compatible.
  • Otros scripts: P2SH y P2WSH se comprueban cuando el script es una sola clave o un multisig básico (bare multisig); todo lo que requiera un intérprete de scripts completo se indica como no compatible.
  • Prueba de fondos: una firma BIP-322 «pof» también gasta monedas reales y aquí no se verifica.

Two formats for one question

A signed message answers a simple question — does the person who sent this control that address? — and Bitcoin has two answers. The older one, standardised as BIP-137, is the "Bitcoin Signed Message" that Bitcoin Core's signmessage, Electrum, Trezor and Ledger produce. The newer one, BIP-322, proves control the way a real spend would, so it works for every kind of address, Taproot and multisig included. The verifier tells them apart from the signature itself; the comparison BIP-137 vs BIP-322 and the article on Bitcoin message signing explain when to use which.

BIP-137: a recoverable signature

The message is prefixed with "\x18Bitcoin Signed Message:\n" and its length, and hashed twice with SHA-256. The 65-byte signature is a compact ECDSA signature with a header byte in front. The header carries the recovery id, which lets the verifier compute the signer's public key from the signature alone (public key recovery), and the address type it was made for: 27–30 for P2PKH with an uncompressed key, 31–34 compressed, 35–38 nested SegWit (P2SH-P2WPKH), 39–42 native SegWit (P2WPKH). The recovered key is turned into an address of that type and compared with the one you entered.

Electrum writes the P2PKH header (31–34) for SegWit addresses too. The verifier accepts such a signature when the recovered key matches the SegWit address, and says so: Bitcoin Core would reject it, because Core verifies P2PKH addresses only (its "Address does not refer to key" error). A key that matches under another address type than the header names is accepted with the same caveat; a key that matches no type is reported together with the address it does belong to. BIP-137 cannot express Taproot or P2WSH addresses at all — for those, only BIP-322 exists.

BIP-322: a spend that never happens

BIP-322 hashes the message with the tagged hash "BIP0322-signed-message" and puts it into a virtual transaction, to_spend, whose single output pays the address's script. A second virtual transaction, to_sign, spends that output to an OP_RETURN. The signature is the proof that to_sign is a valid spend:

  • a simple signature (smp…, or the bare base64 that older verifiers wrote) is just the witness stack, for native SegWit and Taproot addresses;
  • a full signature (ful…) is the whole to_sign transaction, which also covers legacy and P2SH addresses.

The verifier rebuilds both transactions, checks that the full signature spends exactly the right output, and evaluates the spend with the consensus signature hashes: legacy, BIP-143 for SegWit v0 and BIP-341 with Schnorr signatures (BIP-340) for Taproot key paths. Single-key scripts and bare multisig (OP_m … OP_n OP_CHECKMULTISIG, in key order, with the empty NULLDUMMY element) are checked in P2SH, P2WSH and nested forms. Strict DER (BIP-66) is enforced; a high-s signature or an unusual sighash type is accepted with a note, as consensus does.

What it does not evaluate

The verifier evaluates the scripts it can check without a full script interpreter, and says "unsupported" — neither valid nor invalid — for the rest:

  • time locks — scripts with OP_CHECKLOCKTIMEVERIFY or OP_CHECKSEQUENCEVERIFY, whose full signatures set a lock time or sequence;
  • Taproot script paths — only key-path spends are checked;
  • other scripts — hash locks, miniscript policies and anything beyond a single key or bare multisig;
  • proof of funds (pof…) — a BIP-322 variant that also spends real coins, which needs the UTXO set.

Unsupported is not a failure: it means this page cannot decide, and a node with a full interpreter (or the signer's own wallet) must.

What runs locally

Everything: parsing, key recovery, the virtual transactions and every signature check run in your browser with @noble/curves and @scure/btc-signer, and the page sends nothing anywhere. A signature never needs a private key; if a WIF key or a seed phrase is pasted by mistake, it is refused before anything is processed. Wallets that export the armored "BEGIN BITCOIN SIGNED MESSAGE" block can paste it whole into the message field. To inspect a transaction that spends real coins, use the PSBT inspector; to see which addresses an extended public key derives, the xpub inspector.