Skip to content

Address API Reference

The Address module provides utilities for encoding, decoding, and validating Midnight specific Bech32m addresses.

Bech32m Encoding

noxipher.address.bech32m

Bech32m address encoding/decoding for Midnight.

Implements BIP-350 Bech32m (NOT Bech32 v0 from BIP-173). Key difference: Bech32m uses constant 0x2bc830a3 instead of 1.

HRP table from docs.midnight.network (Apr 2026): Unshielded: mn_addr, mn_addr_preprod, mn_addr_preview, mn_addr_undeployed Shielded: mn_shield-addr, mn_shield-addr_preprod, mn_shield-addr_preview, mn_shield-addr_undeployed DUST: mn_dust, mn_dust_preprod, mn_dust_preview, mn_dust_undeployed

bech32m_decode(bech)

Decode Bech32m string → (hrp, data5). Raises AddressError on failure.

Source code in src/noxipher/address/bech32m.py
def bech32m_decode(bech: str) -> tuple[str, list[int]]:
    """Decode Bech32m string → (hrp, data5). Raises AddressError on failure."""
    if any(ord(x) < 33 or ord(x) > 126 for x in bech):
        raise AddressError("Invalid character in Bech32m string")
    if bech.lower() != bech and bech.upper() != bech:
        raise AddressError("Mixed case in Bech32m string")
    bech = bech.lower()
    pos = bech.rfind("1")
    if pos < 1 or pos + 7 > len(bech):
        raise AddressError("Invalid separator position in Bech32m string")
    hrp = bech[:pos]
    data_part = bech[pos + 1 :]
    if not all(x in CHARSET for x in data_part):
        raise AddressError("Invalid character in Bech32m data part")
    data = [CHARSET.find(x) for x in data_part]
    if not _bech32m_verify_checksum(hrp, data):
        raise AddressError("Invalid Bech32m checksum")
    return hrp, data[:-6]

bech32m_encode(hrp, data5)

Encode HRP + 5-bit data to Bech32m string.

Source code in src/noxipher/address/bech32m.py
def bech32m_encode(hrp: str, data5: list[int]) -> str:
    """Encode HRP + 5-bit data to Bech32m string."""
    checksum = _bech32m_create_checksum(hrp, data5)
    return hrp + "1" + "".join(CHARSET[d] for d in data5 + checksum)

decode_address(address)

Decode Bech32m address.

Returns:

Type Description
tuple[str, Network, bytes]

(addr_type, network, payload_bytes)

Source code in src/noxipher/address/bech32m.py
def decode_address(address: str) -> tuple[str, Network, bytes]:
    """
    Decode Bech32m address.

    Returns:
        (addr_type, network, payload_bytes)
    """
    hrp, data5 = bech32m_decode(address)
    info = HRP_REVERSE.get(hrp)
    if info is None:
        raise AddressError(f"Unknown HRP: {hrp}")
    payload = bytes(_convertbits(bytes(data5), 5, 8, pad=False))
    addr_type, network = info
    return addr_type, network, payload

encode_address(payload, addr_type, network)

Encode raw bytes to Bech32m address string.

Parameters:

Name Type Description Default
payload bytes

Raw address bytes (32 bytes for unshielded/dust, 64 bytes for shielded)

required
addr_type str

"unshielded" | "shielded" | "dust"

required
network Network

Target network

required

Returns:

Type Description
str

Bech32m address string (e.g. "mn_addr_preprod1...")

Source code in src/noxipher/address/bech32m.py
def encode_address(payload: bytes, addr_type: str, network: Network) -> str:
    """
    Encode raw bytes to Bech32m address string.

    Args:
        payload: Raw address bytes (32 bytes for unshielded/dust, 64 bytes for shielded)
        addr_type: "unshielded" | "shielded" | "dust"
        network: Target network

    Returns:
        Bech32m address string (e.g. "mn_addr_preprod1...")
    """
    hrp = HRP_TABLE.get((addr_type, network))
    if hrp is None:
        raise AddressError(f"Unknown address type/network: {addr_type}/{network}")
    data5 = _convertbits(payload, 8, 5, pad=True)
    return bech32m_encode(hrp, data5)

validate_address(address)

Return True if address is valid Midnight Bech32m.

Source code in src/noxipher/address/bech32m.py
def validate_address(address: str) -> bool:
    """Return True if address is valid Midnight Bech32m."""
    try:
        decode_address(address)
        return True
    except AddressError:
        return False