"""Utility functions for data encoding and conversions."""
import re
[docs]
def int_to_bytes(i: int, length: int = 1) -> bytes:
"""Encode an integer as little-endian bytes of fixed length."""
assert isinstance(i, int) # noqa: S101
return i.to_bytes(length=length, byteorder="little")
[docs]
def var_int_bytes(i: int) -> bytes:
"""Encode an integer as a Bitcoin variable length integer."""
# https://en.bitcoin.it/wiki/Protocol_specification#Variable_length_integer
if i < 0xFD:
return int_to_bytes(i)
elif i <= 0xFFFF:
return b"\xfd" + int_to_bytes(i, 2)
elif i <= 0xFFFFFFFF:
return b"\xfe" + int_to_bytes(i, 4)
else:
return b"\xff" + int_to_bytes(i, 8)
[docs]
def flatten_bin_array(array: list[bytes]) -> bytes:
"""Flattens an array of byte sequences into a single byte sequence."""
# Calculate total length of all byte sequences
total_length = sum(len(bin) for bin in array)
# Create a bytearray with the total length
flattened = bytearray(total_length)
# Copy each byte sequence into the flattened array
index = 0
for bin in array:
flattened[index : index + len(bin)] = bin
index += len(bin)
return bytes(flattened)
[docs]
def hex_to_bin(valid_hex: str) -> bytes:
"""Expecting raw hex (no 0x prefix)."""
return bytes.fromhex(valid_hex)
[docs]
def is_hex(maybe_hex: str) -> bool:
"""Returns true if the given string is valid hexadecimal (even-length and only has hexadecimal characters)."""
return bool(re.match(r"^([a-fA-F0-9]{2})*$", maybe_hex))