Example #1
0
def from_signature_and_message(sig_msg_str, msg_str):
    from coincurve import PublicKey
    pk = PublicKey.from_signature_and_message(
        bytes(bytearray.fromhex(sig_msg_str)),
        bytes(bytearray.fromhex(msg_str)),
        hasher=None)
    return pk.format(compressed=False).hex()
Example #2
0
    def update_fee(self, channel_id: ChannelId, new_fee: bytes,
                   signature: bytes):
        """ Update the channel with a new fee. New_fee bytes are of the form '0.0012'.encode()"""
        # Fixme: I need a nonce for replay protection
        msg = new_fee
        signer = public_key_to_address(
            PublicKey.from_signature_and_message(signature, msg,
                                                 hasher=sha256))

        participant1, participant2 = self.channel_id_to_addresses[channel_id]
        if is_same_address(participant1, signer):
            sender = participant1
            receiver = participant2
        elif is_same_address(participant2, signer):
            sender = participant2
            receiver = participant1
        else:
            raise ValueError(
                'Signature does not match any of the participants.')

        new_fee = float(new_fee)
        channel_view = self.G[sender][receiver]['view']

        if new_fee >= self.max_fee:
            # Equal case is included to avoid a recalculation of the max fee.
            self.max_fee = new_fee
            channel_view.fee = new_fee
        elif channel_view.fee == self.max_fee:
            # O(n) operation but rarely called, amortized likely constant.
            channel_view.fee = new_fee
            self.max_fee = max(edge_data['view'].fee
                               for _, _, edge_data in self.G.edges(data=True))

        channel_view.fee = new_fee
Example #3
0
def recover_pubkey_from_signature(message: bytes,
                                  signature: Union[bytes, Signature],
                                  v_value_to_try: int,
                                  is_prehashed: bool = False) -> bytes:
    """
    Recovers a serialized, compressed public key from a signature.
    It allows to specify a potential v value, in which case it assumes the signature
    has the traditional (r,s) raw format. If a v value is not present, it assumes
    the signature has the recoverable format (r, s, v).

    :param message: Signed message
    :param signature: The signature from which the pubkey is recovered
    :param v_value_to_try: A potential v value to try
    :param is_prehashed: True if the message is already pre-hashed. Default is False, and message will be hashed with SHA256
    :return: The compressed byte-serialized representation of the recovered public key
    """

    signature = bytes(signature)
    expected_signature_size = Signature.expected_bytes_length()
    if not len(signature) == expected_signature_size:
        raise ValueError(
            f"The signature size should be {expected_signature_size} B.")

    if v_value_to_try in (0, 1, 27, 28):
        if v_value_to_try >= 27:
            v_value_to_try -= 27
        signature = signature + v_value_to_try.to_bytes(1, 'big')
    else:
        raise ValueError("Wrong v value. It should be 0, 1, 27 or 28.")

    kwargs = dict(hasher=None) if is_prehashed else {}
    pubkey = PublicKey.from_signature_and_message(serialized_sig=signature,
                                                  message=message,
                                                  **kwargs)
    return pubkey.format(compressed=True)
Example #4
0
def get_signature_recovery_value(message: bytes,
                                 signature: Union[bytes, Signature],
                                 public_key: Union[bytes, UmbralPublicKey],
                                 is_prehashed: bool = False) -> bytes:
    """
    Obtains the recovery value of a standard ECDSA signature.

    :param message: Signed message
    :param signature: The signature from which the pubkey is recovered
    :param public_key: The public key for verifying the signature
    :param is_prehashed: True if the message is already pre-hashed. Default is False, and message will be hashed with SHA256
    :return: The compressed byte-serialized representation of the recovered public key
    """

    signature = bytes(signature)
    ecdsa_signature_size = Signature.expected_bytes_length()
    if len(signature) != ecdsa_signature_size:
        raise ValueError(
            f"The signature size should be {ecdsa_signature_size} B.")

    kwargs = dict(hasher=None) if is_prehashed else {}
    for v in (0, 1):
        v_byte = bytes([v])
        recovered_pubkey = PublicKey.from_signature_and_message(
            serialized_sig=signature + v_byte, message=message, **kwargs)
        if bytes(public_key) == recovered_pubkey.format(compressed=True):
            return v_byte
    else:
        raise ValueError(
            "Signature recovery failed. "
            "Either the message, the signature or the public key is not correct"
        )
