3 changed files with 110 additions and 0 deletions
@ -0,0 +1,85 @@
|
||||
|
||||
# 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 Exception("Unsupported address type {}".format(address_type)) |
||||
descriptor = "{}({}/*)".format(function, xpub_key) |
||||
if address_type == "p2sh-p2wpkh": |
||||
descriptor = "sh({})".format(descriptor) |
||||
return add_checksum(descriptor) |
||||
|
||||
@ -0,0 +1,23 @@
|
||||
import jmbitcoin as btc |
||||
|
||||
|
||||
def test_address_descriptors(): |
||||
assert(btc.get_address_descriptor("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i") == |
||||
"addr(1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i)#ns3f5w84") |
||||
assert(btc.get_address_descriptor("3CMNFxN1oHBc4R1EpboAL5yzHGgE611Xou") == |
||||
"addr(3CMNFxN1oHBc4R1EpboAL5yzHGgE611Xou)#swk5gt6w") |
||||
assert(btc.get_address_descriptor("bc1qt493axn3wl4gzjxvfg03vkacre0m6f2gzfhv5t") == |
||||
"addr(bc1qt493axn3wl4gzjxvfg03vkacre0m6f2gzfhv5t)#q8mdrmlw") |
||||
|
||||
|
||||
def test_xpub_descriptors(): |
||||
assert(btc.get_xpub_descriptor( |
||||
"xpub6CMAJ67vZWVXuzjzYXUoJgWrmuvFRiqiUG4dwoXNFmJtpTH3WgviANNxGyZYo27zxbMuqhDDym6fnBxmGaYoxr6LHgNDo1eEghkXHTX4Jnx", "p2pkh") == |
||||
"pkh(xpub6CMAJ67vZWVXuzjzYXUoJgWrmuvFRiqiUG4dwoXNFmJtpTH3WgviANNxGyZYo27zxbMuqhDDym6fnBxmGaYoxr6LHgNDo1eEghkXHTX4Jnx/*)#flej8438") |
||||
assert(btc.get_xpub_descriptor( |
||||
"xpub6CMAJ67vZWVXuzjzYXUoJgWrmuvFRiqiUG4dwoXNFmJtpTH3WgviANNxGyZYo27zxbMuqhDDym6fnBxmGaYoxr6LHgNDo1eEghkXHTX4Jnx", "p2sh-p2wpkh") == |
||||
"sh(wpkh(xpub6CMAJ67vZWVXuzjzYXUoJgWrmuvFRiqiUG4dwoXNFmJtpTH3WgviANNxGyZYo27zxbMuqhDDym6fnBxmGaYoxr6LHgNDo1eEghkXHTX4Jnx/*))#f2940w8j") |
||||
assert(btc.get_xpub_descriptor( |
||||
"xpub6CMAJ67vZWVXuzjzYXUoJgWrmuvFRiqiUG4dwoXNFmJtpTH3WgviANNxGyZYo27zxbMuqhDDym6fnBxmGaYoxr6LHgNDo1eEghkXHTX4Jnx", "p2wpkh") == |
||||
"wpkh(xpub6CMAJ67vZWVXuzjzYXUoJgWrmuvFRiqiUG4dwoXNFmJtpTH3WgviANNxGyZYo27zxbMuqhDDym6fnBxmGaYoxr6LHgNDo1eEghkXHTX4Jnx/*)#keekqdjc") |
||||
|
||||
Loading…
Reference in new issue