Utils

basicnanoclient.utils.Utils

Utility functions for working with Nano.

Source code in basicnanoclient/utils.py
class Utils():
    """Utility functions for working with Nano."""
    _CHARS = "13456789abcdefghijkmnopqrstuwxyz"
    NANO_ALPHABET = '13456789abcdefghijkmnopqrstuwxyz'
    base32_alphabet = '13456789abcdefghijkmnopqrstuwxyz'
    account_lookup = "13456789abcdefghijkmnopqrstuwxyz"
    alphabet = "13456789abcdefghijkmnopqrstuwxyz"
    account_reverse = "~0~1234567~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~89:;<=>?@AB~CDEFGHIJK~LMNO~~~~~"
    account_lookup_2 = {char: i for i, char in enumerate(NANO_ALPHABET)}

    @staticmethod
    def generate_seed() -> str:
        """Generate a new Nano seed.

        Returns:
            str: A 64-character hexadecimal string representing the Nano seed.
        """
        return binascii.hexlify(os.urandom(32)).decode()

    @staticmethod
    def dec_to_hex(d: int, n: int) -> str:
        """Convert a decimal number to a hexadecimal string.

        Args:
            d (int): The decimal number to convert.
            n (int): The number of characters in the hexadecimal string.

        Returns:
            str: The hexadecimal string.
        """
        return format(d, "0{}X".format(n*2))

    @staticmethod
    def is_hex(h: str) -> bool:
        """Check if a string is a valid hexadecimal string.

        Args:
            h (str): The string to check.

        Returns:
            bool: True if the string is a valid hexadecimal string, False otherwise
        """
        try:
            binascii.unhexlify(h)
            return True
        except binascii.Error:
            return False

    @staticmethod
    def encode_nano_base32(data: bytes) -> str:
        """Encode data to a Nano base32 string.

        Args:
            data (bytes): The data to encode.

        Returns:
            str: The encoded data.
        """
        # Convert bytes to integer
        data_int = int.from_bytes(data, byteorder="big")
        # Encode integer to Nano base32 string
        encoded = ""
        while data_int:
            data_int, remainder = divmod(data_int, 32)
            encoded = Utils.alphabet[remainder] + encoded
        # Pad with leading '1' characters
        pad_length = (len(data) * 8 + 4) // 5 - len(encoded)
        return '1' * pad_length + encoded

    @staticmethod
    def decode_nano_base32(data: str) -> bytes:
        """Decode a Nano base32 encoded string.

        Args:
            data (str): The encoded data.

        Returns:
            bytes: The decoded data.
        """
        base32_table = {char: i for i, char in enumerate(Utils.base32_alphabet)}
        bits = ''.join(f'{base32_table[char]:05b}' for char in data)
        # Remove padding bits added during encoding
        padding_length = (8 - len(bits) % 8) % 8
        bits = bits[:-padding_length] if padding_length else bits
        result = bytes(int(bits[i:i + 8], 2) for i in range(0, len(bits), 8))
        return result

    @staticmethod
    def account_encode(value):
        assert value < 32
        result = Utils.account_lookup[value]
        return result

    @staticmethod
    def account_decode(value):
        assert ord(value) >= ord('0')
        assert ord(value) <= ord('~')
        result = Utils.account_reverse[ord(value) - 0x30]
        if result != '~':
            result = ord(result) - 0x30
        return result

    @staticmethod
    def nano_address_to_public_key(address: str) -> str:
        """Convert a Nano address to a public key."""
        if address.startswith('nano_'):
            address = address[5:]
        elif address.startswith('xrb_'):
            address = address[4:]

        key_bits = BitArray()
        for char in address:
            key_bits.append(BitArray(uint=Utils.account_lookup_2[char], length=5))

        # The first four bits are dropped
        key_bits = key_bits[4:]

        # Extract exactly 32 bytes (256 bits) for the public key
        public_key_bits = key_bits[:256]
        public_key = public_key_bits.bytes.hex().lower()
        return public_key

generate_seed() staticmethod

Generate a new Nano seed.

Returns:
  • str( str ) –

    A 64-character hexadecimal string representing the Nano seed.

Source code in basicnanoclient/utils.py
@staticmethod
def generate_seed() -> str:
    """Generate a new Nano seed.

    Returns:
        str: A 64-character hexadecimal string representing the Nano seed.
    """
    return binascii.hexlify(os.urandom(32)).decode()

