nucypher/tests/crypto/test_signature.py

95 lines
4.1 KiB
Python

"""
This file is part of nucypher.
nucypher is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
nucypher is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with nucypher. If not, see <https://www.gnu.org/licenses/>.
"""
import pytest
from cryptography.hazmat.backends.openssl import backend
from cryptography.hazmat.primitives import hashes
from umbral.keys import UmbralPrivateKey
from nucypher.crypto.api import ecdsa_sign, verify_ecdsa
from nucypher.crypto.signing import Signature, Signer
from nucypher.crypto.utils import recover_pubkey_from_signature, get_signature_recovery_value
def test_signature_can_verify():
privkey = UmbralPrivateKey.gen_key()
message = b"peace at dawn"
der_sig_bytes = ecdsa_sign(message, privkey)
assert verify_ecdsa(message, der_sig_bytes, privkey.get_pubkey())
signature = Signature.from_bytes(der_sig_bytes, der_encoded=True)
assert signature.verify(message, privkey.get_pubkey())
def test_signature_rs_serialization():
privkey = UmbralPrivateKey.gen_key()
message = b"peace at dawn"
der_sig_bytes = ecdsa_sign(message, privkey)
signature_from_der = Signature.from_bytes(der_sig_bytes, der_encoded=True)
rs_sig_bytes = bytes(signature_from_der)
assert len(rs_sig_bytes) == 64
signature_from_rs = Signature.from_bytes(rs_sig_bytes, der_encoded=False)
assert signature_from_rs == signature_from_der
assert signature_from_rs == der_sig_bytes
assert signature_from_rs.verify(message, privkey.get_pubkey())
@pytest.mark.parametrize('execution_number', range(100)) # Run this test 100 times.
def test_ecdsa_signature_recovery(execution_number):
privkey = UmbralPrivateKey.gen_key()
pubkey = privkey.get_pubkey()
signer = Signer(private_key=privkey)
message = b"peace at dawn"
signature = signer(message=message)
assert signature.verify(message, pubkey)
v_value = 27
pubkey_bytes = recover_pubkey_from_signature(message=message,
signature=signature,
v_value_to_try=v_value)
if not pubkey_bytes == pubkey.to_bytes():
v_value = 28
pubkey_bytes = recover_pubkey_from_signature(message=message,
signature=signature,
v_value_to_try=v_value)
assert pubkey_bytes == pubkey.to_bytes()
assert bytes([v_value - 27]) == get_signature_recovery_value(message, signature, pubkey)
hash_function = hashes.Hash(hashes.SHA256(), backend=backend)
hash_function.update(message)
prehashed_message = hash_function.finalize()
v_value = 27
pubkey_bytes = recover_pubkey_from_signature(message=prehashed_message,
signature=signature,
v_value_to_try=v_value,
is_prehashed=True)
if not pubkey_bytes == pubkey.to_bytes():
v_value = 28
pubkey_bytes = recover_pubkey_from_signature(message=prehashed_message,
signature=signature,
v_value_to_try=v_value,
is_prehashed=True)
assert pubkey_bytes == pubkey.to_bytes()
assert bytes([v_value - 27]) == get_signature_recovery_value(prehashed_message,
signature,
pubkey,
is_prehashed=True)