Example #5
0
async def verify_signature(message):
    """Verifies a signature of a message, return True if verified, false if not"""
    try:
        chain_id, hrp = await get_chain_info(message["sender"])
    except Exception:
        LOGGER.exception("Avalanche sender address deserialization error")
        return False

    try:
        signature = base58.b58decode(message["signature"])
        signature, status = await validate_checksum(signature)
        if not status:
            LOGGER.exception("Avalanche signature checksum error")
            return False
    except Exception:
        LOGGER.exception("Solana signature deserialization error")
        return False

    try:
        verification = await get_verification_buffer(message)
        verification = await pack_message(verification)

        public_key = PublicKey.from_signature_and_message(signature, verification)

        address = await address_from_public_key(public_key.format())
        address = await address_to_string(chain_id, hrp, address)

        result = address == message["sender"]

    except Exception as e:
        LOGGER.exception("Error processing signature for %s" % message["sender"])
        result = False

    return result
Example #6
0
def test_sign():
    msg = b'32' * 16
    assert len(msg) == 32
    sig = sign(SENDER_PRIVATE_KEY, msg)
    pubkey = PublicKey.from_signature_and_message(sig, msg, hasher=None)
    pubkey = pubkey.format(compressed=False)
    assert len(sig) == 65
    assert is_same_address(pubkey_to_addr(pubkey), SENDER_ADDR)
Example #7
0
def test_sign():
    msg = b'32' * 16
    assert len(msg) == 32
    sig = sign(SENDER_PRIVATE_KEY, msg)
    pubkey = PublicKey.from_signature_and_message(sig, msg, hasher=None)
    pubkey = pubkey.format(compressed=False)
    assert len(sig) == 65
    assert is_same_address(pubkey_to_addr(pubkey), SENDER_ADDR)
def _recover_key(msg_hash: bytes, signature: bytes, compressed: bool) -> Optional[bytes]:
    if isinstance(msg_hash, bytes) \
            and len(msg_hash) == 32 \
            and isinstance(signature, bytes) \
            and len(signature) == 65:
        return PublicKey.from_signature_and_message(signature, msg_hash, hasher=None).format(compressed)

    return None
Example #9
0
def recover_publickey(messagedata, signature):
    if len(signature) != 65:
        raise ValueError('invalid signature')

    publickey = PublicKey.from_signature_and_message(
        signature,
        messagedata,
        hasher=sha3,
    )
    return publickey.format(compressed=False)
Example #10
0
def recover_publickey(messagedata, signature, hasher=sha3):
    if len(signature) != 65:
        raise ValueError('invalid signature')

    signature = signature[:-1] + chr(signature[-1] - 27).encode()
    publickey = PublicKey.from_signature_and_message(
        signature,
        messagedata,
        hasher=hasher,
    )
    return publickey.format(compressed=False)
Example #11
0
def recover_publickey(messagedata, signature, hasher=sha3):
    if len(signature) != 65:
        raise ValueError('invalid signature')

    signature = signature[:-1] + chr(signature[-1] - 27).encode()
    publickey = PublicKey.from_signature_and_message(
        signature,
        messagedata,
        hasher=hasher,
    )
    return publickey.format(compressed=False)
Example #12
0
def addr_from_sig(sig: bytes, msg: bytes):
    assert len(sig) == 65
    # Support Ethereum's EC v value of 27 and EIP 155 values of > 35.
    if sig[-1] >= 35:
        network_id = (sig[-1] - 35) // 2
        sig = sig[:-1] + bytes([sig[-1] - 35 - 2 * network_id])
    elif sig[-1] >= 27:
        sig = sig[:-1] + bytes([sig[-1] - 27])

    receiver_pubkey = PublicKey.from_signature_and_message(sig, msg, hasher=None)
    return pubkey_to_addr(receiver_pubkey)
Example #13
0
def addr_from_sig(sig: bytes, msg: bytes):
    assert len(sig) == 65
    # Support Ethereum's EC v value of 27 and EIP 155 values of > 35.
    if sig[-1] >= 35:
        network_id = (sig[-1] - 35) // 2
        sig = sig[:-1] + bytes([sig[-1] - 35 - 2 * network_id])
    elif sig[-1] >= 27:
        sig = sig[:-1] + bytes([sig[-1] - 27])

    receiver_pubkey = PublicKey.from_signature_and_message(sig, msg, hasher=None)
    return pubkey_to_addr(receiver_pubkey)
