def parse_output_script_multisig(script: bytes) -> Tuple[List[bytes], int]: try: r = BytearrayReader(script) threshold = r.get() - 0x50 pubkey_count = script[-2] - 0x50 if (not 1 <= threshold <= 15 or not 1 <= pubkey_count <= 15 or threshold > pubkey_count): raise ValueError public_keys = [] for i in range(pubkey_count): n = read_op_push(r) if n != 33: raise ValueError public_keys.append(r.read(n)) r.get() # ignore pubkey_count if r.get() != 0xAE: # OP_CHECKMULTISIG raise ValueError if r.remaining_count(): raise ValueError except (ValueError, IndexError): raise wire.DataError("Invalid multisig script") return public_keys, threshold
def parse_input_script_p2pkh(script_sig: bytes, ) -> Tuple[bytes, bytes, int]: try: r = BytearrayReader(script_sig) n = read_op_push(r) signature = r.read(n - 1) hash_type = r.get() n = read_op_push(r) pubkey = r.read() if len(pubkey) != n: raise ValueError except (ValueError, IndexError): wire.DataError("Invalid scriptSig.") return pubkey, signature, hash_type
def decode_seq(data: bytes) -> List[bytes]: r = BytearrayReader(data) if r.get() != 0x30: raise ValueError n = decode_length(r) seq = [] end = r.offset + n while r.offset < end: i = decode_int(r) seq.append(i) if r.offset != end or r.remaining_count(): raise ValueError return seq
def decode_length(r: BytearrayReader) -> int: init = r.get() if init < 0x80: # short form encodes length in initial octet return init if init == 0x80 or init == 0xFF or r.peek() == 0x00: raise ValueError # indefinite length, RFU or not shortest possible # long form n = 0 for _ in range(init & 0x7F): n = n * 0x100 + r.get() if n < 128: raise ValueError # encoding is not the shortest possible return n
def verify_nonownership( proof: bytes, script_pubkey: bytes, commitment_data: bytes, keychain: seed.Keychain, coin: CoinInfo, ) -> bool: try: r = BytearrayReader(proof) if r.read(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(_OWNERSHIP_ID_LEN)): not_owned = False # Verify the BIP-322 SignatureProof. proof_body = proof[:r.offset] sighash = hashlib.sha256(proof_body) sighash.update(script_pubkey) sighash.update(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.digest()) except (ValueError, IndexError): raise wire.DataError("Invalid proof of ownership") return not_owned
def parse_witness_multisig( witness: bytes) -> Tuple[bytes, List[Tuple[bytes, int]]]: try: r = BytearrayReader(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, IndexError): raise wire.DataError("Invalid witness.") return script, signatures
def read_op_push(r: BytearrayReader) -> int: prefix = r.get() if prefix < 0x4C: n = prefix elif prefix == 0x4C: n = r.get() elif prefix == 0x4D: n = r.get() n += r.get() << 8 elif prefix == 0x4E: n = r.get() n += r.get() << 8 n += r.get() << 16 n += r.get() << 24 else: raise ValueError return n
def decode_int(r: BytearrayReader) -> bytes: if r.get() != 0x02: raise ValueError n = decode_length(r) if n == 0: raise ValueError if r.peek() & 0x80: raise ValueError # negative integer if r.peek() == 0x00 and n > 1: r.get() n -= 1 if r.peek() & 0x80 == 0x00: raise ValueError # excessive zero-padding if r.peek() == 0x00: raise ValueError # excessive zero-padding return r.read(n)
def parse_witness_p2wpkh(witness: bytes) -> Tuple[bytes, bytes, int]: try: r = BytearrayReader(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, IndexError): raise wire.DataError("Invalid witness.") return pubkey, signature, hash_type
def parse_input_script_multisig( script_sig: bytes, ) -> Tuple[bytes, List[Tuple[bytes, int]]]: try: r = BytearrayReader(script_sig) # Skip over OP_FALSE, which is due to the old OP_CHECKMULTISIG bug. if r.get() != 0: raise ValueError signatures = [] n = read_op_push(r) while r.remaining_count() > n: signature = r.read(n - 1) hash_type = r.get() signatures.append((signature, hash_type)) n = read_op_push(r) script = r.read() if len(script) != n: raise ValueError except (ValueError, IndexError): raise wire.DataError("Invalid scriptSig.") return script, signatures
def read_bytes_prefixed(r: BytearrayReader) -> bytes: n = read_bitcoin_varint(r) return r.read(n)
def read_bip322_signature_proof(r: BytearrayReader) -> Tuple[bytes, bytes]: script_sig = read_bytes_prefixed(r) witness = r.read() return script_sig, witness