Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/embit/bip39.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def mnemonic_to_bytes(mnemonic: str, ignore_checksum: bool = False, wordlist=WOR
# this function is copied from Jimmy Song's HDPrivateKey.from_mnemonic() method

words = mnemonic.strip().split()
if len(words) % 3 != 0 or len(words) < 12:
if len(words) % 3 != 0 or not 12 <= len(words) <= 24:
raise ValueError("Invalid recovery phrase")

binary_seed = bytearray()
Expand Down Expand Up @@ -97,7 +97,7 @@ def _extract_index(bits, b, n):


def mnemonic_from_bytes(entropy, wordlist=WORDLIST):
if len(entropy) % 4 != 0:
if len(entropy) % 4 != 0 or not 16 <= len(entropy) <= 32:
raise ValueError("Byte array should be multiple of 4 long (16, 20, ..., 32)")
total_bits = len(entropy) * 8
checksum_bits = total_bits // 32
Expand Down
3 changes: 3 additions & 0 deletions src/embit/descriptor/descriptor.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ def script_len(self):

@property
def num_branches(self):
if self.miniscript is not None:
return max({k.num_branches for k in self.miniscript.keys})

return max([k.num_branches for k in self.keys])

def branch(self, branch_index=None):
Expand Down
50 changes: 43 additions & 7 deletions src/embit/descriptor/miniscript.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,25 @@ def type(self):

@classmethod
def read_from(cls, s, taproot=False):
op, char = read_until(s, b"(")
def wrapped(m_script):
for w in reversed(wrappers):
if w not in WRAPPER_NAMES:
raise MiniscriptError("Unknown wrapper")
WrapperCls = WRAPPERS[WRAPPER_NAMES.index(w)]
m_script = WrapperCls(m_script, taproot=taproot)
return m_script

op, char = read_until(s, b"(,)")
if char in (b",", b")"):
s.seek(-1, 1)
op = op.decode()
wrappers = ""
if ":" in op:
wrappers, op = op.split(":")
# handle boolean literals: 0 or 1
if op in ("0", "1"):
miniscript = JustOne() if op == "1" else JustZero()
return wrapped(miniscript)
if char != b"(":
raise MiniscriptError("Missing operator")
if op not in OPERATOR_NAMES:
Expand All @@ -67,12 +81,7 @@ def read_from(cls, s, taproot=False):
MiniscriptCls = OPERATORS[OPERATOR_NAMES.index(op)]
args = MiniscriptCls.read_arguments(s, taproot=taproot)
miniscript = MiniscriptCls(*args, taproot=taproot)
for w in reversed(wrappers):
if w not in WRAPPER_NAMES:
raise MiniscriptError("Unknown wrapper")
WrapperCls = WRAPPERS[WRAPPER_NAMES.index(w)]
miniscript = WrapperCls(miniscript, taproot=taproot)
return miniscript
return wrapped(miniscript)

@classmethod
def read_arguments(cls, s, taproot=False):
Expand Down Expand Up @@ -119,6 +128,28 @@ def len_args(self):
########### Known fragments (miniscript operators) ##############


class JustZero(Miniscript):
TYPE = "B"
PROPS = "zud"

def inner_compile(self):
return Number(0).compile()

def __str__(self):
return "0"


class JustOne(Miniscript):
TYPE = "B"
PROPS = "zu"

def inner_compile(self):
return Number(1).compile()

def __str__(self):
return "1"


class OneArg(Miniscript):
NARGS = 1

Expand Down Expand Up @@ -870,6 +901,11 @@ def inner_compile(self):

def __len__(self):
return len(self.arg) + 1

def verify(self):
super().verify()
if self.arg.type != "V":
raise MiniscriptError("t: X must be of type V")

@property
def properties(self):
Expand Down
8 changes: 4 additions & 4 deletions src/embit/liquid/pset.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,10 +138,10 @@ def blinded_vin(self):
witness=TxInWitness(self.issue_rangeproof, self.token_rangeproof),
)

def read_value(self, stream, k):
def read_value(self, stream, k, version=None):
# standard bitcoin stuff
if (b"\xfc\x08elements" not in k) and (b"\xfc\x04pset" not in k):
super().read_value(stream, k)
super().read_value(stream, k, version=version)
elif k == b"\xfc\x04pset\x0e":
# range proof is very large,
# so we don't load it if compress flag is set.
Expand Down Expand Up @@ -384,9 +384,9 @@ def reblind(self, nonce, blinding_pubkey=None, extra_message=b""):
secp256k1.generator_parse(self.asset_commitment),
)

def read_value(self, stream, k):
def read_value(self, stream, k, version=None):
if (b"\xfc\x08elements" not in k) and (b"\xfc\x04pset" not in k):
super().read_value(stream, k)
super().read_value(stream, k, version=version)
# range proof and surjection proof are very large,
# so we don't load them if compress flag is set.
elif k in [b"\xfc\x08elements\x04", b"\xfc\x04pset\x04"]:
Expand Down
Loading