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.
98 lines
2.8 KiB
98 lines
2.8 KiB
|
|
# Descriptor checksum calculation code taken from |
|
# https://github.com/bitcoin-core/HWI/blob/master/hwilib/descriptor.py |
|
|
|
def poly_mod(c: int, val: int) -> int: |
|
""" |
|
:meta private: |
|
Function to compute modulo over the polynomial used for descriptor checksums |
|
From: https://github.com/bitcoin/bitcoin/blob/master/src/script/descriptor.cpp |
|
""" |
|
c0 = c >> 35 |
|
c = ((c & 0x7ffffffff) << 5) ^ val |
|
if (c0 & 1): |
|
c ^= 0xf5dee51989 |
|
if (c0 & 2): |
|
c ^= 0xa9fdca3312 |
|
if (c0 & 4): |
|
c ^= 0x1bab10e32d |
|
if (c0 & 8): |
|
c ^= 0x3706b1677a |
|
if (c0 & 16): |
|
c ^= 0x644d626ffd |
|
return c |
|
|
|
|
|
def descriptor_checksum(desc: str) -> str: |
|
""" |
|
Compute the checksum for a descriptor |
|
:param desc: The descriptor string to compute a checksum for |
|
:return: A checksum |
|
""" |
|
INPUT_CHARSET = "0123456789()[],'/*abcdefgh@:$%{}IJKLMNOPQRSTUVWXYZ&+-.;<=>?!^_|~ijklmnopqrstuvwxyzABCDEFGH`#\"\\ " |
|
CHECKSUM_CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l" |
|
|
|
c = 1 |
|
cls = 0 |
|
clscount = 0 |
|
for ch in desc: |
|
pos = INPUT_CHARSET.find(ch) |
|
if pos == -1: |
|
return "" |
|
c = poly_mod(c, pos & 31) |
|
cls = cls * 3 + (pos >> 5) |
|
clscount += 1 |
|
if clscount == 3: |
|
c = poly_mod(c, cls) |
|
cls = 0 |
|
clscount = 0 |
|
if clscount > 0: |
|
c = poly_mod(c, cls) |
|
for j in range(0, 8): |
|
c = poly_mod(c, 0) |
|
c ^= 1 |
|
|
|
ret = [''] * 8 |
|
for j in range(0, 8): |
|
ret[j] = CHECKSUM_CHARSET[(c >> (5 * (7 - j))) & 31] |
|
return ''.join(ret) |
|
|
|
|
|
def add_checksum(desc: str) -> str: |
|
""" |
|
Compute and attach the checksum for a descriptor |
|
:param desc: The descriptor string to add a checksum to |
|
:return: Descriptor with checksum |
|
""" |
|
return desc + "#" + descriptor_checksum(desc) |
|
|
|
|
|
def get_address_descriptor(address: str) -> str: |
|
return add_checksum("addr({})".format(address)) |
|
|
|
|
|
def get_xpub_descriptor(xpub_key: str, address_type: str) -> str: |
|
if address_type == "p2pkh": |
|
function = "pkh" |
|
elif address_type == "p2sh-p2wpkh" or address_type == "p2wpkh": |
|
function = "wpkh" |
|
else: |
|
raise NotImplementedError( |
|
"Unsupported address type {}".format(address_type)) |
|
descriptor = "{}({}/*)".format(function, xpub_key) |
|
if address_type == "p2sh-p2wpkh": |
|
descriptor = "sh({})".format(descriptor) |
|
return add_checksum(descriptor) |
|
|
|
|
|
def is_address_descriptor(desc: str) -> bool: |
|
return desc.startswith("addr(") |
|
|
|
|
|
def get_address_from_descriptor(desc: str) -> str: |
|
#example |
|
#'desc': 'addr(2MvAfRVvRAeBS18NT7mKVc1gFim169GkFC5)#h5yn9eq4', |
|
if not is_address_descriptor(desc): |
|
raise ValueError("Not an address descriptor {}".format(desc)) |
|
return desc[5:desc.find(")")] |
|
|
|
|