Ejemplo n.º 1
0
def validate_transaction_signature(salt, v, r, s) -> None:
    vrs = (v, r, s)
    signature = keys.Signature(vrs=vrs)

    parts_for_sig = salt
    message = rlp.encode(parts_for_sig)

    try:
        public_key = signature.recover_public_key_from_msg(message)
    except BadSignature as e:
        raise ValidationError("Bad Signature: {0}".format(str(e)))

    if not signature.verify_msg(message, public_key):
        raise ValidationError("Invalid Signature")
Ejemplo n.º 2
0
def decode_auth_plain(
    ciphertext: bytes, privkey: datatypes.PrivateKey
) -> Tuple[datatypes.Signature, datatypes.PublicKey, bytes, int]:
    """Decode legacy pre-EIP-8 auth message format"""
    message = ecies.decrypt(ciphertext, privkey)
    if len(message) != AUTH_MSG_LEN:
        raise BadAckMessage("Unexpected size for auth message: {}".format(
            len(message)))
    signature = keys.Signature(signature_bytes=message[:SIGNATURE_LEN])
    pubkey_start = SIGNATURE_LEN + HASH_LEN
    pubkey = keys.PublicKey(message[pubkey_start:pubkey_start + PUBKEY_LEN])
    nonce_start = pubkey_start + PUBKEY_LEN
    nonce = message[nonce_start:nonce_start + HASH_LEN]
    return signature, pubkey, nonce, SUPPORTED_RLPX_VERSION
Ejemplo n.º 3
0
def decode_auth_eip8(ciphertext: bytes, privkey: datatypes.PrivateKey) -> Tuple[
        datatypes.Signature, datatypes.PublicKey, bytes, int]:
    """Decode EIP-8 auth message format"""
    # The length of the actual msg is stored in plaintext on the first two bytes.
    encoded_size = ciphertext[:2]
    auth_msg = ciphertext[2:]
    message = ecies.decrypt(auth_msg, privkey, shared_mac_data=encoded_size)
    values = rlp.decode(message, sedes=eip8_auth_sedes, strict=False)
    signature_bytes, pubkey_bytes, nonce, version = values[:4]
    return (
        keys.Signature(signature_bytes=signature_bytes),
        keys.PublicKey(pubkey_bytes),
        nonce,
        version
    )
Ejemplo n.º 4
0
def get_advertisement_by_signature(
    conn: sqlite3.Connection, signature: keys.Signature
) -> Advertisement:
    row = conn.execute(
        ADVERTISEMENT_GET_BY_SIGNATURE_QUERY, (signature.to_bytes(),)
    ).fetchone()
    if row is None:
        raise AdvertisementNotFound(f"No advertisement found: signature={signature}")

    content_key, hash_tree_root, signature_bytes, raw_expires_at = row
    expires_at = datetime.datetime.strptime(raw_expires_at, DB_DATETIME_FORMAT)
    signature = keys.Signature(signature_bytes)
    return Advertisement(
        content_key, hash_tree_root, expires_at, signature.v, signature.r, signature.s,
    )
Ejemplo n.º 5
0
def _unpack_v4(
    message: bytes
) -> Tuple[datatypes.PublicKey, int, Tuple[Any, ...], Hash32]:
    """Unpack a discovery v4 UDP message received from a remote node.

    Returns the public key used to sign the message, the cmd ID, payload and hash.
    """
    message_hash = Hash32(message[:MAC_SIZE])
    if message_hash != keccak(message[MAC_SIZE:]):
        raise WrongMAC("Wrong msg mac")
    signature = keys.Signature(message[MAC_SIZE:HEAD_SIZE])
    signed_data = message[HEAD_SIZE:]
    remote_pubkey = signature.recover_public_key_from_msg(signed_data)
    cmd_id = message[HEAD_SIZE]
    payload = tuple(rlp.decode(message[HEAD_SIZE + 1:], strict=False))
    return remote_pubkey, cmd_id, payload, message_hash
