sign bare multisig inputs

This commit is contained in:
4tochka 2018-07-08 21:31:51 +04:00
parent 3fee93ce08
commit 28254bc38c
3 changed files with 104 additions and 17 deletions

View File

@ -1009,23 +1009,74 @@ class TransactionConstructorTests(unittest.TestCase):
redeem_script=redeem, amount=987654321, p2sh_p2wsh=1, sighash_type=SIGHASH_SINGLE)
self.assertEqual(r, tx.serialize())
a1 = Address("cPBuqn4ZsddXunx6EEev6khbfUzFnh3xxdEUPCrm5uy9qGcmbBEt", address_type="P2PKH", testnet=True)
a2 = Address("cVgShyj2q4YKFX8VzCffuQcrJVYhp522NFozNi7ih2KgNVbnysKX", address_type="P2PKH", testnet=True)
a3 = Address("cQWBhFENcN8bKEBsUHvpCyCfWVHDLfn1M65Gd6nenQkpEqL4DNUH", address_type="P2PKH", testnet=True)
script = b"".join([OP_2,
op_push_data(a1.public_key.key),
op_push_data(a2.public_key.key),
op_push_data(a3.public_key.key),
OP_3,
OP_CHECKMULTISIG])
assert a1.address == "mwJMtn5hW54pJC748EExvhRm6FRVmUZXQt"
tx = Transaction(testnet=True)
tx.add_input("d791f8386516bc464e7702159775734559d884a3fd50e45191c6207cdedac8ae", 0)
tx.add_output(64000000, script_pub_key=script)
tx.sign_input(0, private_key="cPBuqn4ZsddXunx6EEev6khbfUzFnh3xxdEUPCrm5uy9qGcmbBEt",
address="mwJMtn5hW54pJC748EExvhRm6FRVmUZXQt")
assert tx.serialize() == "0100000001aec8dade7c20c69151e450fda384d859457375971502774e46bc166538f891d7000000" \
"006a47304402200edb1ded443ea8015390c38afeb0564b52f6f9895c45952461f6ccfaf6639b8402" \
"206c0d3bfd2f7d8c68d5cc3c774a9403d843cd27e33148927e3f575607b91d05c2012103b4603330" \
"291721c0a8e9cae65124a7099ecf0df3b46921d0e30c4220597702cbffffffff010090d003000000" \
"0069522103b4603330291721c0a8e9cae65124a7099ecf0df3b46921d0e30c4220597702cb2102b2" \
"ec7de7e811c05aaf8443e3810483d5dbcf671512d9999f9c9772b0ce9da47a2102c711ad61c9fbd3" \
"600716b981d101cf0a000ab3524525235c42f2cbcd8c17c6da53ae00000000"
"cfe002d20590e2400a26b2dd9e2e6af2369cbb1f5442af286485841798590068"
tx = Transaction(testnet=True)
tx.add_input("cfe002d20590e2400a26b2dd9e2e6af2369cbb1f5442af286485841798590068", 0)
tx.add_output(63000000, address="mwJMtn5hW54pJC748EExvhRm6FRVmUZXQt")
tx.sign_input(0, private_key=["cPBuqn4ZsddXunx6EEev6khbfUzFnh3xxdEUPCrm5uy9qGcmbBEt",
"cVgShyj2q4YKFX8VzCffuQcrJVYhp522NFozNi7ih2KgNVbnysKX"],
script_pub_key=script)
self.assertEqual(tx.serialize(), "0100000001680059981784856428af42541fbb9c36f26a2e9eddb2260a40e29005d202e"
"0cf000000009300483045022100a7383d84ee35fb965978144d9243ca0892a1be81ce70"
"058e70b2ba1ea5a762a7022058647d131fcec2e3a63e57fa475b779b94c81a95b5c164f"
"dfdbcee0124e3448c01483045022100b3945861a5a8a406bd575857e19accdb0f6385eb"
"f1c02938b35462cddeef400802205857f56d83e9ed7e98082d9127b8934262d3a046142"
"9747e865b06345bbf8f9e01ffffffff01c04dc103000000001976a914ad204de226b3d1"
"1a70dc53b4998f4603e138ff3f88ac00000000")
tx = Transaction(testnet=True)
tx.add_input("cfe002d20590e2400a26b2dd9e2e6af2369cbb1f5442af286485841798590068", 0)
tx.add_output(63000000, address="mwJMtn5hW54pJC748EExvhRm6FRVmUZXQt")
tx.sign_input(0, private_key="cPBuqn4ZsddXunx6EEev6khbfUzFnh3xxdEUPCrm5uy9qGcmbBEt",
script_pub_key=script)
tx.sign_input(0, private_key="cVgShyj2q4YKFX8VzCffuQcrJVYhp522NFozNi7ih2KgNVbnysKX",
script_pub_key=script)
self.assertEqual(tx.serialize(), "0100000001680059981784856428af42541fbb9c36f26a2e9eddb2260a40e29005d202e"
"0cf000000009300483045022100a7383d84ee35fb965978144d9243ca0892a1be81ce70"
"058e70b2ba1ea5a762a7022058647d131fcec2e3a63e57fa475b779b94c81a95b5c164f"
"dfdbcee0124e3448c01483045022100b3945861a5a8a406bd575857e19accdb0f6385eb"
"f1c02938b35462cddeef400802205857f56d83e9ed7e98082d9127b8934262d3a046142"
"9747e865b06345bbf8f9e01ffffffff01c04dc103000000001976a914ad204de226b3d1"
"1a70dc53b4998f4603e138ff3f88ac00000000")
tx = Transaction(testnet=True)
tx.add_input("cfe002d20590e2400a26b2dd9e2e6af2369cbb1f5442af286485841798590068", 0)
tx.add_output(63000000, address="mwJMtn5hW54pJC748EExvhRm6FRVmUZXQt")
tx.sign_input(0, private_key="cVgShyj2q4YKFX8VzCffuQcrJVYhp522NFozNi7ih2KgNVbnysKX",
script_pub_key=script)
tx.sign_input(0, private_key="cPBuqn4ZsddXunx6EEev6khbfUzFnh3xxdEUPCrm5uy9qGcmbBEt",
script_pub_key=script)
self.assertEqual(tx.serialize(), "0100000001680059981784856428af42541fbb9c36f26a2e9eddb2260a40e29005d202e"
"0cf000000009300483045022100a7383d84ee35fb965978144d9243ca0892a1be81ce70"
"058e70b2ba1ea5a762a7022058647d131fcec2e3a63e57fa475b779b94c81a95b5c164f"
"dfdbcee0124e3448c01483045022100b3945861a5a8a406bd575857e19accdb0f6385eb"
"f1c02938b35462cddeef400802205857f56d83e9ed7e98082d9127b8934262d3a046142"
"9747e865b06345bbf8f9e01ffffffff01c04dc103000000001976a914ad204de226b3d1"
"1a70dc53b4998f4603e138ff3f88ac00000000")
# print(parse_script("56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae"))

