# -*- coding: utf-8 -*- # Copyright (c) 2022-2024 tecnovert # Distributed under the MIT software license, see the accompanying # file LICENSE or http://www.opensource.org/licenses/mit-license.php. from basicswap.contrib.segwit_addr import bech32_decode, convertbits, bech32_encode from basicswap.util.crypto import ripemd160, sha256 __b58chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' def b58decode(v, length=None): long_value = 0 for (i, c) in enumerate(v[::-1]): ofs = __b58chars.find(c) if ofs < 0: return None long_value += ofs * (58**i) result = bytes() while long_value >= 256: div, mod = divmod(long_value, 256) result = bytes((mod,)) + result long_value = div result = bytes((long_value,)) + result nPad = 0 for c in v: if c == __b58chars[0]: nPad += 1 else: break pad = bytes((0,)) * nPad result = pad + result if length is not None and len(result) != length: return None return result def b58encode(v): long_value = 0 for (i, c) in enumerate(v[::-1]): long_value += (256**i) * c result = '' while long_value >= 58: div, mod = divmod(long_value, 58) result = __b58chars[mod] + result long_value = div result = __b58chars[long_value] + result # leading 0-bytes in the input become leading-1s nPad = 0 for c in v: if c == 0: nPad += 1 else: break return (__b58chars[0] * nPad) + result def encodeStealthAddress(prefix_byte: int, scan_pubkey: bytes, spend_pubkey: bytes) -> str: data = bytes((0x00,)) data += scan_pubkey data += bytes((0x01,)) data += spend_pubkey data += bytes((0x00,)) # number_signatures - unused data += bytes((0x00,)) # num prefix bits b = bytes((prefix_byte,)) + data b += sha256(sha256(b))[:4] return b58encode(b) def decodeWif(encoded_key: str) -> bytes: key = b58decode(encoded_key)[1:-4] if len(key) == 33: return key[:-1] return key def toWIF(prefix_byte: int, b: bytes, compressed: bool = True) -> str: b = bytes((prefix_byte,)) + b if compressed: b += bytes((0x01,)) b += sha256(sha256(b))[:4] return b58encode(b) def getKeyID(key_data: bytes) -> bytes: return ripemd160(sha256(key_data)) def bech32Decode(hrp: str, addr: str) -> bytes: hrpgot, data = bech32_decode(addr) if hrpgot != hrp: return None decoded = convertbits(data, 5, 8, False) if decoded is None or len(decoded) < 2 or len(decoded) > 40: return None return bytes(decoded) def bech32Encode(hrp: str, data: bytes) -> str: ret = bech32_encode(hrp, convertbits(data, 8, 5)) if bech32Decode(hrp, ret) is None: return None return ret def decodeAddress(address: str) -> bytes: addr_data = b58decode(address) if addr_data is None: return None prefixed_data = addr_data[:-4] checksum = addr_data[-4:] if sha256(sha256(prefixed_data))[:4] != checksum: raise ValueError('Checksum mismatch') return prefixed_data def encodeAddress(address: bytes) -> str: checksum = sha256(sha256(address)) return b58encode(address + checksum[0:4]) def pubkeyToAddress(prefix: int, pubkey: bytes) -> str: return encodeAddress(bytes((prefix,)) + getKeyID(pubkey))