Ejemplo n.º 6
0
def get_expired_advertisements(
    conn: sqlite3.Connection, when: datetime.datetime
) -> Iterable[Advertisement]:
    for row in conn.execute(EXPIRED_ADVERTISEMENT_QUERY, (when,)):
        content_key, hash_tree_root, signature_bytes, raw_expires_at = row

        expires_at = datetime.datetime.strptime(raw_expires_at, DB_DATETIME_FORMAT)
        signature = keys.Signature(signature_bytes)
        yield Advertisement(
            content_key,
            hash_tree_root,
            expires_at,
            signature.v,
            signature.r,
            signature.s,
        )
Ejemplo n.º 7
0
def validate_block_header_signature(block_header: BaseBlockHeader) -> None:
    v = extract_signature_v(block_header.v)

    canonical_v = v - 27

    vrs = (canonical_v, block_header.r, block_header.s)
    signature = keys.Signature(vrs=vrs)

    message = block_header.get_message_for_signing()
    
    try:
        public_key = signature.recover_public_key_from_msg(message)
    except BadSignature as e:
        raise ValidationError("Bad Signature: {0}".format(str(e)))

    if not signature.verify_msg(message, public_key):
        raise ValidationError("Invalid Signature")
Ejemplo n.º 8
0
def recover(data: bytes,
            signature: Signature,
            hasher: Callable[[bytes], bytes] = eth_sign_sha3) -> Address:
    """ eth_recover address from data hash and signature """
    _hash = hasher(data)

    # ecdsa_recover accepts only standard [0,1] v's so we add support also for [27,28] here
    # anything else will raise BadSignature
    if signature[-1] >= 27:  # support (0,1,27,28) v values
        signature = Signature(signature[:-1] + bytes([signature[-1] - 27]))

    try:
        sig = keys.Signature(signature_bytes=signature)
        public_key = keys.ecdsa_recover(message_hash=_hash, signature=sig)
    except BadSignature as e:
        raise InvalidSignature from e
    return public_key.to_canonical_address()
Ejemplo n.º 9
0
def _unpack(message: bytes) -> Tuple[datatypes.PublicKey, int, List[Any], bytes]:
    """Unpack a UDP message received from a remote node.

    Returns the public key used to sign the message, the cmd ID, payload and hash.
    """
    message_hash = message[:MAC_SIZE]
    if message_hash != keccak(message[MAC_SIZE:]):
        raise WrongMAC("Wrong msg mac")
    signature = keys.Signature(message[MAC_SIZE:HEAD_SIZE])
    signed_data = message[HEAD_SIZE:]
    remote_pubkey = signature.recover_public_key_from_msg(signed_data)
    cmd_id = message[HEAD_SIZE]
    cmd = CMD_ID_MAP[cmd_id]
    payload = rlp.decode(message[HEAD_SIZE + 1:], strict=False)
    # Ignore excessive list elements as required by EIP-8.
    payload = payload[:cmd.elem_count]
    return remote_pubkey, cmd_id, payload, message_hash
Ejemplo n.º 10
0
def eth_validate(msg_hash, vrs, address):
    v, r, s = vrs
    if isinstance(v, bytes):
        v = int.from_bytes(r, byteorder="big")
    if isinstance(r, bytes):
        r = int.from_bytes(r, byteorder="big")
    if isinstance(s, bytes):
        s = int.from_bytes(s, byteorder="big")
    if v >= 27:
        v -= 27
    sig = keys.Signature(vrs=(v, r, s))
    try:
        pubkey = sig.recover_public_key_from_msg_hash(
            keccak256(b"\x19Ethereum Signed Message:\n32", msg_hash))
        return pubkey.to_checksum_address() == address
    except BadSignature:
        return False
