def parse_witness_multisig( witness: bytes) -> Tuple[bytes, List[Tuple[bytes, int]]]: try: r = utils.BufferReader(witness) # Get number of witness stack items. item_count = read_bitcoin_varint(r) # Skip over OP_FALSE, which is due to the old OP_CHECKMULTISIG bug. if r.get() != 0: raise ValueError signatures = [] for i in range(item_count - 2): n = read_bitcoin_varint(r) signature = r.read(n - 1) hash_type = r.get() signatures.append((signature, hash_type)) script = read_bytes_prefixed(r) if r.remaining_count(): raise ValueError except (ValueError, EOFError): raise wire.DataError("Invalid witness.") return script, signatures
def verify_nonownership( proof: bytes, script_pubkey: bytes, commitment_data: bytes | None, keychain: Keychain, coin: CoinInfo, ) -> bool: try: r = utils.BufferReader(proof) if r.read_memoryview(4) != _VERSION_MAGIC: raise wire.DataError("Unknown format of proof of ownership") flags = r.get() if flags & 0b1111_1110: raise wire.DataError("Unknown flags in proof of ownership") # Determine whether our ownership ID appears in the proof. id_count = read_bitcoin_varint(r) ownership_id = get_identifier(script_pubkey, keychain) not_owned = True for _ in range(id_count): if utils.consteq(ownership_id, r.read_memoryview(_OWNERSHIP_ID_LEN)): not_owned = False # Verify the BIP-322 SignatureProof. proof_body = memoryview(proof)[:r.offset] if commitment_data is None: commitment_data = bytes() sighash = HashWriter(sha256(proof_body)) write_bytes_prefixed(sighash, script_pubkey) write_bytes_prefixed(sighash, commitment_data) script_sig, witness = read_bip322_signature_proof(r) # We don't call verifier.ensure_hash_type() to avoid possible compatibility # issues between implementations, because the hash type doesn't influence # the digest and the value to use is not defined in BIP-322. verifier = SignatureVerifier(script_pubkey, script_sig, witness, coin) verifier.verify(sighash.get_digest()) except (ValueError, EOFError): raise wire.DataError("Invalid proof of ownership") return not_owned
def read_scriptsig_witness( ownership_proof: bytes) -> tuple[memoryview, memoryview]: try: r = utils.BufferReader(ownership_proof) if r.read_memoryview(4) != _VERSION_MAGIC: raise wire.DataError("Unknown format of proof of ownership") flags = r.get() if flags & 0b1111_1110: raise wire.DataError("Unknown flags in proof of ownership") # Skip ownership IDs. id_count = read_bitcoin_varint(r) r.read_memoryview(_OWNERSHIP_ID_LEN * id_count) return read_bip322_signature_proof(r) except (ValueError, EOFError): raise wire.DataError("Invalid proof of ownership")
def parse_witness_p2wpkh(witness: bytes) -> Tuple[bytes, bytes, int]: try: r = utils.BufferReader(witness) if r.get() != 2: # num of stack items, in P2WPKH it's always 2 raise ValueError n = read_bitcoin_varint(r) signature = r.read(n - 1) hash_type = r.get() pubkey = read_bytes_prefixed(r) if r.remaining_count(): raise ValueError except (ValueError, EOFError): raise wire.DataError("Invalid witness.") return pubkey, signature, hash_type
def parse_witness_p2wpkh( witness: bytes) -> tuple[memoryview, memoryview, SigHashType]: try: r = utils.BufferReader(witness) if r.get() != 2: # num of stack items, in P2WPKH it's always 2 raise ValueError n = read_bitcoin_varint(r) signature = r.read_memoryview(n - 1) sighash_type = SigHashType.from_int(r.get()) pubkey = read_memoryview_prefixed(r) if r.remaining_count(): raise ValueError except (ValueError, EOFError): raise wire.DataError("Invalid witness.") return pubkey, signature, sighash_type
def parse_witness_p2tr(witness: bytes) -> tuple[memoryview, SigHashType]: try: r = utils.BufferReader(witness) if r.get() != 1: # Number of stack items. # Only Taproot key path spending without annex is supported. raise ValueError n = read_bitcoin_varint(r) if n not in (64, 65): raise ValueError signature = r.read_memoryview(64) if n == 65: sighash_type = SigHashType.from_int(r.get()) else: sighash_type = SigHashType.SIGHASH_ALL_TAPROOT if r.remaining_count(): raise ValueError except (ValueError, EOFError): raise wire.DataError("Invalid witness.") return signature, sighash_type
def read_bytes_prefixed(r: BytearrayReader) -> bytes: n = read_bitcoin_varint(r) return r.read(n)
def read_memoryview_prefixed(r: BufferReader) -> memoryview: n = read_bitcoin_varint(r) return r.read_memoryview(n)