def test_session_key_derivation(initiator_private_key, recipient_private_key,
                                id_nonce):
    initiator_private_key_object = PrivateKey(initiator_private_key)
    recipient_private_key_object = PrivateKey(recipient_private_key)

    initiator_public_key = initiator_private_key_object.public_key.to_bytes()
    recipient_public_key = recipient_private_key_object.public_key.to_bytes()

    initiator_node_id = keccak(
        initiator_private_key_object.public_key.to_bytes())
    recipient_node_id = keccak(
        recipient_private_key_object.public_key.to_bytes())

    initiator_session_keys = V4IdentityScheme.compute_session_keys(
        local_private_key=initiator_private_key,
        remote_public_key=recipient_public_key,
        local_node_id=initiator_node_id,
        remote_node_id=recipient_node_id,
        id_nonce=id_nonce,
        is_locally_initiated=True,
    )
    recipient_session_keys = V4IdentityScheme.compute_session_keys(
        local_private_key=recipient_private_key,
        remote_public_key=initiator_public_key,
        local_node_id=recipient_node_id,
        remote_node_id=initiator_node_id,
        id_nonce=id_nonce,
        is_locally_initiated=False,
    )

    assert initiator_session_keys.auth_response_key == recipient_session_keys.auth_response_key
    assert initiator_session_keys.encryption_key == recipient_session_keys.decryption_key
    assert initiator_session_keys.decryption_key == recipient_session_keys.encryption_key
def test_enr_public_key():
    private_key = PrivateKey(b"\x11" * 32)
    public_key = private_key.public_key.to_compressed_bytes()
    unsigned_enr = UnsignedENR(0, {
        b"id": b"v4",
        b"secp256k1": public_key,
        b"key1": b"value1",
    })
    enr = unsigned_enr.to_signed_enr(private_key.to_bytes())

    assert V4IdentityScheme.extract_public_key(unsigned_enr) == public_key
    assert V4IdentityScheme.extract_public_key(enr) == public_key
def test_enr_signature_validation():
    private_key = PrivateKey(b"\x11" * 32)
    unsigned_enr = UnsignedENR(
        0, {
            b"id": b"v4",
            b"secp256k1": private_key.public_key.to_compressed_bytes(),
            b"key1": b"value1",
        })
    enr = unsigned_enr.to_signed_enr(private_key.to_bytes())

    V4IdentityScheme.validate_enr_signature(enr)

    forged_enr = ENR(enr.sequence_number, dict(enr), b"\x00" * 64)
    with pytest.raises(ValidationError):
        V4IdentityScheme.validate_enr_signature(forged_enr)
def test_valid_id_nonce_signature_validation(private_key, id_nonce,
                                             ephemeral_key):
    ephemeral_public_key = PrivateKey(ephemeral_key).public_key.to_bytes()
    signature = V4IdentityScheme.create_id_nonce_signature(
        id_nonce=id_nonce,
        private_key=private_key,
        ephemeral_public_key=ephemeral_public_key,
    )
    public_key = PrivateKey(private_key).public_key.to_compressed_bytes()
    V4IdentityScheme.validate_id_nonce_signature(
        id_nonce=id_nonce,
        ephemeral_public_key=ephemeral_public_key,
        signature=signature,
        public_key=public_key,
    )
def test_official_auth_header_packet_preparation(tag,
                                                 auth_tag,
                                                 id_nonce,
                                                 encoded_message,
                                                 local_private_key,
                                                 auth_response_key,
                                                 encryption_key,
                                                 ephemeral_public_key,
                                                 auth_message_rlp):
    message_type_id = encoded_message[0]
    message_type = default_message_type_registry[message_type_id]
    message = rlp.decode(encoded_message[1:], message_type)
    assert message.to_bytes() == encoded_message

    id_nonce_signature = V4IdentityScheme.create_id_nonce_signature(
        id_nonce=id_nonce,
        ephemeral_public_key=ephemeral_public_key,
        private_key=local_private_key,
    )

    packet = AuthHeaderPacket.prepare(
        tag=tag,
        auth_tag=auth_tag,
        id_nonce=id_nonce,
        message=message,
        initiator_key=encryption_key,
        id_nonce_signature=id_nonce_signature,
        auth_response_key=auth_response_key,
        enr=None,
        ephemeral_public_key=ephemeral_public_key,
    )
    packet_wire_bytes = packet.to_wire_bytes()
    assert packet_wire_bytes == auth_message_rlp
