module Eth::Signature
def dissect(signature)
-
(SignatureError)
- if signature is of unknown size.
Returns:
-
(String, String, String)
- the `r`, `s`, and `v` values.
Parameters:
-
signature
(String
) -- a concatenated Secp256k1 signature string.
def dissect(signature) signature = Util.bin_to_hex signature unless Util.hex? signature signature = Util.remove_hex_prefix signature if signature.size < 130 raise SignatureError, "Unknown signature length #{signature.size}!" end r = signature[0, 64] s = signature[64, 64] v = signature[128..] return r, s, v end
def personal_recover(message, signature, chain_id = Chain::ETHEREUM)
-
(String)
- a hexa-decimal, uncompressed public key.
Parameters:
-
chain_id
(Integer
) -- the chain ID the signature should be recovered from. -
signature
(String
) -- the hex string containing the signature. -
message
(String
) -- the message string.
def personal_recover(message, signature, chain_id = Chain::ETHEREUM) prefixed_message = prefix_message message hashed_message = Util.keccak256 prefixed_message recover hashed_message, signature, chain_id end
def prefix_message(message)
-
(String)
- an EIP-191 prefixed string.
Parameters:
-
message
(String
) -- the message string to be prefixed.
def prefix_message(message) "#{EIP191_PREFIX_BYTE}Ethereum Signed Message:\n#{message.bytesize}#{message}" end
def recover(blob, signature, chain_id = Chain::ETHEREUM)
-
(SignatureError)
- if signature is of invalid size or invalid v.
Returns:
-
(String)
- a hexa-decimal, uncompressed public key.
Parameters:
-
chain_id
(Integer
) -- the chain ID the signature should be recovered from. -
signature
(String
) -- the hex string containing the signature. -
blob
(String
) -- that arbitrary data to be recovered.
def recover(blob, signature, chain_id = Chain::ETHEREUM) context = Secp256k1::Context.new r, s, v = dissect signature v = v.to_i(16) if !Chain.ledger? v and !Chain.legacy? v min_v = 2 * chain_id + 35 raise SignatureError, "Invalid signature v byte #{v} for chain ID #{chain_id}!" if v < min_v end recovery_id = Chain.to_recovery_id v, chain_id signature_rs = Util.hex_to_bin "#{r}#{s}" recoverable_signature = context.recoverable_signature_from_compact signature_rs, recovery_id public_key = recoverable_signature.recover_public_key blob Util.bin_to_hex public_key.uncompressed end
def recover_typed_data(typed_data, signature, chain_id = Chain::ETHEREUM)
-
(String)
- a hexa-decimal, uncompressed public key.
Parameters:
-
chain_id
(Integer
) -- the chain ID the signature should be recovered from. -
signature
(String
) -- the hex string containing the signature. -
typed_data
(Array
) -- all the data in the typed data structure to be recovered.
def recover_typed_data(typed_data, signature, chain_id = Chain::ETHEREUM) hash_to_sign = Eip712.hash typed_data recover hash_to_sign, signature, chain_id end
def verify(blob, signature, public_key, chain_id = Chain::ETHEREUM)
-
(SignatureError)
- if it cannot determine the type of data or public key.
Returns:
-
(Boolean)
- true if signature matches provided public key.
Parameters:
-
chain_id
(Integer
) -- the chain ID used to sign. -
public_key
(String
) -- either a public key or an Ethereum address. -
signature
(String
) -- the hex string containing the signature. -
blob
(String
) -- that arbitrary data to be verified.
def verify(blob, signature, public_key, chain_id = Chain::ETHEREUM) recovered_key = nil if blob.instance_of? Array or blob.instance_of? Hash # recover Array from sign_typed_data recovered_key = recover_typed_data blob, signature, chain_id elsif blob.instance_of? String and blob.encoding != Encoding::ASCII_8BIT # recover message from personal_sign recovered_key = personal_recover blob, signature, chain_id elsif blob.instance_of? String and (Util.hex? blob or blob.encoding == Encoding::ASCII_8BIT) # if nothing else, recover from arbitrary signature recovered_key = recover blob, signature, chain_id end # raise if we cannot determine the data format raise SignatureError, "Unknown data format to verify: #{blob}" if recovered_key.nil? if public_key.instance_of? Address # recovering using an Eth::Address address = public_key.to_s recovered_address = Util.public_key_to_address(recovered_key).to_s return address == recovered_address elsif public_key.instance_of? Secp256k1::PublicKey # recovering using an Secp256k1::PublicKey public_hex = Util.bin_to_hex public_key.uncompressed return public_hex == recovered_key elsif public_key.size == 42 # recovering using an address String address = Address.new(public_key).to_s recovered_address = Util.public_key_to_address(recovered_key).to_s return address == recovered_address elsif public_key.size == 130 # recovering using an uncompressed public key String return public_key == recovered_key else # raise if we cannot determine the public key format used raise SignatureError, "Invalid public key or address supplied #{public_key}!" end end