Ejemplo n.º 11
0
def validate_transaction_signature(transaction):
    if is_eip_155_signed_transaction(transaction):
        v = extract_signature_v(transaction.v)
    else:
        v = transaction.v

    canonical_v = v - 27
    vrs = (canonical_v, transaction.r, transaction.s)
    signature = keys.Signature(vrs=vrs)
    message = transaction.get_message_for_signing()
    try:
        public_key = signature.recover_public_key_from_msg(message)
    except BadSignature as e:
        raise ValidationError("Bad Signature: {0}".format(str(e)))

    if not signature.verify_msg(message, public_key):
        raise ValidationError("Invalid Signature")
Ejemplo n.º 12
0
def extract_block_header_sender(block_header: BaseBlockHeader) -> bytes:
    if is_even(block_header.v):
        v = 28
    else:
        v = 27

    r, s = block_header.r, block_header.s

    canonical_v = v - 27
    vrs = (canonical_v, r, s)
    signature = keys.Signature(vrs=vrs)

    message = block_header.get_message_for_signing()
    
    public_key = signature.recover_public_key_from_msg(message)
    sender = public_key.to_canonical_address()
    return sender
Ejemplo n.º 13
0
def test_advertisement_partitioning(content_keys):
    advertisements = tuple(
        AdvertisementFactory(
            content_key=content_key, signature=keys.Signature(b"\x00" * 65)
        )
        for content_key in content_keys
    )
    batches = partition_advertisements(advertisements, 512)

    for batch in batches:
        ssz_payload = tuple(ad.to_sedes_payload() for ad in batch)
        encoded = ssz.encode(ssz_payload, sedes=AdvertiseSedes)
        assert len(encoded) <= 512

    for left, right in sliding_window(2, batches):
        ssz_payload = tuple(ad.to_sedes_payload() for ad in left + (right[0],))
        encoded = ssz.encode(ssz_payload, sedes=AdvertiseSedes)
        assert len(encoded) > 512
Ejemplo n.º 14
0
def get_proximate_advertisements(
    conn: sqlite3.Connection, node_id: NodeID, reverse: bool
) -> Iterable[Advertisement]:
    short_node_id = int.from_bytes(node_id, "big") >> 193
    query = ADVERTISEMENT_CLOSEST_QUERY.format(order="DESC" if reverse else "")
    for row in conn.execute(query, (short_node_id,)):
        content_key, hash_tree_root, signature_bytes, raw_expires_at = row

        expires_at = datetime.datetime.strptime(raw_expires_at, DB_DATETIME_FORMAT)
        signature = keys.Signature(signature_bytes)
        yield Advertisement(
            content_key,
            hash_tree_root,
            expires_at,
            signature.v,
            signature.r,
            signature.s,
        )
Ejemplo n.º 15
0
def extract_transaction_sender(transaction):
    if is_eip_155_signed_transaction(transaction):
        if is_even(transaction.v):
            v = 28
        else:
            v = 27
    else:
        v = transaction.v

    r, s = transaction.r, transaction.s

    canonical_v = v - 27
    vrs = (canonical_v, r, s)
    signature = keys.Signature(vrs=vrs)
    message = transaction.get_message_for_signing()
    public_key = signature.recover_public_key_from_msg(message)
    sender = public_key.to_canonical_address()
    return sender
Ejemplo n.º 16
0
def _unpack_v5(
    message: bytes
) -> Tuple[datatypes.PublicKey, int, Tuple[Any, ...], Hash32]:
    """Unpack a discovery v5 UDP message received from a remote node.

    Returns the public key used to sign the message, the cmd ID, payload and msg hash.
    """
    if not message.startswith(V5_ID_STRING):
        raise DefectiveMessage("Missing v5 version prefix")
    message_hash = keccak(message[len(V5_ID_STRING):])
    signature = keys.Signature(message[len(V5_ID_STRING):HEAD_SIZE_V5])
    body = message[HEAD_SIZE_V5:]
    remote_pubkey = signature.recover_public_key_from_msg(body)
    cmd_id = body[0]
    cmd = CMD_ID_MAP_V5[cmd_id]
    payload = tuple(rlp.decode(body[1:], strict=False))
    # Ignore excessive list elements as required by EIP-8.
    payload = payload[:cmd.elem_count]
    return remote_pubkey, cmd_id, payload, message_hash
