New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details
Socket
Book a DemoSign in
Socket

ECPy

Package Overview
Dependencies
Maintainers
1
Versions
15
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

ECPy - pypi Package Compare versions

Comparing version
1.0.1
to
1.1.0
+16
-1
PKG-INFO
Metadata-Version: 1.1
Name: ECPy
Version: 1.0.1
Version: 1.1.0
Summary: Pure Pyhton Elliptic Curve Library

@@ -58,2 +58,17 @@ Home-page: https://github.com/cslashm/ECPy

1.1.0
-----
Fix DER encoding for length greater than 128
Declare ONE infinity point per curve.
Consider global (non attached to a curve) infinity point as deprecated
Fix infinity point management in ECDSA
Fix issue #13
1.0.1beta

@@ -60,0 +75,0 @@ ---------

@@ -50,2 +50,17 @@ ECPy

1.1.0
-----
Fix DER encoding for length greater than 128
Declare ONE infinity point per curve.
Consider global (non attached to a curve) infinity point as deprecated
Fix infinity point management in ECDSA
Fix issue #13
1.0.1beta

@@ -52,0 +67,0 @@ ---------

+1
-1

@@ -29,3 +29,3 @@ # Copyright 2016 Cedric Mesnil, Ubinity SAS

setup(name='ECPy',
version='1.0.1',
version='1.1.0',
description='Pure Pyhton Elliptic Curve Library',

@@ -32,0 +32,0 @@ long_description=long_description,

@@ -44,3 +44,3 @@ # encoding: UTF-8

- Short Weierstrass form: y²=x³+a*x+b
- Twisted Edward a*x²+y2=1+d*x²*y²
- Twisted Edward a*x²+y²=1+d*x²*y²
- Montgomery: b.y²=x³+a*x²+x.

@@ -115,2 +115,4 @@

self._infinity_point = Point(0,0,self._domain['name'],False)
self._infinity_point._at_infinity = True

@@ -125,2 +127,7 @@ def __getattr__(self, name):

@property
def infinity(self):
return self._infinity_point
def is_on_curve(self, P):

@@ -409,3 +416,3 @@ """Check if P is on this curve

else:
return _infinity_point
return self.infinity

@@ -433,3 +440,3 @@ def _mul_point(self, k, P):

else:
return _infinity_point
return self.infinity

@@ -663,3 +670,3 @@ def _neg_point(self, P):

else:
return _infinity_point
return self.infinity

@@ -686,3 +693,3 @@ def _mul_point(self, k, P):

else:
return _infinity_point
return self.infinity

@@ -827,3 +834,3 @@ def _neg_point(self, P):

if Q.has_y and P == -Q:
return _infinity_point
return self.infinity

@@ -882,3 +889,3 @@ if P == Q:

else:
return _infinity_point
return self.infinity

@@ -1080,4 +1087,2 @@ def _neg_point(self, P):

if isinstance(Q,Point) :
if self._curve.name != Q._curve.name:
raise ECPyException('__add__: points on same curve')
if self.is_infinity:

@@ -1087,2 +1092,4 @@ return Q

return self
if self._curve.name != Q._curve.name:
raise ECPyException('__add__: points on same curve')
return self.curve._add_point(self,Q)

@@ -1093,4 +1100,2 @@ raise ECPyException('__add__: type not supported: %s'%type(Q))

if isinstance(Q,Point) :
if self._curve.name != Q._curve.name:
raise ECPyException('__sub__: points on same curve')
if self.is_infinity:

@@ -1100,2 +1105,4 @@ return -Q

return self
if self._curve.name != Q._curve.name:
raise ECPyException('__sub__: points on same curve')
return self.curve._add_point(self,-Q)

@@ -1108,3 +1115,4 @@ raise ECPyException('__sub__: type not supported: %s'%type(Q))

return self
if scal%self.curve.order == 0:
scal = scal%self.curve.order
if scal == 0:
return Point.infinity()

@@ -1111,0 +1119,0 @@ return self.curve._mul_point(scal,self)

@@ -52,3 +52,3 @@ # Copyright 2016 Cedric Mesnil <cedric.mesnil@ubinity.com>, Ubinity SAS

def sign_rfc6979(self, msg, pv_key, hasher, canonical=False):
""" Signs a message hash according to RFC6979
""" Signs a message hash according to RFC6979

@@ -67,5 +67,5 @@ Args:

return sig
return None
def sign_k(self, msg, pv_key, k,canonical=False):

@@ -80,3 +80,3 @@ """ Signs a message hash with provided random

return self._do_sign(msg, pv_key, k, canonical)
def _do_sign(self, msg, pv_key, k, canonical=False):

@@ -91,4 +91,7 @@ if (pv_key.curve == None):

msg = int.from_bytes(msg, 'big')
Q = G*k
if Q.is_infinity:
return None
kinv = pow(k,n-2,n)

@@ -105,5 +108,5 @@ r = Q.x % n

s = n-s
sig = encode_sig(r,s,self.fmt)
# r = r.to_bytes((r.bit_length()+7)//8, 'big')

@@ -119,5 +122,5 @@ # s = s.to_bytes((s.bit_length()+7)//8, 'big')

return sig
def verify(self,msg,sig,pu_key):
""" Verifies a message signature.
""" Verifies a message signature.

@@ -134,5 +137,5 @@ Args:

r,s = decode_sig(sig, self.fmt)
if (r == None or
r > n or
s > n ) :
if (r == None or s == None or
r == 0 or r >= n or
s == 0 or s >= n ) :
return False

@@ -148,2 +151,4 @@

GQ = u1G+u2Q
if GQ.is_infinity:
return False
x = GQ.x % n

@@ -153,9 +158,12 @@

if __name__ == "__main__":
import binascii
try:
### ECDSA
signer = ECDSA()
### ECDSA secp256k1
cv = Curve.get_curve('secp256k1')
pu_key = ECPublicKey(Point(0x65d5b8bf9ab1801c9f168d4815994ad35f1dcb6ae6c7a1a303966b677b813b00,
0xe6b865e529b8ecbf71cf966e900477d49ced5846d7662dd2dd11ccd55c0aff7f,

@@ -181,3 +189,3 @@ cv))

# 008dffe3c592a0c7e5168dcb3d4121a60ee727082be4fbf79eae564929156305fc
msg = int(0xba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad)

@@ -188,3 +196,2 @@ sig = int(0x304502200623b4159c7112125be51716d1e706d68e52f5b321da68d8b86b3c7c7019a9da0221008dffe3c592a0c7e5168dcb3d4121a60ee727082be4fbf79eae564929156305fc)

signer = ECDSA()
assert(signer.verify(msg,sig,pu_key))

@@ -212,3 +219,3 @@

sig = signer.sign(msg,pv_key)
assert(signer.verify(msg,sig,pu_key))
assert(signer.verify(msg,sig,pu_key))

@@ -218,3 +225,21 @@ #sign with krfc

assert(sig == expected_sig)
### ECDSA secp256k1
cv = Curve.get_curve('secp521r1')
pv_key = ECPrivateKey(0x018cd813ca254d350b6e4a4a0a0fe2a27eac701d8ccfb1564085d612f315d5aa6c055390cfb7bedf7fc8c02af2360423e8c8a2e3cb045f844f3ec0a6c75025f4a4fa,
cv)
pu_key = ECPublicKey(Point(0x016d523c74262368b2f066859dfd36645cfd7aa7f7c782732c8bee450cd9d42384bb3b9b480df9b440374856a37061d023ff99861796d7b5d146c5c5c3f9a0e34872,
0x002377c7bee60c8dd47ce351c6e3f05d47fd0a1d62c8e2d0a61413e2ee453a38debf67de2da37bcdbd7e80ea5082021ad3f32c829f12d72240bc9f997b483366035a,
cv))
W = pv_key.d * cv.generator
assert(W == pu_key.W)
msg = int(0xba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad)
msg = msg.to_bytes(32,'big')
sig = signer.sign(msg,pv_key)
assert(signer.verify(msg,sig,pu_key))
##OK!

@@ -221,0 +246,0 @@ print("All internal assert OK!")

@@ -29,3 +29,3 @@ # Copyright 2016 Cedric Mesnil <cedric.mesnil@ubinity.com>, Ubinity SAS

""" ECSchnorr signer implementation according to:
- `BSI:TR03111 <https://www.bsi.bund.de/SharedDocs/Downloads/EN/BSI/Publications/TechGuidelines/TR03111/BSI-TR-03111_pdf.html>`_

@@ -36,3 +36,3 @@ - `ISO/IEC:14888-3 <http://www.iso.org/iso/iso_catalogue/catalogue_ics/catalogue_detail_ics.htm?csnumber=43656>`_

In order to select the specification to be conform to, choose
In order to select the specification to be conform to, choose
the corresponding string option: "BSI", "ISO", "ISOx", "LIBSECP", "Z"

@@ -42,3 +42,3 @@

- "BSI": compute r,s according to to BSI :
- "BSI": compute r,s according to to BSI :
1. k = RNG(1:n-1)

@@ -51,3 +51,3 @@ 2. Q = [k]G

5. Output (r, s)
- "ISO": compute r,s according to ISO :
- "ISO": compute r,s according to ISO :
1. k = RNG(1:n-1)

@@ -60,3 +60,3 @@ 2. Q = [k]G

5. Output (r, s)
- "ISOx": compute r,s according to optimized ISO variant:
- "ISOx": compute r,s according to optimized ISO variant:
1. k = RNG(1:n-1)

@@ -69,3 +69,3 @@ 2. Q = [k]G

5. Output (r, s)
- "LIBSECP": compute r,s according to bitcoin lib:
- "LIBSECP": compute r,s according to bitcoin lib:
1. k = RNG(1:n-1)

@@ -90,3 +90,3 @@ 2. Q = [k]G

- "BSI": verify r,s according to to BSI :
- "BSI": verify r,s according to to BSI :
1. Verify that r in {0, . . . , 2**t - 1} and s in {1, 2, . . . , n - 1}.

@@ -98,3 +98,3 @@ If the check fails, output False and terminate.

4. Output True if v = r, and False otherwise.
- "ISO": verify r,s according to ISO :
- "ISO": verify r,s according to ISO :
1. check...

@@ -105,3 +105,3 @@ 2. Q = [s]G - [r]W

4. Output True if v = r, and False otherwise.
- "ISOx": verify r,s according to optimized ISO variant:
- "ISOx": verify r,s according to optimized ISO variant:
1. check...

@@ -112,8 +112,8 @@ 2. Q = [s]G - [r]W

4. Output True if v = r, and False otherwise.
- "LIBSECP":
- "LIBSECP":
1. Signature is invalid if s >= order.
Signature is invalid if r >= p.
2. h = H(r || m).
2. h = H(r || m).
Signature is invalid if h == 0 or h >= order.
3. R = [h]Q + [s]G.
3. R = [h]Q + [s]G.
Signature is invalid if R is infinity or R's y coordinate is odd.

@@ -129,3 +129,3 @@ 4. Signature is valid if the serialization of R's x coordinate equals r.

Default is "ISO"
Args:

@@ -136,3 +136,3 @@ hasher (hashlib): callable constructor returning an object with update(), digest() interface. Example: hashlib.sha256, hashlib.sha512...

"""
def __init__(self, hasher, option="ISO", fmt="DER"):

@@ -146,5 +146,5 @@ if not option in ("ISO","ISOx","BSI","LIBSECP","Z"):

self.fmt = fmt
self.maxtries=10
self.maxtries = 100
self.option = option
def sign(self, msg, pv_key):

@@ -162,3 +162,3 @@ """ Signs a message hash.

if sig:
return sig
return sig
return None

@@ -175,3 +175,3 @@

return self._do_sign(msg, pv_key,k)
def _do_sign(self, msg, pv_key, k):

@@ -184,7 +184,7 @@ if (pv_key.curve == None):

size = curve.size>>3
Q = G*k
hasher = self._hasher()
if self.option == "ISO":
xQ = (Q.x).to_bytes(size,'big')
xQ = (Q.x).to_bytes(size,'big')
yQ = (Q.y).to_bytes(size,'big')

@@ -194,22 +194,28 @@ hasher.update(xQ+yQ+msg)

r = int.from_bytes(r,'big')
if r % n == 0:
return None
s = (k+r*pv_key.d)%n
if r==0 or s==0:
if s==0:
return None
elif self.option == "ISOx":
xQ = (Q.x).to_bytes(size,'big')
xQ = (Q.x).to_bytes(size,'big')
hasher.update(xQ+msg)
r = hasher.digest()
r = int.from_bytes(r,'big')
if r % n == 0:
return None
s = (k+r*pv_key.d)%n
if r==0 or s==0:
if s==0:
return None
elif self.option == "BSI":
xQ = Q.x.to_bytes(size,'big')
xQ = Q.x.to_bytes(size,'big')
hasher.update(msg+xQ)
r = hasher.digest()
r = int.from_bytes(r,'big')
if r%n == 0:
return None
s = (k-r*pv_key.d)%n
if r==0 or s==0:
if s==0:
return None

@@ -225,2 +231,4 @@

h = int.from_bytes(h,'big')
if h > n:
return None
r = Q.x % n

@@ -242,10 +250,12 @@ s = (k - h*pv_key.d)%n

r = int.from_bytes(r,'big') % n
if r % n == 0:
return None
s = (k - r*pv_key.d) %n
if r==0 or s==0:
if s==0:
return None
return encode_sig(r, s, self.fmt)
def verify(self,msg,sig,pu_key):
""" Verifies a message signature.
""" Verifies a message signature.

@@ -261,8 +271,6 @@ Args:

size = curve.size>>3
r,s = decode_sig(sig, self.fmt)
if (r == None or
r > (pow(2,size*8)-1) or
s == 0 or
s > n-1 ) :
if (r == None or r > (pow(2,size*8)-1) or
s == 0 or s >= n ) :
return False

@@ -273,3 +281,3 @@ hasher = self._hasher()

rW = r*pu_key.W
Q = sG - rW
Q = sG - rW
xQ = Q.x.to_bytes(size,'big')

@@ -280,7 +288,7 @@ yQ = Q.y.to_bytes(size,'big')

v = int.from_bytes(v,'big')
elif self.option == "ISOx":
sG = s * G
rW = r*pu_key.W
Q = sG - rW
Q = sG - rW
xQ = Q.x.to_bytes(size,'big')

@@ -290,7 +298,7 @@ hasher.update(xQ+msg)

v = int.from_bytes(v,'big')
elif self.option == "BSI":
sG = s * G
rW = r*pu_key.W
Q = sG + rW
Q = sG + rW
xQ = (Q.x).to_bytes(size,'big')

@@ -302,3 +310,3 @@ hasher.update(msg+xQ)

elif self.option == "LIBSECP":
rb = r.to_bytes(size,'big')
rb = r.to_bytes(size,'big')
hasher.update(rb+msg)

@@ -332,5 +340,5 @@ h = hasher.digest()

return v == r
if __name__ == "__main__":
import sys
import sys,random
try:

@@ -400,3 +408,3 @@ cv = Curve.get_curve('NIST-P256')

expect_s = 0xacd417b277ab7e7d993cc4a601dd01a71696fd0dd2e93561d9de9b69dd4dc75c
signer = ECSchnorr(hashlib.sha256,"LIBSECP","ITUPLE")

@@ -407,3 +415,37 @@ sig = signer.sign_k(msg,pv_key,k)

assert(signer.verify(msg,sig,pu_key))
def _round8(v):
v += 7
return v-v%8
CURVES = ["secp256k1", "secp256r1", "Brainpool-p256r1", "Brainpool-p256t1"]
MODES = ["LIBSECP", "ISO", "ISOx", "BSI", "Z"]
SUCCESS_LIMIT = 100
hashname = "sha256"
for curvename in CURVES:
for modename in MODES:
print(f"CURVE={curvename}, MODE={modename}, HASH={hashname}")
i = 1
while i < SUCCESS_LIMIT:
hasher = eval(f"hashlib.{hashname}")()
hasherclass = eval(f"hashlib.{hashname}")
curveobj = Curve.get_curve(curvename)
curvesize = _round8(curveobj.size)//8
signer = ECSchnorr(hasherclass, option=modename)
d = random.randint(0, curveobj.order)
priv_key = ECPrivateKey(d, curveobj)
pub_key = priv_key.get_public_key()
msg = random.randint(0, pow(2, 256))
msg = msg.to_bytes(32, 'big')
hasher.update(msg)
msg = hasher.digest()
sig_host = signer.sign(msg, priv_key)
try:
assert(signer.verify(msg, sig_host, pub_key))
except AssertionError:
print(f"failed at {i}th round")
break
else:
i += 1
# ##OK!

@@ -410,0 +452,0 @@ print("All internal assert OK!")

@@ -38,18 +38,34 @@ # Copyright 2016 Cedric Mesnil <cedric.mesnil@ubinity.com>, Ubinity SAS

"""
if fmt=="DER":
r = r.to_bytes((r.bit_length()+7)//8, 'big')
s = s.to_bytes((s.bit_length()+7)//8, 'big')
if (r[0] & 0x80) == 0x80 :
r = b'\0'+r
if (s[0] & 0x80) == 0x80 :
s = b'\0'+s
sig = (b'\x30'+int((len(r)+len(s)+4)).to_bytes(1,'big') +
b'\x02'+int(len(r)).to_bytes(1,'big') + r +
b'\x02'+int(len(s)).to_bytes(1,'big') + s )
def _int2bin(x, size=None):
if not size:
size = (x.bit_length()+7)//8
return x.to_bytes(size, 'big')
if fmt=="DER":
def _strip_leading_zero(x):
while x[0] == 0:
x = x[1:]
if x[0] &0x80:
x = b'\0'+x
return x
def _tlv(t,v):
"""
t(bin),v(bin) -> tlv(bin)
"""
l = _int2bin(len(v))
if len(v) > 0x80:
l = bytes([0x80 + len(l)])+l
return t+l+v
r = _tlv(b'\x02', _strip_leading_zero(_int2bin(r)))
s = _tlv(b'\x02', _strip_leading_zero(_int2bin(s)))
sig = _tlv(b'\x30',r+s)
return sig
if fmt=="BTUPLE":
r = r.to_bytes((r.bit_length()+7)//8, 'big')
s = s.to_bytes((s.bit_length()+7)//8, 'big')
r = _int2bin(r)
s = _int2bin(s)
return (r,s)

@@ -59,8 +75,8 @@

return (r,s)
if fmt=="RAW":
if size == 0:
raise ECPyException("size must be specified when encoding in RAW")
r = r.to_bytes(size, 'big')
s = s.to_bytes(size, 'big')
r = _int2bin(r, size)
s = _int2bin(s, size)
return r+s

@@ -75,3 +91,3 @@

def decode_sig(sig,fmt="DER") :

@@ -81,35 +97,67 @@ """ encore signature according format

Args:
rs (bytes,ints,tuple) : r,s value
rs (bytes,ints,tuple) : r,s value
fmt (str): 'DER'|'BTUPLE'|'ITUPLES'|'RAW'|'EDDSA'
Returns:
ints: (r,s)
Returns:
ints: (r,s)
"""
def _untlv(tlv):
t = tlv[0]
l = tlv[1]
tlv = tlv[2:]
if l & 0x80 :
l = l&0x7F
if l == 1:
l = tlv[0]
tlv = tlv[1:]
elif l ==2:
l = tlv[0]<<8 | tlv[1]
tlv = tlv[2:]
elif l ==3:
l = tlv[0]<<16 | tlv[1]<<8 | tlv[2]
tlv = tlv[3:]
elif l ==4:
l = tlv[0]<<24 | tlv[1]<<16 | tlv[2]<<8 | tlv[3]
tlv = tlv[4:]
else :
return None,None,None,None
if len(tlv)<l:
return None,None,None,None
v = tlv[0:l]
return t,l,v, tlv[l:]
if fmt=="DER":
sig_len = sig[1]+2
r_offset = 4
r_len = sig[3]
s_offset = 4+r_len+2
s_len = sig[4+r_len+1]
if ( sig[0] != 0x30 or
sig_len != r_len+s_len+6 or
sig[r_offset-2] != 0x02 or
sig[s_offset-2] != 0x02 ):
t,l,v, tail = _untlv(sig)
if t != 0x30 or len(tail) != 0:
return None,None
r = int.from_bytes(sig[r_offset:r_offset+r_len], 'big')
s = int.from_bytes(sig[s_offset:s_offset+s_len], 'big')
tr,lr,vr , tail = _untlv(v)
ts,ls,vs , tail = _untlv(tail)
if ts != 0x02 or tr != 0x02 or len(tail) != 0:
return None,None
r = int.from_bytes(vr, 'big')
s = int.from_bytes(vs, 'big')
return r,s
if fmt=="ITUPLE":
return (sig[0],sig[1])
if fmt=="BTUPLE":
if fmt=="ITUPLE":
return sig[0], sig[1]
if fmt=="BTUPLE":
r = int.from_bytes(sig[0], 'big')
s = int.from_bytes(sig[1], 'big')
s = int.from_bytes(sig[1], 'big')
return r,s
if fmt=="RAW":
l = len(sig)>>1
l = len(sig)
if l & 1:
return None,None
l = l>>1
r = int.from_bytes(sig[0:l], 'big')

@@ -120,5 +168,8 @@ s = int.from_bytes(sig[l:], 'big')

if fmt=="EDDSA":
l = len(sig)>>1
l = len(sig)
if l & 1:
return None,None
l = l>>1
r = int.from_bytes(sig[0:l], 'little')
s = int.from_bytes(sig[l:], 'little')
return r,s