Browse Source

support hex

tb 4.1.0
ofek 7 years ago
parent
commit
52a0d9e0f0
  1. 4
      README.rst
  2. 11
      coincurve/keys.py
  3. 27
      coincurve/utils.py
  4. 2
      setup.py
  5. 12
      tests/test_keys.py
  6. 16
      tests/test_utils.py

4
README.rst

@ -84,6 +84,8 @@ All instances have a ``public_key`` of type ``coincurve.PublicKey``
Methods
~~~~~~~
*classmethod* ``from_hex(hexed, context=GLOBAL_CONTEXT)``
*classmethod* ``from_int(num, context=GLOBAL_CONTEXT)``
*classmethod* ``from_pem(pem, context=GLOBAL_CONTEXT)``
@ -136,6 +138,8 @@ Computes a Diffie-Hellman secret in constant time.
* Returns: ``coincurve.PrivateKey``
``to_hex()``
``to_int()``
``to_pem()``

11
coincurve/keys.py

@ -7,8 +7,8 @@ from coincurve.context import GLOBAL_CONTEXT
from coincurve.ecdsa import cdata_to_der, der_to_cdata, recoverable_to_der
from coincurve.flags import EC_COMPRESSED, EC_UNCOMPRESSED
from coincurve.utils import (
bytes_to_int, der_to_pem, ensure_unicode, get_valid_secret, int_to_bytes,
pad_scalar, pem_to_der, sha256, validate_secret
bytes_to_hex, bytes_to_int, der_to_pem, ensure_unicode, get_valid_secret,
hex_to_bytes, int_to_bytes, pad_scalar, pem_to_der, sha256, validate_secret
)
from ._libsecp256k1 import ffi, lib
@ -108,6 +108,9 @@ class PrivateKey:
return PrivateKey(secret, self.context)
def to_hex(self):
return bytes_to_hex(self.secret)
def to_int(self):
return bytes_to_int(self.secret)
@ -134,6 +137,10 @@ class PrivateKey:
'private_key': pk
}).dump()
@classmethod
def from_hex(cls, hexed, context=GLOBAL_CONTEXT):
return PrivateKey(hex_to_bytes(hexed), context)
@classmethod
def from_int(cls, num, context=GLOBAL_CONTEXT):
return PrivateKey(int_to_bytes(num), context)

27
coincurve/utils.py

@ -1,5 +1,5 @@
from base64 import b64decode, b64encode
from binascii import unhexlify
from binascii import hexlify, unhexlify
from hashlib import sha256 as _sha256
from os import urandom
@ -21,6 +21,11 @@ def ensure_unicode(s):
return s
def pad_hex(hexed):
# Pad odd-length hex strings.
return hexed if not len(hexed) & 1 else '0' + hexed
if hasattr(int, "from_bytes"):
def bytes_to_int(bytestr):
return int.from_bytes(bytestr, 'big')
@ -36,13 +41,23 @@ if hasattr(int, "to_bytes"):
)
else:
def int_to_bytes(num):
hexed = '%x' % num
return pad_scalar(unhexlify(pad_hex('%x' % num)))
if hasattr(bytes, "hex"):
def bytes_to_hex(bytestr):
return bytestr.hex()
else:
def bytes_to_hex(bytestr):
return ensure_unicode(hexlify(bytestr))
# Handle odd-length hex strings.
if len(hexed) & 1:
hexed = '0' + hexed
return pad_scalar(unhexlify(hexed))
if hasattr(bytes, "fromhex"):
def hex_to_bytes(hexed):
return pad_scalar(bytes.fromhex(pad_hex(hexed)))
else:
def hex_to_bytes(hexed):
return pad_scalar(unhexlify(pad_hex(hexed)))
def sha256(bytestr):

2
setup.py

@ -261,7 +261,7 @@ else:
setup(
name='coincurve',
version='4.0.0',
version='4.1.0',
description='Cross-platform Python CFFI bindings for libsecp256k1',
long_description=open('README.rst', 'r').read(),

12
tests/test_keys.py

@ -6,9 +6,9 @@ import pytest
from coincurve.keys import PrivateKey, PublicKey
from coincurve.utils import bytes_to_int, int_to_bytes, verify_signature
from .samples import (
PRIVATE_KEY_BYTES, PRIVATE_KEY_DER, PRIVATE_KEY_NUM, PRIVATE_KEY_PEM,
PUBLIC_KEY_COMPRESSED, PUBLIC_KEY_UNCOMPRESSED, PUBLIC_KEY_X,
PUBLIC_KEY_Y, MESSAGE, SIGNATURE
PRIVATE_KEY_BYTES, PRIVATE_KEY_DER, PRIVATE_KEY_HEX, PRIVATE_KEY_NUM,
PRIVATE_KEY_PEM, PUBLIC_KEY_COMPRESSED, PUBLIC_KEY_UNCOMPRESSED,
PUBLIC_KEY_X, PUBLIC_KEY_Y, MESSAGE, SIGNATURE
)
@ -40,6 +40,9 @@ class TestPrivateKey:
with pytest.raises(ValueError):
PrivateKey().sign(MESSAGE, lambda x: sha512(x).digest())
def test_to_hex(self):
assert PrivateKey(PRIVATE_KEY_BYTES).to_hex() == PRIVATE_KEY_HEX
def test_to_int(self):
assert PrivateKey(PRIVATE_KEY_BYTES).to_int() == PRIVATE_KEY_NUM
@ -49,6 +52,9 @@ class TestPrivateKey:
def test_to_der(self):
assert PrivateKey(PRIVATE_KEY_BYTES).to_der() == PRIVATE_KEY_DER
def test_from_hex(self):
assert PrivateKey.from_hex(PRIVATE_KEY_HEX).secret == PRIVATE_KEY_BYTES
def test_from_int(self):
assert PrivateKey.from_int(PRIVATE_KEY_NUM).secret == PRIVATE_KEY_BYTES

16
tests/test_utils.py

@ -3,8 +3,9 @@ from os import urandom
import pytest
from coincurve.utils import (
GROUP_ORDER, ZERO, bytes_to_int, chunk_data, der_to_pem, get_valid_secret,
int_to_bytes, pad_scalar, pem_to_der, validate_secret, verify_signature
GROUP_ORDER, ZERO, bytes_to_hex, bytes_to_int, chunk_data, der_to_pem,
get_valid_secret, hex_to_bytes, int_to_bytes, pad_scalar, pem_to_der,
validate_secret, verify_signature
)
from .samples import (
MESSAGE, PRIVATE_KEY_DER, PUBLIC_KEY_COMPRESSED, PUBLIC_KEY_UNCOMPRESSED,
@ -42,9 +43,14 @@ class TestValidateSecret:
validate_secret(GROUP_ORDER)
def test_bytes_conversion():
n = b'\x00' + urandom(31)
assert int_to_bytes(bytes_to_int(n)) == n
def test_bytes_hex_conversion():
bytestr = b'\x00' + urandom(31)
assert hex_to_bytes(bytes_to_hex(bytestr)) == bytestr
def test_bytes_int_conversion():
bytestr = b'\x00' + urandom(31)
assert int_to_bytes(bytes_to_int(bytestr)) == bytestr
def test_der_conversion():

Loading…
Cancel
Save