Example #14
0
def ecdsa_verify(pubkey, signature, message):
    verify_pubkey(pubkey)
    message = sha3(message)
    try:
        pk = PublicKey.from_signature_and_message(signature,
                                                  message,
                                                  hasher=None)
    except Exception as e:
        raise exceptions.InvalidSignature() from e
    if not pk.format(compressed=False) == b'\04' + pubkey:
        raise exceptions.InvalidSignature()
    return True
Example #15
0
    def recover_pk(message, zb32_sig):
        """
        Recovers an ECDSA public key from a given message and zbase32 signature.

        Args:
            message(:obj:`bytes`): original message from where the signature was generated.
            zb32_sig(:obj:`str`): the zbase32 signature of the message.

        Returns:
           :obj:`PublicKey`: The public key if it can be recovered.

        Raises:
             :obj:`InvalidParameter`: if the message and/or signature have a wrong value.
             :obj:`SignatureError`: if a public key cannot be recovered from the given signature.
        """

        if not isinstance(message, bytes):
            raise InvalidParameter(
                "Wrong value passed as message. Received {}, expected (bytes)".
                format(type(message)))

        if not isinstance(zb32_sig, str):
            raise InvalidParameter(
                "Wrong value passed as zbase32_sig. Received {}, expected (str)"
                .format(type(zb32_sig)))

        sigrec = pyzbase32.decode_bytes(zb32_sig)

        try:
            rsig_recid = sigrec_decode(sigrec)
            pk = PublicKey.from_signature_and_message(rsig_recid,
                                                      LN_MESSAGE_PREFIX +
                                                      message,
                                                      hasher=sha256d)
            return pk

        except ValueError as e:
            # Several errors fit here: Signature length != 65, wrong recover id and failed to parse signature.
            # All of them return raise ValueError.
            raise SignatureError(
                "Cannot recover a public key from the given signature. " +
                str(e))

        except Exception as e:
            if "failed to recover ECDSA public key" in str(e):
                raise SignatureError(
                    "Cannot recover a public key from the given signature")
            else:
                raise SignatureError("Unknown exception. " + str(e))
def recover_ecdsa(message, signature):
    """Gets public key from the message and ECDSA signature."""

    if not isinstance(message, (bytes, bytearray)):
        raise TypeError(f"Invalid message")
    if len(message) != 32:
        raise ValueError(f"Invalid length message: {len(message)} != 32")
    if not isinstance(signature, (bytes, bytearray)):
        raise TypeError(f"Invalid signature key")
    if len(signature) != 65:
        raise ValueError(f"Invalid length signature key: {len(signature)} != 65")

    return PublicKey.from_signature_and_message(signature, message, hasher=None).format(
        compressed=False
    )[1:]
def public_key_from_signature(data: bytes, signature: bytes, hasher=keccak):
    """Convert an EC signature into a public key."""
    if not isinstance(signature, bytes) or len(signature) != 65:
        raise Exception('Invalid signature, must be 65 bytes')

    signature = convert_eth_signature(signature)

    try:
        signer_pubkey = PublicKey.from_signature_and_message(signature,
                                                             data,
                                                             hasher=hasher)
        return signer_pubkey
    except Exception as e:  # pylint: disable=broad-except
        # coincurve raises bare exception on verify error
        raise Exception('Invalid signature')
Example #18
0
def recover_public_key(msg_hash: bytes,
                       signature: bytes,
                       compressed: bool = True) -> bytes:
    try:
        return recover_key(msg_hash, signature)
    except Exception as e:
        _check_recoverable_error(e)
        log_warning("fail to recover_key, try coincurve")
        if isinstance(msg_hash, bytes) \
                and len(msg_hash) == 32 \
                and isinstance(signature, bytes) \
                and len(signature) == 65:
            return PublicKey.from_signature_and_message(
                signature, msg_hash, hasher=None).format(compressed)
        return None
Example #19
0
    def verify_signature(self, origin_data: bytes, signature: bytes, is_hash: bool):
        """
        1. get PublicKey from signature and message
        2. convert PublicKey address from PublicKey
        3. verify_address
        """
        hash_method = self.sha3_256 if not is_hash else None

        try:
            extract_pubkey = PublicKey.from_signature_and_message(signature,
                                                                  origin_data,
                                                                  hasher=hash_method)
            pubkey_address = extract_pubkey.format(compressed=False)
            return self.verify_address(pubkey_address)
        except Exception as e:
            raise RuntimeError(f"signature verification fail : {origin_data} {signature}\n"
                               f"{e}")
