def test_multisig_sig(): sig_script = Script('OP_0 0x30440220762ce7bca626942975bfd5b130ed3470b9f538eb2ac120c2043b445709369628022051d73c80328b543f744aa64b7e9ebefa7ade3e5c716eab4a09b408d2c307ccd701 0x3045022100abf740b58d79cab000f8b0d328c2fff7eb88933971d1b63f8b99e89ca3f2dae602203354770db3cc2623349c87dea7a50cee1f78753141a5052b2d58aeb592bcf50f01 0x524104a882d414e478039cd5b52a92ffb13dd5e6bd4515497439dffd691a0f12af9575fa349b5694ed3155b136f09e63975a1700c9f4d4df849323dac06cf3bd6458cd41046ce31db9bdd543e72fe3039a1f1c047dab87037c36a669ff90e28da1848f640de68c2fe913d363a51154a0c62d7adea1b822d05035077418267b1a1379790187410411ffd36c70776538d079fbae117dc38effafb33304af83ce4894589747aee1ef992f63280567f52f5ba870678b4ab4ff6c8ea600bd217870a8b4f1f09f3a8e8353ae') # nopep8 assert sig_script.is_multisig_sig() r = sig_script.extract_multisig_sig_info() redeem_info = r['redeem_script'].extract_multisig_redeem_info() assert len(r['signatures']) == 2 assert r['redeem_script'] assert isinstance(r['redeem_script'], Script) s = Script.build_multisig_sig(r['signatures'], r['redeem_script']) assert bytes(s) == bytes(sig_script) # This is a test case where there is no OP_PUSHDATA raw_scr = "00483045022100fa1225f8828fd6fe52665c3c4258169a84af52b41525f2e288082f174c032f47022022758d5519db3ab2cec4a330e96568b9289fb77c5653bce49397df01a3fcff5101475221038b5fa60aee4c4e9ab3a66e6bb32211a54da6b054c6143dd221c122ce936315d921023180e1b49b7f3fd1254a19c7aa8016ad995089b99c9dac89752cd17e40d9072d52ae" # nopep8 s, _ = Script.from_bytes(pack_var_str(bytes.fromhex(raw_scr))) assert sig_script.is_multisig_sig() r = s.extract_multisig_sig_info() assert len(r['signatures']) == 1 assert r['redeem_script'] assert isinstance(r['redeem_script'], Script) sig_addresses = sig_script.get_addresses() assert len(sig_addresses) == redeem_info['n'] + 1 assert sig_addresses == ['1JzVFZSN1kxGLTHG41EVvY5gHxLAX7q1Rh', '14JfSvgEq8A8S7qcvxeaSCxhn1u1L71vo4', '1Kyy7pxzSKG75L9HhahRZgYoer9FePZL4R', '347N1Thc213QqfYCz3PZkjoJpNv5b14kBd']
def _do_multisig_script(self, sigs, message, current_script_sig, redeem_script, hash_type): # If the current script is empty or None, create it sig_script = None if current_script_sig is None or not str(current_script_sig): sig_bytes = [s['signature'].to_der() + pack_compact_int(hash_type) for s in sigs] sig_script = Script.build_multisig_sig(sigs=sig_bytes, redeem_script=redeem_script) else: # Need to extract all the sigs already present multisig_params = redeem_script.extract_multisig_redeem_info() sig_info = current_script_sig.extract_multisig_sig_info() # Do a few quick sanity checks if str(sig_info['redeem_script']) != str(redeem_script): raise ValueError( "Redeem script in signature script does not match redeem_script!") if len(sig_info['signatures']) == multisig_params['n']: # Already max number of signatures return current_script_sig # Go through the signatures and match them up to the public keys # in the redeem script pub_keys = [] for pk in multisig_params['public_keys']: pub_keys.append(crypto.PublicKey.from_bytes(pk)) existing_sigs = [] for s in sig_info['signatures']: s1, h = s[:-1], s[-1] # Last byte is hash_type existing_sigs.append(crypto.Signature.from_der(s1)) if h != hash_type: raise ValueError("hash_type does not match that of the existing signatures.") # Match them up existing_sig_indices = self._match_sigs_to_pub_keys(existing_sigs, pub_keys, message) sig_indices = {s['index']: s['signature'] for s in sigs} # Make sure there are no dups all_indices = set(list(existing_sig_indices.keys()) + list(sig_indices.keys())) if len(all_indices) < len(existing_sig_indices) + len(sig_indices): raise ValueError("At least one signature matches an existing signature.") if len(all_indices) > multisig_params['n']: raise ValueError("There are too many signatures.") all_sigs = [] for i in sorted(all_indices): if i in existing_sig_indices: all_sigs.append(existing_sig_indices[i]) elif i in sig_indices: all_sigs.append(sig_indices[i]) all_sigs_bytes = [s.to_der() + pack_compact_int(hash_type) for s in all_sigs] sig_script = Script.build_multisig_sig(all_sigs_bytes, redeem_script) return sig_script
def _do_multisig_script(self, sigs, message, current_script_sig, redeem_script, hash_type): # If the current script is empty or None, create it sig_script = None if current_script_sig is None or not str(current_script_sig): sig_bytes = [s['signature'].to_der() + pack_compact_int(hash_type) for s in sigs] sig_script = Script.build_multisig_sig(sigs=sig_bytes, redeem_script=redeem_script) else: # Need to extract all the sigs already present multisig_params = redeem_script.extract_multisig_redeem_info() sig_info = current_script_sig.extract_multisig_sig_info() # Do a few quick sanity checks if str(sig_info['redeem_script']) != str(redeem_script): raise ValueError( "Redeem script in signature script does not match redeem_script!") if len(sig_info['signatures']) == multisig_params['n']: # Already max number of signatures return current_script_sig # Go through the signatures and match them up to the public keys # in the redeem script pub_keys = [] for pk in multisig_params['public_keys']: pub_keys.append(crypto.PublicKey.from_bytes(pk)) existing_sigs = [] for s in sig_info['signatures']: s1, h = s[:-1], s[-1] # Last byte is hash_type existing_sigs.append(crypto.Signature.from_der(s1)) if h != hash_type: raise ValueError("hash_type does not match that of the existing signatures.") # Match them up existing_sig_indices = self._match_sigs_to_pub_keys(existing_sigs, pub_keys, message) sig_indices = {s['index']: s['signature'] for s in sigs} # Make sure there are no dups all_indices = set(list(existing_sig_indices.keys()) + list(sig_indices.keys())) if len(all_indices) < len(existing_sig_indices) + len(sig_indices): raise ValueError("At least one signature matches an existing signature.") if len(all_indices) > multisig_params['n']: raise ValueError("There are too many signatures.") all_sigs = [] for i in sorted(all_indices): if i in existing_sig_indices: all_sigs.append(existing_sig_indices[i]) elif i in sig_indices: all_sigs.append(sig_indices[i]) all_sigs_bytes = [s.to_der() + pack_compact_int(hash_type) for s in all_sigs] sig_script = Script.build_multisig_sig(all_sigs_bytes, redeem_script) return sig_script