Ejemplo n.º 17
0
def _unpack_v4(message: bytes) -> Tuple[datatypes.PublicKey, int, Tuple[Any, ...], Hash32]:
    """Unpack a discovery v4 UDP message received from a remote node.

    Returns the public key used to sign the message, the cmd ID, payload and hash.
    """
    message_hash = Hash32(message[:MAC_SIZE])
    if message_hash != keccak(message[MAC_SIZE:]):
        raise WrongMAC("Wrong msg mac")
    signature = keys.Signature(message[MAC_SIZE:HEAD_SIZE])
    signed_data = message[HEAD_SIZE:]
    remote_pubkey = signature.recover_public_key_from_msg(signed_data)
    cmd_id = message[HEAD_SIZE]
    try:
        cmd = CMD_ID_MAP[cmd_id]
    except KeyError as e:
        raise UnknownCommand(f"Invalid Command ID {cmd_id}") from e
    payload = tuple(rlp.decode(message[HEAD_SIZE + 1:], strict=False))
    # Ignore excessive list elements as required by EIP-8.
    payload = payload[:cmd.elem_count]
    return remote_pubkey, cmd_id, payload, message_hash
Ejemplo n.º 18
0
def eth_validate(
    msg_hash: bytes,
    vrs: Tuple[Union[int, bytes], Union[int, bytes], Union[int, bytes]],
    address: str,
):
    v, r, s = vrs
    if isinstance(v, bytes):
        v = int.from_bytes(v, byteorder="big")
    if isinstance(r, bytes):
        r = int.from_bytes(r, byteorder="big")
    if isinstance(s, bytes):
        s = int.from_bytes(s, byteorder="big")
    if v >= 27:
        v -= 27
    sig = keys.Signature(vrs=(v, r, s))
    try:
        pubkey = sig.recover_public_key_from_msg_hash(
            Web3.sha3(b"\x19Ethereum Signed Message:\n32" + msg_hash))
        return pubkey.to_checksum_address() == address
    except BadSignature:
        return False
Ejemplo n.º 19
0
def validate_transaction_signature(transaction: Union[BaseTransaction,
                                                      BaseReceiveTransaction],
                                   return_sender=False) -> None:

    v = extract_signature_v(transaction.v)

    canonical_v = v - 27
    vrs = (canonical_v, transaction.r, transaction.s)
    signature = keys.Signature(vrs=vrs)

    message = transaction.get_message_for_signing()

    try:
        public_key = signature.recover_public_key_from_msg(message)
    except BadSignature as e:
        raise ValidationError("Bad Signature: {0}".format(str(e)))

    if not signature.verify_msg(message, public_key):
        raise ValidationError("Invalid Signature")

    if return_sender:
        return public_key.to_canonical_address()
Ejemplo n.º 20
0
def ecrecover(computation: BaseComputation) -> BaseComputation:
    computation.consume_gas(constants.GAS_ECRECOVER,
                            reason="ECRecover Precompile")
    data = computation.msg.data_as_bytes
    raw_message_hash = data[:32]
    message_hash = pad32r(raw_message_hash)

    v_bytes = pad32r(data[32:64])
    v = big_endian_to_int(v_bytes)

    r_bytes = pad32r(data[64:96])
    r = big_endian_to_int(r_bytes)

    s_bytes = pad32r(data[96:128])
    s = big_endian_to_int(s_bytes)

    try:
        validate_lt_secpk1n(r, title="ECRecover: R")
        validate_lt_secpk1n(s, title="ECRecover: S")
        validate_lte(v, 28, title="ECRecover: V")
        validate_gte(v, 27, title="ECRecover: V")
    except ValidationError:
        return computation

    canonical_v = v - 27

    try:
        signature = keys.Signature(vrs=(canonical_v, r, s))
        public_key = signature.recover_public_key_from_msg_hash(message_hash)
    except BadSignature:
        return computation

    address = public_key.to_canonical_address()
    padded_address = pad32(address)

    computation.output = padded_address
    return computation
