def test_p2ms_p2sh() -> None: "BIP67 test vectors https://en.bitcoin.it/wiki/BIP_0067" data_folder = path.join(path.dirname(__file__), "test_data") filename = path.join(data_folder, "bip67_test_vectors.json") with open(filename, "r") as f: # json.dump(test_vectors, f, indent=4) test_vectors = json.load(f) m = 2 for i in test_vectors: keys, address = test_vectors[i] errmsg = f"Test vector #{int(i)}" scriptPubKey = p2ms(keys, m) addr = base58address.p2sh(scriptPubKey) assert addr.decode() == address, errmsg scriptPubKey = scriptPubKey_from_payload("p2ms", keys, m) addr = base58address.p2sh(scriptPubKey) assert addr.decode() == address, errmsg script_type, payload, m2 = payload_from_scriptPubKey(scriptPubKey) assert script_type == "p2ms", errmsg for key, k in zip(sorted(keys), payload): assert key == k.hex(), errmsg assert m2 == m, errmsg
def test_p2ms_p2sh(self): test_vectors = [ [0, ['022df8750480ad5b26950b25c7ba79d3e37d75f640f8e5d9bcd5b150a0f85014da', '03e3818b65bcc73a7d64064106a859cc1a5a728c4345ff0b641209fba0d90de6e9', '021f2f6e1e50cb6a953935c3601284925decd3fd21bc445712576873fb8c6ebc18', ], b'3Q4sF6tv9wsdqu2NtARzNCpQgwifm2rAba' ], [1, ['02ff12471208c14bd580709cb2358d98975247d8765f92bc25eab3b2763ed605f8', '02fe6f0a5a297eb38c391581c4413e084773ea23954d93f7753db7dc0adc188b2f', ], b'39bgKC7RFbpoCRbtD5KEdkYKtNyhpsNa3Z' ], [2, ['02632b12f4ac5b1d1b72b2a3b508c19172de44f6f46bcee50ba33f3f9291e47ed0', '027735a29bae7780a9755fae7a1c4374c656ac6a69ea9f3697fda61bb99a4f3e77', '02e2cc6bd5f45edd43bebe7cb9b675f0ce9ed3efe613b177588290ad188d11b404', ], b'3CKHTjBKxCARLzwABMu9yD85kvtm7WnMfH' ], [3, ['030000000000000000000000000000000000004141414141414141414141414141', '020000000000000000000000000000000000004141414141414141414141414141', '020000000000000000000000000000000000004141414141414141414141414140', '030000000000000000000000000000000000004141414141414141414141414140', ], b'32V85igBri9zcfBRVupVvwK18NFtS37FuD' ], [4, ['022df8750480ad5b26950b25c7ba79d3e37d75f640f8e5d9bcd5b150a0f85014da', '03e3818b65bcc73a7d64064106a859cc1a5a728c4345ff0b641209fba0d90de6e9', '021f2f6e1e50cb6a953935c3601284925decd3fd21bc445712576873fb8c6ebc18', ], b'3Q4sF6tv9wsdqu2NtARzNCpQgwifm2rAba' ], ] m = 2 for i, keys, address in test_vectors: errmsg = f"Test vector #{int(i)}" script = p2ms(keys, m) addr = base58address.p2sh(script) self.assertEqual(addr, address, errmsg) script = scriptPubKey_from_payload('p2ms', keys, m) addr = base58address.p2sh(script) self.assertEqual(addr, address, errmsg) script_type, payload, m2 = payload_from_scriptPubKey(script) self.assertEqual(script_type, 'p2ms', errmsg) for key, k in zip(sorted(keys), payload): self.assertEqual(key, k.hex(), errmsg) self.assertEqual(m2, m, errmsg)
def test_p2ms(self): script_type = "p2ms" # self-consistency pubkey1 = ( "04" "cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaf" "f7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4" ) pubkey2 = ( "04" "61cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d765" "19aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af" ) pubkeys = [bytes.fromhex(pubkey1), bytes.fromhex(pubkey2)] m = 1 # straight to the scriptPubKey scriptPubKey = p2ms(pubkeys, m) n = len(pubkeys) script = encode([m] + sorted(pubkeys) + [n, "OP_CHECKMULTISIG"]) self.assertEqual(scriptPubKey.hex(), script.hex()) # to the scriptPubKey in two steps (through payload) scriptPubKey = scriptPubKey_from_payload(script_type, pubkeys, m) self.assertEqual(scriptPubKey.hex(), script.hex()) # back from the scriptPubKey to the payload script_type2, payload2, m2 = payload_from_scriptPubKey(scriptPubKey) self.assertEqual(script_type, script_type2) self.assertEqual(m, m2) self.assertEqual(sorted(pubkeys), payload2) script_type2, payload2, m2 = payload_from_scriptPubKey(script) self.assertEqual(script_type, script_type2) self.assertEqual(m, m2) self.assertEqual(sorted(pubkeys), payload2) # data -> payload in this case is invertible (no hash functions) # No address for p2ms script self.assertRaises(ValueError, address_from_scriptPubKey, scriptPubKey) # address_from_scriptPubKey(scriptPubKey) # documented test case: https://learnmeabitcoin.com/guide/p2ms pubkey1 = ( "04" "cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaf" "f7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4" ) pubkey2 = ( "04" "61cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d765" "19aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af" ) pubkeys = [bytes.fromhex(pubkey1), bytes.fromhex(pubkey2)] m = 1 n = 2 script = ( "51" # OP_1 "41" # canonical 65-bytes push "04" "cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaf" "f7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4" "41" # canonical 65-bytes push "04" "61cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d765" "19aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af" "52" # OP_2 "ae" # OP_CHECKMULTISIG ) scriptPubKey = p2ms(pubkeys, 1, lexicographic_sort=False) self.assertEqual(scriptPubKey.hex(), script) # Impossible m>n 3-of-2 multisignature self.assertRaises(ValueError, p2ms, pubkeys, 3) # p2ms(pubkeys, 3) # Invalid m (0) for p2ms script self.assertRaises(ValueError, p2ms, pubkeys, 0) # p2ms(pubkeys, 0) # Invalid size: 66 bytes instead of 65 self.assertRaises(ValueError, p2ms, [pubkey1 + "00", pubkey2], 1) # p2ms([pubkey1 + "00", pubkey2], 1) # Invalid n (17) in 3-of-17 multisignature self.assertRaises(ValueError, p2ms, [pubkey1] * 17, 3) # p2ms([pubkey1]*17, 3) # Invalid key length (66) in p2ms badpubkeys = sorted(pubkeys) badpubkeys[0] = badpubkeys[0] + b"\x00" self.assertRaises( ValueError, scriptPubKey_from_payload, script_type, badpubkeys, m ) # scriptPubKey_from_payload(script_type, badpubkeys, m) # Invalid key length (66) in p2ms script = encode([m] + sorted(badpubkeys) + [n, "OP_CHECKMULTISIG"]) self.assertRaises(ValueError, payload_from_scriptPubKey, script) # payload_from_scriptPubKey(script) # Invalid key in p2ms script = encode([m] + [0, pubkeys[1]] + [n, "OP_CHECKMULTISIG"]) self.assertRaises(ValueError, payload_from_scriptPubKey, script) # payload_from_scriptPubKey(script) # Invalid m (0) for p2ms script self.assertRaises( ValueError, scriptPubKey_from_payload, script_type, pubkeys, 17 )
def test_p2ms_p2sh(self): "BIP67 test vectors https://en.bitcoin.it/wiki/BIP_0067" test_vectors = { 0: [ [ ( "022df8750480ad5b26950b25c7ba79d3e37d75f640f8e5d9bcd5b1" "50a0f85014da" ), ( "03e3818b65bcc73a7d64064106a859cc1a5a728c4345ff0b641209" "fba0d90de6e9" ), ( "021f2f6e1e50cb6a953935c3601284925decd3fd21bc4457125768" "73fb8c6ebc18" ), ], b"3Q4sF6tv9wsdqu2NtARzNCpQgwifm2rAba", ], 1: [ [ ( "02ff12471208c14bd580709cb2358d98975247d8765f92bc25eab3" "b2763ed605f8" ), ( "02fe6f0a5a297eb38c391581c4413e084773ea23954d93f7753db7" "dc0adc188b2f" ), ], b"39bgKC7RFbpoCRbtD5KEdkYKtNyhpsNa3Z", ], 2: [ [ ( "02632b12f4ac5b1d1b72b2a3b508c19172de44f6f46bcee50ba33f" "3f9291e47ed0" ), ( "027735a29bae7780a9755fae7a1c4374c656ac6a69ea9f3697fda6" "1bb99a4f3e77" ), ( "02e2cc6bd5f45edd43bebe7cb9b675f0ce9ed3efe613b177588290" "ad188d11b404" ), ], b"3CKHTjBKxCARLzwABMu9yD85kvtm7WnMfH", ], 3: [ [ ( "030000000000000000000000000000000000004141414141414141" "414141414141" ), ( "020000000000000000000000000000000000004141414141414141" "414141414141" ), ( "020000000000000000000000000000000000004141414141414141" "414141414140" ), ( "030000000000000000000000000000000000004141414141414141" "414141414140" ), ], b"32V85igBri9zcfBRVupVvwK18NFtS37FuD", ], 4: [ [ ( "022df8750480ad5b26950b25c7ba79d3e37d75f640f8e5d9bcd5b1" "50a0f85014da" ), ( "03e3818b65bcc73a7d64064106a859cc1a5a728c4345ff0b641209" "fba0d90de6e9" ), ( "021f2f6e1e50cb6a953935c3601284925decd3fd21bc4457125768" "73fb8c6ebc18" ), ], b"3Q4sF6tv9wsdqu2NtARzNCpQgwifm2rAba", ], } m = 2 for i in test_vectors: keys, address = test_vectors[i] errmsg = f"Test vector #{int(i)}" script = p2ms(keys, m) addr = base58address.p2sh(script) self.assertEqual(addr, address, errmsg) script = scriptPubKey_from_payload("p2ms", keys, m) addr = base58address.p2sh(script) self.assertEqual(addr, address, errmsg) script_type, payload, m2 = payload_from_scriptPubKey(script) self.assertEqual(script_type, "p2ms", errmsg) for key, k in zip(sorted(keys), payload): self.assertEqual(key, k.hex(), errmsg) self.assertEqual(m2, m, errmsg)
def test_p2ms() -> None: script_type = "p2ms" # self-consistency pubkey1 = ( "04" "cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaf" "f7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4") pubkey2 = ( "04" "61cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d765" "19aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af") pubkeys = [bytes.fromhex(pubkey1), bytes.fromhex(pubkey2)] m = 1 # straight to the scriptPubKey payload = sorted(pubkeys) n = len(pubkeys) scriptPubKey = script.encode([m] + payload + [n, "OP_CHECKMULTISIG"]) assert scriptPubKey == p2ms(pubkeys, m) # to the scriptPubKey in two steps (through payload) assert scriptPubKey == scriptPubKey_from_payload(script_type, pubkeys, m) # back from the scriptPubKey to the payload assert (script_type, payload, m) == payload_from_scriptPubKey(scriptPubKey) err_msg = "no address for p2ms scriptPubKey" with pytest.raises(ValueError, match=err_msg): address_from_scriptPubKey(scriptPubKey) # documented test case: https://learnmeabitcoin.com/guide/p2ms pubkeys = [bytes.fromhex(pubkey1), bytes.fromhex(pubkey2)] m = 1 n = 2 scriptPubKey = ( # fmt: off "51" # OP_1 "41" # canonical 65-bytes push + pubkey1 + "41" # noqa E148 # canonical 65-bytes push + pubkey2 + "52" # noqa E148 # OP_2 "ae" # OP_CHECKMULTISIG ) # fmt: on assert scriptPubKey == p2ms(pubkeys, 1, lexicographic_sort=False).hex() err_msg = "number-of-pubkeys < m in " with pytest.raises(ValueError, match=err_msg): p2ms(pubkeys, 3) err_msg = "invalid m for p2ms scriptPubKey: " with pytest.raises(ValueError, match=err_msg): p2ms(pubkeys, 0) err_msg = "not a private or public key: " with pytest.raises(ValueError, match=err_msg): p2ms([pubkey1 + "00", pubkey2], 1) err_msg = "too many pubkeys in m-of-n multisignature: " with pytest.raises(ValueError, match=err_msg): p2ms([pubkey1] * 17, 3) err_msg = "invalid size: " badpubkeys = sorted(pubkeys) badpubkeys[0] = badpubkeys[0] + b"\x00" with pytest.raises(ValueError, match=err_msg): scriptPubKey_from_payload(script_type, badpubkeys, m) scriptPubKey = script.encode([m] + sorted(badpubkeys) + [n, "OP_CHECKMULTISIG"]) with pytest.raises(ValueError, match=err_msg): payload_from_scriptPubKey(scriptPubKey) err_msg = "invalid key in p2ms" scriptPubKey = script.encode([m] + [0, pubkeys[1]] + [n, "OP_CHECKMULTISIG"]) with pytest.raises(ValueError, match=err_msg): payload_from_scriptPubKey(scriptPubKey) err_msg = "invalid m in m-of-n multisignature: " with pytest.raises(ValueError, match=err_msg): scriptPubKey_from_payload(script_type, pubkeys, 17)