Guide: Signing & Verification¶
libcrypto provides two layers of signing:
- Raw ECDSA (
signing) — sign an arbitrary 32-byte hash. You control the hashing. - Message signing (
messages) — Ethereum (EIP-191) and Bitcoin signed-message standards, handled end to end.
Both are deterministic (RFC 6979) and self-contained: no external cryptography package is used.
Raw ECDSA¶
import hashlib
from libcrypto import sign, verify, recover_public_key, Signature
from libcrypto.secp256k1 import private_key_to_public_key
key = 0xC0FFEE... # your private key integer in [1, N-1]
digest = hashlib.sha256(b"payload").digest()
sig = sign(key, digest) # canonical low-S by default
pub = private_key_to_public_key(key)
assert verify(pub, digest, sig)
assert recover_public_key(digest, sig) == pub
# Serialize for transport
der = sig.to_der() # strict DER
compact = sig.to_compact() # 64-byte r||s
Custom nonce hash¶
RFC 6979 uses SHA-256 by default. To use a different HMAC hash (rarely needed):
Low-S / canonical form¶
Bitcoin and EVM chains require the s value to be in the lower half of the
curve order to prevent signature malleability. This is the default. Disable it
only when you have a specific reason:
Ethereum message signing (EIP-191)¶
from libcrypto import (
sign_message_ethereum, recover_address_ethereum, verify_message_ethereum,
)
key = 1
signature = sign_message_ethereum(key, "Hello, world!") # 65 bytes: r||s||v
signer = recover_address_ethereum("Hello, world!", signature)
assert verify_message_ethereum(signer, "Hello, world!", signature)
The digest matches ethers.hashMessage / MetaMask personal_sign, and v is
27 or 28.
Bitcoin message signing¶
from libcrypto import (
sign_message_bitcoin, recover_address_bitcoin, verify_message_bitcoin,
)
key = 1
signature = sign_message_bitcoin(key, "Hello, world!", compressed=True) # Base64
signer = recover_address_bitcoin("Hello, world!", signature)
assert verify_message_bitcoin(signer, "Hello, world!", signature)
The output format matches Bitcoin Core's signmessage / verifymessage.
Choosing the right layer¶
| Need | Use |
|---|---|
| Sign a transaction hash or custom payload | signing.sign |
| Prove control of an Ethereum address | messages.sign_message_ethereum |
| Prove control of a Bitcoin address | messages.sign_message_bitcoin |
| Recover the signer of an existing signature | recover_public_key / recover_address_* |