Example #20
0
    def recover_pk(message, zb32_sig):
        """
        Recovers an ECDSA public key from a given message and zbase32 signature.

        Args:
            message(:obj:`bytes`): the data to be signed.
            zb32_sig(:obj:`str`): the zbase32 signature of the message.

        Returns:
           :obj:`PublicKey`: The recovered public key.
        """

        if not isinstance(message, bytes):
            logger.error("The message must be bytes. {} received".format(
                type(message)))
            return None

        if not isinstance(zb32_sig, str):
            logger.error("The zbase32_sig must be str. {} received".format(
                type(zb32_sig)))
            return None

        sigrec = pyzbase32.decode_bytes(zb32_sig)
        rsig_recid = sigrec_decode(sigrec)

        try:
            pk = PublicKey.from_signature_and_message(rsig_recid,
                                                      LN_MESSAGE_PREFIX +
                                                      message,
                                                      hasher=sha256d)
            return pk

        except ValueError as e:
            # Several errors fit here: Signature length != 65, wrong recover id and failed to parse signature.
            # All of them return raise ValueError.
            logger.error(str(e))
            return None

        except Exception as e:
            if "failed to recover ECDSA public key" in str(e):
                logger.error("Cannot recover public key from signature".format(
                    type(rsig_recid)))
            else:
                logger.error("Unknown exception", error=e)

            return None
Example #21
0
def recover_public_key(message, signature, hasher=None):
    """
    Recovers public key from signed message
    :param message: message
    :param signature: signature
    :param hasher: hash function to use on message (usually sha256 or keccak_hash)
    :return: public key
    """

    if len(signature) != eth_common_constants.SIGNATURE_LEN:
        raise ValueError("Expected signature len of {0} but was {1}".format(
            eth_common_constants.SIGNATURE_LEN, len(signature)))

    public_key = PublicKey.from_signature_and_message(signature,
                                                      message,
                                                      hasher=hasher)
    return public_key.format(compressed=False)[1:]
Example #22
0
 def recoverMessageAddress(signature,
                           message,
                           chain_id=1,
                           prefix=None,
                           address_type=1):
     """ Verifies a signature of a hash and returns the address that signed it.
     If no address is returned, signature is bad.
     """
     message = prepareMessage(message)
     pub = PublicKey.from_signature_and_message(coincurveSig(signature),
                                                message)
     addr_hash = Address.publicKeyToHash(pub.format(),
                                         chain_id=chain_id,
                                         address_type=address_type)
     if prefix is None:
         prefix = Define.NETWORKS[chain_id]
     address = Address.addressFromHash(addr_hash, prefix=prefix)
     return address
Example #23
0
def _recover(data: bytes,
             signature: bytes,
             hasher: Callable[[bytes], bytes] = _eth_sign_sha3) -> bytes:
    """ Returns account address in canonical format which signed data """
    if len(signature) != 65:
        logger.error("invalid signature")
        return b""
    if signature[-1] >= 27:
        signature = signature[:-1] + bytes([signature[-1] - 27])
    try:
        publickey_bytes = PublicKey.from_signature_and_message(
            signature, data, hasher=hasher).format(compressed=False)
    except Exception as e:
        # secp256k1 is using bare Exception cls: raised if the recovery failed
        logger.error("error while recovering pubkey: %s", e)
        return b""

    address = _sha3(publickey_bytes[1:])[12:]
    return address
Example #24
0
def verify_signature(msg_hash: bytes, signature: bytes, sender: str) -> bool:
    if isinstance(msg_hash, bytes) \
            and len(msg_hash) == 32 \
            and isinstance(signature, bytes) \
            and len(signature) == 65:

        public_key = PublicKey.from_signature_and_message(
            serialized_sig=signature,
            message=msg_hash,
            hasher=None
        )

        address: str = address_from_pubkey(public_key.format(compressed=False))
        if address == sender:
            return True

        Logger.info(f'Expected address={sender}', "verify_signature")
        Logger.info(f'Signed address={address}', "verify_signature")

    return False
