奇亚(Chia, XCH) 核心之 xch
地址和 puzzle_hash
之间的相互转换,这个转换应该来说是至关重要的。
以 xch
开头的 address
便于我们直观使用,而 puzzle_hash
则便于程序使用
相关的程序如下,对了,使用 Python3 写的
import io from typing import List, Optional, Tuple from typing import Any, BinaryIO def hexstr_to_bytes(input_str: str) -> bytes: """ Converts a hex string into bytes, removing the 0x if it's present. """ if input_str.startswith("0x") or input_str.startswith("0X"): return bytes.fromhex(input_str[2:]) return bytes.fromhex(input_str) def make_sized_bytes(size: int): """ Create a streamable type that subclasses "bytes" but requires instances to be a certain, fixed size. """ name = "bytes%d" % size def __new__(cls, v): v = bytes(v) if not isinstance(v, bytes) or len(v) != size: raise ValueError("bad %s initializer %s" % (name, v)) return bytes.__new__(cls, v) # type: ignore @classmethod # type: ignore def parse(cls, f: BinaryIO) -> Any: b = f.read(size) assert len(b) == size return cls(b) def stream(self, f): f.write(self) @classmethod # type: ignore def from_bytes(cls: Any, blob: bytes) -> Any: # pylint: disable=no-member f = io.BytesIO(blob) result = cls.parse(f) assert f.read() == b"" return result def __bytes__(self: Any) -> bytes: f = io.BytesIO() self.stream(f) return bytes(f.getvalue()) def __str__(self): return self.hex() def __repr__(self): return "<%s: %s>" % (self.__class__.__name__, str(self)) namespace = dict( __new__=__new__, parse=parse, stream=stream, from_bytes=from_bytes, __bytes__=__bytes__, __str__=__str__, __repr__=__repr__, ) return type(name, (bytes,), namespace) bytes32 = make_sized_bytes(32) CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l" def bech32_polymod(values: List[int]) -> int: """Internal function that computes the Bech32 checksum.""" generator = [0x3B6A57B2, 0x26508E6D, 0x1EA119FA, 0x3D4233DD, 0x2A1462B3] chk = 1 for value in values: top = chk >> 25 chk = (chk & 0x1FFFFFF) << 5 ^ value for i in range(5): chk ^= generator[i] if ((top >> i) & 1) else 0 return chk def bech32_hrp_expand(hrp: str) -> List[int]: """Expand the HRP into values for checksum computation.""" return [ord(x) >> 5 for x in hrp] + [0] + [ord(x) & 31 for x in hrp] M = 0x2BC830A3 def bech32_verify_checksum(hrp: str, data: List[int]) -> bool: return bech32_polymod(bech32_hrp_expand(hrp) + data) == M def bech32_create_checksum(hrp: str, data: List[int]) -> List[int]: values = bech32_hrp_expand(hrp) + data polymod = bech32_polymod(values + [0, 0, 0, 0, 0, 0]) ^ M return [(polymod >> 5 * (5 - i)) & 31 for i in range(6)] def bech32_encode(hrp: str, data: List[int]) -> str: """Compute a Bech32 string given HRP and data values.""" combined = data + bech32_create_checksum(hrp, data) return hrp + "1" + "".join([CHARSET[d] for d in combined]) def bech32_decode(bech: str) -> Tuple[Optional[str], Optional[List[int]]]: """Validate a Bech32 string, and determine HRP and data.""" if (any(ord(x) < 33 or ord(x) > 126 for x in bech)) or (bech.lower() != bech and bech.upper() != bech): return (None, None) bech = bech.lower() pos = bech.rfind("1") if pos < 1 or pos + 7 > len(bech) or len(bech) > 90: return (None, None) if not all(x in CHARSET for x in bech[pos + 1 :]): return (None, None) hrp = bech[:pos] data = [CHARSET.find(x) for x in bech[pos + 1 :]] if not bech32_verify_checksum(hrp, data): return (None, None) return hrp, data[:-6] def convertbits(data: List[int], frombits: int, tobits: int, pad: bool = True) -> List[int]: """General power-of-2 base conversion.""" acc = 0 bits = 0 ret = [] maxv = (1 << tobits) - 1 max_acc = (1 << (frombits + tobits - 1)) - 1 for value in data: if value < 0 or (value >> frombits): raise ValueError("Invalid Value") acc = ((acc << frombits) | value) & max_acc bits += frombits while bits >= tobits: bits -= tobits ret.append((acc >> bits) & maxv) if pad: if bits: ret.append((acc << (tobits - bits)) & maxv) elif bits >= frombits or ((acc << (tobits - bits)) & maxv): raise ValueError("Invalid bits") return ret def encode_puzzle_hash(puzzle_hash: bytes32, prefix: str) -> str: encoded = bech32_encode(prefix, convertbits(puzzle_hash, 8, 5)) return encoded def decode_puzzle_hash(address: str) -> bytes32: hrpgot, data = bech32_decode(address) if data is None: raise ValueError("Invalid Address") decoded = convertbits(data, 5, 8, False) decoded_bytes = bytes(decoded) return decoded_bytes
使用方式如下
将 xch
地址转换为 puzzle_hash
bb = hexstr_to_bytes("0xe1e45b735b87f904c85d10104191af5988449a6ddb12a913e8f3478eb028fa9c") print(encode_puzzle_hash(bytes32.from_bytes(bb),"xch"))
从 puzzle_hash
生成 xch
地址
bc = decode_puzzle_hash("xch1u8j9ku6mslusfjzazqgyryd0txyyfxndmvf2jylg7drcavpgl2wqka6kyx") print(encode_puzzle_hash(bc,"xch"))
目前尚无回复