Using ECDSA

ecdsa

Elliptic curve signature library.

Common Methods

Common default ecdsa methods.

Generating Signing Keys

sk = SigningKey.generate()

Method Definition

@classmethod
def generate(cls, curve=SECP256k1, entropy=None, hashfunc=sha1):
    """
    Generate a random private key.

    :param curve: The curve on which the point needs to reside, defaults
        to SECP256k1
    :type curve: ecdsa.curves.Curve
    :param entropy: Source of randomness for generating the private keys,
        should provide cryptographically secure random numbers if the keys
        need to be secure. Uses os.urandom() by default.
    :type entropy: callable
    :param hashfunc: The default hash function that will be used for
        signing, needs to implement the same interface
        as hashlib.sha1
    :type hashfunc: callable

    :return: Initialised SigningKey object
    :rtype: SigningKey
    """

Example(s)

Using the default curve:

>>> from ecdsa import SigningKey
>>>
>>> sk = SigningKey.generate() # generates a signing key

Using another curve, for example NIST384p:

>>> from ecdsa import SigningKey
>>> from ecdsa import NIST384p
>>>
>>> sk = SigningKey.generate(curve=NIST384p)

Getting the generated keys

From the SigningKey object we can get the keys.

Example(s)

Getting the signing key (private key):

>>> print(sk.to_pem()) # shows the generated key on pem format
-----BEGIN EC PRIVATE KEY-----
MIGkAgEBBDAVt3nyVSEUF8FmzLFFguhXBSE6DWw5f1GLkMxvw3Pcty+XK2uMErC1
TdfVeHLSk6egBwYFK4EEACKhZANiAAQMaJjs/lNMYno9XUbtoej4S6cLIPrLPoQP
RNr4rhp2ZWob3z5O5SNH5Od/V6rP27mIMm2C2onuVyeujByQ3XYvD7f8a1H5vFZN
fbfFWks910gktA/xgmUkh3oiWgKsMnM=

-----END EC PRIVATE KEY-----

>>> print(sk.to_hex()) # show the generated key in hex
0x15b779f255211417c166ccb14582e85705213a0d6c397f518b90cc6fc373dcb72f972b6b8c12b0b54dd7d57872d293a7

Getting the verifying key (public key):

>>> vk = sk.verifying_key
>>> print(vk.to_pem())
-----BEGIN PUBLIC KEY-----
MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEDGiY7P5TTGJ6PV1G7aHo+EunCyD6yz6E
D0Ta+K4admVqG98+TuUjR+Tnf1eqz9u5iDJtgtqJ7lcnrowckN12Lw+3/GtR+bxW
TX23xVpLPddIJLQP8YJlJId6IloCrDJz

-----END PUBLIC KEY-----

>>> print(vk.to_hex())
0x0c6898ecfe534c627a3d5d46eda1e8f84ba70b20facb3e840f44daf8ae1a76656a1bdf3e4ee52347e4e77f57aacfdbb988326d82da89ee5727ae8c1c90dd762f0fb7fc6b51f9bc564d7db7c55a4b3dd74824b40ff1826524877a225a02ac3273

Signing a message

Signing a message using the key.

sk = SigningKey.generate()
signature = sk.sign(b"message")

Method Definition

def sign(self, data, entropy=None, hashfunc=None, sigencode=sigencode_string, k=None):
    """
    Create signature over data using the probabilistic ECDSA algorithm.

    This method uses the standard ECDSA algorithm that requires a
    cryptographically secure random number generator.

    It's recommended to use the :func:`~SigningKey.sign_deterministic`
    method instead of this one.

    :param data: data that will be hashed for signing
    :type data: bytes like object
    :param callable entropy: randomness source, os.urandom by default
    :param hashfunc: hash function to use for hashing the provided `data`.
        If unspecified the default hash function selected during
        object initialisation will be used (see
        `VerifyingKey.default_hashfunc`).
        Should behave like hashlib.sha1. The output length of the
        hash (in bytes) must not be longer than the length of the curve
        order (rounded up to the nearest byte), so using SHA256 with
        NIST256p is ok, but SHA256 with NIST192p is not. (In the 2**-96ish
        unlikely event of a hash output larger than the curve order, the
        hash will effectively be wrapped mod n).
        Use hashfunc=hashlib.sha1 to match openssl's -ecdsa-with-SHA1 mode,
        or hashfunc=hashlib.sha256 for openssl-1.0.0's -ecdsa-with-SHA256.
    :type hashfunc: callable
    :param sigencode: function used to encode the signature.
        The function needs to accept three parameters: the two integers
        that are the signature and the order of the curve over which the
        signature was computed. It needs to return an encoded signature.
        See `ecdsa.util.sigencode_string` and `ecdsa.util.sigencode_der`
        as examples of such functions.
    :type sigencode: callable
    :param int k: a pre-selected nonce for calculating the signature.
        In typical use cases, it should be set to None (the default) to
        allow its generation from an entropy source.

    :raises RSZeroError: in the unlikely event when "r" parameter or
        "s" parameter is equal 0 as that would leak the key. Calee should
        try a better entropy source or different 'k' in such case.
    :return: encoded signature of the hash of `data`
    :rtype: bytes or sigencode function dependant type
    """

Example

>>> message = b"message"
>>> signature = sk.sign(message)
>>> signature
'\xf0l\xf9\x9a\x86\x1c\xb2\xd8\xfbz\xc6o\x84\x92q\xa1\xd4\x89/?\x03\x82J\xb1\xfc\x00_z\xf99\xd7\xe7\xa6\xa7\xb4/\x80e\xd6\x95\xc3\xbe\xd8\xf3\xa8\xd4\xdf\x08LoH:\x0b\xd3\x94\xd6\xed<\xda\xd1\xd87\xf3\x9a'
>>>
>>> import binascii
>>> binascii.hexlify(signature)
'f06cf99a861cb2d8fb7ac66f849271a1d4892f3f03824ab1fc005f7af939d7e7a6a7b42f8065d695c3bed8f3a8d4df084c6f483a0bd394d6ed3cdad1d837f39a'

