def classic_address_to_xaddress(classic_address: str, tag: Optional[int], is_test_network: bool) -> str: """ Returns the X-Address representation of the data. Args: classic_address: The base58 encoding of the classic address. tag: The destination tag. is_test_network: Whether it is the test network or the main network. Returns: The X-Address representation of the data. Raises: XRPLAddressCodecException: If the classic address does not have enough bytes or the tag is invalid. """ classic_address_bytes = decode_classic_address(classic_address) if len(classic_address_bytes) != 20: raise XRPLAddressCodecException("Account ID must be 20 bytes") if tag is not None and tag > MAX_32_BIT_UNSIGNED_INT: raise XRPLAddressCodecException("Invalid tag") flag = tag is not None if tag is None: tag = 0 bytestring = PREFIX_BYTES_TEST if is_test_network else PREFIX_BYTES_MAIN bytestring += classic_address_bytes encoded_tag = bytes([ flag, tag & 0xFF, tag >> 8 & 0xFF, tag >> 16 & 0xFF, tag >> 24 & 0xFF, 0, 0, 0, 0, ]) bytestring += encoded_tag return base58.b58encode_check(bytestring, alphabet=XRPL_ALPHABET).decode("utf-8")
def _decode(b58_string: str, prefix: bytes) -> bytes: """ b58_string: A base58 value prefix: The prefix prepended to the bytestring Returns the byte decoding of the base58-encoded string. """ prefix_length = len(prefix) decoded = base58.b58decode_check(b58_string, alphabet=XRPL_ALPHABET) if decoded[:prefix_length] != prefix: raise XRPLAddressCodecException("Provided prefix is incorrect") return decoded[prefix_length:]
def _get_tag_from_buffer(buffer: bytes) -> Optional[int]: """ Returns the destination tag extracted from the suffix of the X-Address. Args: buffer: The buffer to extract a destination tag from. Returns: The destination tag extracted from the suffix of the X-Address. """ flag = buffer[0] if flag >= 2: raise XRPLAddressCodecException("Unsupported X-Address") if flag == 1: # Little-endian to big-endian return (buffer[1] + buffer[2] * 0x100 + buffer[3] * 0x10000 + buffer[4] * 0x1000000) # inverse of what happens in encode if flag != 0: raise XRPLAddressCodecException("Flag must be zero to indicate no tag") if bytes.fromhex("0000000000000000") != buffer[1:9]: raise XRPLAddressCodecException("Remaining bytes must be zero") return None
def _encode(bytestring: bytes, prefix: List[int], expected_length: int) -> str: """ Returns the base58 encoding of the bytestring, with the given data prefix (which indicates type) and while ensuring the bytestring is the expected length. """ if expected_length and len(bytestring) != expected_length: error_message = """unexpected_payload_length: len(bytestring) does not match expected_length. Ensure that the bytes are a bytestring.""" raise XRPLAddressCodecException(error_message) encoded_prefix = bytes(prefix) payload = encoded_prefix + bytestring return base58.b58encode_check(payload, alphabet=XRPL_ALPHABET).decode("utf-8")
def encode_seed(entropy: bytes, encoding_type: CryptoAlgorithm) -> str: """ Returns an encoded seed. Args: entropy: Entropy bytes of SEED_LENGTH. encoding_type: Either ED25519 or SECP256K1. Returns: An encoded seed. Raises: XRPLAddressCodecException: If entropy is not of length SEED_LENGTH or the encoding type is not one of CryptoAlgorithm. """ if len(entropy) != SEED_LENGTH: raise XRPLAddressCodecException(f"Entropy must have length {SEED_LENGTH}") if encoding_type not in CryptoAlgorithm: raise XRPLAddressCodecException( f"Encoding type must be one of {CryptoAlgorithm}" ) prefix = _ALGORITHM_TO_PREFIX_MAP[encoding_type] return _encode(entropy, prefix, SEED_LENGTH)
def _is_test_address(prefix: bytes) -> bool: """ Returns whether a decoded X-Address is a test address. Args: prefix: The first 2 bytes of an X-Address. Returns: Whether a decoded X-Address is a test address. Raises: XRPLAddressCodecException: If the prefix is invalid. """ if PREFIX_BYTES_MAIN == prefix: return False if PREFIX_BYTES_TEST == prefix: return True raise XRPLAddressCodecException("Invalid X-Address: bad prefix")
def decode_seed(seed: str) -> Tuple[bytes, CryptoAlgorithm]: """ Returns (decoded seed, its algorithm). Args: seed: b58 encoding of a seed. Returns: (decoded seed, its algorithm). Raises: XRPLAddressCodecException: If the seed is invalid. """ for algorithm in CryptoAlgorithm: prefix = _ALGORITHM_TO_PREFIX_MAP[algorithm] try: decoded_result = _decode(seed, bytes(prefix)) return decoded_result, algorithm except XRPLAddressCodecException: # prefix is incorrect, wrong algorithm continue raise XRPLAddressCodecException( "Invalid seed; could not determine encoding algorithm")