diff --git a/README.md b/README.md index 5237a854..4e730626 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,9 @@ A minimal bitcoin library for MicroPython and Python3 with a focus on embedded s Should remain minimal to fit in a microcontroller. Also easy to audit. +The core package stays focused on Bitcoin primitives and wallet formats. Optional +features live under `embit.ext`, including Liquid support and SLIP-39. + Examples can be found in [`examples/`](./examples) folder. Documentation: https://embit.rocks/ @@ -16,7 +19,9 @@ Support the project: `bc1qd4flfrxjctls9ya244u39hd67pcprhvka723gv` Requires a custom MicroPython build with extended [`hashlib`](https://github.com/diybitcoinhardware/f469-disco/tree/master/usermods/uhashlib) module and [`secp256k1`](https://github.com/diybitcoinhardware/secp256k1-embedded) bindings. -To install copy the content of `embit` folder to the board. To save some space you can remove files `embit/util/ctypes_secp256k1.py` and `embit/util/pyhashlib.py` - they are used only in Python3. +To install, copy the content of the `embit` folder to the board. For a core-only +deployment you can omit `embit/ext`. To save some space you can also remove +`embit/util/ctypes_secp256k1.py` - it is used only in Python3. ## Python 3 @@ -26,7 +31,7 @@ To install in development mode (editable) clone and run `pip3 install -e .` from PyPi installation includes prebuilt libraries for common platforms (win, macos, linux, raspi) - see [`src/embit/util/prebuilt/`](./src/embit/util/prebuilt/) folder. Library is built from [libsecp-zkp](https://github.com/ElementsProject/secp256k1-zkp) fork for Liquid support, but will work with pure [libsecp256k1](https://github.com/bitcoin-core/secp256k1) as well - just Liquid functionality doesn't work. If it fails to use the prebuilt or system library it will fallback to pure python implementation. -If you want to build the lib yourself, see: [Building secp256k1 for `embit`](/secp256k1/README.md). +If you want to build the lib yourself, see: [Building secp256k1 for `embit`](./secp256k1/README.md). ## Using non-English BIP39 wordlists @@ -87,6 +92,13 @@ Run tests with desktop python: pytest ``` +Run only the core or extension suites: + +```sh +pytest tests/core +pytest tests/ext +``` + Run tests with micropython: ```sh diff --git a/docs/README.md b/docs/README.md index 4663db02..f81d3574 100644 --- a/docs/README.md +++ b/docs/README.md @@ -9,9 +9,9 @@ For cryptography it uses [libsecp256k1](https://github.com/bitcoin-core/secp256k - [BIP-39](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki), [BIP-32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki) key derivation (API docs: [bip39](./api/bip39.md), [bip32](./api/bip32.md)) - parsing and signing [PSBT](https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki) transactions - both version 1 and 2 ([API docs](./api/psbt.md)) - signing with custom SIGHASH flags -- Descriptors and miniscript support ([API docs](./api/descriptor.md)) -- SLIP-39 Shamir Secret Sharing scheme (experimental, [API docs](./api/slip39.md)) -- Liquid network support (experimental, [API docs](./api/liquid/README.md)) +- Descriptors and miniscript support ([API docs](./api/descriptor/README.md)) +- SLIP-39 Shamir Secret Sharing scheme (`embit.ext.slip39`, experimental, [API docs](./api/ext/slip39.md)) +- Liquid network support (`embit.ext.liquid`, experimental, [API docs](./api/ext/liquid/README.md)) - Taproot support (in progress, experimental) ## Installation @@ -23,7 +23,10 @@ pip3 install embit **Micropython:** requires custom build with C bindings to hashlib and secp256k1. Docs TBD, see examples for now: [stm32](https://github.com/diybitcoinhardware/f469-disco), [RiscV](https://github.com/stepansnigirev/MaixPy), [esp32](https://github.com/stepansnigirev/esp32_embit) - +The full Python package includes both core modules and optional extensions under +`embit.ext`. Core-only MicroPython or vendored deployments can omit `embit/ext`. + + ## Basic usage diff --git a/docs/api/README.md b/docs/api/README.md index cdba1aa1..046d608b 100644 --- a/docs/api/README.md +++ b/docs/api/README.md @@ -45,7 +45,7 @@ Library is splitted into modules, list of modules sorted by topic: **Keys:** -- [ec](./ec.md) - individual elliptic curve keys (`PrivateKey`, `PublicKey`) and signatures (`Signature`, `SchnorrSig`) +- [ec](./ec/README.md) - individual elliptic curve keys (`PrivateKey`, `PublicKey`) and signatures (`Signature`, `SchnorrSig`) - [bip39](./bip39.md) - helper functions for mnemonics - [bip32](./bip32.md) - extended private and public keys (`HDKey`) @@ -69,5 +69,5 @@ Library is splitted into modules, list of modules sorted by topic: - [hashes](./hashes.md) - common bitcoin hash functions like `tagged_hash`, `double_sha256` etc **Extensions / experimental:** -- [liquid](./liquid/README.md) - support for confidential assets, liquid transactions, blinded descriptors and psets (elements version of psbt) -- [slip39](./slip39.md) - shamir secret sharing scheme +- [liquid](./ext/liquid/README.md) - `embit.ext.liquid` support for confidential assets, liquid transactions, blinded descriptors and psets (elements version of psbt) +- [slip39](./ext/slip39.md) - `embit.ext.slip39` shamir secret sharing scheme diff --git a/docs/api/_sidebar.md b/docs/api/_sidebar.md index 0dabee59..9c2646b7 100644 --- a/docs/api/_sidebar.md +++ b/docs/api/_sidebar.md @@ -16,6 +16,6 @@ - [bech32](/api/bech32.md) - [compact](/api/compact.md) - [hashes](/api/hashes.md) - - [liquid](/api/liquid/README.md) - - [slip39](/api/slip39.md) -- [Recepies](/recepies/README.md) \ No newline at end of file + - [liquid](/api/ext/liquid/README.md) + - [slip39](/api/ext/slip39.md) +- [Recepies](/recepies/README.md) diff --git a/docs/api/ec/_sidebar.md b/docs/api/ec/_sidebar.md index 873bc636..42f72ca9 100644 --- a/docs/api/ec/_sidebar.md +++ b/docs/api/ec/_sidebar.md @@ -20,6 +20,6 @@ - [bech32](/api/bech32.md) - [compact](/api/compact.md) - [hashes](/api/hashes.md) - - [liquid](/api/liquid/README.md) - - [slip39](/api/slip39.md) -- [Recepies](/recepies/README.md) \ No newline at end of file + - [liquid](/api/ext/liquid/README.md) + - [slip39](/api/ext/slip39.md) +- [Recepies](/recepies/README.md) diff --git a/docs/api/ec/public_key.md b/docs/api/ec/public_key.md index 96dddb8f..c285ea2e 100644 --- a/docs/api/ec/public_key.md +++ b/docs/api/ec/public_key.md @@ -125,7 +125,7 @@ Verifies Schnorr signature against the message. **Arguments** -- `sig` - Instance of [`SchnorrSig`](./shcnorr_sig.md) to verify +- `sig` - Instance of [`SchnorrSig`](./schnorr_sig.md) to verify - `msg` - `32`-byte hash of the message to verify against. **Returns** diff --git a/docs/api/ext/liquid/README.md b/docs/api/ext/liquid/README.md new file mode 100644 index 00000000..6ecbf168 --- /dev/null +++ b/docs/api/ext/liquid/README.md @@ -0,0 +1,4 @@ +# Liquid network + +Liquid support is an optional extension. Import Liquid modules from +`embit.ext.liquid`. diff --git a/docs/api/ext/slip39.md b/docs/api/ext/slip39.md new file mode 100644 index 00000000..6ebe6773 --- /dev/null +++ b/docs/api/ext/slip39.md @@ -0,0 +1,3 @@ +# Shamir Secret Sharing scheme + +SLIP-39 support is an optional extension. Import it from `embit.ext.slip39`. diff --git a/docs/api/liquid/README.md b/docs/api/liquid/README.md deleted file mode 100644 index e66859b3..00000000 --- a/docs/api/liquid/README.md +++ /dev/null @@ -1 +0,0 @@ -# Liquid network \ No newline at end of file diff --git a/docs/api/networks.md b/docs/api/networks.md index 3395a3d5..d699477e 100644 --- a/docs/api/networks.md +++ b/docs/api/networks.md @@ -32,7 +32,7 @@ Here is a list of keys for `NETWORKS['main']`: } ``` -> If you are using Liquid you should also check out [`liquid.networks`](./liquid/networks.md) module. +> If you are using Liquid you should also check out the `embit.ext.liquid.networks` module. If you want to add any bitcoin-compatible altcoin (doge, litecoin, whatever) - just add a new network dict to `embit.networks.NETWORKS`. @@ -82,4 +82,4 @@ sc = script.p2wpkh(prv) print(sc.address(net)) # >>> bcrt1qsvsxz8lsxg3rc86tk8am6g53l54n7s7eq98mfg -``` \ No newline at end of file +``` diff --git a/docs/api/slip39.md b/docs/api/slip39.md deleted file mode 100644 index f19734c9..00000000 --- a/docs/api/slip39.md +++ /dev/null @@ -1 +0,0 @@ -# Shamir Secret Sharing scheme \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index b37b810d..563ae336 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -52,12 +52,13 @@ embit = ["util/prebuilt/*"] [tool.pytest.ini_options] addopts = "--cov=embit" testpaths = [ - "tests/tests", + "tests/core", + "tests/ext", ] [tool.coverage.run] omit = [ - "*/liquid/*", + "*/ext/liquid/*", ] [tool.mypy] @@ -74,4 +75,3 @@ warn_return_any = true warn_unreachable = true warn_unused_configs = true no_implicit_reexport = false - diff --git a/src/embit/descriptor/miniscript.py b/src/embit/descriptor/miniscript.py index 9783afc1..612dc27c 100644 --- a/src/embit/descriptor/miniscript.py +++ b/src/embit/descriptor/miniscript.py @@ -87,7 +87,7 @@ def wrapped(m_script): def read_arguments(cls, s, taproot=False): args = [] if cls.NARGS is None: - if type(cls.ARGCLS) == tuple: + if isinstance(cls.ARGCLS, tuple): firstcls, nextcls = cls.ARGCLS else: firstcls, nextcls = cls.ARGCLS, cls.ARGCLS @@ -901,7 +901,7 @@ def inner_compile(self): def __len__(self): return len(self.arg) + 1 - + def verify(self): super().verify() if self.arg.type != "V": diff --git a/src/embit/ext/__init__.py b/src/embit/ext/__init__.py new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/src/embit/ext/__init__.py @@ -0,0 +1 @@ + diff --git a/src/embit/liquid/__init__.py b/src/embit/ext/liquid/__init__.py similarity index 100% rename from src/embit/liquid/__init__.py rename to src/embit/ext/liquid/__init__.py diff --git a/src/embit/liquid/addresses.py b/src/embit/ext/liquid/addresses.py similarity index 98% rename from src/embit/liquid/addresses.py rename to src/embit/ext/liquid/addresses.py index 8ae2a328..eafa0d48 100644 --- a/src/embit/liquid/addresses.py +++ b/src/embit/ext/liquid/addresses.py @@ -1,4 +1,4 @@ -from .. import bech32, ec, script, base58 +from ... import bech32, ec, script, base58 from . import blech32 from .networks import NETWORKS diff --git a/src/embit/liquid/blech32.py b/src/embit/ext/liquid/blech32.py similarity index 100% rename from src/embit/liquid/blech32.py rename to src/embit/ext/liquid/blech32.py diff --git a/src/embit/liquid/blip32.py b/src/embit/ext/liquid/blip32.py similarity index 92% rename from src/embit/liquid/blip32.py rename to src/embit/ext/liquid/blip32.py index 1d49471d..5f0117b2 100644 --- a/src/embit/liquid/blip32.py +++ b/src/embit/ext/liquid/blip32.py @@ -1,6 +1,5 @@ """BIP-32 for blinding keys. Non-standard yet!!!""" -import sys -from .. import bip32, ec +from ... import bip32, ec from .networks import NETWORKS import hmac diff --git a/src/embit/liquid/descriptor.py b/src/embit/ext/liquid/descriptor.py similarity index 96% rename from src/embit/liquid/descriptor.py rename to src/embit/ext/liquid/descriptor.py index 23829315..1da28421 100644 --- a/src/embit/liquid/descriptor.py +++ b/src/embit/ext/liquid/descriptor.py @@ -1,13 +1,13 @@ -from .. import ec -from ..descriptor.descriptor import Descriptor -from ..descriptor.base import DescriptorBase -from ..descriptor.errors import DescriptorError -from ..descriptor.arguments import Key +from ... import ec +from ...descriptor.descriptor import Descriptor +from ...descriptor.base import DescriptorBase +from ...descriptor.errors import DescriptorError +from ...descriptor.arguments import Key from .networks import NETWORKS from .addresses import address from . import slip77 -from ..hashes import tagged_hash, sha256 -from ..misc import secp256k1 +from ...hashes import tagged_hash, sha256 +from ...misc import secp256k1 class LDescriptor(Descriptor): diff --git a/src/embit/liquid/finalizer.py b/src/embit/ext/liquid/finalizer.py similarity index 94% rename from src/embit/liquid/finalizer.py rename to src/embit/ext/liquid/finalizer.py index d8faaec4..10df62a7 100644 --- a/src/embit/liquid/finalizer.py +++ b/src/embit/ext/liquid/finalizer.py @@ -1,6 +1,6 @@ -from .. import ec -from ..script import Witness, Script -from .transaction import TxOutWitness, Proof, LTransaction +from ... import ec +from ...script import Witness, Script +from .transaction import LTransaction def parse_multisig(sc): diff --git a/src/embit/liquid/networks.py b/src/embit/ext/liquid/networks.py similarity index 98% rename from src/embit/liquid/networks.py rename to src/embit/ext/liquid/networks.py index 2fa08378..6984c07c 100644 --- a/src/embit/liquid/networks.py +++ b/src/embit/ext/liquid/networks.py @@ -1,4 +1,4 @@ -from .. import networks +from ... import networks const = lambda x: x diff --git a/src/embit/liquid/pset.py b/src/embit/ext/liquid/pset.py similarity index 99% rename from src/embit/liquid/pset.py rename to src/embit/ext/liquid/pset.py index 290c59ac..9a79b0eb 100644 --- a/src/embit/liquid/pset.py +++ b/src/embit/ext/liquid/pset.py @@ -3,12 +3,10 @@ if sys.implementation.name == "micropython": import secp256k1 else: - from ..util import secp256k1 + from ...util import secp256k1 -from .. import compact, hashes -from ..psbt import * -from collections import OrderedDict -from io import BytesIO +from ... import hashes +from ...psbt import * from .transaction import ( LTransaction, LTransactionOutput, @@ -22,7 +20,8 @@ unblind, ) from . import slip77 -import hashlib, gc +import hashlib +import gc class LInputScope(InputScope): diff --git a/src/embit/liquid/psetview.py b/src/embit/ext/liquid/psetview.py similarity index 99% rename from src/embit/liquid/psetview.py rename to src/embit/ext/liquid/psetview.py index 70dda48e..405b7dd4 100644 --- a/src/embit/liquid/psetview.py +++ b/src/embit/ext/liquid/psetview.py @@ -1,4 +1,4 @@ -from ..psbtview import * +from ...psbtview import * from .pset import * import hashlib @@ -232,7 +232,7 @@ def sighash_segwit( h.update(inp.sequence.to_bytes(4, "little")) if inp.has_issuance: inp.asset_issuance.hash_to(h) - if not (sh in [SIGHASH.NONE, SIGHASH.SINGLE]): + if sh not in [SIGHASH.NONE, SIGHASH.SINGLE]: h.update(hashlib.sha256(self.hash_outputs()).digest()) if hash_rangeproofs: h.update(hashlib.sha256(self.hash_rangeproofs()).digest()) diff --git a/src/embit/liquid/slip77.py b/src/embit/ext/liquid/slip77.py similarity index 93% rename from src/embit/liquid/slip77.py rename to src/embit/ext/liquid/slip77.py index bb8b7221..300aa050 100644 --- a/src/embit/liquid/slip77.py +++ b/src/embit/ext/liquid/slip77.py @@ -1,5 +1,5 @@ import hmac -from ..ec import PrivateKey +from ...ec import PrivateKey DOMAIN = b"Symmetric key seed" LABEL = b"SLIP-0077" diff --git a/src/embit/liquid/transaction.py b/src/embit/ext/liquid/transaction.py similarity index 98% rename from src/embit/liquid/transaction.py rename to src/embit/ext/liquid/transaction.py index ca7af0a5..2821328a 100644 --- a/src/embit/liquid/transaction.py +++ b/src/embit/ext/liquid/transaction.py @@ -1,16 +1,14 @@ import sys -import io -from .. import compact -from ..script import Script, Witness -from .. import hashes -from ..transaction import * -from ..base import EmbitBase +from ... import compact +from ...script import Script, Witness +from ...transaction import * +from ...base import EmbitBase import hashlib if sys.implementation.name == "micropython": import secp256k1 else: - from ..util import secp256k1 + from ...util import secp256k1 class LSIGHASH(SIGHASH): @@ -369,7 +367,7 @@ def sighash_segwit( h.update(inp.sequence.to_bytes(4, "little")) if inp.has_issuance: inp.asset_issuance.hash_to(h) - if not (sh in [SIGHASH.NONE, SIGHASH.SINGLE]): + if sh not in [SIGHASH.NONE, SIGHASH.SINGLE]: h.update(hashlib.sha256(self.hash_outputs()).digest()) if hash_rangeproofs: h.update(hashlib.sha256(self.hash_rangeproofs()).digest()) diff --git a/src/embit/slip39.py b/src/embit/ext/slip39.py similarity index 99% rename from src/embit/slip39.py rename to src/embit/ext/slip39.py index 86927b39..c31283dd 100644 --- a/src/embit/slip39.py +++ b/src/embit/ext/slip39.py @@ -1,7 +1,7 @@ import hmac import hashlib -from .bip39 import mnemonic_from_bytes, mnemonic_to_bytes -from .misc import secure_randint +from ..bip39 import mnemonic_from_bytes, mnemonic_to_bytes +from ..misc import secure_randint from .wordlists.slip39 import SLIP39_WORDS diff --git a/src/embit/ext/wordlists/__init__.py b/src/embit/ext/wordlists/__init__.py new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/src/embit/ext/wordlists/__init__.py @@ -0,0 +1 @@ + diff --git a/src/embit/wordlists/slip39.py b/src/embit/ext/wordlists/slip39.py similarity index 100% rename from src/embit/wordlists/slip39.py rename to src/embit/ext/wordlists/slip39.py diff --git a/src/embit/ext/wordlists/uslip39.py b/src/embit/ext/wordlists/uslip39.py new file mode 100644 index 00000000..eff65159 --- /dev/null +++ b/src/embit/ext/wordlists/uslip39.py @@ -0,0 +1,4 @@ +from ...wordlists.base import WordlistBase as _WordlistBase +import uembit as _uembit + +SLIP39_WORDS = _WordlistBase(_uembit.ext.wordlists.slip39) diff --git a/src/embit/misc.py b/src/embit/misc.py index 97669ade..9c5e7162 100644 --- a/src/embit/misc.py +++ b/src/embit/misc.py @@ -4,9 +4,9 @@ # implementation-specific functions and libraries: if sys.implementation.name == "micropython": from micropython import const - import secp256k1 + import secp256k1 as secp256k1 else: - from .util import secp256k1 + from .util import secp256k1 as secp256k1 def const(x): return x diff --git a/src/embit/transaction.py b/src/embit/transaction.py index 6eec9b87..4ff02850 100644 --- a/src/embit/transaction.py +++ b/src/embit/transaction.py @@ -282,7 +282,7 @@ def sighash_segwit(self, input_index, script_pubkey, value, sighash=SIGHASH.ALL) h.update(script_pubkey.serialize()) h.update(int(value).to_bytes(8, "little")) h.update(inp.sequence.to_bytes(4, "little")) - if not (sh in [SIGHASH.NONE, SIGHASH.SINGLE]): + if sh not in [SIGHASH.NONE, SIGHASH.SINGLE]: h.update(hashlib.sha256(self.hash_outputs()).digest()) elif sh == SIGHASH.SINGLE and input_index < len(self.vout): h.update( diff --git a/src/embit/util/ctypes_secp256k1.py b/src/embit/util/ctypes_secp256k1.py index 8068355e..43448cd9 100644 --- a/src/embit/util/ctypes_secp256k1.py +++ b/src/embit/util/ctypes_secp256k1.py @@ -1,4 +1,5 @@ -import ctypes, os +import ctypes +import os import ctypes.util import platform import threading @@ -7,14 +8,12 @@ cast, byref, c_char, - c_byte, c_int, c_uint, c_char_p, c_size_t, c_void_p, c_uint64, - create_string_buffer, CFUNCTYPE, POINTER, ) @@ -730,7 +729,7 @@ def _hashfn(out, x, y): y = ctypes.string_at(y, 32) try: res = hashfn(x, y, data) - except Exception as e: + except Exception: return 0 out = cast(out, POINTER(c_char * 32)) out.contents.value = res diff --git a/src/embit/util/secp256k1.py b/src/embit/util/secp256k1.py index a3ed8d9a..cb00df2b 100644 --- a/src/embit/util/secp256k1.py +++ b/src/embit/util/secp256k1.py @@ -1,6 +1,5 @@ try: # if it's micropython - from micropython import const from secp256k1 import * except: # we are in python diff --git a/src/embit/wordlists/uslip39.py b/src/embit/wordlists/uslip39.py deleted file mode 100644 index b3bebadc..00000000 --- a/src/embit/wordlists/uslip39.py +++ /dev/null @@ -1,4 +0,0 @@ -from .base import WordlistBase as _WordlistBase -import uembit as _uembit - -SLIP39_WORDS = _WordlistBase(_uembit.wordlists.slip39) diff --git a/tests/tests/__init__.py b/tests/core/__init__.py similarity index 89% rename from tests/tests/__init__.py rename to tests/core/__init__.py index 2593ae54..a9940c27 100644 --- a/tests/tests/__init__.py +++ b/tests/core/__init__.py @@ -1,3 +1,4 @@ +# ruff: noqa: F403 import sys from .test_ecc import * from .test_base58 import * @@ -5,7 +6,6 @@ from .test_bip32 import * from .test_psbt import * from .test_bip39 import * -from .test_slip39 import * from .test_descriptor import * from .test_psbtview import * from .test_taproot import * @@ -18,4 +18,3 @@ from .test_ecdh import * from .test_ripemd160 import * from .test_bindings import * - from .test_threading import * diff --git a/tests/tests/data/bip39_es.py b/tests/core/data/bip39_es.py similarity index 100% rename from tests/tests/data/bip39_es.py rename to tests/core/data/bip39_es.py diff --git a/tests/tests/data/finalizer.py b/tests/core/data/finalizer.py similarity index 100% rename from tests/tests/data/finalizer.py rename to tests/core/data/finalizer.py diff --git a/tests/tests/test_base58.py b/tests/core/test_base58.py similarity index 100% rename from tests/tests/test_base58.py rename to tests/core/test_base58.py diff --git a/tests/tests/test_bech32.py b/tests/core/test_bech32.py similarity index 100% rename from tests/tests/test_bech32.py rename to tests/core/test_bech32.py diff --git a/tests/tests/test_bindings.py b/tests/core/test_bindings.py similarity index 99% rename from tests/tests/test_bindings.py rename to tests/core/test_bindings.py index 4dae0e43..7d15c189 100644 --- a/tests/tests/test_bindings.py +++ b/tests/core/test_bindings.py @@ -1,4 +1,4 @@ -from binascii import unhexlify, hexlify +from binascii import hexlify from unittest import TestCase from embit.util import py_secp256k1 from embit.util import ctypes_secp256k1 diff --git a/tests/tests/test_bip32.py b/tests/core/test_bip32.py similarity index 87% rename from tests/tests/test_bip32.py rename to tests/core/test_bip32.py index 4a74b72d..ce8cdbac 100644 --- a/tests/tests/test_bip32.py +++ b/tests/core/test_bip32.py @@ -6,7 +6,10 @@ from embit.ec import ECError from unittest import TestCase -HARD = lambda x: x + 0x80000000 + +def HARD(x): + return x + 0x80000000 + SEEDS = [ "000102030405060708090a0b0c0d0e0f", @@ -17,109 +20,106 @@ DERIVE_VECTORS = [ # Vector 1: https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#test-vector-1 - ( # Chain m + ( # Chain m SEEDS[0], [], "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi", "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8", ), - ( # Chain m/0H + ( # Chain m/0H SEEDS[0], [HARD(0)], "xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7", "xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw", ), - ( # Chain m/0H/1 + ( # Chain m/0H/1 SEEDS[0], [HARD(0), 1], "xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs", "xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ", ), - ( # Chain m/0H/1/2H + ( # Chain m/0H/1/2H SEEDS[0], [HARD(0), 1, HARD(2)], "xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM", "xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5", ), - ( # Chain m/0H/1/2H/2 + ( # Chain m/0H/1/2H/2 SEEDS[0], [HARD(0), 1, HARD(2), 2], "xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334", "xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV", ), - ( # Chain m/0H/1/2H/2/1000000000 + ( # Chain m/0H/1/2H/2/1000000000 SEEDS[0], [HARD(0), 1, HARD(2), 2, 1000000000], "xprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76", "xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy", ), - # Vector 2: https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#test-vector-2 - ( # Chain m + ( # Chain m SEEDS[1], [], "xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U", "xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB", ), - ( # Chain m/0 + ( # Chain m/0 SEEDS[1], [0], "xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt", "xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH", ), - ( # Chain m/0/2147483647H + ( # Chain m/0/2147483647H SEEDS[1], [0, HARD(2147483647)], "xprv9wSp6B7kry3Vj9m1zSnLvN3xH8RdsPP1Mh7fAaR7aRLcQMKTR2vidYEeEg2mUCTAwCd6vnxVrcjfy2kRgVsFawNzmjuHc2YmYRmagcEPdU9", "xpub6ASAVgeehLbnwdqV6UKMHVzgqAG8Gr6riv3Fxxpj8ksbH9ebxaEyBLZ85ySDhKiLDBrQSARLq1uNRts8RuJiHjaDMBU4Zn9h8LZNnBC5y4a", ), - ( # Chain m/0/2147483647H/1 + ( # Chain m/0/2147483647H/1 SEEDS[1], [0, HARD(2147483647), 1], "xprv9zFnWC6h2cLgpmSA46vutJzBcfJ8yaJGg8cX1e5StJh45BBciYTRXSd25UEPVuesF9yog62tGAQtHjXajPPdbRCHuWS6T8XA2ECKADdw4Ef", "xpub6DF8uhdarytz3FWdA8TvFSvvAh8dP3283MY7p2V4SeE2wyWmG5mg5EwVvmdMVCQcoNJxGoWaU9DCWh89LojfZ537wTfunKau47EL2dhHKon", ), - ( # Chain m/0/2147483647H/1/2147483646H + ( # Chain m/0/2147483647H/1/2147483646H SEEDS[1], [0, HARD(2147483647), 1, HARD(2147483646)], "xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc", "xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL", ), - ( # Chain m/0/2147483647H/1/2147483646H/2 + ( # Chain m/0/2147483647H/1/2147483646H/2 SEEDS[1], [0, HARD(2147483647), 1, HARD(2147483646), 2], "xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j", "xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLFbdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt", ), - # Vector 3: https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#test-vector-3 - ( # Chain m + ( # Chain m SEEDS[2], [], "xprv9s21ZrQH143K25QhxbucbDDuQ4naNntJRi4KUfWT7xo4EKsHt2QJDu7KXp1A3u7Bi1j8ph3EGsZ9Xvz9dGuVrtHHs7pXeTzjuxBrCmmhgC6", "xpub661MyMwAqRbcEZVB4dScxMAdx6d4nFc9nvyvH3v4gJL378CSRZiYmhRoP7mBy6gSPSCYk6SzXPTf3ND1cZAceL7SfJ1Z3GC8vBgp2epUt13", ), - ( # Chain m/0H + ( # Chain m/0H SEEDS[2], [HARD(0)], "xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L", "xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y", ), - # Vector 4: https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#test-vector-4 - ( # Chain m + ( # Chain m SEEDS[3], [], "xprv9s21ZrQH143K48vGoLGRPxgo2JNkJ3J3fqkirQC2zVdk5Dgd5w14S7fRDyHH4dWNHUgkvsvNDCkvAwcSHNAQwhwgNMgZhLtQC63zxwhQmRv", "xpub661MyMwAqRbcGczjuMoRm6dXaLDEhW1u34gKenbeYqAix21mdUKJyuyu5F1rzYGVxyL6tmgBUAEPrEz92mBXjByMRiJdba9wpnN37RLLAXa", ), - ( # Chain m/0H + ( # Chain m/0H SEEDS[3], [HARD(0)], "xprv9vB7xEWwNp9kh1wQRfCCQMnZUEG21LpbR9NPCNN1dwhiZkjjeGRnaALmPXCX7SgjFTiCTT6bXes17boXtjq3xLpcDjzEuGLQBM5ohqkao9G", "xpub69AUMk3qDBi3uW1sXgjCmVjJ2G6WQoYSnNHyzkmdCHEhSZ4tBok37xfFEqHd2AddP56Tqp4o56AePAgCjYdvpW2PU2jbUPFKsav5ut6Ch1m", ), - ( # Chain m/0H/1H + ( # Chain m/0H/1H SEEDS[3], [HARD(0), HARD(1)], "xprv9xJocDuwtYCMNAo3Zw76WENQeAS6WGXQ55RCy7tDJ8oALr4FWkuVoHJeHVAcAqiZLE7Je3vZJHxspZdFHfnBEjHqU5hG1Jaj32dVoS6XLT1", @@ -129,67 +129,67 @@ FROM_BASE58_ERROR_VECTORS = ( # Vector 5: https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#test-vector-5 - ( # Invalid (pubkey version / prvkey mismatch) + ( # Invalid (pubkey version / prvkey mismatch) "xpub661MyMwAqRbcEYS8w7XLSVeEsBXy79zSzH1J8vCdxAZningWLdN3zgtU6LBpB85b3D2yc8sfvZU521AAwdZafEz7mnzBBsz4wKY5fTtTQBm", HDError, ), - ( # Invalid (prvkey version / pubkey mismatch) + ( # Invalid (prvkey version / pubkey mismatch) "xprv9s21ZrQH143K24Mfq5zL5MhWK9hUhhGbd45hLXo2Pq2oqzMMo63oStZzFGTQQD3dC4H2D5GBj7vWvSQaaBv5cxi9gafk7NF3pnBju6dwKvH", HDError, ), - ( # Invalid (invalid pubkey prefix 04) + ( # Invalid (invalid pubkey prefix 04) "xpub661MyMwAqRbcEYS8w7XLSVeEsBXy79zSzH1J8vCdxAZningWLdN3zgtU6Txnt3siSujt9RCVYsx4qHZGc62TG4McvMGcAUjeuwZdduYEvFn", ECError, ), - ( # Invalid (invalid prvkey prefix 04) + ( # Invalid (invalid prvkey prefix 04) "xprv9s21ZrQH143K24Mfq5zL5MhWK9hUhhGbd45hLXo2Pq2oqzMMo63oStZzFGpWnsj83BHtEy5Zt8CcDr1UiRXuWCmTQLxEK9vbz5gPstX92JQ", ECError, ), - ( # Invalid (invalid pubkey prefix 01) + ( # Invalid (invalid pubkey prefix 01) "xpub661MyMwAqRbcEYS8w7XLSVeEsBXy79zSzH1J8vCdxAZningWLdN3zgtU6N8ZMMXctdiCjxTNq964yKkwrkBJJwpzZS4HS2fxvyYUA4q2Xe4", ECError, ), - ( # Invalid (invalid prvkey prefix 01) + ( # Invalid (invalid prvkey prefix 01) "xprv9s21ZrQH143K24Mfq5zL5MhWK9hUhhGbd45hLXo2Pq2oqzMMo63oStZzFAzHGBP2UuGCqWLTAPLcMtD9y5gkZ6Eq3Rjuahrv17fEQ3Qen6J", ECError, ), - ( # Invalid (zero depth with non-zero parent fingerprint) + ( # Invalid (zero depth with non-zero parent fingerprint) "xprv9s2SPatNQ9Vc6GTbVMFPFo7jsaZySyzk7L8n2uqKXJen3KUmvQNTuLh3fhZMBoG3G4ZW1N2kZuHEPY53qmbZzCHshoQnNf4GvELZfqTUrcv", HDError, ), - ( # Invalid (zero depth with non-zero parent fingerprint) + ( # Invalid (zero depth with non-zero parent fingerprint) "xpub661no6RGEX3uJkY4bNnPcw4URcQTrSibUZ4NqJEw5eBkv7ovTwgiT91XX27VbEXGENhYRCf7hyEbWrR3FewATdCEebj6znwMfQkhRYHRLpJ", HDError, ), - ( # Invalid (zero depth with non-zero index) + ( # Invalid (zero depth with non-zero index) "xprv9s21ZrQH4r4TsiLvyLXqM9P7k1K3EYhA1kkD6xuquB5i39AU8KF42acDyL3qsDbU9NmZn6MsGSUYZEsuoePmjzsB3eFKSUEh3Gu1N3cqVUN", HDError, ), - ( # Invalid (zero depth with non-zero index) + ( # Invalid (zero depth with non-zero index) "xpub661MyMwAuDcm6CRQ5N4qiHKrJ39Xe1R1NyfouMKTTWcguwVcfrZJaNvhpebzGerh7gucBvzEQWRugZDuDXjNDRmXzSZe4c7mnTK97pTvGS8", HDError, ), - ( # Invalid (unknown extended key version) + ( # Invalid (unknown extended key version) "DMwo58pR1QLEFihHiXPVykYB6fJmsTeHvyTp7hRThAtCX8CvYzgPcn8XnmdfHGMQzT7ayAmfo4z3gY5KfbrZWZ6St24UVf2Qgo6oujFktLHdHY4", HDError, ), - ( # Invalid (unknown extended key version) + ( # Invalid (unknown extended key version) "DMwo58pR1QLEFihHiXPVykYB6fJmsTeHvyTp7hRThAtCX8CvYzgPcn8XnmdfHPmHJiEDXkTiJTVV9rHEBUem2mwVbbNfvT2MTcAqj3nesx8uBf9", HDError, ), - ( # Invalid (private key 0 not in 1..n-1) + ( # Invalid (private key 0 not in 1..n-1) "xprv9s21ZrQH143K24Mfq5zL5MhWK9hUhhGbd45hLXo2Pq2oqzMMo63oStZzF93Y5wvzdUayhgkkFoicQZcP3y52uPPxFnfoLZB21Teqt1VvEHx", ECError, ), - ( # Invalid (private key n not in 1..n-1) + ( # Invalid (private key n not in 1..n-1) "xprv9s21ZrQH143K24Mfq5zL5MhWK9hUhhGbd45hLXo2Pq2oqzMMo63oStZzFAzHGBP2UuGCqWLTAPLcMtD5SDKr24z3aiUvKr9bJpdrcLg1y3G", ECError, ), - ( # Invalid (invalid pubkey 020000000000000000000000000000000000000000000000000000000000000007) + ( # Invalid (invalid pubkey 020000000000000000000000000000000000000000000000000000000000000007) "xpub661MyMwAqRbcEYS8w7XLSVeEsBXy79zSzH1J8vCdxAZningWLdN3zgtU6Q5JXayek4PRsn35jii4veMimro1xefsM58PgBMrvdYre8QyULY", ECError, ), - ( # Invalid (invalid checksum) + ( # Invalid (invalid checksum) "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHL", ValueError, ), @@ -213,7 +213,7 @@ def test_bip32_derive(self): def test_from_base58_errors(self): for inv_xkey, exp_err in FROM_BASE58_ERROR_VECTORS: with self.assertRaises(exp_err): - HDKey.from_base58(inv_xkey) + HDKey.from_base58(inv_xkey) def test_identity(self): xkeys = [ diff --git a/tests/tests/test_bip39.py b/tests/core/test_bip39.py similarity index 100% rename from tests/tests/test_bip39.py rename to tests/core/test_bip39.py diff --git a/tests/tests/test_bip85.py b/tests/core/test_bip85.py similarity index 82% rename from tests/tests/test_bip85.py rename to tests/core/test_bip85.py index 7b6280b9..0169f8fb 100644 --- a/tests/tests/test_bip85.py +++ b/tests/core/test_bip85.py @@ -48,12 +48,29 @@ class Bip85Test(TestCase): - def test_derive_entropy(self): for app_index, path, expected in [ - (39, [0, 12, 0], unhexlify("6250b68daf746d12a24d58b4787a714bf1b58d69e4c2a466276fb16fe93dc52b6fac6b756894072241447cad56f6405ee326dbb473d2f5e943543590082927c0")), - (2, [0], unhexlify("7040bb53104f27367f317558e78a994ada7296c6fde36a364e5baf206e502bb1f988080b7dd814e7ae7d6d83edbb6689886a560e165f4a740877cdf3beecacf8")), - (32, [0], unhexlify("52405cd0dd21c5be78314a7c1a3c65ffd8d896536cc7dee3157db5824f0c92e2ead0b33988a616cf6a497f1c169d9e92562604e38305ccd3fc96f2252c177682")), + ( + 39, + [0, 12, 0], + unhexlify( + "6250b68daf746d12a24d58b4787a714bf1b58d69e4c2a466276fb16fe93dc52b6fac6b756894072241447cad56f6405ee326dbb473d2f5e943543590082927c0" + ), + ), + ( + 2, + [0], + unhexlify( + "7040bb53104f27367f317558e78a994ada7296c6fde36a364e5baf206e502bb1f988080b7dd814e7ae7d6d83edbb6689886a560e165f4a740877cdf3beecacf8" + ), + ), + ( + 32, + [0], + unhexlify( + "52405cd0dd21c5be78314a7c1a3c65ffd8d896536cc7dee3157db5824f0c92e2ead0b33988a616cf6a497f1c169d9e92562604e38305ccd3fc96f2252c177682" + ), + ), ]: result = bip85.derive_entropy(ROOT, app_index, path) self.assertEqual(result, expected) diff --git a/tests/tests/test_descriptor.py b/tests/core/test_descriptor.py similarity index 96% rename from tests/tests/test_descriptor.py rename to tests/core/test_descriptor.py index 2101227b..8ce1fb71 100644 --- a/tests/tests/test_descriptor.py +++ b/tests/core/test_descriptor.py @@ -132,16 +132,29 @@ def test_descriptors(self): 2, ), ( - "wsh(sortedmulti(2,%s,%s,%s))" % tuple(key.replace("<0;1>", "0") for key in keys[:3]), + "wsh(sortedmulti(2,%s,%s,%s))" + % tuple(key.replace("<0;1>", "0") for key in keys[:3]), "522103801b3a4e3ca0d61d469445621561c47f6c1424d0fd353a44c2c3ebb84ae78f592103b8fa5d5959fa4027ccbf0736a86ccde4242e3051ea363437b4ff0d52598d7cec2103e7d285b4817f83f724cd29394da75dfc84fe639ed147a944e7e6064703b1413053ae", 1, ), - ("wpkh(%s)" % keys[0], "0014f8f93df2160de8fd3ca716e2f905c74da3f9839f", 2,), - ("sh(wpkh(%s))" % keys[0], "0014f8f93df2160de8fd3ca716e2f905c74da3f9839f", 2,), - ("pkh(%s)" % keys[0], "76a914f8f93df2160de8fd3ca716e2f905c74da3f9839f88ac", 2,), + ( + "wpkh(%s)" % keys[0], + "0014f8f93df2160de8fd3ca716e2f905c74da3f9839f", + 2, + ), + ( + "sh(wpkh(%s))" % keys[0], + "0014f8f93df2160de8fd3ca716e2f905c74da3f9839f", + 2, + ), + ( + "pkh(%s)" % keys[0], + "76a914f8f93df2160de8fd3ca716e2f905c74da3f9839f88ac", + 2, + ), ] - error_cases = [1,2,3,4,5,6,7,8,11] + error_cases = [1, 2, 3, 4, 5, 6, 7, 8, 11] for i, (d, a, n_branches) in enumerate(dd): if i in error_cases: self.assertRaises(DescriptorError, Descriptor.from_string, d) @@ -164,74 +177,53 @@ def test_descriptor_from_string_validation(self): keys = [ # # LIANA_MINISCRIPT_DESCRIPTOR "wsh(or_d(pk([55f8fc5d/48'/0'/0'/2']xpub6EKmKYGYc1WY6t9d3d9SksR8keSaPZbFa6tqsGiH4xVxx8d2YyxSX7WG6yXEX3CmG54dPCxaapDw1XsjwCmfoqP7tbsAeqMVfKvqSAu4ndy/<0;1>/*),and_v(v:pkh([3e15470d/48'/0'/0'/2']xpub6F2P6Pz5KLPgCc6pTBd2xxCunaSYWc8CdkL28W5z15pJrN3aCYY7mCUAkCMtqrgT2wdhAGgRnJxAkCCUpGKoXKxQ57yffEGmPwtYA3DEXwu/<0;1>/*),older(6))))#x09nw3rv", - # # LIANA_TAPROOT_MINISCRIPT_DESCRIPTOR "tr([55f8fc5d/48'/0'/0'/2']xpub6EKmKYGYc1WY6t9d3d9SksR8keSaPZbFa6tqsGiH4xVxx8d2YyxSX7WG6yXEX3CmG54dPCxaapDw1XsjwCmfoqP7tbsAeqMVfKvqSAu4ndy/<0;1>/*,and_v(v:pk([3e15470d/48'/0'/0'/2']xpub6F2P6Pz5KLPgCc6pTBd2xxCunaSYWc8CdkL28W5z15pJrN3aCYY7mCUAkCMtqrgT2wdhAGgRnJxAkCCUpGKoXKxQ57yffEGmPwtYA3DEXwu/<4;2>/*),older(6)))#qjluv5ue", - # # LIANA_TAP_EXPANDING_MINISCRIPT_DESCRIPTOR "tr(xpub661MyMwAqRbcFHMDceyRcHhEfeDBXneBmbTnqujM6EumzeNcd8wrs3SHGzkETt7dDwqSCmDJx2rz6uKEddXRcYUWuAu6rkaj4L2QuVxqNUS/<0;1>/*,{and_v(v:multi_a(2,[55f8fc5d/48'/0'/0'/2']xpub6EKmKYGYc1WY6t9d3d9SksR8keSaPZbFa6tqsGiH4xVxx8d2YyxSX7WG6yXEX3CmG54dPCxaapDw1XsjwCmfoqP7tbsAeqMVfKvqSAu4ndy/<2;3>/*,[3e15470d/48'/0'/0'/2']xpub6F2P6Pz5KLPgCc6pTBd2xxCunaSYWc8CdkL28W5z15pJrN3aCYY7mCUAkCMtqrgT2wdhAGgRnJxAkCCUpGKoXKxQ57yffEGmPwtYA3DEXwu/<2;3>/*,[d3a80c8b/48'/0'/0'/2']xpub6FKYY6y3oVi7ihSCszFKRSeZj5SzrfSsUFXhKqjMV4iigrLhxwMX3mrjioNyLTZ5iD3u4wU9S3tyzpJGxhd5geaXoQ68jGz2M6dfh2zJrUv/<0;1>/*),older(65535)),multi_a(2,[55f8fc5d/48'/0'/0'/2']xpub6EKmKYGYc1WY6t9d3d9SksR8keSaPZbFa6tqsGiH4xVxx8d2YyxSX7WG6yXEX3CmG54dPCxaapDw1XsjwCmfoqP7tbsAeqMVfKvqSAu4ndy/<0;1>/*,[3e15470d/48'/0'/0'/2']xpub6F2P6Pz5KLPgCc6pTBd2xxCunaSYWc8CdkL28W5z15pJrN3aCYY7mCUAkCMtqrgT2wdhAGgRnJxAkCCUpGKoXKxQ57yffEGmPwtYA3DEXwu/<0;1>/*)})#uyj29ygt", - # # UNSORTED_MULTISIG_DESCRIPTOR "wsh(multi(2,[3e15470d/48h/0h/0h/2h]xpub6F2P6Pz5KLPgCc6pTBd2xxCunaSYWc8CdkL28W5z15pJrN3aCYY7mCUAkCMtqrgT2wdhAGgRnJxAkCCUpGKoXKxQ57yffEGmPwtYA3DEXwu/<0;1>/*,[55f8fc5d/48h/0h/0h/2h]xpub6EKmKYGYc1WY6t9d3d9SksR8keSaPZbFa6tqsGiH4xVxx8d2YyxSX7WG6yXEX3CmG54dPCxaapDw1XsjwCmfoqP7tbsAeqMVfKvqSAu4ndy/<0;1>/*,[d3a80c8b/48h/0h/0h/2h]xpub6FKYY6y3oVi7ihSCszFKRSeZj5SzrfSsUFXhKqjMV4iigrLhxwMX3mrjioNyLTZ5iD3u4wU9S3tyzpJGxhd5geaXoQ68jGz2M6dfh2zJrUv/<0;1>/*))", - # # UNRELATED_TAP_MINISCRIPT_DESCRIPTOR "tr(tpubD6NzVbkrYhZ4Y18xhod7E8V6Sy3YF36bge8HJb4ww1QgTrdkNvCEzcvUmFGQkTJA32gqr3j94iE8vsUzYpv8Pn29JezD9YiYnxgUREhN3QR/<0;1>/*,{and_v(v:multi_a(2,[1f280825/48'/1'/0'/2']tpubDEx7EkaqE8rG5NsCrijASmBjWiNv6teugndQCs4YN6JDS4hpJ3QtSC4ifPAcE7LQXtjRgB96trmEucoLbsiYYMuvLthymAhssZQpEPPb1pU/<2;3>/*,[e1efb2e7/48'/1'/0'/2']tpubDFhm1JYGdsR6Uv7SvXVd6JfjVkYimPDizEwwXRR9EhESpMhx3qL9nVjpfbtPRLzicWhYkMF4mn4AuZ4zYDjNMvuWSqugFBEJnYsMJurmbLM/<2;3>/*,[b32caab5/48'/1'/0'/2']tpubDEwY4xag4eQabW74PwS8BZb3aYy9mBzBffzBKqS74NjxzaDHodGGqfFLumwQGM5JYExNjs1mG3u8MaeEr94HNmxTaBPHERkoJXEcZ12aPdF/<0;1>/*),older(144)),multi_a(2,[1f280825/48'/1'/0'/2']tpubDEx7EkaqE8rG5NsCrijASmBjWiNv6teugndQCs4YN6JDS4hpJ3QtSC4ifPAcE7LQXtjRgB96trmEucoLbsiYYMuvLthymAhssZQpEPPb1pU/<0;1>/*,[e1efb2e7/48'/1'/0'/2']tpubDFhm1JYGdsR6Uv7SvXVd6JfjVkYimPDizEwwXRR9EhESpMhx3qL9nVjpfbtPRLzicWhYkMF4mn4AuZ4zYDjNMvuWSqugFBEJnYsMJurmbLM/<0;1>/*)})#u5clzmqy", - # # UNRELATED_MINISCRIPT_DESCRIPTOR "wsh(or_d(multi(2,[1f280825/48'/1'/0'/2']tpubDEx7EkaqE8rG5NsCrijASmBjWiNv6teugndQCs4YN6JDS4hpJ3QtSC4ifPAcE7LQXtjRgB96trmEucoLbsiYYMuvLthymAhssZQpEPPb1pU/<0;1>/*,[e1efb2e7/48'/1'/0'/2']tpubDFhm1JYGdsR6Uv7SvXVd6JfjVkYimPDizEwwXRR9EhESpMhx3qL9nVjpfbtPRLzicWhYkMF4mn4AuZ4zYDjNMvuWSqugFBEJnYsMJurmbLM/<0;1>/*),and_v(v:thresh(2,pkh([1f280825/48'/1'/0'/2']tpubDEx7EkaqE8rG5NsCrijASmBjWiNv6teugndQCs4YN6JDS4hpJ3QtSC4ifPAcE7LQXtjRgB96trmEucoLbsiYYMuvLthymAhssZQpEPPb1pU/<2;3>/*),a:pkh([e1efb2e7/48'/1'/0'/2']tpubDFhm1JYGdsR6Uv7SvXVd6JfjVkYimPDizEwwXRR9EhESpMhx3qL9nVjpfbtPRLzicWhYkMF4mn4AuZ4zYDjNMvuWSqugFBEJnYsMJurmbLM/<2;3>/*),a:pkh([b32caab5/48'/1'/0'/2']tpubDEwY4xag4eQabW74PwS8BZb3aYy9mBzBffzBKqS74NjxzaDHodGGqfFLumwQGM5JYExNjs1mG3u8MaeEr94HNmxTaBPHERkoJXEcZ12aPdF/<0;1>/*)),older(144))))#tfk3syfj", - # # UNAMBIGUOUS_MULTISIG_DESCRIPTOR "wsh(sortedmulti(2,[55f8fc5d/48h/0h/0h/2h]xpub6EKmKYGYc1WY6t9d3d9SksR8keSaPZbFa6tqsGiH4xVxx8d2YyxSX7WG6yXEX3CmG54dPCxaapDw1XsjwCmfoqP7tbsAeqMVfKvqSAu4ndy/<0;1>/*,[3e15470d/48h/0h/0h/2h]xpub6F2P6Pz5KLPgCc6pTBd2xxCunaSYWc8CdkL28W5z15pJrN3aCYY7mCUAkCMtqrgT2wdhAGgRnJxAkCCUpGKoXKxQ57yffEGmPwtYA3DEXwu/<0;1>/*,[d3a80c8b/48h/0h/0h/2h]xpub6FKYY6y3oVi7ihSCszFKRSeZj5SzrfSsUFXhKqjMV4iigrLhxwMX3mrjioNyLTZ5iD3u4wU9S3tyzpJGxhd5geaXoQ68jGz2M6dfh2zJrUv/<0;1>/*))", - # # UNAMBIGUOUS_SINGLESIG_DESCRIPTOR "wpkh([55f8fc5d/84h/0h/0h]xpub6DPMTPxGMqdtzMwpqT1dDQaVdyaEppEm2qYSaJ7ANsuES7HkNzrXJst1Ed8D7NAnijUdgSDUFgph1oj5LKKAD5gyxWNhNP2AuDqaKYqzphA/<0;1>/*)", - # # MULTIPLE BRANCHES UNAMBIGUOUS_SINGLESIG_DESCRIPTOR "wpkh([55f8fc5d/84h/0h/0h]xpub6DPMTPxGMqdtzMwpqT1dDQaVdyaEppEm2qYSaJ7ANsuES7HkNzrXJst1Ed8D7NAnijUdgSDUFgph1oj5LKKAD5gyxWNhNP2AuDqaKYqzphA/<0;1;4;2;0;5>/*)", - # # UR_BYTES_MULTISIG_DESCRIPTOR "wsh(sortedmulti(2,[55f8fc5d/48h/0h/0h/2h]xpub6EKmKYGYc1WY6t9d3d9SksR8keSaPZbFa6tqsGiH4xVxx8d2YyxSX7WG6yXEX3CmG54dPCxaapDw1XsjwCmfoqP7tbsAeqMVfKvqSAu4ndy/0/*,[3e15470d/48h/0h/0h/2h]xpub6F2P6Pz5KLPgCc6pTBd2xxCunaSYWc8CdkL28W5z15pJrN3aCYY7mCUAkCMtqrgT2wdhAGgRnJxAkCCUpGKoXKxQ57yffEGmPwtYA3DEXwu/0/*,[d3a80c8b/48h/0h/0h/2h]xpub6FKYY6y3oVi7ihSCszFKRSeZj5SzrfSsUFXhKqjMV4iigrLhxwMX3mrjioNyLTZ5iD3u4wU9S3tyzpJGxhd5geaXoQ68jGz2M6dfh2zJrUv/0/*))", - # # MULTIPLE BRANCHES UR_BYTES_MULTISIG_DESCRIPTOR "wsh(sortedmulti(2,[55f8fc5d/48h/0h/0h/2h]xpub6EKmKYGYc1WY6t9d3d9SksR8keSaPZbFa6tqsGiH4xVxx8d2YyxSX7WG6yXEX3CmG54dPCxaapDw1XsjwCmfoqP7tbsAeqMVfKvqSAu4ndy/0/2/4/1/0/*,[3e15470d/48h/0h/0h/2h]xpub6F2P6Pz5KLPgCc6pTBd2xxCunaSYWc8CdkL28W5z15pJrN3aCYY7mCUAkCMtqrgT2wdhAGgRnJxAkCCUpGKoXKxQ57yffEGmPwtYA3DEXwu/0/*,[d3a80c8b/48h/0h/0h/2h]xpub6FKYY6y3oVi7ihSCszFKRSeZj5SzrfSsUFXhKqjMV4iigrLhxwMX3mrjioNyLTZ5iD3u4wU9S3tyzpJGxhd5geaXoQ68jGz2M6dfh2zJrUv/0/1/*))", - # # UR_OUTPUT_MULTISIG_DESCRIPTOR "wsh(multi(1,xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/1/0/*,xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/0/0/*))", - # # MULTIPLE BRANCHES UR_OUTPUT_MULTISIG_DESCRIPTOR "wsh(multi(1,xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB/1/0/2/1/0/2/1/1/*,xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH/0/0/1/1/*))", - # # BLUEWALLET_MULTISIG_DESCRIPTOR "wsh(sortedmulti(2,[55f8fc5d/48h/0h/0h/2h]xpub6EKmKYGYc1WY6t9d3d9SksR8keSaPZbFa6tqsGiH4xVxx8d2YyxSX7WG6yXEX3CmG54dPCxaapDw1XsjwCmfoqP7tbsAeqMVfKvqSAu4ndy,[3e15470d/48h/0h/0h/2h]xpub6F2P6Pz5KLPgCc6pTBd2xxCunaSYWc8CdkL28W5z15pJrN3aCYY7mCUAkCMtqrgT2wdhAGgRnJxAkCCUpGKoXKxQ57yffEGmPwtYA3DEXwu,[d3a80c8b/48h/0h/0h/2h]xpub6FKYY6y3oVi7ihSCszFKRSeZj5SzrfSsUFXhKqjMV4iigrLhxwMX3mrjioNyLTZ5iD3u4wU9S3tyzpJGxhd5geaXoQ68jGz2M6dfh2zJrUv))", - # # SPECTER_SINGLESIG_DESCRIPTOR "wpkh([55f8fc5d/84h/0h/0h]xpub6DPMTPxGMqdtzMwpqT1dDQaVdyaEppEm2qYSaJ7ANsuES7HkNzrXJst1Ed8D7NAnijUdgSDUFgph1oj5LKKAD5gyxWNhNP2AuDqaKYqzphA/0/*)", - # # SPECTER_MULTISIG_DESCRIPTOR "wsh(sortedmulti(2,[55f8fc5d/48h/0h/0h/2h]xpub6EKmKYGYc1WY6t9d3d9SksR8keSaPZbFa6tqsGiH4xVxx8d2YyxSX7WG6yXEX3CmG54dPCxaapDw1XsjwCmfoqP7tbsAeqMVfKvqSAu4ndy/0/*,[3e15470d/48h/0h/0h/2h]xpub6F2P6Pz5KLPgCc6pTBd2xxCunaSYWc8CdkL28W5z15pJrN3aCYY7mCUAkCMtqrgT2wdhAGgRnJxAkCCUpGKoXKxQ57yffEGmPwtYA3DEXwu/0/*,[d3a80c8b/48h/0h/0h/2h]xpub6FKYY6y3oVi7ihSCszFKRSeZj5SzrfSsUFXhKqjMV4iigrLhxwMX3mrjioNyLTZ5iD3u4wU9S3tyzpJGxhd5geaXoQ68jGz2M6dfh2zJrUv/0/*))", - # # liana miniscript primary tapkey anytime, else 1of2 after 3 confirmations recovery taproot "tr([d63dc4a7/48'/1'/0'/2']tpubDEXCvh2aPYzMz2xfgsh9ZM6dQZxioYfCafUgw16keqschYbED4VeS46Qhr7EoonDHNr9dSsKPEGeRP5WRzDGdY3aazneR7wKmtDVNTf6qic/<0;1>/*,and_v(v:multi_a(1,[c98cbe58/48'/1'/0'/2']tpubDFXZ3rcRyvU6AvNrb4kRQFomJbtCTCyMX9jDJmfN5XfHLEAZq7a8h3CrYDZYtdexk6XWfT5DB8PYgySWA5GSdyWdzWwveQcbrzvVQw3u7bV/<0;1>/*,[9590b69a/48'/1'/0'/2']tpubDEgtrNHQ68KvQPABjV4Ah39MpUH6aniH8gbHKygJSwNwbsQpnzPJMcssdqjwPtNshjAj8nP35iZisEFchFdZtPG4rXi7FW35dsCtQSj93Qv/<0;1>/*),older(3)))#9550ke77", - # # liana miniscript wsh single primary key anytime, else a secondary key after 6 confirmations "wsh(or_d(pk([d63dc4a7/48'/1'/0'/2']tpubDEXCvh2aPYzMz2xfgsh9ZM6dQZxioYfCafUgw16keqschYbED4VeS46Qhr7EoonDHNr9dSsKPEGeRP5WRzDGdY3aazneR7wKmtDVNTf6qic/<0;1>/*),and_v(v:pkh([c98cbe58/48'/1'/0'/2']tpubDFXZ3rcRyvU6AvNrb4kRQFomJbtCTCyMX9jDJmfN5XfHLEAZq7a8h3CrYDZYtdexk6XWfT5DB8PYgySWA5GSdyWdzWwveQcbrzvVQw3u7bV/<0;1>/*),older(6))))#szdmyf2d", - # # liana expanding multisig taproot w/ NUMS tapkey and 2 taproot paths, primary 2of2 anytime else 2of3 after 36 confirmations. - "tr(tpubD6NzVbkrYhZ4X6BRkDMxFyZxfUCQdjpK27dNgqwDqsQ2PUbMmjjPPFxfcTJiGEjeNz2zLbZ1PRmgCAzXn4pE6tEuQPScXyUbuAgdcec6pMN/<0;1>/*,{and_v(v:multi_a(2,[07fd816d/48'/1'/0'/2']tpubDDvFWduSiwhW7hUbL1oMyUfcNgeSyZgHbooe1WjHyRaXYH3uUjm1xdxWXAGbQFn8QGScDg4b4a6WMGNiEAq2uQdmPDhDKPE5Dr8DX24mwd5/<2;3>/*,[da855a1f/48'/1'/0'/2']tpubDEHRt73d4guqR5BLGQud4XMW8vDCGHUj54qDTFtsdFstF6PAYx1oAy3jfKg1PffqLUWuSsXmnetKeTJFKfKLXeJR97yUuqvvojnoBcUDHg5/<2;3>/*,[cdef7cd9/48'/1'/0'/2']tpubDEzdWp7365AFAExeUsHiwRmkZN5it3sSAZsd6GKUXvUiJBytXnZrRKMAt9UgCkWB2mP3K9WujLuTjrRLBn51Y18pMVyg2v18un4ivqWSAk2/<0;1>/*),older(36)),multi_a(2,[07fd816d/48'/1'/0'/2']tpubDDvFWduSiwhW7hUbL1oMyUfcNgeSyZgHbooe1WjHyRaXYH3uUjm1xdxWXAGbQFn8QGScDg4b4a6WMGNiEAq2uQdmPDhDKPE5Dr8DX24mwd5/<0;1>/*,[da855a1f/48'/1'/0'/2']tpubDEHRt73d4guqR5BLGQud4XMW8vDCGHUj54qDTFtsdFstF6PAYx1oAy3jfKg1PffqLUWuSsXmnetKeTJFKfKLXeJR97yUuqvvojnoBcUDHg5/<0;1>/*)})#tvh3u2lu" + "tr(tpubD6NzVbkrYhZ4X6BRkDMxFyZxfUCQdjpK27dNgqwDqsQ2PUbMmjjPPFxfcTJiGEjeNz2zLbZ1PRmgCAzXn4pE6tEuQPScXyUbuAgdcec6pMN/<0;1>/*,{and_v(v:multi_a(2,[07fd816d/48'/1'/0'/2']tpubDDvFWduSiwhW7hUbL1oMyUfcNgeSyZgHbooe1WjHyRaXYH3uUjm1xdxWXAGbQFn8QGScDg4b4a6WMGNiEAq2uQdmPDhDKPE5Dr8DX24mwd5/<2;3>/*,[da855a1f/48'/1'/0'/2']tpubDEHRt73d4guqR5BLGQud4XMW8vDCGHUj54qDTFtsdFstF6PAYx1oAy3jfKg1PffqLUWuSsXmnetKeTJFKfKLXeJR97yUuqvvojnoBcUDHg5/<2;3>/*,[cdef7cd9/48'/1'/0'/2']tpubDEzdWp7365AFAExeUsHiwRmkZN5it3sSAZsd6GKUXvUiJBytXnZrRKMAt9UgCkWB2mP3K9WujLuTjrRLBn51Y18pMVyg2v18un4ivqWSAk2/<0;1>/*),older(36)),multi_a(2,[07fd816d/48'/1'/0'/2']tpubDDvFWduSiwhW7hUbL1oMyUfcNgeSyZgHbooe1WjHyRaXYH3uUjm1xdxWXAGbQFn8QGScDg4b4a6WMGNiEAq2uQdmPDhDKPE5Dr8DX24mwd5/<0;1>/*,[da855a1f/48'/1'/0'/2']tpubDEHRt73d4guqR5BLGQud4XMW8vDCGHUj54qDTFtsdFstF6PAYx1oAy3jfKg1PffqLUWuSsXmnetKeTJFKfKLXeJR97yUuqvvojnoBcUDHg5/<0;1>/*)})#tvh3u2lu", ] for d in keys: Descriptor.from_string(d) - # invalid keys = [ # # LIANA_MINISCRIPT_DESCRIPTOR "wsh(or_d(pk([55f8fc5d/48'/0'/0'/2']xpub6EKmKYGYc1WY6t9d3d9SksR8keSaPZbFa6tqsGiH4xVxx8d2YyxSX7WG6yXEX3CmG54dPCxaapDw1XsjwCmfoqP7tbsAeqMVfKvqSAu4ndy/<0;1;2>/*),and_v(v:pkh([3e15470d/48'/0'/0'/2']xpub6F2P6Pz5KLPgCc6pTBd2xxCunaSYWc8CdkL28W5z15pJrN3aCYY7mCUAkCMtqrgT2wdhAGgRnJxAkCCUpGKoXKxQ57yffEGmPwtYA3DEXwu/<0;1>/*),older(6))))#x09nw3rv", - # # UNRELATED_MINISCRIPT_DESCRIPTOR "wsh(or_d(multi(2,[1f280825/48'/1'/0'/2']tpubDEx7EkaqE8rG5NsCrijASmBjWiNv6teugndQCs4YN6JDS4hpJ3QtSC4ifPAcE7LQXtjRgB96trmEucoLbsiYYMuvLthymAhssZQpEPPb1pU/<0;1>/*,[e1efb2e7/48'/1'/0'/2']tpubDFhm1JYGdsR6Uv7SvXVd6JfjVkYimPDizEwwXRR9EhESpMhx3qL9nVjpfbtPRLzicWhYkMF4mn4AuZ4zYDjNMvuWSqugFBEJnYsMJurmbLM/<0;1>/*),and_v(v:thresh(2,pkh([1f280825/48'/1'/0'/2']tpubDEx7EkaqE8rG5NsCrijASmBjWiNv6teugndQCs4YN6JDS4hpJ3QtSC4ifPAcE7LQXtjRgB96trmEucoLbsiYYMuvLthymAhssZQpEPPb1pU/<2;3>/*),a:pkh([e1efb2e7/48'/1'/0'/2']tpubDFhm1JYGdsR6Uv7SvXVd6JfjVkYimPDizEwwXRR9EhESpMhx3qL9nVjpfbtPRLzicWhYkMF4mn4AuZ4zYDjNMvuWSqugFBEJnYsMJurmbLM/<2;3>/*),a:pkh([b32caab5/48'/1'/0'/2']tpubDEwY4xag4eQabW74PwS8BZb3aYy9mBzBffzBKqS74NjxzaDHodGGqfFLumwQGM5JYExNjs1mG3u8MaeEr94HNmxTaBPHERkoJXEcZ12aPdF/<0;1;2>/*)),older(144))))#tfk3syfj", - # # liana miniscript wsh single primary key anytime, else a secondary key after 6 confirmations "wsh(or_d(pk([d63dc4a7/48'/1'/0'/2']tpubDEXCvh2aPYzMz2xfgsh9ZM6dQZxioYfCafUgw16keqschYbED4VeS46Qhr7EoonDHNr9dSsKPEGeRP5WRzDGdY3aazneR7wKmtDVNTf6qic/<0;1>/*),and_v(v:pkh([c98cbe58/48'/1'/0'/2']tpubDFXZ3rcRyvU6AvNrb4kRQFomJbtCTCyMX9jDJmfN5XfHLEAZq7a8h3CrYDZYtdexk6XWfT5DB8PYgySWA5GSdyWdzWwveQcbrzvVQw3u7bV/*),older(6))))#szdmyf2d", ] @@ -297,7 +289,7 @@ def test_branch_mixing(self): try: Key.from_string(k) print(k) - except: + except Exception: pass self.assertRaises(Exception, Key.from_string, k) @@ -344,36 +336,11 @@ def test_multisig(self): keys = tuple([ec.PrivateKey(bytes([i + 1] * 32)).to_public() for i in range(4)]) descriptors = [ # descriptor: str, is_basic_multisig: bool, is_sorted: bool - ( - "wsh(c:andor(multi(1,%s,%s),pk_k(%s),pk_k(%s)))" % keys, - False, - False, - 1 - ), - ( - "wsh(multi(2,%s,%s,%s,%s))" % keys, - True, - False, - 1 - ), - ( - "wsh(sortedmulti(2,%s,%s,%s,%s))" % keys, - True, - True, - 1 - ), - ( - "tr(%s,multi_a(2,%s,%s,%s))" % keys, - False, - False, - 1 - ), - ( - "tr(%s,sortedmulti_a(2,%s,%s,%s))" % keys, - False, - False, - 1 - ), + ("wsh(c:andor(multi(1,%s,%s),pk_k(%s),pk_k(%s)))" % keys, False, False, 1), + ("wsh(multi(2,%s,%s,%s,%s))" % keys, True, False, 1), + ("wsh(sortedmulti(2,%s,%s,%s,%s))" % keys, True, True, 1), + ("tr(%s,multi_a(2,%s,%s,%s))" % keys, False, False, 1), + ("tr(%s,sortedmulti_a(2,%s,%s,%s))" % keys, False, False, 1), ] for dstr, is_basic, is_sorted, n_branches in descriptors: d = Descriptor.from_string(dstr) diff --git a/tests/tests/test_ecc.py b/tests/core/test_ecc.py similarity index 98% rename from tests/tests/test_ecc.py rename to tests/core/test_ecc.py index bb842184..4f06b380 100644 --- a/tests/tests/test_ecc.py +++ b/tests/core/test_ecc.py @@ -1,4 +1,4 @@ -from binascii import unhexlify, hexlify +from binascii import hexlify from unittest import TestCase from embit.ec import PublicKey, PrivateKey, Signature, secp256k1 from io import BytesIO diff --git a/tests/tests/test_ecdh.py b/tests/core/test_ecdh.py similarity index 98% rename from tests/tests/test_ecdh.py rename to tests/core/test_ecdh.py index 20396115..be298a42 100644 --- a/tests/tests/test_ecdh.py +++ b/tests/core/test_ecdh.py @@ -1,5 +1,5 @@ from unittest import TestCase -from embit.ec import PublicKey, PrivateKey +from embit.ec import PrivateKey import hashlib diff --git a/tests/tests/test_finalizer.py b/tests/core/test_finalizer.py similarity index 100% rename from tests/tests/test_finalizer.py rename to tests/core/test_finalizer.py diff --git a/tests/tests/test_psbt.py b/tests/core/test_psbt.py similarity index 100% rename from tests/tests/test_psbt.py rename to tests/core/test_psbt.py diff --git a/tests/tests/test_psbtview.py b/tests/core/test_psbtview.py similarity index 99% rename from tests/tests/test_psbtview.py rename to tests/core/test_psbtview.py index 6eac6f88..0f750fc3 100644 --- a/tests/tests/test_psbtview.py +++ b/tests/core/test_psbtview.py @@ -2,7 +2,7 @@ from embit.psbtview import PSBTView from embit.psbt import PSBT, InputScope, CompressMode from embit import bip32, bip39 -from binascii import a2b_base64, b2a_base64 +from binascii import a2b_base64 from io import BytesIO ROOT = bip32.HDKey.from_seed( diff --git a/tests/tests/test_ripemd160.py b/tests/core/test_ripemd160.py similarity index 100% rename from tests/tests/test_ripemd160.py rename to tests/core/test_ripemd160.py diff --git a/tests/tests/test_script.py b/tests/core/test_script.py similarity index 100% rename from tests/tests/test_script.py rename to tests/core/test_script.py diff --git a/tests/tests/test_taproot.py b/tests/core/test_taproot.py similarity index 100% rename from tests/tests/test_taproot.py rename to tests/core/test_taproot.py diff --git a/tests/tests/test_taptree.py b/tests/core/test_taptree.py similarity index 100% rename from tests/tests/test_taptree.py rename to tests/core/test_taptree.py diff --git a/tests/tests/test_liquid.py b/tests/ext/liquid/test_liquid.py similarity index 99% rename from tests/tests/test_liquid.py rename to tests/ext/liquid/test_liquid.py index 76f9f8b1..26c93437 100644 --- a/tests/tests/test_liquid.py +++ b/tests/ext/liquid/test_liquid.py @@ -1,11 +1,11 @@ from unittest import TestCase from embit.util import secp256k1 -from binascii import hexlify, unhexlify -from embit.liquid.pset import PSET -from embit.liquid.transaction import LTransaction, LTransactionInput, LTransactionOutput -from embit.liquid import slip77 +from binascii import unhexlify +from embit.ext.liquid.pset import PSET +from embit.ext.liquid.transaction import LTransaction +from embit.ext.liquid import slip77 from embit.script import Script -from embit.liquid.descriptor import LDescriptor +from embit.ext.liquid.descriptor import LDescriptor from embit.bip32 import HDKey from embit.ec import PrivateKey from embit.hashes import tagged_hash diff --git a/tests/tests/test_psetview.py b/tests/ext/liquid/test_psetview.py similarity index 99% rename from tests/tests/test_psetview.py rename to tests/ext/liquid/test_psetview.py index d6a48ed0..3281bb35 100644 --- a/tests/tests/test_psetview.py +++ b/tests/ext/liquid/test_psetview.py @@ -1,9 +1,9 @@ from unittest import TestCase -from embit.liquid.psetview import PSETView, GlobalLTransactionView -from embit.liquid.pset import PSET -from embit.liquid.transaction import LTransaction +from embit.ext.liquid.psetview import PSETView, GlobalLTransactionView +from embit.ext.liquid.pset import PSET +from embit.ext.liquid.transaction import LTransaction from embit import bip32, bip39 -from binascii import a2b_base64, b2a_base64 +from binascii import a2b_base64 from io import BytesIO ROOT = bip32.HDKey.from_seed( diff --git a/tests/tests/test_threading.py b/tests/ext/liquid/test_threading.py similarity index 99% rename from tests/tests/test_threading.py rename to tests/ext/liquid/test_threading.py index 34d6c44e..c41b9628 100644 --- a/tests/tests/test_threading.py +++ b/tests/ext/liquid/test_threading.py @@ -1,8 +1,8 @@ from unittest import TestCase from embit.ec import PrivateKey -from embit.liquid.pset import PSET +from embit.ext.liquid.pset import PSET from embit.hashes import tagged_hash -from embit.liquid import slip77 +from embit.ext.liquid import slip77 import threading mbkey = PrivateKey.from_string("L2U2zGBgimb2vNee3bTw2y936PDJZXq3p7nMXEWuPP5MmpE1nCfv") diff --git a/tests/tests/test_slip39.py b/tests/ext/test_slip39.py similarity index 99% rename from tests/tests/test_slip39.py rename to tests/ext/test_slip39.py index 088257d8..279f2afd 100644 --- a/tests/tests/test_slip39.py +++ b/tests/ext/test_slip39.py @@ -2,9 +2,8 @@ # https://github.com/trezor/python-shamir-mnemonic/blob/master/test_shamir.py # https://github.com/trezor/python-shamir-mnemonic/blob/master/vectors.json -from binascii import hexlify, unhexlify -from embit.bip32 import HDKey -from embit.slip39 import ( +from binascii import unhexlify +from embit.ext.slip39 import ( Share, ShareSet, ) diff --git a/tests/integration/core/__init__.py b/tests/integration/core/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/integration/tests/test_psbt.py b/tests/integration/core/test_psbt.py similarity index 98% rename from tests/integration/tests/test_psbt.py rename to tests/integration/core/test_psbt.py index b425722e..87b1b9ae 100644 --- a/tests/integration/tests/test_psbt.py +++ b/tests/integration/core/test_psbt.py @@ -1,4 +1,4 @@ -from unittest import TestCase, skip +from unittest import TestCase from util.bitcoin import daemon import random from embit.descriptor import Descriptor diff --git a/tests/integration/ext/__init__.py b/tests/integration/ext/__init__.py new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/tests/integration/ext/__init__.py @@ -0,0 +1 @@ + diff --git a/tests/integration/ext/liquid/__init__.py b/tests/integration/ext/liquid/__init__.py new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/tests/integration/ext/liquid/__init__.py @@ -0,0 +1 @@ + diff --git a/tests/integration/tests/test_pset.py b/tests/integration/ext/liquid/test_pset.py similarity index 94% rename from tests/integration/tests/test_pset.py rename to tests/integration/ext/liquid/test_pset.py index 2f976d26..deb92434 100644 --- a/tests/integration/tests/test_pset.py +++ b/tests/integration/ext/liquid/test_pset.py @@ -1,17 +1,15 @@ -from unittest import TestCase, skip +from unittest import TestCase from util.liquid import daemon import random -import time import os -from embit.liquid.descriptor import LDescriptor as Descriptor +from embit.ext.liquid.descriptor import LDescriptor as Descriptor from embit.descriptor.checksum import add_checksum from embit.bip32 import HDKey -from embit.liquid.networks import get_network -from embit.liquid.pset import PSET as PSBT -from embit.liquid.transaction import LSIGHASH -from embit.liquid.finalizer import finalize_psbt -from embit.liquid.addresses import addr_decode +from embit.ext.liquid.networks import get_network +from embit.ext.liquid.pset import PSET as PSBT +from embit.ext.liquid.finalizer import finalize_psbt +from embit.ext.liquid.addresses import addr_decode from embit.ec import PrivateKey wallet_prefix = "test" + random.randint(0, 0xFFFFFFFF).to_bytes(4, "big").hex() @@ -138,7 +136,6 @@ def sign_with_descriptor(self, d1, d2, root, selfblind=False): self.assertTrue(res[0]["allowed"]) if selfblind: # check we can reblind all outputs - import json raw = w.unblindrawtransaction(raw)["hex"] decoded = w.decoderawtransaction(raw) diff --git a/tests/integration/run_tests.py b/tests/integration/run_tests.py index 05e88eed..f3c90fd1 100644 --- a/tests/integration/run_tests.py +++ b/tests/integration/run_tests.py @@ -1,5 +1,8 @@ # this should run with python3 import sys +import time +import unittest +from pathlib import Path if sys.implementation.name == "micropython": print("This file should run with python3, not micropython!") @@ -7,19 +10,41 @@ from util.bitcoin import daemon as bitcoind from util.liquid import daemon as elementsd -import unittest -import time + + +ROOT = Path(__file__).resolve().parent + + +def discover(*parts): + return unittest.defaultTestLoader.discover( + str(ROOT.joinpath(*parts)), top_level_dir=str(ROOT) + ) def main(): + mode = sys.argv[1] if len(sys.argv) > 1 else "all" + if mode not in ("all", "core", "ext", "liquid"): + raise SystemExit("usage: run_tests.py [all|core|ext|liquid]") + + suite = unittest.TestSuite() + daemons = [] + if mode in ("all", "core"): + daemons.append(bitcoind) + suite.addTests(discover("core")) + if mode in ("all", "ext", "liquid"): + daemons.append(elementsd) + suite.addTests(discover("ext", "liquid")) + try: - bitcoind.start() - elementsd.start() - unittest.main("tests") + for daemon in daemons: + daemon.start() + result = unittest.TextTestRunner(verbosity=2).run(suite) time.sleep(10) + if not result.wasSuccessful(): + raise SystemExit(1) finally: - bitcoind.stop() - elementsd.stop() + for daemon in reversed(daemons): + daemon.stop() if __name__ == "__main__": diff --git a/tests/integration/tests/__init__.py b/tests/integration/tests/__init__.py deleted file mode 100644 index d180f755..00000000 --- a/tests/integration/tests/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from .test_psbt import * -from .test_pset import * diff --git a/tests/integration/util/rpc.py b/tests/integration/util/rpc.py index 9ebfafe7..4f679e58 100644 --- a/tests/integration/util/rpc.py +++ b/tests/integration/util/rpc.py @@ -1,7 +1,8 @@ import logging -import requests, json, os -import os, sys, errno -import time +import requests +import json +import os +import sys logger = logging.getLogger(__name__) @@ -207,7 +208,7 @@ def autodetect_rpc_confs( try: rpc.getmininginfo() available_conf_arr.append(conf) - except requests.exceptions.RequestException as e: + except requests.exceptions.RequestException: pass # no point in reporting that here except RpcError: @@ -234,13 +235,13 @@ def __init__(self, message, response): try: self.status_code = response.status_code error = response.json() - except Exception as e: + except Exception: # it's a dict already error = response try: self.error_code = error["error"]["code"] self.error_msg = error["error"]["message"] - except Exception as e: + except Exception: self.error = "UNKNOWN API-ERROR:%s" % response.text diff --git a/tests/run_tests.py b/tests/run_tests.py index 3358d8fd..1a255298 100644 --- a/tests/run_tests.py +++ b/tests/run_tests.py @@ -6,4 +6,4 @@ import unittest if __name__ == "__main__": - unittest.main("tests") + unittest.main("core")