Example #25
0
def recover_pubkey_from_signature(prehashed_message,
                                  signature,
                                  v_value_to_try=None) -> bytes:
    """
    Recovers a serialized, compressed public key from a signature.
    It allows to specify a potential v value, in which case it assumes the signature
    has the traditional (r,s) raw format. If a v value is not present, it assumes
    the signature has the recoverable format (r, s, v).

    :param prehashed_message: Prehashed message
    :param signature: The signature from which the pubkey is recovered
    :param v_value_to_try: A potential v value to try
    :return: The compressed byte-serialized representation of the recovered public key
    """

    signature = bytes(signature)
    ecdsa_signature_size = Signature.expected_bytes_length()

    if not v_value_to_try:
        expected_signature_size = ecdsa_signature_size + 1
        if not len(signature) == expected_signature_size:
            raise ValueError(
                f"When not passing a v value, "
                f"the signature size should be {expected_signature_size} B.")
    elif v_value_to_try in (0, 1, 27, 28):
        expected_signature_size = ecdsa_signature_size
        if not len(signature) == expected_signature_size:
            raise ValueError(
                f"When passing a v value, "
                f"the signature size should be {expected_signature_size} B.")
        if v_value_to_try >= 27:
            v_value_to_try -= 27
        signature = signature + v_value_to_try.to_bytes(1, 'big')
    else:
        raise ValueError("Wrong v value. It should be 0, 1, 27 or 28.")

    pubkey = PublicKey.from_signature_and_message(serialized_sig=signature,
                                                  message=prehashed_message,
                                                  hasher=None)
    return pubkey.format(compressed=True)
Example #26
0
def address_from_signature(data: bytes,
                           signature: bytes,
                           hasher: Hasher = sha3) -> Address:
    """Convert an EC signature into an ethereum address"""
    if not isinstance(signature, bytes) or len(signature) != 65:
        raise InvalidSignature('Invalid signature, must be 65 bytes')
    # Support Ethereum's EC v value of 27 and EIP 155 values of > 35.
    if signature[-1] >= 35:
        network_id = (signature[-1] - 35) // 2
        signature = signature[:-1] + bytes(
            [signature[-1] - 35 - 2 * network_id])
    elif signature[-1] >= 27:
        signature = signature[:-1] + bytes([signature[-1] - 27])

    try:
        signer_pubkey = PublicKey.from_signature_and_message(signature,
                                                             data,
                                                             hasher=hasher)
        return public_key_to_address(signer_pubkey)
    except Exception as e:  # pylint: disable=broad-except
        # coincurve raises bare exception on verify error
        raise InvalidSignature('Invalid signature') from e
Example #27
0
def test(full_pubkey, transaction_hash, signature):
    print('sign_transaction_hash:', transaction_hash.hex())
    r = signature[0:32]
    s = signature[32:64]
    v = None
    for v_i in range(4):
        signed_s = signature + bytes([v_i])
        try:
            public_key_bytes = PublicKey.from_signature_and_message(
                signed_s, transaction_hash,
                hasher=None).format(compressed=False)[1:]
            # print('rec', public_key_bytes.hex())
            if full_pubkey.hex() == public_key_bytes.hex():
                v = bytes([v_i])
                print('GET V!')
                break
        except Exception as e:
            # print(e)
            pass
    r = big_endian_to_int(r)
    s = big_endian_to_int(s)
    v = ord(v)
    print('signature_r_s_v:', signature.hex() + bytes([v]).hex())
Example #28
0
    def test_verify_recoverable_sign(self):
        """Verifies recovering a signature."""

        test_requests = [
            TEST_REQUEST_TRANSFER_ICX, TEST_REQUEST_SCORE_FUNCTION_CALL,
            TEST_REQUEST_SEND_MESSAGE, TEST_REQUEST_SCORE_UPDATE,
            TEST_REQUEST_SCORE_ISNTALL
        ]

        for request in test_requests:
            # Serialize a signature
            private_key_object: PrivateKey = PrivateKey()
            private_key_bytes: bytes = private_key_object.secret

            msg = serialize(request["params"])
            message_hash = sha3_256(msg).digest()
            sign_bytes = sign(message_hash, private_key_bytes)

            public_key = PublicKey.from_signature_and_message(sign_bytes,
                                                              message_hash,
                                                              hasher=None)
            self.assertEqual(public_key.format(),
                             private_key_object.public_key.format())
