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()
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
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)
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" )
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
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
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)
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)
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)
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
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')
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
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}")
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
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:]
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
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
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
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)
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
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())
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())
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
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
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
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:]