View File

@ -609,6 +609,8 @@ class Transaction(dict):
elif st["type"] == "P2WSH":
script_sig = self.__sign_p2wsh(n, private_key, public_key, script_pub_key,
redeem_script, sighash_type, amount)
elif st["type"] == "MULTISIG":
script_sig = self.__sign_bare_multisig__(n, private_key, public_key, script_pub_key, sighash_type)
else:
raise RuntimeError("not implemented")
@ -621,6 +623,15 @@ class Transaction(dict):
self.__refresh__()
return self
def __sign_bare_multisig__(self, n, private_key, public_key, script_pub_key, sighash_type):
sighash = self.sig_hash(n, script_pub_key=script_pub_key, sighash_type=sighash_type)
sighash = s2rh(sighash) if isinstance(sighash, str) else sighash
sig = [sign_message(sighash, p, 0) + bytes([sighash_type]) for p in private_key]
return b''.join(self.__get_bare_multisig_script_sig__(self["vIn"][n]["scriptSig"],
script_pub_key,
public_key, sig,
n))
def __sign_pubkey__(self, n, private_key, script_pub_key, sighash_type):
sighash = self.sig_hash(n, script_pub_key=script_pub_key, sighash_type=sighash_type)
sighash = s2rh(sighash) if isinstance(sighash, str) else sighash
@ -782,6 +793,31 @@ class Transaction(dict):
# 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 __get_multisig_script_sig__(self, script_sig,
keys, signatures,
script_code,

View File

@ -5,7 +5,7 @@ from setuptools import setup, find_packages
setup(name='pybtc',
version='2.0.1',
version='2.0.2',
description='Python Bitcoin library',
keywords='bitcoin',
url='https://github.com/bitaps-com/pybtc',