Example #29
0
def sign(privkey: str, msg_hash: bytes, v: int = 0) -> bytes:
    if not isinstance(msg_hash, bytes):
        raise TypeError("sign(): msg_hash is not an instance of bytes")
    if len(msg_hash) != 32:
        raise ValueError("sign(): msg_hash has to be exactly 32 bytes")
    if not isinstance(privkey, str):
        raise TypeError("sign(): privkey is not an instance of str")
    if v not in {0, 27}:
        raise ValueError(f"sign(): got v = {v} expected 0 or 27.")

    pk = PrivateKey.from_hex(remove_0x_prefix(privkey))
    sig: bytes = pk.sign_recoverable(msg_hash, hasher=None)
    assert len(sig) == 65

    pub = pk.public_key
    recovered = PublicKey.from_signature_and_message(sig,
                                                     msg_hash,
                                                     hasher=None)
    assert pub == recovered

    sig = sig[:-1] + bytes([sig[-1] + v])

    return sig
Example #30
0
def address_from_signature(data: bytes,
                           signature: bytes,
                           hasher: Hasher = sha3) -> Address:
    """Convert an EC signature into an ethereum address"""
    if not isinstance(signature, bytes) or len(signature) != 65:
        raise InvalidSignature('Invalid signature, must be 65 bytes')
    v = signature[-1]
    # Support Ethereum's EC v value of 27,28 but also 0,1 to be in
    # sync with the values accepted by the contracts:
    # https://github.com/raiden-network/raiden-contracts/blob/aea36ce403605670edc23fe0d14cf422e2b8e69b/raiden_contracts/contracts/lib/ECVerify.sol#L27
    if v in (27, 28):
        signature = signature[:-1] + bytes([signature[-1] - 27])
    elif v not in (0, 1):
        raise InvalidSignature(
            f'Invalid signature. v value of {v} is illegal.')

    try:
        signer_pubkey = PublicKey.from_signature_and_message(signature,
                                                             data,
                                                             hasher=hasher)
        return public_key_to_address(signer_pubkey)
    except Exception as e:  # pylint: disable=broad-except
        # coincurve raises bare exception on verify error
        raise InvalidSignature('Invalid signature') from e
Example #31
0
def verify_signature(pubkey, signature, message):
    """
    Verifies signature
    :param pubkey: signing public key
    :param signature: message signature
    :param message: signature
    :return: returns True if signature is valid, False otherwise
    """

    if len(pubkey) != eth_common_constants.PUBLIC_KEY_LEN:
        raise ValueError("Pubkey is expected of len {0} but was {1}".format(
            eth_common_constants.PUBLIC_KEY_LEN, len(pubkey)))

    if len(signature) != eth_common_constants.SIGNATURE_LEN:
        raise ValueError("Signature is expected of len {0} but was {1}".format(
            eth_common_constants.PUBLIC_KEY_LEN, len(signature)))

    if not message:
        raise ValueError("Message is required")

    public_key = PublicKey.from_signature_and_message(signature,
                                                      message,
                                                      hasher=None)
    return public_key.format(compressed=False) == b"\04" + pubkey
Example #32
0
from eth_utils import decode_hex, keccak
from server import prefix, convert_eth_signature_and_data
import binascii

from coincurve import PublicKey, PrivateKey
signature_jozef_orig = decode_hex(
    'CC9E2B0B338D1BDD1328D88E6750F7CE5F7C6DEA8D73D4DE43E7755029576C1F07D8954640CB698A802729C4C31B17E9D1BF92B23A6CAEEAA2477087D5CCF3541C'
)
message = b'{"timestamp":4180,"temperature":{"val1":25,"val2":173643},"lat":{"val1":1,"val2":2},"lon":{"val1":-4,"val2":5}}'

private_key = PrivateKey()
public_key = private_key.public_key
private_key_2 = PrivateKey()
public_key_2 = private_key.public_key

# Prepare data! Message needs to be prefixed. Signature needs to be EIP converted?
signature_jozef, message = convert_eth_signature_and_data(
    signature_jozef_orig, message)

signature = private_key.sign_recoverable(prefix(message), hasher=keccak)
print(signature.hex())

public_key_recovered = PublicKey.from_signature_and_message(signature,
                                                            prefix(message),
                                                            hasher=keccak)

# Apparently verify() is never used because it doesn't do the signature schema!
def ecdsa_recover(message, signature):
    assert len(signature) == 65
    pk = PublicKey.from_signature_and_message(signature, message, hasher=None)
    return pk.format(compressed=False)[1:]