def test_official_id_nonce_signature(id_nonce, ephemeral_public_key,
                                     local_secret_key, id_nonce_signature):
    created_signature = V4IdentityScheme.create_id_nonce_signature(
        id_nonce=id_nonce,
        ephemeral_public_key=ephemeral_public_key,
        private_key=local_secret_key,
    )
    assert created_signature == id_nonce_signature
def test_id_nonce_signing(private_key, id_nonce, ephemeral_key):
    ephemeral_public_key = PrivateKey(ephemeral_key).public_key.to_bytes()
    signature = V4IdentityScheme.create_id_nonce_signature(
        id_nonce=id_nonce,
        private_key=private_key,
        ephemeral_public_key=ephemeral_public_key,
    )
    signature_object = NonRecoverableSignature(signature)
    message_hash = sha256(ID_NONCE_SIGNATURE_PREFIX + id_nonce +
                          ephemeral_public_key).digest()
    assert signature_object.verify_msg_hash(message_hash,
                                            PrivateKey(private_key).public_key)
def test_enr_node_id():
    private_key = PrivateKey(b"\x11" * 32)
    unsigned_enr = UnsignedENR(
        0, {
            b"id": b"v4",
            b"secp256k1": private_key.public_key.to_compressed_bytes(),
            b"key1": b"value1",
        })
    enr = unsigned_enr.to_signed_enr(private_key.to_bytes())

    node_id = V4IdentityScheme.extract_node_id(enr)
    assert node_id == keccak(private_key.public_key.to_bytes())
def test_enr_signing():
    private_key = PrivateKey(b"\x11" * 32)
    unsigned_enr = UnsignedENR(
        0, {
            b"id": b"v4",
            b"secp256k1": private_key.public_key.to_compressed_bytes(),
            b"key1": b"value1",
        })
    signature = V4IdentityScheme.create_enr_signature(unsigned_enr,
                                                      private_key.to_bytes())

    message_hash = keccak(unsigned_enr.get_signing_message())
    assert private_key.public_key.verify_msg_hash(
        message_hash, NonRecoverableSignature(signature))
def test_official_auth_response_encryption(secret_key,
                                           id_nonce,
                                           enr,
                                           auth_response_key,
                                           ephemeral_public_key,
                                           auth_cipher_text):
    id_nonce_signature = V4IdentityScheme.create_id_nonce_signature(
        id_nonce=id_nonce,
        private_key=secret_key,
        ephemeral_public_key=ephemeral_public_key,
    )
    assert compute_encrypted_auth_response(
        auth_response_key=auth_response_key,
        id_nonce_signature=id_nonce_signature,
        enr=enr,
    ) == auth_cipher_text
def test_invalid_id_nonce_signature_validation():
    id_nonce = b"\xff" * 10
    private_key = b"\x11" * 32
    ephemeral_public_key = b"\x22" * 64
    signature = V4IdentityScheme.create_id_nonce_signature(
        id_nonce=id_nonce,
        ephemeral_public_key=ephemeral_public_key,
        private_key=private_key,
    )

    public_key = PrivateKey(private_key).public_key.to_compressed_bytes()
    different_public_key = PrivateKey(b"\x22" *
                                      32).public_key.to_compressed_bytes()
    different_id_nonce = b"\x00" * 10
    different_ephemeral_public_key = b"\x00" * 64
    assert different_public_key != public_key
    assert different_id_nonce != id_nonce

    with pytest.raises(ValidationError):
        V4IdentityScheme.validate_id_nonce_signature(
            id_nonce=id_nonce,
            ephemeral_public_key=ephemeral_public_key,
            signature=signature,
            public_key=different_public_key,
        )

    with pytest.raises(ValidationError):
        V4IdentityScheme.validate_id_nonce_signature(
            id_nonce=different_id_nonce,
            ephemeral_public_key=ephemeral_public_key,
            signature=signature,
            public_key=public_key,
        )

    with pytest.raises(ValidationError):
        V4IdentityScheme.validate_id_nonce_signature(
            id_nonce=id_nonce,
            ephemeral_public_key=different_ephemeral_public_key,
            signature=signature,
            public_key=public_key,
        )
def test_handshake_public_key_validation_invalid(public_key):
    with pytest.raises(ValidationError):
        V4IdentityScheme.validate_handshake_public_key(public_key)
def test_handshake_public_key_validation_valid(public_key):
    V4IdentityScheme.validate_handshake_public_key(public_key)
def test_handshake_key_generation():
    private_key, public_key = V4IdentityScheme.create_handshake_key_pair()
    V4IdentityScheme.validate_uncompressed_public_key(public_key)
    V4IdentityScheme.validate_handshake_public_key(public_key)
    assert PrivateKey(private_key).public_key.to_bytes() == public_key