Verifying a signed message

Verifying the signature.

vk = sk.verifying_key
vk.verify(signature, b"message")

Method Definition

def verify(self, signature, data, hashfunc=None, sigdecode=sigdecode_string):
    """
    Verify a signature made over provided data.

    Will hash `data` to verify the signature.

    By default expects signature in :term:`raw encoding`. Can also be used
    to verify signatures in ASN.1 DER encoding by using
    :func:`ecdsa.util.sigdecode_der`
    as the `sigdecode` parameter.

    :param signature: encoding of the signature
    :type signature: sigdecode method dependant
    :param data: data signed by the `signature`, will be hashed using
        `hashfunc`, if specified, or default hash function
    :type data: bytes like object
    :param hashfunc: The default hash function that will be used for
        verification, needs to implement the same interface as hashlib.sha1
    :type hashfunc: callable
    :param sigdecode: Callable to define the way the signature needs to
        be decoded to an object, needs to handle `signature` as the
        first parameter, the curve order (an int) as the second and return
        a tuple with two integers, "r" as the first one and "s" as the
        second one. See :func:`ecdsa.util.sigdecode_string` and
        :func:`ecdsa.util.sigdecode_der` for examples.
    :type sigdecode: callable

    :raises BadSignatureError: if the signature is invalid or malformed

    :return: True if the verification was successful
    :rtype: bool
    """

Example

>>> message = b"message"
>>> signature = sk.sign(message)
>>> vk = sk.verifying_key
>>> vk.verify(signature, message)
True

Using a custom key

Generating the signing key using a custom private key.

SigningKey.from_string()

Method Definition

@classmethod
def from_string(cls, string, curve=SECP256k1, hashfunc=sha1, validate_point=True):
    """
    Initialise the object from byte encoding of public key.

    The method does accept and automatically detect the type of point
    encoding used. It supports the :term:`raw encoding`,
    :term:`uncompressed`, :term:`compressed` and :term:`hybrid` encodings.

    Note, while the method is named "from_string" it's a misnomer from
    Python 2 days when there were no binary strings. In Python 3 the
    input needs to be a bytes-like object.

    :param string: single point encoding of the public key
    :type string: :term:`bytes-like object`
    :param curve: the curve on which the public key is expected to lie
    :type curve: ecdsa.curves.Curve
    :param hashfunc: The default hash function that will be used for
        verification, needs to implement the same interface as hashlib.sha1
    :type hashfunc: callable
    :param validate_point: whether to verify that the point lies on the
        provided curve or not, defaults to True
    :type validate_point: bool

    :raises MalformedPointError: if the public point does not lie on the
        curve or the encoding is invalid

    :return: Initialised VerifyingKey object
    :rtype: VerifyingKey
    """

Example

Using the default curve:

>>> from ecdsa import SigningKey
>>> import binascii
>>>
>>> private_key = b"2574c4b3ba6ecc8714740cedf1554ec3332d30589ff535f38de5d028a51f0165"
>>>
>>> sk = SigningKey.from_string(binascii.unhexlify(private_key))
>>> sk
<ecdsa.SigningKey object at 0x7f2aeaf2c8d0>
>>>
>>> print(sk.to_pem())
-----BEGIN EC PRIVATE KEY-----
MHQCAQEEICV0xLO6bsyHFHQM7fFVTsMzLTBYn/U1843l0CilHwFloAcGBSuBBAAK
oUQDQgAEu14vI2I6+QcwfpGOwWWZpL233gr2oRSgc9y4KksXkg1QbnVAbStPTFM1
bTRPudZLTVuzPyzjQSAeS6/qZma2UQ==

-----END EC PRIVATE KEY-----

Etherium Methods

Etherium related methods.

Signing

Signing a Etherium message.

SigningKey.eth_sign(msg, private_key)

Method Definition

@classmethod
def eth_sign(cls, plain_message, priv):
    """
    Create Etherium signature for the message using the private key.

    :param plain_message: the plain message
    :param priv: the private key
    :return: The signed plain message, hex (v, r and s) and the hashed message
    """

Example

>>> from ecdsa import SigningKey
>>>
>>> msg = b'Hello World!'
>>> private_key = b'0x2574c4b3ba6ecc8714740cedf1554ec3332d30589ff535f38de5d028a51f0165'
>>> signature, v, r, s, message_hash = SigningKey.eth_sign(msg, private_key)
>>> signature
'0xa2b1a77352ebe2730cb433a5757b400da6626af4353695f7df3f49daa2b6e6b677dba1b8d9b5aa6dfaf40611b699872a65fc506bc13d5ae8182cf1ceeeb304a1c'

Verifying

Verifying a Etherium signed message.

SigningKey.eth_verify(msg, r, s, public_key)

Method Definition

@classmethod
def eth_verify(cls, plain_message, hex_r, hex_s, public):
    """
    Verify Etherium signature for message using the public key and the r,s values.

    :param plain_message: the plain message
    :param hex_r: the signature r value
    :param hex_s: the signature s value
    :param public: the public key
    :return: True if the signature is valid
    """

Example

>>> msg = b'Hello World!'
>>> public_key = b'0xbb5e2f23623af907307e918ec16599a4bdb7de0af6a114a073dcb82a4b17920d506e75406d2b4f4c53356d344fb9d64b4d5bb33f2ce341201e4bafea6666b651'
>>> SigningKey.eth_verify(msg, r, s, public_key)
True