Host-customized fork of https://github.com/tecnovert/basicswap/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
128 lines
3.5 KiB
128 lines
3.5 KiB
# -*- coding: utf-8 -*- |
|
|
|
# Copyright (c) 2022-2023 tecnovert |
|
# Distributed under the MIT software license, see the accompanying |
|
# file LICENSE or http://www.opensource.org/licenses/mit-license.php. |
|
|
|
import hashlib |
|
from basicswap.contrib.segwit_addr import bech32_decode, convertbits, bech32_encode |
|
from basicswap.util.crypto import ripemd160 |
|
|
|
__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 += hashlib.sha256(hashlib.sha256(b).digest()).digest()[: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 += hashlib.sha256(hashlib.sha256(b).digest()).digest()[:4] |
|
return b58encode(b) |
|
|
|
|
|
def getKeyID(key_data: bytes) -> str: |
|
sha256_hash = hashlib.sha256(key_data).digest() |
|
return ripemd160(sha256_hash) |
|
|
|
|
|
def bech32Decode(hrp, addr): |
|
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, data): |
|
ret = bech32_encode(hrp, convertbits(data, 8, 5)) |
|
if bech32Decode(hrp, ret) is None: |
|
return None |
|
return ret |
|
|
|
|
|
def decodeAddress(address_str: str): |
|
b58_addr = b58decode(address_str) |
|
if b58_addr is not None: |
|
address = b58_addr[:-4] |
|
checksum = b58_addr[-4:] |
|
assert (hashlib.sha256(hashlib.sha256(address).digest()).digest()[:4] == checksum), 'Checksum mismatch' |
|
return b58_addr[:-4] |
|
return None |
|
|
|
|
|
def encodeAddress(address: bytes) -> str: |
|
checksum = hashlib.sha256(hashlib.sha256(address).digest()).digest() |
|
return b58encode(address + checksum[0:4]) |
|
|
|
|
|
def pubkeyToAddress(prefix: int, pubkey: bytes) -> str: |
|
return encodeAddress(bytes((prefix,)) + getKeyID(pubkey))
|
|
|