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:
objectElliptic 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:
CurveAn 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)¶
- class ecpy.curves.Point(x, y, curve, check=True)¶
Bases:
objectImmutable 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:
CurveAn 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:
CurveAn 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)¶
- 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:
objectPublic 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:
objectECDSA 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:
objectEDDSA 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:
objectECSchnorr 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:
objectBorromean 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