{"id":753,"library":"ecdsa","title":"ECDSA Cryptographic Signature Library","description":"ecdsa is a pure Python implementation of Elliptic Curve Cryptography (ECC) supporting ECDSA (Elliptic Curve Digital Signature Algorithm), EdDSA (Edwards-curve Digital Signature Algorithm), and ECDH (Elliptic Curve Diffie-Hellman). It is actively maintained with several releases per year, providing a robust solution for digital signatures in Python applications. The current version is 0.19.2.","status":"active","version":"0.19.2","language":"python","source_language":"en","source_url":"http://github.com/tlsfuzzer/python-ecdsa","tags":["cryptography","security","signatures","ecdsa","eddsa","ecdh","elliptic-curve"],"install":[{"cmd":"pip install ecdsa","lang":"bash","label":"Install latest version"}],"dependencies":[{"reason":"Mandatory dependency for compatibility, automatically installed by pip.","package":"six","optional":false}],"imports":[{"symbol":"SigningKey","correct":"from ecdsa import SigningKey"},{"symbol":"VerifyingKey","correct":"from ecdsa import VerifyingKey"},{"symbol":"NIST256p","correct":"from ecdsa import NIST256p"},{"symbol":"SECP256k1","correct":"from ecdsa import SECP256k1"}],"quickstart":{"code":"import hashlib\nfrom ecdsa import SigningKey, NIST256p, VerifyingKey\n\n# 1. Generate a private key using the NIST256p curve\nsk = SigningKey.generate(curve=NIST256p)\nprint(\"Private Key (hex):\", sk.to_string().hex())\n\n# 2. Derive the public key\nvk = sk.get_verifying_key()\nprint(\"Public Key (hex):\", vk.to_string().hex())\n\n# 3. Message to sign (must be bytes)\nmessage = b\"This is a test message to be signed.\"\n\n# Hash the message before signing\nmessage_hash = hashlib.sha256(message).digest()\n\n# 4. Sign the message hash\nsignature = sk.sign_digest(message_hash)\nprint(\"Signature (hex):\", signature.hex())\n\n# 5. Verify the signature\ntry:\n    assert vk.verify_digest(signature, message_hash) == True\n    print(\"Signature is valid.\")\nexcept Exception as e:\n    print(f\"Signature verification failed: {e}\")","lang":"python","description":"This quickstart demonstrates how to generate an ECDSA private and public key pair using the NIST256p curve, sign a message digest with the private key, and then verify the signature using the corresponding public key."},"warnings":[{"fix":"For security-sensitive applications where side-channel resistance is critical, consider using a cryptographic library with constant-time implementations (e.g., `cryptography` library) or ensure your environment mitigates timing attacks.","message":"CVE-2024-23342 (Minerva Timing Attack) affects P-256 curves in versions 0.18.0 and prior. This side-channel vulnerability allows attackers to leak the internal nonce via timing measurements, potentially leading to private key discovery. The maintainers consider side-channel attacks out of scope, and no fix is planned for this pure-Python implementation.","severity":"breaking","affected_versions":"<=0.18.0"},{"fix":"Update to version 0.19.2 or later to ensure robust DER parsing and prevent potential DoS from malformed inputs. Carefully validate any DER-encoded inputs from untrusted sources.","message":"CVE-2026-33936 fixed a DER parsing issue where truncated buffers were not detected, which could lead to unexpected exceptions in functions like `SigningKey.from_der()` when parsing malformed data.","severity":"breaking","affected_versions":"<0.19.2"},{"fix":"Always specify `format=\"pkcs8\"` when calling `to_pem()` or `to_der()` for private keys: `key.to_pem(format=\"pkcs8\")`.","message":"When serializing keys using `to_pem()` or `to_der()`, in versions 0.16.0 and later, it is recommended to explicitly set `format=\"pkcs8\"`. Not doing so will default to the legacy 'ssleay' format, which may not be the desired standard for modern applications or interoperability.","severity":"gotcha","affected_versions":">=0.16.0"},{"fix":"Upgrade to a currently supported Python version (e.g., Python 3.8 or newer).","message":"Official support for Python 3.3 and 3.4 was dropped starting from version 0.19.0 due to CI environment challenges.","severity":"deprecated","affected_versions":">=0.19.0"},{"fix":"Handle the return value as `bytes` when using `to_string()`.","message":"The `to_string()` method, inherited from Python 2 naming conventions, actually returns `bytes` objects, not Python `str`.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Ensure you store and provide the correct elliptic curve (e.g., `NIST256p`) when using `from_string()`.","message":"When deserializing keys using `SigningKey.from_string(s, curve)` or `VerifyingKey.from_string(s, curve)`, the `curve` parameter *must* be explicitly provided as the short string format does not embed curve information. If the wrong curve is provided, verification will fail or lead to incorrect keys.","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"last_verified":"2026-05-12T18:36:22.363Z","next_check":"2026-06-27T00:00:00.000Z","problems":[{"fix":"Install the library using pip: `pip install ecdsa`.","cause":"The 'ecdsa' library has not been installed in the Python environment, or the environment where the code is being run is different from where it was installed.","error":"ModuleNotFoundError: No module named 'ecdsa'"},{"fix":"Correct the curve name to 'SECP256k1': `from ecdsa import SECP256k1, SigningKey`.","cause":"This error occurs due to a common typo when trying to import the SECP256k1 elliptic curve; the lowercase 'l' is used instead of the numeral '1'.","error":"ImportError: cannot import name 'SECP256kl' from 'ecdsa'"},{"fix":"When verifying, ensure you explicitly provide the `hashfunc` argument, or use the `VerifyingKey.from_string` (or similar) method to properly reconstruct the key if it was serialized, and ensure compatibility with the library version. Example: `verifying_key.verify(signature, message_hash, sigdecode=ecdsa.util.sigdecode_string, hashfunc=hashlib.sha256)`.","cause":"This error typically arises when attempting to verify a signature using an older method or when a `VerifyingKey` object has been incorrectly serialized and deserialized, leading to missing internal state, especially when `hashfunc` is not explicitly provided.","error":"AttributeError: 'VerifyingKey' object has no attribute 'default_hashfunc'"},{"fix":"Refer to the `ecdsa.curves` module for available curves (e.g., `ecdsa.NIST224p` or `ecdsa.SECP256k1`) or use `ecdsa.curves.Curve` to define a custom curve if it's supported and parameters are known.","cause":"The `ecdsa` library does not directly expose all elliptic curves as top-level attributes or may not support specific curves like 'secp224k1' (often confused with 'secp224r1' or requiring a different curve instantiation method).","error":"AttributeError: module 'ecdsa' has no attribute 'secp224k1'"},{"fix":"Ensure the message is hashed correctly before signing and verifying, the correct public key is used, and the signature encoding (e.g., DER) is consistently applied during both signing and verification. Double-check the elliptic curve used for key generation and signature operations.","cause":"This exception is raised when a signature cannot be successfully verified. Common reasons include incorrect message hashing, wrong public key, signature corruption, or mismatches in signature encoding formats (e.g., DER vs. raw R+S concatenation) or curve parameters between signing and verification processes.","error":"ecdsa.BadSignatureError"}],"ecosystem":"pypi","meta_description":null,"install_score":100,"install_tag":"verified","quickstart_score":80,"quickstart_tag":"verified","pypi_latest":"0.19.2","cli_name":"","install_checks":{"last_tested":"2026-05-12","tag":"verified","tag_description":"installs cleanly on critical runtimes, fast import, recently tested","installed_version":null,"pypi_latest":"0.19.2","is_stale":null,"results":[{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"ecdsa","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.03,"mem_mb":1.4,"disk_size":"19.0M"},{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"ecdsa","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.03,"mem_mb":1.4,"disk_size":"19.0M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"ecdsa","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":null,"install_time_s":1.6,"import_time_s":0.03,"mem_mb":1.4,"disk_size":"20M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"ecdsa","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.02,"mem_mb":1.4,"disk_size":"20M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"ecdsa","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.05,"mem_mb":1.6,"disk_size":"21.2M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"ecdsa","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.06,"mem_mb":1.6,"disk_size":"21.2M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"ecdsa","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":null,"install_time_s":1.7,"import_time_s":0.04,"mem_mb":1.6,"disk_size":"22M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"ecdsa","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.04,"mem_mb":1.6,"disk_size":"22M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"ecdsa","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.04,"mem_mb":1.1,"disk_size":"13.0M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"ecdsa","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.04,"mem_mb":1.1,"disk_size":"13.0M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"ecdsa","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":null,"install_time_s":1.6,"import_time_s":0.04,"mem_mb":1.1,"disk_size":"14M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"ecdsa","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.04,"mem_mb":1.1,"disk_size":"14M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"ecdsa","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.04,"mem_mb":1.3,"disk_size":"12.7M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"ecdsa","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.04,"mem_mb":1.3,"disk_size":"12.6M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"ecdsa","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":null,"install_time_s":1.5,"import_time_s":0.04,"mem_mb":1.1,"disk_size":"13M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"ecdsa","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.04,"mem_mb":1.1,"disk_size":"13M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"ecdsa","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.05,"mem_mb":1.7,"disk_size":"18.5M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"ecdsa","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.04,"mem_mb":1.7,"disk_size":"18.5M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"ecdsa","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":null,"install_time_s":1.9,"import_time_s":0.03,"mem_mb":1.7,"disk_size":"19M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"ecdsa","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.03,"mem_mb":1.7,"disk_size":"19M"}]},"quickstart_checks":{"last_tested":"2026-04-24","tag":"verified","tag_description":"quickstart runs on critical runtimes, recently tested","results":[{"runtime":"python:3.10-alpine","exit_code":0},{"runtime":"python:3.10-slim","exit_code":0},{"runtime":"python:3.11-alpine","exit_code":0},{"runtime":"python:3.11-slim","exit_code":0},{"runtime":"python:3.12-alpine","exit_code":0},{"runtime":"python:3.12-slim","exit_code":0},{"runtime":"python:3.13-alpine","exit_code":0},{"runtime":"python:3.13-slim","exit_code":0},{"runtime":"python:3.9-alpine","exit_code":0},{"runtime":"python:3.9-slim","exit_code":0}]}}