- Python Versions Supported
- Operating Systems Supported
- Supported Primitives
This is a python package for doing fast elliptic curve cryptography, specifically digital signatures.
- Minerva - see issue #40
There is no nonce reuse, no branching on secret material, and all points are validated before any operations are performed on them. Timing side challenges are mitigated via Montgomery point multiplication. Nonces are generated per RFC6979. The default curve used throughout the package is P256 which provides 128 bits of security. If you require a higher level of security you can specify the curve parameter in a method to use a curve over a bigger field e.g. P384. All that being said, crypto is tricky and I'm not beyond making mistakes. Please use a more established and reviewed library for security critical applications. Open an issue or email me if you see any security issue or risk with this library.
The initial release of this package was targeted at python2.7. Earlier versions may work but have no guarantee of correctness or stability. As of release 1.2.1+ python3 is now supported as well.
This package is targeted at the Linux and MacOS operating systems. Due to the the dependency on the GMP C library building this package on Windows is difficult and no official support or distributions are provided for Windows OSes. See issue11 for what users have done to get things building.
|P192 / secp192r1||
||NIST / NSA|
|P224 / secp224r1||
||NIST / NSA|
|P256 / secp256r1||
||NIST / NSA|
|P384 / secp384r1||
||NIST / NSA|
|P521 / secp521r1||
||NIST / NSA|
|secp256k1 (bitcoin curve)||
As of version 1.5.1 construction of arbitrary curves in Weierstrass form
y^2 = x^3 + ax + b (mod p)) is supported. I advise against using custom curves for any
security critical applications. It's up to you to make sure that the parameters you pass here are
correct, no validation of the base point is done, and in general no sanity checks are done. Use
at your own risk.
from fastecdsa.curve import Curve curve = Curve( name, # (str): The name of the curve p, # (long): The value of p in the curve equation. a, # (long): The value of a in the curve equation. b, # (long): The value of b in the curve equation. q, # (long): The order of the base point of the curve. gx, # (long): The x coordinate of the base point of the curve. gy, # (long): The y coordinate of the base point of the curve. oid # (str): The object identifier of the curve (optional). )
Any hash function in the
hashlib module (
md5, sha1, sha224, sha256, sha384, sha512)
will work, as will any hash function that implements the same interface / core functionality as the
hashlib. For instance, if you wish to use SHA3 as the hash function the
pysha3 package will work with this library as long as it is at version >=1.0b1 (as previous
versions didn't work with the
hmac module which is used in nonce generation). Note
sha3_224, sha3_256, sha3_384, sha3_512 are all in
hashlib as of python3.6.
Currently it does elliptic curve arithmetic significantly faster than the
package. You can see the times for 1,000 signature and verification operations over
various curves below. These were run on an early 2014 MacBook Air with a 1.4 GHz Intel
If you'd like to benchmark performance on your machine you can do so using the command:
$ python setup.py benchmark
This will use the
timeit module to benchmark 1000 signature and verification operations
for each curve supported by this package.
You can use pip:
$ pip install fastecdsa or clone the repo and use
$ python setup.py install. Note that you need to have a C compiler.
You also need to have GMP on your system as the underlying
C code in this package includes the
gmp.h header (and links against gmp
-lgmp flag). You can install all dependencies as follows:
$ sudo apt-get install python-dev libgmp3-dev
$ sudo yum install python-devel gmp-devel
You can use this package to generate keys if you like. Recall that private keys on elliptic curves are integers, and public keys are points i.e. integer pairs.
from fastecdsa import keys, curve """The reason there are two ways to generate a keypair is that generating the public key requires a point multiplication, which can be expensive. That means sometimes you may want to delay generating the public key until it is actually needed.""" # generate a keypair (i.e. both keys) for curve P256 priv_key, pub_key = keys.gen_keypair(curve.P256) # generate a private key for curve P256 priv_key = keys.gen_private_key(curve.P256) # get the public key corresponding to the private key we just generated pub_key = keys.get_public_key(priv_key, curve.P256)
Some basic usage is shown below:
from fastecdsa import curve, ecdsa, keys from hashlib import sha384 m = "a message to sign via ECDSA" # some message ''' use default curve and hash function (P256 and SHA2) ''' private_key = keys.gen_private_key(curve.P256) public_key = keys.get_public_key(private_key, curve.P256) # standard signature, returns two integers r, s = ecdsa.sign(m, private_key) # should return True as the signature we just generated is valid. valid = ecdsa.verify((r, s), m, public_key) ''' specify a different hash function to use with ECDSA ''' r, s = ecdsa.sign(m, private_key, hashfunc=sha384) valid = ecdsa.verify((r, s), m, public_key, hashfunc=sha384) ''' specify a different curve to use with ECDSA ''' private_key = keys.gen_private_key(curve.P224) public_key = keys.get_public_key(private_key, curve.P224) r, s = ecdsa.sign(m, private_key, curve=curve.P224) valid = ecdsa.verify((r, s), m, public_key, curve=curve.P224) ''' using SHA3 via pysha3>=1.0b1 package ''' import sha3 # pip install [--user] pysha3==1.0b1 from hashlib import sha3_256 private_key, public_key = keys.gen_keypair(curve.P256) r, s = ecdsa.sign(m, private_key, hashfunc=sha3_256) valid = ecdsa.verify((r, s), m, public_key, hashfunc=sha3_256)
Point class allows arbitrary arithmetic to be performed over curves. The two main
operations are point addition and point multiplication (by a scalar) which can be done via the
standard python operators (
# example taken from the document below (section 4.3.2): # https://koclab.cs.ucsb.edu/teaching/cren/docs/w02/nist-routines.pdf from fastecdsa.curve import P256 from fastecdsa.point import Point xs = 0xde2444bebc8d36e682edd27e0f271508617519b3221a8fa0b77cab3989da97c9 ys = 0xc093ae7ff36e5380fc01a5aad1e66659702de80f53cec576b6350b243042a256 S = Point(xs, ys, curve=P256) xt = 0x55a8b00f8da1d44e62f6b3b25316212e39540dc861c89575bb8cf92e35e0986b yt = 0x5421c3209c2d6c704835d82ac4c3dd90f61a8a52598b9e7ab656e9d8c8b24316 T = Point(xt, yt, curve=P256) # Point Addition R = S + T # Point Subtraction: (xs, ys) - (xt, yt) = (xs, ys) + (xt, -yt) R = S - T # Point Doubling R = S + S # produces the same value as the operation below R = 2 * S # S * 2 works fine too i.e. order doesn't matter d = 0xc51e4753afdec1e6b6c6a5b992f43f8dd0c7a8933072708b6522468b2ffb06fd # Scalar Multiplication R = d * S # S * d works fine too i.e. order doesn't matter e = 0xd37f628ece72a462f0145cbefe3f0b355ee8332d37acdd83a358016aea029db7 # Joint Scalar Multiplication R = d * S + e * T
from fastecdsa.curve import P256 from fastecdsa.keys import export_key, gen_keypair d, Q = gen_keypair(P256) # save the private key to disk export_key(d, curve=P256, filepath='/path/to/exported/p256.key') # save the public key to disk export_key(Q, curve=P256, filepath='/path/to/exported/p256.pub')
Keys stored in this format can also be imported. The import function will figure out if the key is a public or private key and parse it accordingly:
from fastecdsa.keys import import_key # if the file is a private key then parsed_d is a long and parsed_Q is a Point object # if the file is a public key then parsed_d will be None parsed_d, parsed_Q = import_key('/path/to/file.key')
Other encoding formats can also be specified, such as SEC1 for public keys. This is done using
classes found in the
fastecdsa.encoding package, and passing them as keyword args to
the key functions:
from fastecdsa.curve import P256 from fastecdsa.encoding.sec1 import SEC1Encoder from fastecdsa.keys import export_key, gen_keypair, import_key _, Q = gen_keypair(P256) export_key(Q, curve=P256, filepath='/path/to/p256.key', encoder=SEC1Encoder) parsed_Q = import_key('/path/to/p256.key', curve=P256, public=True, decoder=SEC1Encoder)
DER encoding of ECDSA signatures as defined in RFC2459 is also supported. The
fastecdsa.encoding.der provides the
DEREncoder class which encodes signatures:
from fastecdsa.encoding.der import DEREncoder r, s = 0xdeadc0de, 0xbadc0de encoded = DEREncoder.encode_signature(r, s) decoded_r, decoded_s = DEREncoder.decode_signature(encoded)
Thanks to those below for contributing improvements: