Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions ecdsa/keys.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from .util import string_to_number, number_to_string, randrange
from .util import sigencode_string, sigdecode_string
from .util import oid_ecPublicKey, encoded_oid_ecPublicKey
from .numbertheory import square_root_mod_prime
from .six import PY3, b
from hashlib import sha1

Expand Down Expand Up @@ -47,6 +48,30 @@ def from_string(klass, string, curve=NIST192p, hashfunc=sha1,
point = ellipticcurve.Point(curve.curve, x, y, order)
return klass.from_public_point(point, curve, hashfunc)

# based on code from https://github.com/richardkiss/pycoin
@classmethod
def from_sec (klass, string, curve=NIST192p, hashfunc=sha1, validate_point=True):
if string.startswith (b'\x04'):
# uncompressed
return klass.from_string (string[1:], curve, hashfunc, validate_point)
elif string.startswith (b('\x02')) or string.startswith (b'\x03'):
# compressed
is_even = string.startswith (b'\x02')
x = string_to_number (string[1:])
order = curve.order
p = curve.curve.p()
alpha = (pow(x, 3, p) + curve.curve.a() * x + curve.curve.b()) % p
beta = square_root_mod_prime (alpha, p)
if is_even == bool(beta & 1):
y = p - beta
else:
y = beta
if validate_point:
assert ecdsa.point_is_valid(curve.generator, x, y)
from . import ellipticcurve
point = ellipticcurve.Point (curve.curve, x, y, order)
return klass.from_public_point (point, curve, hashfunc)

@classmethod
def from_pem(klass, string):
return klass.from_der(der.unpem(string))
Expand Down Expand Up @@ -83,6 +108,20 @@ def to_string(self):
y_str = number_to_string(self.pubkey.point.y(), order)
return x_str + y_str

def to_sec(self, compressed=True):
order = self.pubkey.order
x = self.pubkey.point.x()
y = self.pubkey.point.y()
x_str = number_to_string(x, order)
if compressed:
if y & 1:
return b('\x03') + x_str
else:
return b('\x02') + x_str
else:
y_str = number_to_string(y, order)
return b('\x04') + x_str + y_str

def to_pem(self):
return der.topem(self.to_der(), "PUBLIC KEY")

Expand Down
17 changes: 17 additions & 0 deletions ecdsa/test_pyecdsa.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,23 @@ def test_basic(self):
pub2 = VerifyingKey.from_string(pub.to_string())
self.assertTrue(pub2.verify(sig, data))

def test_sec(self):
for i in range (20):
skey = SigningKey.generate()
pkey0 = skey.get_verifying_key()
sec0 = pkey0.to_sec()
pkey1 = VerifyingKey.from_sec (sec0)
self.assertEqual (pkey0.to_string(), pkey1.to_string())
pkey2 = VerifyingKey.from_sec (unhexlify (b (
'045b9dfc2af65bd5fb0bd01103ab21e9cfeb1eeafa10795d6801b14e09beadd7f8'
'55981f2803fc3c07edfc2435fbf2326d65d3f237f0bcc2399514255b8d4285c5')),
curve=SECP256k1
)
self.assertEqual (
pkey2.to_sec (compressed=True),
unhexlify (b('035b9dfc2af65bd5fb0bd01103ab21e9cfeb1eeafa10795d6801b14e09beadd7f8'))
)

def test_deterministic(self):
data = b("blahblah")
secexp = int("9d0219792467d7d37b4d43298a7d0c05", 16)
Expand Down