def _decode_auth(encoded_packet: bytes) -> Tuple[Union[AuthHeader, Nonce], int]: try: decoded_auth, _, message_start_index = rlp.codec.consume_item(encoded_packet, TAG_SIZE) except DecodingError as error: raise ValidationError("Packet authentication section is not proper RLP") from error if is_bytes(decoded_auth): validate_nonce(decoded_auth) return Nonce(decoded_auth), message_start_index elif is_list_like(decoded_auth): validate_length(decoded_auth, 5, "auth header") for index, element in enumerate(decoded_auth): if not is_bytes(element): raise ValidationError(f"Element {index} in auth header is not bytes: {element}") auth_header = AuthHeader( auth_tag=decoded_auth[0], id_nonce=decoded_auth[1], auth_scheme_name=decoded_auth[2], ephemeral_public_key=decoded_auth[3], encrypted_auth_response=decoded_auth[4], ) validate_auth_header(auth_header) return auth_header, message_start_index else: raise Exception("unreachable: RLP can only encode bytes and lists")
def validate_auth_header(auth_header: AuthHeader) -> None: validate_nonce(auth_header.auth_tag) if auth_header.auth_scheme_name != AUTH_SCHEME_NAME: raise ValidationError( f"Auth header uses scheme {auth_header.auth_scheme_name!r}, but only " f"{AUTH_SCHEME_NAME!r} is supported") validate_length(auth_header.id_nonce, ID_NONCE_SIZE, "id nonce")
def write(self, start_position: int, size: int, value: bytes) -> None: if size: validate_uint256(start_position) validate_uint256(size) validate_is_bytes(value) validate_length(value, length=size) validate_lte(start_position + size, maximum=len(self)) for idx, v in enumerate(value): self._bytes[start_position + idx] = v
def write(self, start_position: int, size: int, value: bytes) -> None: """ Write `value` into memory. """ if size: validate_uint256(start_position) validate_uint256(size) validate_is_bytes(value) validate_length(value, length=size) validate_lte(start_position + size, maximum=len(self)) if len(self._bytes) < start_position + size: self._bytes.extend( itertools.repeat( 0, len(self._bytes) - (start_position + size), )) for idx, v in enumerate(value): self._bytes[start_position + idx] = v
def check_pow(block_number: int, mining_hash: Hash32, mix_hash: Hash32, nonce: bytes, difficulty: int) -> None: validate_length(mix_hash, 32, title="Mix Hash") validate_length(mining_hash, 32, title="Mining Hash") validate_length(nonce, 8, title="POW Nonce") cache = get_cache(block_number) mining_output = hashimoto_light(block_number, cache, mining_hash, big_endian_to_int(nonce)) if mining_output[b'mix digest'] != mix_hash: raise ValidationError("mix hash mismatch; {0} != {1}".format( encode_hex(mining_output[b'mix digest']), encode_hex(mix_hash))) result = big_endian_to_int(mining_output[b'result']) validate_lte(result, 2**256 // difficulty, title="POW Difficulty")
def check_pow(block_number: int, mining_hash: Hash32, mix_hash: Hash32, nonce: bytes, difficulty: int) -> None: validate_length(mix_hash, 32, title="Mix Hash") validate_length(mining_hash, 32, title="Mining Hash") validate_length(nonce, 8, title="POW Nonce") cache = get_cache(block_number) mining_output = hashimoto_light(block_number, cache, mining_hash, big_endian_to_int(nonce)) if mining_output[b'mix digest'] != mix_hash: raise ValidationError( f"mix hash mismatch; expected: {encode_hex(mining_output[b'mix digest'])} " f"!= actual: {encode_hex(mix_hash)}. " f"Mix hash calculated from block #{block_number}, " f"mine hash {encode_hex(mining_hash)}, nonce {encode_hex(nonce)}" f", difficulty {difficulty}, cache hash {encode_hex(keccak(cache))}" ) result = big_endian_to_int(mining_output[b'result']) validate_lte(result, 2**256 // difficulty, title="POW Difficulty")
def test_validate_length(value, length, is_valid): if is_valid: validate_length(value, length) else: with pytest.raises(ValidationError): validate_length(value, length)
def validate_nonce(nonce: bytes) -> None: validate_length(nonce, NONCE_SIZE, "nonce")
def validate_aes128_key(key: AES128Key) -> None: validate_length(key, AES128_KEY_SIZE, "AES128 key")