def __get_multisig_script_sig__(self, script_sig, keys, signatures, script_code, redeem_script, n, amount=None): sig_map = {keys[i]:signatures[i] for i in range(len(keys))} pub_keys = get_multisig_public_keys(redeem_script) p2wsh = True if isinstance(script_sig, list) else False if not p2wsh: s = get_stream(script_sig) o, d = read_opcode(s) while o: o, d = read_opcode(s) if d and is_valid_signature_encoding(d): for i in range(4): sighash = self.sig_hash(n, script_pub_key=script_code, sighash_type=d[-1]) sighash = s2rh(sighash) if isinstance(sighash, str) else sighash pk = public_key_recovery(d[:-1], sighash, i, hex=0) if pk in pub_keys: sig_map[pk] = d break # recreate script sig r = [OP_0] for k in pub_keys: try: r.append(op_push_data(sig_map[k])) except: pass r += [op_push_data(redeem_script)] else: for w in script_sig: if isinstance(w, str): w = bytes.fromhex(w) if w and is_valid_signature_encoding(w): d = w[:-1] for i in range(4): sighash = self.sig_hash_segwit(n, amount, script_pub_key=script_code, sighash_type=w[-1]) pk = public_key_recovery(d, sighash, i, hex=0) if pk in pub_keys: sig_map[pk] = w break r = [b""] for k in pub_keys: try: r.append(sig_map[k]) except: pass r += [redeem_script] return r
def __init__(self, key=None, address_type="P2WPKH", testnet=False, compressed=True): if key is None: #: instance of ``PrivateKey`` class self.private_key = PrivateKey(testnet=testnet, compressed=compressed) #: instance of ``PublicKey`` class self.public_key = PublicKey(self.private_key) #: flag for testnet network address (boolean) self.testnet = testnet if isinstance(key, str) or isinstance(key, bytes): key = PrivateKey(key, testnet=testnet, compressed=compressed) if isinstance(key, PrivateKey): self.private_key = key self.testnet = key.testnet compressed = key.compressed self.public_key = PublicKey(self.private_key) elif isinstance(key, PublicKey): self.public_key = key self.testnet = testnet compressed = key.compressed if address_type not in ("P2PKH", "PUBKEY", "P2WPKH", "P2SH_P2WPKH"): raise TypeError("address type invalid") if not compressed: if address_type not in ("P2PKH", "PUBKEY", "P2SH"): raise TypeError("compressed public key invalid") #: flag for testnet network address (boolean) self.type = address_type if address_type == "PUBKEY": self.pubkey_script = b"%s%s" % (op_push_data( self.public_key.key), OP_CHECKSIG) self.pubkey_script_hex = self.pubkey_script.hex() #: version of witness program for SEGWIT address (string) self.witness_version = 0 if address_type == "P2WPKH" else None self.compressed = compressed if address_type == "P2SH_P2WPKH": #: flag for script hash address (boolean) self.script_hash = True #: redeeem script, only for P2SH_P2WPKH (bytes) self.redeem_script = public_key_to_p2sh_p2wpkh_script( self.public_key.key) #: redeeem script HEX, only for P2SH_P2WPKH (string) self.redeem_script_hex = self.redeem_script.hex() #: address hash self.hash = hash160(self.redeem_script) self.witness_version = None else: self.script_hash = False self.hash = hash160(self.public_key.key) #: address hash HEX (string) self.hash_hex = self.hash.hex() #: address in base58 or bech32 encoding (string) self.address = hash_to_address(self.hash, script_hash=self.script_hash, witness_version=self.witness_version, testnet=self.testnet)
def __sign_p2sh_p2wpkh(self, n, private_key, public_key, redeem_script, sighash_type, amount): s = [b'\x19', OP_DUP, OP_HASH160, op_push_data(hash160(public_key[0], 0)), OP_EQUALVERIFY, OP_CHECKSIG] if amount is None: try: amount = self["vIn"][n]["value"] except: raise RuntimeError("no input amount") sighash = self.sig_hash_segwit(n, amount, script_pub_key=b"".join(s), sighash_type=sighash_type) sighash = bytes.fromhex(sighash) if isinstance(sighash, str) else sighash signature = sign_message(sighash, private_key[0], 0) + bytes([sighash_type]) self["segwit"] = True if self["format"] == "raw": self["vIn"][n]['txInWitness'] = [signature, public_key[0]] else: self["vIn"][n]['txInWitness'] = [signature.hex(), public_key[0].hex()] self["vIn"][n]['signatures'] = [signature,] if self["format"] == "raw" else [signature.hex(),] return op_push_data(redeem_script)
def test_op_push_data(): assert op_push_data("") == b"\x00" assert op_push_data(b"1234567890") == b'\n1234567890' assert op_push_data(b"1" * 75) == b'K' + b"1" * 75 assert op_push_data(b"1" * 76) != b'\x4c' + b"1" * 76 assert op_push_data(b"1" * 76) == get_bytes( [OP_PUSHDATA1, b"\x4c", b"1" * 76]) assert op_push_data(b"1" * 256) == get_bytes( [OP_PUSHDATA2, pack('<H', 256), b"1" * 256]) p = b"1" * 65537 l = op_push_data(p) == OP_PUSHDATA4 + pack('<L', 65537) + p assert l
def __sign_p2sh_p2wsh_multisig(self, n, private_key, public_key, redeem_script, sighash_type, amount): self["segwit"] = True script_code = int_to_var_int(len(redeem_script)) + redeem_script sighash = self.sig_hash_segwit(n, amount, script_pub_key=script_code, sighash_type=sighash_type) sighash = bytes.fromhex(sighash) if isinstance(sighash, str) else sighash sig = [sign_message(sighash, p, 0) + bytes([sighash_type]) for p in private_key] self["vIn"][n]['signatures'] = [s if self["format"] == "raw" else s.hex() for s in sig] if "txInWitness" not in self["vIn"][n]: self["vIn"][n]["txInWitness"] = [] witness = self.__get_multisig_script_sig__(self["vIn"][n]["txInWitness"], public_key, sig, script_code, redeem_script, n, amount) if self["format"] == "raw": self["vIn"][n]['txInWitness'] = list(witness) else: self["vIn"][n]["txInWitness"] = list([w.hex() for w in witness]) # calculate P2SH redeem script from P2WSH redeem script return op_push_data(b"\x00" + op_push_data(sha256(redeem_script)))
def __get_bare_multisig_script_sig__(self, script_sig, script_pub_key, keys, signatures, n): sig_map = {keys[i]:signatures[i] for i in range(len(keys))} pub_keys = get_multisig_public_keys(script_pub_key) s = get_stream(script_sig) o, d = read_opcode(s) while o: o, d = read_opcode(s) if d and is_valid_signature_encoding(d): for i in range(4): sighash = self.sig_hash(n, script_pub_key=script_pub_key, sighash_type=d[-1]) sighash = s2rh(sighash) if isinstance(sighash, str) else sighash pk = public_key_recovery(d[:-1], sighash, i, hex=0) if pk in pub_keys: sig_map[pk] = d break # recreate script sig r = [OP_0] for k in pub_keys: try: r.append(op_push_data(sig_map[k])) except: pass return r
def op_push_data(data): return __parent__.op_push_data(data)