Rework to use pysodium, document and test further

Still on key_pair, sign and verify
This commit is contained in:
Luke Murphy 2019-10-05 14:11:14 +02:00
parent 1072d2662a
commit c11909012a
No known key found for this signature in database
GPG Key ID: 5E2EF5A63E3718CC
4 changed files with 49 additions and 27 deletions

View File

@ -1,15 +1,8 @@
"""hypercore-crypto module.""" """hypercore-crypto module."""
# Note(decentral1se): Included to match export list of the original Javascript
# reference implementation. However, we don't implement this function
# ourselves.
from nacl.hash import blake2b # noqa
from hypercore_crypto.crypto import ( # noqa from hypercore_crypto.crypto import ( # noqa
blake2b,
data, data,
discovery_key, discovery_key,
encode_unsigned_int64,
key_pair, key_pair,
leaf, leaf,
parent, parent,

View File

@ -2,14 +2,13 @@
from typing import Optional, Tuple from typing import Optional, Tuple
import nacl.exceptions from pysodium import (
from nacl.bindings import ( crypto_sign_detached,
crypto_sign,
crypto_sign_keypair, crypto_sign_keypair,
crypto_sign_seed_keypair, crypto_sign_seed_keypair,
crypto_sign_SEEDBYTES,
crypto_sign_verify_detached,
) )
from nacl.hash import blake2b
from nacl.signing import VerifyKey
# https://en.wikipedia.org/wiki/Merkle_tree#Second_preimage_attack # https://en.wikipedia.org/wiki/Merkle_tree#Second_preimage_attack
LEAF_TYPE = bytearray([0]) LEAF_TYPE = bytearray([0])
@ -21,23 +20,35 @@ HYPERCORE = bytearray('hypercore', encoding='utf-8')
def key_pair(seed: Optional[bytes] = None) -> Tuple[bytes, bytes]: def key_pair(seed: Optional[bytes] = None) -> Tuple[bytes, bytes]:
"""A new public key and secret key pair. """A new public key and secret key pair.
The seed must be at least 32 characters in length. :param seed: Seed value. Must be at least 32 characters in length
""" """
if seed: if seed:
if len(seed) < crypto_sign_SEEDBYTES:
message = "'seed' argument must be of length > {}"
raise ValueError(message.format(crypto_sign_SEEDBYTES))
return crypto_sign_seed_keypair(seed) return crypto_sign_seed_keypair(seed)
return crypto_sign_keypair() return crypto_sign_keypair()
def sign(message: bytes, secret_key: bytes) -> bytes: def sign(message: bytes, secret_key: bytes) -> bytes:
"""Signed message from a secret key.""" """A message signature.
return crypto_sign(message, secret_key)
:param message: The message to be signed
:param secret_key: The secret key to use during signing
"""
return crypto_sign_detached(message, secret_key)
def verify(signed_message: bytes, signature: bytes, public_key: bytes) -> bool: def verify(message: bytes, signature: bytes, public_key: bytes) -> bool:
"""Verify a signed message.""" """Verify an unsigned message with accompanying signature.
:param message: The unsigned message to verify
:param signature: The signature to be verified
:param public_key: The public key to use during verifying
"""
try: try:
VerifyKey(public_key).verify(signed_message, signature=signature) crypto_sign_verify_detached(signature, message, public_key)
except (nacl.exceptions.TypeError, nacl.exceptions.BadSignatureError): except ValueError:
return False return False
return True return True
@ -64,7 +75,3 @@ def random_bytes():
def discovery_key(): def discovery_key():
pass pass
def encode_unsigned_int64():
pass

View File

@ -43,7 +43,7 @@ package_dir =
packages = find: packages = find:
zip_safe = False zip_safe = False
install_requires = install_requires =
PyNaCl >= 1.3.0, < 2.0 pysodium >= 0.7.2, < 0.8
[options.packages.find] [options.packages.find]
where = . where = .

View File

@ -1,9 +1,31 @@
"""Cryptography primitives test module.""" """Cryptography primitives test module."""
from hypercore_crypto import key_pair import pytest
from hypercore_crypto import key_pair, sign, verify
from pysodium import crypto_sign_PUBLICKEYBYTES, crypto_sign_SECRETKEYBYTES
def test_key_pair_seed_length():
with pytest.raises(ValueError) as exception:
key_pair(b'wrong')
assert 'must be of length' in str(exception)
def test_key_pair_length(): def test_key_pair_length():
public_key, secret_key = key_pair() public_key, secret_key = key_pair()
assert len(public_key) == 32 assert len(public_key) == crypto_sign_PUBLICKEYBYTES
assert len(secret_key) == 64 assert len(secret_key) == crypto_sign_SECRETKEYBYTES
def test_sign():
message = b'mymessage'
_, secret_key = key_pair()
assert message not in sign(message, secret_key)
def test_verify():
message = b'mymessage'
public_key, secret_key = key_pair()
signature = sign(message, secret_key)
assert verify(message, signature, public_key)