ECPy: Pure Python Elliptic Curve Library
ECPy is a pure Python Elliptic Curve library providing implementations of ECDSA, EDDSA (Ed25519), ECSchnorr, and Borromean signatures, alongside fundamental Point operations. The library is currently at version 1.2.5, with its last release in October 2020. While its documentation historically noted a 'beta stage' status, the current lack of recent development suggests it is in maintenance mode rather than active feature development.
Common errors
-
ECPyException: Point not on curve
cause This error occurs when attempting to create a Point object with coordinates (x, y) that do not satisfy the elliptic curve equation (y² = x³ + ax + b for Weierstrass form, or equivalent for other forms) of the specified curve. It can also happen during point addition/multiplication if intermediate points fall off the curve due to incorrect parameters or operations.fixVerify that the x and y coordinates used to instantiate a Point object are indeed valid points on the `Curve` object provided. Double-check curve parameters (a, b, field, order) if defining custom curves, and ensure all cryptographic operations are correctly chained with valid points. -
AttributeError: '_TwistedEdwardCurvePoint' object has no attribute '_coord_size' when using EDDSA with Curve25519
cause This issue (reported in GitHub issues) indicates an internal incompatibility or missing attribute in older versions of ECPy when attempting EDDSA operations, specifically with the Curve25519 (a Twisted Edward curve).fixUpgrade ECPy to the latest available version (1.2.5). If the issue persists, carefully review the EDDSA example code and ensure all inputs (keys, messages) conform to the expected types and formats for Curve25519 in ECPy. -
NameError: name 'reqs' is not defined
cause This error has been reported in older issues and likely stems from an internal variable not being correctly defined or imported within the ECPy library itself, possibly due to an incomplete installation or specific execution environment.fixEnsure ECPy is properly installed via `pip install ECPy`. If using a custom build, verify `setup.py` and environment. Consider creating a fresh virtual environment. This error might be resolved in newer versions of the library.
Warnings
- deprecated The handling of infinity points was changed in version 1.1.0. Relying on a global (non-curve-attached) infinity point is now deprecated, and it is recommended to declare one infinity point per curve.
- gotcha Prior to version 1.2.4, ECDSA signatures could fail or behave unexpectedly if the message hash length was greater than the domain order length of the elliptic curve.
- gotcha Versions prior to 1.2.3 had issues with ECSchnorr signatures where the 'r' value (part of the signature) was greater than the curve's order, especially when using hash functions with a bitlength greater than the curve size.
- breaking A critical bug in ECDSA's rfc6979 implementation prior to version 1.2.0 caused the curve's field value to be used instead of the order for maximum random generation, potentially leading to insecure signatures. Version 1.2.0 fixed this to conform with RFC 6979.
Install
-
pip install ECPy
Imports
- Curve
from ecpy.curves import Curve
- Point
from ecpy.curves import Point
- ECPublicKey
from ecpy.keys import ECPublicKey
- ECPrivateKey
from ecpy.keys import ECPrivateKey
- ECDSA
from ecpy.ecdsa import ECDSA
Quickstart
from ecpy.curves import Curve, Point
from ecpy.keys import ECPublicKey, ECPrivateKey
from ecpy.ecdsa import ECDSA
# Get a predefined elliptic curve (secp256k1 is commonly used)
cv = Curve.get_curve('secp256k1')
# Define public and private keys (example values, in a real scenario these would be generated securely)
# Private key (scalar 'd')
pv_scalar = 0xfb26a4e75eec75544c0f44e937dcf5ee6355c7176600b9688c667e5c283b43c5
pv_key = ECPrivateKey(pv_scalar, cv)
# Public key (Point 'Q' = d * G, where G is the generator point of the curve)
# For secp256k1, the generator is part of the curve definition.
# The public key point is derived from the private scalar.
Q_x = 0x65d5b8bf9ab1801c9f168d4815994ad35f1dcb6ae6c7a1a303966b677b813b00
Q_y = 0xe6b865e529b8ecbf71cf966e900477d49ced5846d7662dd2dd11ccd55c0aff7f
pu_key_point = Point(Q_x, Q_y, cv)
pu_key = ECPublicKey(pu_key_point)
# Create an ECDSA signer instance
signer = ECDSA()
# Message to be signed (must be bytes)
message = b'This is a test message to be signed.'
# Sign the message
sig = signer.sign(message, pv_key)
# Verify the signature
is_valid = signer.verify(message, sig, pu_key)
print(f"Message: {message.decode()}")
print(f"Private Key (scalar): {hex(pv_scalar)}")
print(f"Public Key (Point): ({hex(pu_key_point.x)}, {hex(pu_key_point.y)})")
print(f"Signature: {sig.hex()}")
print(f"Signature Valid: {is_valid}")
assert is_valid, "Signature verification failed!"
print("Signature successfully verified.")