Ejemplo n.º 21
0
secret_sig = base56.encode(base16.decode(sig.to_hex()[2:].upper()))
vessel_img = lsbset.hide("sample.png", secret_sig, generators.eratosthenes())
vessel_img.save("sig0.png")

# 5. Hash vessel_img
vih = sha3.keccak_256(vessel_img.tobytes()).digest()


'''VERIFICATION EXAMPLE'''
# 4. Prover provides verifer with secret_sig and generator used, verifer extracts secret_sig
revealed_sig = lsbset.reveal("sig0.png", generators.eratosthenes())
# "sanity" check
# base16.encode(base56.decode(revealed_sig)).lower() == sig.to_hex()[2:]

# Convert back into a eth_key Signature
rsig = keys.Signature(bytes.fromhex(base16.encode(base56.decode(revealed_sig))))

# 5. Verifier provides nonce
nonce = b'717f4e012baa4450ccdff3477a5c652bc55f224a054712d46e60aa05022aeac3_2018-12-16T19:30:41Z'

# 6. Prover provides signed nonce to Verifier (and message ws sent at some point)
signed_nonce = pk.sign_msg(nonce)

# 7. Verifer confirms sigs match
signed_nonce.recover_public_key_from_msg(nonce) == rsig.recover_public_key_from_msg(msg)

import os
os.remove("sig0.png")
os.remove("sample.png")

Ejemplo n.º 22
0
 def get_sender(self):
     signature = keys.Signature(vrs=(self.v - V_OFFSET, self.r, self.s))
     message_for_signing = get_message_for_signing(self)
     public_key = signature.recover_public_key_from_msg(message_for_signing)
     return public_key.to_canonical_address()
def test_get_attestation(app):
    with app.app_context():
        db = get_db()
        with db.scoped_session() as session:
            setup_db(session)

            # Tests:
            # - Happy path
            # - No user_challenge
            # - Challenge not finished
            # - No disbursement
            # - Invalid oracle
            oracle_address = "0x32a10e91820fd10366AC363eD0DEa40B2e598D22"
            redis_handle.set(oracle_addresses_key, oracle_address)

            delegate_owner_wallet, signature = get_attestation(
                session,
                user_id=1,
                challenge_id="boolean_challenge_2",
                oracle_address=oracle_address,
                specifier="1",
            )

            attestation = Attestation(
                amount="5",
                oracle_address=oracle_address,
                user_address="0x38C68fF3926bf4E68289672F75ee1543117dD9B3",
                challenge_id="boolean_challenge_2",
                challenge_specifier="1",
            )

            # Test happy path

            # confirm the attestation is what we think it should be
            config_owner_wallet = shared_config["delegate"]["owner_wallet"]
            config_private_key = shared_config["delegate"]["private_key"]

            # Ensure we returned the correct owner wallet
            assert delegate_owner_wallet == config_owner_wallet

            # Ensure we can derive the owner wallet from the signed stringified attestation
            attestation_bytes = attestation.get_attestation_bytes()
            to_sign_hash = Web3.keccak(attestation_bytes)
            private_key = keys.PrivateKey(HexBytes(config_private_key))
            public_key = keys.PublicKey.from_private(private_key)
            signture_bytes = to_bytes(hexstr=signature)
            msg_signature = keys.Signature(signature_bytes=signture_bytes,
                                           vrs=None)

            recovered_pubkey = public_key.recover_from_msg_hash(
                message_hash=to_sign_hash, signature=msg_signature)

            assert (Web3.toChecksumAddress(
                recovered_pubkey.to_address()) == config_owner_wallet)

            # Test no matching user challenge
            with pytest.raises(AttestationError):
                get_attestation(
                    session,
                    user_id=1,
                    challenge_id="boolean_challenge_2",
                    oracle_address=oracle_address,
                    specifier="xyz",
                )

            # Test challenge not finished
            with pytest.raises(AttestationError):
                get_attestation(
                    session,
                    user_id=1,
                    challenge_id="boolean_challenge_3",
                    oracle_address=oracle_address,
                    specifier="1",
                )

            # Test challenge already disbursed
            with pytest.raises(AttestationError):
                get_attestation(
                    session,
                    user_id=1,
                    challenge_id="boolean_challenge_1",
                    oracle_address=oracle_address,
                    specifier="1",
                )

            # Test with bad AAO
            with pytest.raises(AttestationError):
                get_attestation(
                    session,
                    user_id=1,
                    challenge_id="boolean_challenge_2",
                    oracle_address="wrong_oracle_address",
                    specifier="1",
                )
