Skip to content
This repository has been archived by the owner on Jan 24, 2024. It is now read-only.

Commit

Permalink
Merge pull request #65 from BrentDouglasB1/support-SECP256r1
Browse files Browse the repository at this point in the history
Support SECP256r1 keys
  • Loading branch information
deckb committed Jun 29, 2021
2 parents f9e55c0 + 97aefa8 commit 1981ce9
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 22 deletions.
51 changes: 29 additions & 22 deletions eospy/keys.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,20 @@
import ecdsa
import re
from binascii import hexlify, unhexlify
from .utils import sha256, ripemd160, str_to_hex, hex_to_int
from .utils import sha256, ripemd160
from .signer import Signer
import hashlib
import time
import struct
import array

def get_curve(key_type) :
if key_type == 'R1' :
return ecdsa.NIST256p
return ecdsa.SECP256k1

def check_wif(key):
if isinstance(key, str):
try:
def check_wif(key) :
if isinstance(key, str) :
try :
EOSKey(key)
return True
except Exception as ex:
Expand All @@ -26,10 +29,14 @@ def __init__(self, private_str=''):
''' '''
if private_str:
private_key, format, key_type = self._parse_key(private_str)
self._sk = ecdsa.SigningKey.from_string(unhexlify(private_key), curve=ecdsa.SECP256k1)
else:
self._key_type = key_type
self._curve = get_curve(key_type)
self._sk = ecdsa.SigningKey.from_string(unhexlify(private_key), curve=self._curve)
else :
prng = self._create_entropy()
self._sk = ecdsa.SigningKey.generate(curve=ecdsa.SECP256k1, entropy=prng)
self._key_type = 'K1'
self._curve = get_curve(self._key_type)
self._sk = ecdsa.SigningKey.generate(curve=self._curve, entropy=prng)
self._vk = self._sk.get_verifying_key()

def __str__(self):
Expand Down Expand Up @@ -97,10 +104,10 @@ def _recover_key(self, digest, signature, i):
''' Recover the public key from the sig
http://www.secg.org/sec1-v2.pdf
'''
curve = ecdsa.SECP256k1.curve
G = ecdsa.SECP256k1.generator
order = ecdsa.SECP256k1.order
yp = (i % 2)
curve = self._curve.curve
G = self._curve.generator
order = self._curve.order
yp = (i %2)
r, s = ecdsa.util.sigdecode_string(signature, order)
x = r + (i // 2) * order
alpha = ((x * x * x) + (curve.a() * x) + curve.b()) % curve.p()
Expand All @@ -112,12 +119,12 @@ def _recover_key(self, digest, signature, i):
# compute Q
Q = ecdsa.numbertheory.inverse_mod(r, order) * (s * R + (-e % order) * G)
# verify message
if not ecdsa.VerifyingKey.from_public_point(Q, curve=ecdsa.SECP256k1).verify_digest(signature, digest,
sigdecode=ecdsa.util.sigdecode_string):
if not ecdsa.VerifyingKey.from_public_point(Q, curve=self._curve).verify_digest(signature, digest,
sigdecode=ecdsa.util.sigdecode_string) :
return None
return ecdsa.VerifyingKey.from_public_point(Q, curve=ecdsa.SECP256k1)

def _recovery_pubkey_param(self, digest, signature):
return ecdsa.VerifyingKey.from_public_point(Q, curve=self._curve)
def _recovery_pubkey_param(self, digest, signature) :
''' Use to derive a number that will allow for the easy recovery
of the public key from the signature
'''
Expand Down Expand Up @@ -199,20 +206,20 @@ def sign(self, digest):
sigstr = struct.pack('<B', i) + sig
break
# if self._is_canonical(sigstr):
# break
# break
cnt += 1
if not cnt % 10:
print('Still searching for a signature. Tried {} times.'.format(cnt))
if not cnt % 10 :
print('Still searching for a signature. Tried {} times.'.format(cnt))
# encode
return 'SIG_K1_' + self._check_encode(hexlify(sigstr), 'K1').decode()
return 'SIG_' + self._key_type + '_' + self._check_encode(hexlify(sigstr), self._key_type).decode()

def verify(self, encoded_sig, digest):
''' '''
# remove SIG_ prefix
encoded_sig = encoded_sig[4:]
# remove curve prefix
curvePre = encoded_sig[:3].strip('_')
if curvePre != 'K1':
if curvePre != self._key_type :
raise TypeError('Unsupported curve prefix {}'.format(curvePre))

decoded_sig = self._check_decode(encoded_sig[3:], curvePre)
Expand Down
35 changes: 35 additions & 0 deletions tests/test_sig.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import sys

sys.path.append('../eospy')

from eospy.cleos import EOSKey
import hashlib


class TestSig:
payload = "some important data"
digest = hashlib.sha256(payload.encode('utf-8').rstrip()).hexdigest()

legacy = ("EOS6JWAwA6goJmmAGwQEwbFne8zNxhuVTjgk1aLqVW9efHWhGfvwU",
"5JU8RktQ72qFtJyiW3DJ54B2ZY6Ad83HdoGg78Nk8kUNMJEmCUg")

r1 = ("PUB_R1_65vcmkCEJuxQ2rvYxBZSiUGP9FJPaqMfrLyakHduxEULWcBUxW",
"PVT_R1_2sTZXHRWPfgWfn4gTD4bXjVsKRTSYBCekebBgJq1P9SW7ckoXk")

k1 = ("PUB_K1_6ctHgq55Tt4u3ksvDw1jadhC5tytemHs8fHM4YfFVqMe4F8XWU",
"PVT_K1_r9seSVdS9yTRmSXtLrpELLZ5dhbEqr12jLCRg5NJAWr5q8U9o")

def test_legacy(self):
key = EOSKey(self.legacy[1])
sig = key.sign(self.digest)
assert key.verify(sig, self.digest)

def test_r1(self):
key = EOSKey(self.r1[1])
sig = key.sign(self.digest)
assert key.verify(sig, self.digest)

def test_k1(self):
key = EOSKey(self.k1[1])
sig = key.sign(self.digest)
assert key.verify(sig, self.digest)

0 comments on commit 1981ce9

Please sign in to comment.