Coincurve: secp256k1 Elliptic Curve Operations
Coincurve is a Python library providing fast and secure bindings for libsecp256k1, the highly optimized C library used by Bitcoin Core for elliptic curve cryptography operations. It offers a clean, easy-to-use API for tasks like key generation, signing, and verification. The current version is 21.0.0, and it maintains frequent updates to libsecp256k1.
Warnings
- breaking Python 3.8 support was dropped in `coincurve` version 21.0.0. Users on Python 3.8 or older must upgrade their Python environment or use an earlier `coincurve` version.
- breaking CMake is a build dependency starting from `coincurve` version 20.0.0. While `pip` typically handles this for standard installations by fetching `cmake` from PyPI, redistributors or users building from source in custom environments will need to ensure CMake is available.
- breaking Binary wheels for Windows 32-bit are no longer built as of `coincurve` version 20.0.0. Users on Windows 32-bit systems will need to compile from source (which requires appropriate build tools and dependencies) or use an older version.
- gotcha The `PrivateKey.sign_recoverable()` method produces a 65-byte compact signature, which is NOT compatible with the module-level `coincurve.verify_signature()` function that expects a DER-encoded signature (produced by `PrivateKey.sign()`). Attempting to verify a recoverable signature with `verify_signature()` will raise a `ValueError`.
- gotcha A packaging issue in `coincurve==21.0.0` (specifically a missing LICENSE file in the `cffi` distribution during build) can lead to installation failures when `coincurve` is a dependency of another package. This was observed with `ccxt`.
Install
-
pip install coincurve
Imports
- PrivateKey
from coincurve import PrivateKey
- PublicKey
from coincurve import PublicKey
- verify_signature
from coincurve import verify_signature
Quickstart
import os
from coincurve import PrivateKey, verify_signature
import hashlib
# 1. Generate a new private key (or use an existing one)
private_key = PrivateKey()
# Get the corresponding public key
public_key = private_key.public_key.format(compressed=True)
print(f"Public Key (compressed): {public_key.hex()}")
# 2. Define a message to sign (must be hashed to 32 bytes for signing)
message_str = "Hello, Coincurve!"
message_hash = hashlib.sha256(message_str.encode('utf-8')).digest()
print(f"Message hash: {message_hash.hex()}")
# 3. Sign the message
signature = private_key.sign(message_hash)
print(f"Signature (DER-encoded): {signature.hex()}")
# 4. Verify the signature using the public key and message hash
is_valid = verify_signature(signature, message_hash, public_key)
if is_valid:
print("Signature is valid!")
else:
print("Signature is INVALID.")
# Example of direct verification via PublicKey object (also works)
# is_valid_direct = private_key.public_key.verify(signature, message_hash)
# print(f"Signature is valid (direct Public Key method): {is_valid_direct}")