Ejemplo n.º 24
0
 def Verify(cls, data, sign, pub):
     signature = keys.Signature(sign)
     return KeyAPI().ecdsa_verify(data, signature, pub)
Ejemplo n.º 25
0
 def _signature(self):
     return keys.Signature(
         vrs=[1 if self.v % 2 == 0 else 0, self.r, self.s])
Ejemplo n.º 26
0
 def RecoverPubBytesFromSignature(cls, data, sign):
     signature = keys.Signature(sign)
     return KeyAPI().ecdsa_recover(data, signature)
Ejemplo n.º 27
0
    def equivocation_logger(self, equivocated_block_hashes):
        """Log a reported equivocation event.

        Equivocation reports are logged into files separated by the proposers
        address. Logged information are the proposer of the blocks, the steps
        at which all blocks have been equivocated and a list of all block hashes
        with their timestamp. Additionally two representing blocks are logged
        with their RLP encoded header and related signature, which can be used
        for an equivocation proof on reporting a validator.
        """

        assert len(equivocated_block_hashes) >= 2

        blocks = [
            self.w3.eth.getBlock(block_hash)
            for block_hash in equivocated_block_hashes
        ]

        block_hashes_and_timestamp_strings = [
            BLOCK_HASH_AND_TIMESTAMP_TEMPLATE.format(
                block_hash=encode_hex(block.hash),
                block_timestamp=datetime.datetime.utcfromtimestamp(
                    block.timestamp),
            ) for block in blocks
        ]

        block_hash_and_timestamp_summary = "\n".join(
            block_hashes_and_timestamp_strings)

        # Use the first two blocks as representational data for the equivocation proof.
        block_one = get_canonicalized_block(blocks[0])
        block_two = get_canonicalized_block(blocks[1])

        proposer_address_hex = encode_hex(get_proposer(block_one))

        equivocation_report_template_variables = {
            "proposer_address":
            proposer_address_hex,
            "block_step":
            block_one.step,
            "detection_time":
            datetime.datetime.utcnow(),
            "block_hash_timestamp_summary":
            block_hash_and_timestamp_summary,
            "rlp_encoded_block_header_one":
            encode_hex(rlp_encoded_block(block_one)),
            "signature_block_header_one":
            keys.Signature(block_one.signature),
            "rlp_encoded_block_header_two":
            encode_hex(rlp_encoded_block(block_two)),
            "signature_block_header_two":
            keys.Signature(block_two.signature),
        }

        equivocation_report_file_name = (
            f"equivocation_reports_for_proposer_{proposer_address_hex}")

        with open(self.report_dir / equivocation_report_file_name,
                  "a") as equivocation_report_file:
            equivocation_report_file.write(
                EQUIVOCATION_REPORT_TEMPLATE.format(
                    **equivocation_report_template_variables))
Ejemplo n.º 28
0
 def signature(self) -> keys.Signature:
     return keys.Signature(vrs=(self.signature_v, self.signature_r,
                                self.signature_s))