Welcome to ECPy’s documentation!¶
Indices and tables¶
Status¶
- Version
0.8.2
- Authors
Cedric Mesnil, <cedric.mesnil@ubinity.com>
- License
Apache 2.0
Install¶
ECPy is originally coded for Python 3, but run under python 2.7 (and maybe 2.6) by using future. If you run Python 2, please install the future into the present:
pip install future
Then install ECPy:
- From pypi (using pip or pip3)
pip install ECPy
- Rebuild from git clone:
python3 setup.py sdist
cd dist
tar xzvf ECPy-M.m.tar.gz
python3 setup install
- Install from dist package:
Download last dist tarball
tar xzvf ECPy-M.m.tar.gz
python3 setup.py install
Overview¶
ECPy (pronounced ekpy), is a pure python Elliptic Curve library. It provides ECDSA, EDDSA, ECSchnorr signature as well as Point operation.
ECDSA sample
from ecpy.curves import Curve,Point
from ecpy.keys import ECPublicKey, ECPrivateKey
from ecpy.ecdsa import ECDSA
cv = Curve.get_curve('secp256k1')
pu_key = ECPublicKey(Point(0x65d5b8bf9ab1801c9f168d4815994ad35f1dcb6ae6c7a1a303966b677b813b00,
0xe6b865e529b8ecbf71cf966e900477d49ced5846d7662dd2dd11ccd55c0aff7f,
cv))
pv_key = ECPrivateKey(0xfb26a4e75eec75544c0f44e937dcf5ee6355c7176600b9688c667e5c283b43c5,
cv)
signer = ECDSA()
sig = signer.sign(b'01234567890123456789012345678912',pv_key)
assert(signer.verify(b'01234567890123456789012345678912',sig,pu_key))
Point sample
from ecpy.curves import Curve,Point
cv = Curve.get_curve('secp256k1')
P = Point(0x65d5b8bf9ab1801c9f168d4815994ad35f1dcb6ae6c7a1a303966b677b813b00,
0xe6b865e529b8ecbf71cf966e900477d49ced5846d7662dd2dd11ccd55c0aff7f,
cv)
k = 0xfb26a4e75eec75544c0f44e937dcf5ee6355c7176600b9688c667e5c283b43c5
Q = k*P
R = P+Q
Supported Curves & Signature¶
- ECPy support the following curves
Short Weierstrass form: y²=x³+a*x+b
Twisted Edward a*x²+y2=1+d*x²*y²
See pyec.Curve. get_curve_names
ECPy supports the following
Types¶
ECPY use binary bytes and int as primary types.
Other main types are Point
, Curve
, Key
, ECDSA
, EDDSA
, ECSchnorr
. Borromean
.
See API details…
API¶
curves module¶
Elliptic Curve and Point manipulation
-
exception
ecpy.curves.
ECPyException
(value)¶ Bases:
Exception
-
class
ecpy.curves.
Curve
(parameters)¶ Bases:
object
Elliptic Curve abstraction
You should not directly create such Object. Use get_curve to get the predefined curve or create a well-know type of curve with your parameters
- Supported well know elliptic curve are:
Short Weierstrass form: y²=x³+a*x+b
Twisted Edward a*x²+y2=1+d*x²*y²
-
name
¶ curve name, the one given to get_curve or return by get_curve_names
- Type
str
-
size
¶ bit size of curve
- Type
int
-
a
¶ first curve parameter
- Type
int
-
b d
second curve parameter
- Type
int
-
field
¶ curve field
- Type
int
-
order
¶ order of generator
- Type
int
-
add_point
(P, Q)¶ Returns the sum of P and Q
This function ignores the default curve attach to P and Q, and assumes P and Q are on this curve.
- Parameters
- Returns
A new Point R = P+Q
- Return type
- Raises
ECPyException – with “Point not on curve”, if Point R is not on curve, thus meaning either P or Q was not on.
-
decode_point
(eP)¶ decode/decompress a point according to its curve
-
encode_point
(P)¶ encode/compress a point according to its curve
-
static
get_curve
(name)¶ Return a Curve object according to its name
- Parameters
name (str) – curve name to retrieve
- Returns
Curve object
- Return type
-
static
get_curve_names
()¶ Returns all known curve names
- Returns
list of names as str
- Return type
tuple
-
is_on_curve
(P)¶ Check if P is on this curve
This function ignores the default curve attach to P
- Parameters
P (Point) – Point to check
- Returns
True if P is on curve, False else
- Return type
bool
-
mul_point
(k, P)¶ Returns the scalar multiplication P with k.
This function ignores the default curve attach to P and Q, and assumes P and Q are on this curve.
- Parameters
P (Point) – point to mul_point
k (int) – scalar to multiply
- Returns
A new Point R = k*Q
- Return type
- Raises
ECPyException – with “Point not on curve”, if Point R is not
on curve, thus meaning P was not on. –
-
sub_point
(P, Q)¶ Returns the difference of P and Q
This function ignores the default curve attach to P and Q, and assumes P and Q are on this curve.
- Parameters
- Returns
A new Point R = P-Q
- Return type
- Raises
ECPyException – with “Point not on curve”, if Point R is not on curve, thus meaning either P or Q was not on.
-
class
ecpy.curves.
MontgomeryCurve
(domain)¶ Bases:
ecpy.curves.Curve
An elliptic curve defined by the equation: b.y²=x³+a*x²+x.
- The given domain must be a dictionary providing the following keys/values:
name (str) : curve unique name
size (int) : bit size
a (int) : a equation coefficient
b (int) : b equation coefficient
field (inf) : field value
generator (int[2]) : x,y coordinate of generator
order (int) : order of generator
Note: you should not use the constructor and only use
Curve.get_curve()
builder to ensure using supported curve.- Parameters
domain (dict) – a dictionary providing curve domain parameters
-
decode_point
(eP)¶ Decodes a point P according to RFC7748.
- Parameters
eP (bytes) – encoded point
curve (Curve) – curve on witch point is
- Returns
Point : decoded point
-
encode_point
(P)¶ Encodes a point P according to RFC7748.
- Parameters
P – point to encode
- Returns
bytes : encoded point
-
is_on_curve
(P)¶
-
mul_point
(k, P)¶
-
y_recover
(x, sign=0)¶
-
class
ecpy.curves.
Point
(x, y, curve, check=True)¶ Bases:
object
Immutable Elliptic Curve Point.
A Point support the following operator:
+ : Point Addition, with automatic doubling support.
* : Scalar multiplication, can write as k*P or P*k, with P :class:Point and k :class:int
==: Point comparison
-
x
¶ Affine x coordinate
- Type
int
-
y
¶ Affine y coordinate
- Type
int
- Parameters
x (int) – x coordinate
y (int) – y coordinate
check (bool) – if True enforce x,y is on curve
- Raises
ECPyException – if check=True and x,y is not on curve
-
class
ecpy.curves.
TwistedEdwardCurve
(domain)¶ Bases:
ecpy.curves.Curve
An elliptic curve defined by the equation: a*x²+y²=1+d*x²*y²
- The given domain must be a dictionary providing the following keys/values:
name (str) : curve unique name
size (int) : bit size
a (int) : a equation coefficient
d (int) : b equation coefficient
field (inf) : field value
generator (int[2]) : x,y coordinate of generator
order (int) : order of generator
Note: you should not use the constructor and only use
Curve.get_curve()
builder to ensure using supported curve.- Parameters
domain (dict) – a dictionary providing curve domain parameters
-
add_point
(P, Q)¶
-
decode_point
(eP)¶ Decodes a point P according to draft_irtf-cfrg-eddsa-04.
- Parameters
eP (bytes) – encoded point
curve (Curve) – curve on witch point is
- Returns
Point : decoded point
-
encode_point
(P)¶ Encodes a point P according to draft_irtf-cfrg-eddsa-04.
- Parameters
P – point to encode
- Returns
bytes : encoded point
-
is_on_curve
(P)¶
-
mul_point
(k, P)¶
-
x_recover
(y, sign=0)¶ Retrieves the x coordinate according to the y one, such that point (x,y) is on curve.
- Parameters
y (int) – y coordinate
sign (int) – sign of x
- Returns
the computed x coordinate
- Return type
int
-
class
ecpy.curves.
WeierstrassCurve
(domain)¶ Bases:
ecpy.curves.Curve
An elliptic curve defined by the equation: y²=x³+a*x+b.
- The given domain must be a dictionary providing the following keys/values:
name (str) : curve unique name
size (int) : bit size
a (int) : a equation coefficient
b (int) : b equation coefficient
field (inf) : field value
generator (int[2]) : x,y coordinate of generator
order (int) : order of generator
cofactor (int) : cofactor
Note: you should not use the constructor and only use
Curve.get_curve()
builder to ensure using supported curve.- Parameters
domain (dict) – a dictionary providing curve parameters
-
add_point
(P, Q)¶
-
decode_point
(eP)¶ Decodes a point P according to P1363-2000.
- Parameters
eP (bytes) – encoded point
curve (Curve) – curve on witch point is
- Returns
Point : decoded point
-
encode_point
(P, compressed=False)¶ Encodes a point P according to P1363-2000.
- Parameters
P – point to encode
- Returns
bytes : encoded point [04 | x | y] or [02 | x | sign]
-
is_on_curve
(P)¶
-
mul_point
(k, P)¶
-
y_recover
(x, sign=0)¶
-
ecpy.curves.
decode_scalar_25519
(k)¶ decode scalar according to RF7748 and draft-irtf-cfrg-eddsa
- Parameters
k (bytes) – scalar to decode
- Returns
decoded scalar
- Return type
int
-
ecpy.curves.
encode_scalar_25519
(k)¶ encode scalar according to RF7748 and draft-irtf-cfrg-eddsa
- Parameters
k (int) – scalar to encode
- Returns
encoded scalar
- Return type
bytes
keys module¶
-
class
ecpy.keys.
ECPrivateKey
(d, curve)¶ Bases:
object
Public EC key.
Can be used for both ECDSA and EDDSA signature
- Attributes
d (int) : private key scalar curve (Curve) : curve
- Parameters
d (int) – private key value
curve (Curve) – curve
-
get_public_key
()¶ Returns the public key corresponding to this private key
This method considers the private key the generator multiplier and return pv*Generator in all cases.
For specific derivation such as in EdDSA, see ecpy.eddsa.get_public_key
- Returns
public key
- Return type
ECDSA module¶
-
class
ecpy.ecdsa.
ECDSA
(fmt='DER')¶ Bases:
object
ECDSA signer.
- Parameters
fmt (str) – in/out signature format. See
ecpy.formatters
-
sign
(msg, pv_key, canonical=False)¶ Signs a message hash.
- Parameters
msg (bytes) – the message hash to sign
pv_key (ecpy.keys.ECPrivateKey) – key to use for signing
-
sign_k
(msg, pv_key, k, canonical=False)¶ Signs a message hash with provided random
- Parameters
msg (bytes) – the hash of message to sign
pv_key (ecpy.keys.ECPrivateKey) – key to use for signing
k (ecpy.keys.ECPrivateKey) – random to use for signing
-
sign_rfc6979
(msg, pv_key, hasher, canonical=False)¶ Signs a message hash according to RFC6979
- Parameters
msg (bytes) – the message hash to sign
pv_key (ecpy.keys.ECPrivateKey) – key to use for signing
hasher (hashlib) – hasher conform to hashlib interface
-
verify
(msg, sig, pu_key)¶ Verifies a message signature.
- Parameters
msg (bytes) – the message hash to verify the signature
sig (bytes) – signature to verify
pu_key (ecpy.keys.ECPublicKey) – key to use for verifying
EDDSA module¶
-
class
ecpy.eddsa.
EDDSA
(hasher, hash_len=None, fmt='EDDSA')¶ Bases:
object
EDDSA signer implemenation according to:
IETF draft-irtf-cfrg-eddsa-05.
- Parameters
hasher (hashlib) – callable constructor returning an object with update(), digest() interface. Example: hashlib.sha256, hashlib.sha512…
fmt (str) – in/out signature format. See
ecpy.formatters
.
-
static
get_public_key
(pv_key, hasher=<built-in function openssl_sha512>, hash_len=None)¶ Returns the public key corresponding to this private key
This method compute the public key according to draft-irtf-cfrg-eddsa-05.
The hash parameter shall be the same as the one used for signing and verifying.
- Parameters
hasher (hashlib) – callable constructor returning an object with update(), digest() interface. Example: hashlib.sha256, hashlib.sha512…
pv_key (ecpy.keys.ECPrivateKey) – key to use for signing
- Returns
public key
- Return type
-
sign
(msg, pv_key)¶ Signs a message.
- Parameters
msg (bytes) – the message to sign
pv_key (ecpy.keys.ECPrivateKey) – key to use for signing
-
verify
(msg, sig, pu_key)¶ Verifies a message signature.
- Parameters
msg (bytes) – the message to verify the signature
sig (bytes) – signature to verify
pu_key (ecpy.keys.ECPublicKey) – key to use for verifying
ECSchnorr module¶
-
class
ecpy.ecschnorr.
ECSchnorr
(hasher, option='ISO', fmt='DER')¶ Bases:
object
ECSchnorr signer implementation according to:
In order to select the specification to be conform to, choose the corresponding string option: “BSI”, “ISO”, “ISOx”, “LIBSECP”, “Z”
Signature:
- “BSI”: compute r,s according to to BSI :
k = RNG(1:n-1)
Q = [k]G
r = H(M ||Qx) If r = 0 mod n, goto 1.
s = k - r.d mod n If s = 0 goto 1.
Output (r, s)
- “ISO”: compute r,s according to ISO :
k = RNG(1:n-1)
Q = [k]G If r = 0 mod n, goto 1.
r = H(Qx||Qy||M).
s = (k + r.d) mod n If s = 0 goto 1.
Output (r, s)
- “ISOx”: compute r,s according to optimized ISO variant:
k = RNG(1:n-1)
Q = [k]G If r = 0 mod n, goto 1.
r = H(Qx||Qy||M).
s = (k + r.d) mod n If s = 0 goto 1.
Output (r, s)
- “LIBSECP”: compute r,s according to bitcoin lib:
k = RNG(1:n-1)
Q = [k]G if Qy is odd, negate k and goto 2
r = Qx % n
h = H(r || m). if h == 0 or h >= order goto 1
s = k - h.d.
Output (r, s)
- “Z”: compute r,s according to zilliqa lib:
Generate a random k from [1, …, order-1]
Compute the commitment Q = kG, where G is the base point
Compute the challenge r = H(Q, kpub, m) [CME: mod n according to pdf/code, Q and kpub compressed “02|03 x” according to code)
If r = 0 mod(order), goto 1
Compute s = k - r*kpriv mod(order)
If s = 0 goto 1.
Output (r, s)
Verification
- “BSI”: verify r,s according to to BSI :
Verify that r in {0, … , 2**t - 1} and s in {1, 2, … , n - 1}. If the check fails, output False and terminate.
Q = [s]G + [r]W If Q = 0, output Error and terminate.
v = H(M||Qx)
Output True if v = r, and False otherwise.
- “ISO”: verify r,s according to ISO :
check…
Q = [s]G - [r]W If Q = 0, output Error and terminate.
v = H(Qx||Qy||M).
Output True if v = r, and False otherwise.
- “ISOx”: verify r,s according to optimized ISO variant:
check…
Q = [s]G - [r]W If Q = 0, output Error and terminate.
v = H(Qx||M).
Output True if v = r, and False otherwise.
- “LIBSECP”:
Signature is invalid if s >= order. Signature is invalid if r >= p.
h = H(r || m). Signature is invalid if h == 0 or h >= order.
R = [h]Q + [s]G. Signature is invalid if R is infinity or R’s y coordinate is odd.
Signature is valid if the serialization of R’s x coordinate equals r.
- “Z”:
Check if r,s is in [1, …, order-1]
Compute Q = sG + r*kpub
If Q = O (the neutral point), return 0;
r’ = H(Q, kpub, m) [CME: mod n according to pdf/code, according to code), Q and kpub compressed “02|03 x”]
return r’ == r
Default is “ISO”
- Parameters
hasher (hashlib) – callable constructor returning an object with update(), digest() interface. Example: hashlib.sha256, hashlib.sha512…
option (str) – one of “BSI”,”ISO”,”ISOx”,”LIBSECP”
fmt (str) – in/out signature format. See
ecpy.formatters
-
sign
(msg, pv_key)¶ Signs a message hash.
- Parameters
hash_msg (bytes) – the message hash to sign
pv_key (ecpy.keys.ECPrivateKey) – key to use for signing
-
sign_k
(msg, pv_key, k)¶ Signs a message hash with provided random
- Parameters
hash_msg (bytes) – the message hash to sign
pv_key (ecpy.keys.ECPrivateKey) – key to use for signing
k (ecpy.keys.ECPrivateKey) – random to use for signing
-
verify
(msg, sig, pu_key)¶ Verifies a message signature.
- Parameters
msg (bytes) – the message hash to verify the signature
sig (bytes) – signature to verify
pu_key (ecpy.keys.ECPublicKey) – key to use for verifying
Borromean module¶
-
class
ecpy.borromean.
Borromean
(fmt='BTUPLE')¶ Bases:
object
Borromean Ring signer implementation according to:
https://github.com/Blockstream/borromean_paper/blob/master/borromean_draft_0.01_9ade1e49.pdf
ElementsProject implementation has some tweaks compared to PDF. This implementation is ElementsProject compliant.
For now, only secp256k1+sha256 is supported. This constraint will be release soon.
- Parameters
fmt (str) – in/out signature format. See
ecpy.formatters
. IGNORED.
-
sign
(msg, rings, pv_keys, pv_keys_index)¶ Signs a message hash.
The public rings argument is a tuple of public key array. In other words each element of the ring tuple is an array containing the public keys list of that ring
A Private key must be given for each provided ring. For each private key, the corresponding public key is specified by its index in the ring.
- Exemple:
let r1 be the first ring with 2 keys: pu11, pu12 let 21 be the second ring with 3 keys: pu21,pu22,pu23 let say we want to produce a signature with sec12 and sec21 sign should be called as:
borromean.sign(m, ([pu11,pu12],[pu21,pu22,pu23]), [sec12, sec21], [1,0])
The return value is a tuple (e0, [s0,s1….]). Each value is encoded as binary (bytes).
- Parameters
msg (bytes) – the message hash to sign
rings (tuple of (ecpy.keys.ECPublicKey[]) – public key rings
pv_keys (ecpy.keys.ECPrivateKey[]) – key to use for signing
pv_keys_index (int[]) –
- Returns
signature
- Return type
(e0, [s0,s1….])
-
verify
(msg, sig, rings)¶ Verifies a message signature.
- Parameters
msg (bytes) – the message hash to verify the signature
sig (bytes) – signature to verify
rings (key.ECPublicKey) – key to use for verifying
- Returns
True if signature is verified, False else
- Return type
boolean
ecrand module¶
-
ecpy.ecrand.
rnd
(q)¶ Returns a random number less than q, with the same bits length than q
- Parameters
q (int) – field/modulo
- Returns
random
- Return type
int
-
ecpy.ecrand.
rnd_rfc6979
(hashmsg, secret, q, hasher, V=None)¶ Generates a deterministic value according to RF6979.
See https://tools.ietf.org/html/rfc6979#section-3.2
if V == None, this is the first try, so compute the initial value for V. Else it means the previous value has been rejected by the caller, so generate the next one!
Warning: the hashmsg parameter is the message hash, not the message itself. In other words, hashmsg is equal to h1 in the rfc6979, section-3.2, step a.
- Parameters
hasher (hashlib) – hasher
hashmsg (bytes) – message hash
secret (int) – secret
q (int) – field/modulo
V – previous value for continuation
The function returns a couple (k,V) with k the expected value and V is the continuation value to pass to next cal if k is rejected.
- Returns
(k,V)
- Return type
tuple
formatters module¶
-
ecpy.formatters.
decode_sig
(sig, fmt='DER')¶ encore signature according format
- Parameters
rs (bytes,ints,tuple) – r,s value
fmt (str) – ‘DER’|’BTUPLE’|’ITUPLES’|’RAW’|’EDDSA’
- Returns
(r,s)
- Return type
ints
-
ecpy.formatters.
encode_sig
(r, s, fmt='DER', size=0)¶ encore signature according format
- Parameters
r (int) – r value
s (int) – s value
fmt (str) – ‘DER’|’BTUPLE’|’ITUPLE’|’RAW’|’EDDSA
- Returns
TLV for DER encoding
- Return type
bytes
- Returns
(r,s) for BTUPLE encoding
- Return type
bytes
- Returns
(r,s) for ITUPLE encoding
- Return type
ints
- Returns
r|s for RAW encoding
- Return type
bytes