dec_to_hex(d, n) staticmethod

Convert a decimal number to a hexadecimal string.

Parameters:
  • d (int) –

    The decimal number to convert.

  • n (int) –

    The number of characters in the hexadecimal string.

Returns:
  • str( str ) –

    The hexadecimal string.

Source code in basicnanoclient/utils.py
@staticmethod
def dec_to_hex(d: int, n: int) -> str:
    """Convert a decimal number to a hexadecimal string.

    Args:
        d (int): The decimal number to convert.
        n (int): The number of characters in the hexadecimal string.

    Returns:
        str: The hexadecimal string.
    """
    return format(d, "0{}X".format(n*2))

is_hex(h) staticmethod

Check if a string is a valid hexadecimal string.

Parameters:
  • h (str) –

    The string to check.

Returns:
  • bool( bool ) –

    True if the string is a valid hexadecimal string, False otherwise

Source code in basicnanoclient/utils.py
@staticmethod
def is_hex(h: str) -> bool:
    """Check if a string is a valid hexadecimal string.

    Args:
        h (str): The string to check.

    Returns:
        bool: True if the string is a valid hexadecimal string, False otherwise
    """
    try:
        binascii.unhexlify(h)
        return True
    except binascii.Error:
        return False

encode_nano_base32(data) staticmethod

Encode data to a Nano base32 string.

Parameters:
  • data (bytes) –

    The data to encode.

Returns:
  • str( str ) –

    The encoded data.

Source code in basicnanoclient/utils.py
@staticmethod
def encode_nano_base32(data: bytes) -> str:
    """Encode data to a Nano base32 string.

    Args:
        data (bytes): The data to encode.

    Returns:
        str: The encoded data.
    """
    # Convert bytes to integer
    data_int = int.from_bytes(data, byteorder="big")
    # Encode integer to Nano base32 string
    encoded = ""
    while data_int:
        data_int, remainder = divmod(data_int, 32)
        encoded = Utils.alphabet[remainder] + encoded
    # Pad with leading '1' characters
    pad_length = (len(data) * 8 + 4) // 5 - len(encoded)
    return '1' * pad_length + encoded

decode_nano_base32(data) staticmethod

Decode a Nano base32 encoded string.

Parameters:
  • data (str) –

    The encoded data.

Returns:
  • bytes( bytes ) –

    The decoded data.

Source code in basicnanoclient/utils.py
@staticmethod
def decode_nano_base32(data: str) -> bytes:
    """Decode a Nano base32 encoded string.

    Args:
        data (str): The encoded data.

    Returns:
        bytes: The decoded data.
    """
    base32_table = {char: i for i, char in enumerate(Utils.base32_alphabet)}
    bits = ''.join(f'{base32_table[char]:05b}' for char in data)
    # Remove padding bits added during encoding
    padding_length = (8 - len(bits) % 8) % 8
    bits = bits[:-padding_length] if padding_length else bits
    result = bytes(int(bits[i:i + 8], 2) for i in range(0, len(bits), 8))
    return result

account_encode(value) staticmethod

Source code in basicnanoclient/utils.py
@staticmethod
def account_encode(value):
    assert value < 32
    result = Utils.account_lookup[value]
    return result

account_decode(value) staticmethod

Source code in basicnanoclient/utils.py
@staticmethod
def account_decode(value):
    assert ord(value) >= ord('0')
    assert ord(value) <= ord('~')
    result = Utils.account_reverse[ord(value) - 0x30]
    if result != '~':
        result = ord(result) - 0x30
    return result

nano_address_to_public_key(address) staticmethod

Convert a Nano address to a public key.

Source code in basicnanoclient/utils.py
@staticmethod
def nano_address_to_public_key(address: str) -> str:
    """Convert a Nano address to a public key."""
    if address.startswith('nano_'):
        address = address[5:]
    elif address.startswith('xrb_'):
        address = address[4:]

    key_bits = BitArray()
    for char in address:
        key_bits.append(BitArray(uint=Utils.account_lookup_2[char], length=5))

    # The first four bits are dropped
    key_bits = key_bits[4:]

    # Extract exactly 32 bytes (256 bits) for the public key
    public_key_bits = key_bits[:256]
    public_key = public_key_bits.bytes.hex().lower()
    return public_key