def test_slip132_test_vector() -> None: """SLIP132 test vector https://github.com/satoshilabs/slips/blob/master/slip-0132.md """ mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about" kpath = "./0/0" test_vectors: List[Tuple[bytes, str, str, str, str]] = [ ( NETWORKS["mainnet"]["bip32_prv"], "m / 44h / 0h / 0h", "xprv9xpXFhFpqdQK3TmytPBqXtGSwS3DLjojFhTGht8gwAAii8py5X6pxeBnQ6ehJiyJ6nDjWGJfZ95WxByFXVkDxHXrqu53WCRGypk2ttuqncb", "xpub6BosfCnifzxcFwrSzQiqu2DBVTshkCXacvNsWGYJVVhhawA7d4R5WSWGFNbi8Aw6ZRc1brxMyWMzG3DSSSSoekkudhUd9yLb6qx39T9nMdj", "1LqBGSKuX5yYUonjxT5qGfpUsXKYYWeabA", ), ( NETWORKS["mainnet"]["slip132_p2wpkh_p2sh_prv"], "m / 49h / 0h / 0h", "yprvAHwhK6RbpuS3dgCYHM5jc2ZvEKd7Bi61u9FVhYMpgMSuZS613T1xxQeKTffhrHY79hZ5PsskBjcc6C2V7DrnsMsNaGDaWev3GLRQRgV7hxF", "ypub6Ww3ibxVfGzLrAH1PNcjyAWenMTbbAosGNB6VvmSEgytSER9azLDWCxoJwW7Ke7icmizBMXrzBx9979FfaHxHcrArf3zbeJJJUZPf663zsP", "37VucYSaXLCAsxYyAPfbSi9eh4iEcbShgf", ), ( NETWORKS["mainnet"]["slip132_p2wpkh_prv"], "m / 84h / 0h / 0h", "zprvAdG4iTXWBoARxkkzNpNh8r6Qag3irQB8PzEMkAFeTRXxHpbF9z4QgEvBRmfvqWvGp42t42nvgGpNgYSJA9iefm1yYNZKEm7z6qUWCroSQnE", "zpub6rFR7y4Q2AijBEqTUquhVz398htDFrtymD9xYYfG1m4wAcvPhXNfE3EfH1r1ADqtfSdVCToUG868RvUUkgDKf31mGDtKsAYz2oz2AGutZYs", "bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu", ), ] for version, der_path, prv, pub, addr_str in test_vectors: addr = addr_str.encode() rxprv = bip32.mxprv_from_bip39_mnemonic(mnemonic, "") mxprv = bip32.derive(rxprv, der_path, version) assert prv.encode() == mxprv mxpub = bip32.xpub_from_xprv(mxprv) assert pub.encode() == mxpub xpub = bip32.derive(mxpub, kpath) address = slip132.address_from_xpub(xpub) assert addr == address address = slip132.address_from_xkey(xpub) assert addr == address xprv = bip32.derive(mxprv, kpath) address = slip132.address_from_xkey(xprv) assert addr == address if version == NETWORKS["mainnet"]["bip32_prv"]: address = base58address.p2pkh(xpub) assert addr == address address = base58address.p2pkh(xprv) assert addr == address elif version == NETWORKS["mainnet"]["slip132_p2wpkh_p2sh_prv"]: address = base58address.p2wpkh_p2sh(xpub) assert addr == address address = base58address.p2wpkh_p2sh(xprv) assert addr == address elif version == NETWORKS["mainnet"]["slip132_p2wpkh_prv"]: address = bech32address.p2wpkh(xpub) assert addr == address address = bech32address.p2wpkh(xprv) assert addr == address
def test_slip32_test_vector(self): """SLIP32 test vector https://github.com/satoshilabs/slips/blob/master/slip-0132.md """ mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about" kpath = "./0/0" test_vectors = [ [ MAIN_xprv, "m / 44h / 0h / 0h", b'xprv9xpXFhFpqdQK3TmytPBqXtGSwS3DLjojFhTGht8gwAAii8py5X6pxeBnQ6ehJiyJ6nDjWGJfZ95WxByFXVkDxHXrqu53WCRGypk2ttuqncb', b'xpub6BosfCnifzxcFwrSzQiqu2DBVTshkCXacvNsWGYJVVhhawA7d4R5WSWGFNbi8Aw6ZRc1brxMyWMzG3DSSSSoekkudhUd9yLb6qx39T9nMdj', b'1LqBGSKuX5yYUonjxT5qGfpUsXKYYWeabA' ], [ MAIN_yprv, "m / 49h / 0h / 0h", b'yprvAHwhK6RbpuS3dgCYHM5jc2ZvEKd7Bi61u9FVhYMpgMSuZS613T1xxQeKTffhrHY79hZ5PsskBjcc6C2V7DrnsMsNaGDaWev3GLRQRgV7hxF', b'ypub6Ww3ibxVfGzLrAH1PNcjyAWenMTbbAosGNB6VvmSEgytSER9azLDWCxoJwW7Ke7icmizBMXrzBx9979FfaHxHcrArf3zbeJJJUZPf663zsP', b'37VucYSaXLCAsxYyAPfbSi9eh4iEcbShgf' ], [ MAIN_zprv, "m / 84h / 0h / 0h", b'zprvAdG4iTXWBoARxkkzNpNh8r6Qag3irQB8PzEMkAFeTRXxHpbF9z4QgEvBRmfvqWvGp42t42nvgGpNgYSJA9iefm1yYNZKEm7z6qUWCroSQnE', b'zpub6rFR7y4Q2AijBEqTUquhVz398htDFrtymD9xYYfG1m4wAcvPhXNfE3EfH1r1ADqtfSdVCToUG868RvUUkgDKf31mGDtKsAYz2oz2AGutZYs', b'bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu' ], ] for v in test_vectors: rxprv = bip32.rootxprv_from_bip39mnemonic(mnemonic, '', v[0]) mxprv = bip32.derive(rxprv, v[1]) self.assertEqual(v[2], mxprv) mxpub = bip32.xpub_from_xprv(mxprv) self.assertEqual(v[3], mxpub) xpub = bip32.derive(mxpub, kpath) address = slip32.address_from_xpub(xpub) self.assertEqual(v[4], address) address = slip32.address_from_xkey(xpub) self.assertEqual(v[4], address) xprv = bip32.derive(mxprv, kpath) address = slip32.address_from_xkey(xprv) self.assertEqual(v[4], address) if v[0] == MAIN_xprv: address = base58address.p2pkh(xpub) self.assertEqual(v[4], address) address = base58address.p2pkh(xprv) self.assertEqual(v[4], address) elif v[0] == MAIN_yprv: address = base58address.p2wpkh_p2sh(xpub) self.assertEqual(v[4], address) address = base58address.p2wpkh_p2sh(xprv) self.assertEqual(v[4], address) elif v[0] == MAIN_zprv: address = bech32address.p2wpkh(xpub) self.assertEqual(v[4], address) address = bech32address.p2wpkh(xprv) self.assertEqual(v[4], address)
def test_p2wpkh_p2sh() -> None: # https://matthewdowney.github.io/create-segwit-address.html pub = " 03 a1af804ac108a8a51782198c2d034b28bf90c8803f5a53f76276fa69a4eae77f" address = p2wpkh_p2sh(pub) assert address == b"36NvZTcMsMowbt78wPzJaHHWaNiyR73Y4g" address = p2wpkh_p2sh(pub, "testnet") assert address == b"2Mww8dCYPUpKHofjgcXcBCEGmniw9CoaiD2" # http://bitcoinscri.pt/pages/segwit_p2sh_p2wpkh pub = "02 f118cc409775419a931c57664d0c19c405e856ac0ee2f0e2a4137d8250531128" address = p2wpkh_p2sh(pub) assert address == b"3Mwz6cg8Fz81B7ukexK8u8EVAW2yymgWNd"
def test_address_from_wif() -> None: q = 0x19E14A7B6A307F426A94F8114701E7C8E774E7F9A47E2C2035DB29A206321725 test_cases: List[Tuple[bool, str, str, str]] = [ ( False, "mainnet", "5J1geo9kcAUSM6GJJmhYRX1eZEjvos9nFyWwPstVziTVueRJYvW", "1LPM8SZ4RQDMZymUmVSiSSvrDfj1UZY9ig", ), ( True, "mainnet", "Kx621phdUCp6sgEXPSHwhDTrmHeUVrMkm6T95ycJyjyxbDXkr162", "1HJC7kFvXHepkSzdc8RX6khQKkAyntdfkB", ), ( False, "testnet", "91nKEXyJCPYaK9maw7bTJ7ZcCu6dy2gybvNtUWF1LTCYggzhZgy", "mzuJRVe3ERecM6F6V4R6GN9B5fKiPC9HxF", ), ( True, "testnet", "cNT1UjhUuGWN37hnmr754XxvPWwtAJTSq8bcCQ4pUrdxqxbA1iU1", "mwp9QoLuLK65XZUFKhPtvfujBjmgkZnmPx", ), ] for compressed, network, wif, address in test_cases: assert wif.encode() == wif_from_prvkey(q, network, compressed) assert prvkeyinfo_from_prvkey(wif) == (q, network, compressed) b58 = p2pkh(wif) assert b58 == address.encode() _, payload, net, is_script = h160_from_b58address(b58) assert net == network assert not is_script if compressed: b32 = p2wpkh(wif) assert (payload, network, is_script) == witness_from_b32address(b32)[1:] b = p2wpkh_p2sh(wif) _, payload2, net, is_script = h160_from_b58address(b) assert is_script assert (hash160(b"\x00\x14" + payload), network) == (payload2, net) else: err_msg = "not a private or compressed public key: " with pytest.raises(ValueError, match=err_msg): p2wpkh(wif) # type: ignore with pytest.raises(ValueError, match=err_msg): p2wpkh_p2sh(wif) # type: ignore
def test_p2wpkh() -> None: # self-consistency pubkey = "02 cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaf" payload = hash160(pubkey) scriptPubKey = script.encode([0, payload]) assert scriptPubKey == p2wpkh(pubkey) # to the scriptPubKey in two steps (through payload) script_type = "p2wpkh" assert scriptPubKey == scriptPubKey_from_payload(script_type, payload) # back from the scriptPubKey to the payload assert (script_type, payload, 0) == payload_from_scriptPubKey(scriptPubKey) # bech32 address network = "mainnet" address = bech32address.p2wpkh(pubkey, network) assert address == address_from_scriptPubKey(scriptPubKey, network) wit_ver = 0 assert address == b32address_from_witness(wit_ver, payload, network) # back from the address to the scriptPubKey assert (scriptPubKey, network) == scriptPubKey_from_address(address) # p2sh-wrapped base58 address address = base58address.p2wpkh_p2sh(pubkey, network) assert address == b58address_from_witness(payload, network)
def test_witness(self): pub = "03 a1af804ac108a8a51782198c2d034b28bf90c8803f5a53f76276fa69a4eae77f" b58addr = p2wpkh_p2sh(pub) _, h160, network, is_script_hash = h160_from_b58address(b58addr) self.assertEqual(network, 'mainnet') self.assertEqual(is_script_hash, True) #?!?!? self.assertEqual(len(h160), 20) b58addr = _b58segwitaddress(hash160(to_pubkey_bytes(pub, True, ec)), network) _, h160_2, network, is_script_hash = h160_from_b58address(b58addr) self.assertEqual(network, 'mainnet') self.assertEqual(is_script_hash, True) #?!?!? self.assertEqual(len(h160), 20) self.assertEqual(h160.hex(), h160_2.hex()) wscript = "a8a58c2d034b28bf90c8803f5a53f769a4" b58addr = p2wsh_p2sh(wscript) _, h160, network, is_script_hash = h160_from_b58address(b58addr) self.assertEqual(network, 'mainnet') self.assertEqual(is_script_hash, True) #?!?!? self.assertEqual(len(h160), 20) b58addr = _b58segwitaddress(sha256(wscript), network) _, h160_2, network, is_script_hash = h160_from_b58address(b58addr) self.assertEqual(network, 'mainnet') self.assertEqual(is_script_hash, True) #?!?!? self.assertEqual(len(h160), 20) self.assertEqual(h160.hex(), h160_2.hex()) # Invalid witness program length (19) self.assertRaises(ValueError, _b58segwitaddress, h160[:-1], network)
def test_one_prvkey_multiple_addresses(self): msg = "Paolo is afraid of ephemeral random numbers" # Compressed WIF wif = b'Kx45GeUBSMPReYQwgXiKhG9FzNXrnCeutJp4yjTd5kKxCitadm3C' pubkey, network = pubkey_info_from_prvkey(wif) address1 = p2pkh(pubkey, network) address2 = p2wpkh_p2sh(pubkey, network) address3 = p2wpkh(pubkey, network) # sign with no address (or compressed P2PKH) sig1 = bms.sign(msg, wif) # True for Bitcoin Core self.assertTrue(bms.verify(msg, address1, sig1)) # True for Electrum p2wpkh_p2sh self.assertTrue(bms.verify(msg, address2, sig1)) # True for Electrum p2wpkh self.assertTrue(bms.verify(msg, address3, sig1)) # sign with p2wpkh_p2sh address (BIP137) sig2 = bms.sign(msg, wif, address2) # False for Bitcoin Core self.assertFalse(bms.verify(msg, address1, sig2)) # True for BIP137 p2wpkh_p2sh self.assertTrue(bms.verify(msg, address2, sig2)) # False for BIP137 p2wpkh self.assertFalse(bms.verify(msg, address3, sig2)) # sign with p2wpkh address (BIP137) sig3 = bms.sign(msg, wif, address3) # False for Bitcoin Core self.assertFalse(bms.verify(msg, address1, sig3)) # False for BIP137 p2wpkh_p2sh self.assertFalse(bms.verify(msg, address2, sig3)) # True for BIP137 p2wpkh self.assertTrue(bms.verify(msg, address3, sig3)) # uncompressed WIF / P2PKH address q, network, _ = prvkey_info_from_prvkey(wif) wif2 = wif_from_prvkey(q, network, False) pubkey, network = pubkey_info_from_prvkey(wif2) address4 = p2pkh(pubkey, network) # sign with uncompressed P2PKH sig4 = bms.sign(msg, wif2, address4) # False for Bitcoin Core compressed p2pkh self.assertFalse(bms.verify(msg, address1, sig4)) # False for BIP137 p2wpkh_p2sh self.assertFalse(bms.verify(msg, address2, sig4)) # False for BIP137 p2wpkh self.assertFalse(bms.verify(msg, address3, sig4)) # True for Bitcoin Core uncompressed p2pkh self.assertTrue(bms.verify(msg, address4, sig4)) self.assertRaises(ValueError, bms.sign, msg, wif2, address1) self.assertRaises(ValueError, bms.sign, msg, wif, address4)
def test_p2w_p2sh(self): pubkey = "03 a1af804ac108a8a51782198c2d034b28bf90c8803f5a53f76276fa69a4eae77f" h160pubkey, network = hash160_from_pubkey(pubkey) b58addr = p2wpkh_p2sh(pubkey, network) b58addr2 = b58address_from_witness(h160pubkey, network) self.assertEqual(b58addr2, b58addr) script = encode(['OP_DUP', 'OP_HASH160', h160pubkey, 'OP_EQUALVERIFY', 'OP_CHECKSIG']) h256script = hash256_from_script(script) b58addr = p2wsh_p2sh(script, network) b58addr2 = b58address_from_witness(h256script, network) self.assertEqual(b58addr2, b58addr) # Invalid witness program length (19) self.assertRaises(ValueError, b58address_from_witness, h256script[:-1], network)
def test_p2wpkh(self): script_type = "p2wpkh" # self-consistency pubkey = "02" "cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaf" payload = hash160(pubkey) script = encode([0, payload]) # straight to the scriptPubKey scriptPubKey = p2wpkh(pubkey) self.assertEqual(scriptPubKey.hex(), script.hex()) # to the scriptPubKey in two steps (through payload) scriptPubKey = scriptPubKey_from_payload(script_type, payload) 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(0, m2) self.assertEqual(payload.hex(), payload2.hex()) script_type2, payload2, m2 = payload_from_scriptPubKey(script) self.assertEqual(script_type, script_type2) self.assertEqual(0, m2) self.assertEqual(payload.hex(), payload2.hex()) # data -> payload is not invertible (hash functions) # bech32 address network = "mainnet" address = bech32address.p2wpkh(pubkey, network) address2 = address_from_scriptPubKey(scriptPubKey, network) self.assertEqual(address, address2) address2 = b32address_from_witness(0, payload, network) self.assertEqual(address, address2) scriptPubKey2, network2 = scriptPubKey_from_address(address) self.assertEqual(scriptPubKey2, scriptPubKey) self.assertEqual(network2, network) # p2sh-wrapped base58 address address = base58address.p2wpkh_p2sh(pubkey, network) address2 = b58address_from_witness(payload, network) self.assertEqual(address, address2)
def test_segwit(self): msg = "test" wif = "L4xAvhKR35zFcamyHME2ZHfhw5DEyeJvEMovQHQ7DttPTM8NLWCK" pubkey, _ = pubkeyinfo_from_prvkey(wif) p2pkh = base58address.p2pkh(pubkey) p2wpkh = bech32address.p2wpkh(pubkey) p2wpkh_p2sh = base58address.p2wpkh_p2sh(pubkey) # p2pkh base58 address (Core, Electrum, BIP137) exp_sig = ("IBFyn+h9m3pWYbB4fBFKlRzBD4eJKojgCIZSNdhLKKHPSV2/WkeV7R7IO" "I0dpo3uGAEpCz9eepXLrA5kF35MXuU=").encode() self.assertTrue(bms.verify(msg, p2pkh, exp_sig)) sig = bms.sign(msg, wif) # no address: p2pkh assumed self.assertTrue(bms.verify(msg, p2pkh, sig)) self.assertEqual(bms.serialize(*sig), exp_sig) # p2wpkh-p2sh base58 address (Electrum) self.assertTrue(bms.verify(msg, p2wpkh_p2sh, sig)) # p2wpkh bech32 address (Electrum) self.assertTrue(bms.verify(msg, p2wpkh, sig)) # p2wpkh-p2sh base58 address (BIP137) # different first letter in sig because of different rf exp_sig = ("JBFyn+h9m3pWYbB4fBFKlRzBD4eJKojgCIZSNdhLKKHPSV2/WkeV7R7IO" "I0dpo3uGAEpCz9eepXLrA5kF35MXuU=").encode() self.assertTrue(bms.verify(msg, p2wpkh_p2sh, exp_sig)) sig = bms.sign(msg, wif, p2wpkh_p2sh) self.assertTrue(bms.verify(msg, p2wpkh_p2sh, sig)) self.assertEqual(bms.serialize(*sig), exp_sig) # p2wpkh bech32 address (BIP137) # different first letter in sig because of different rf exp_sig = ("KBFyn+h9m3pWYbB4fBFKlRzBD4eJKojgCIZSNdhLKKHPSV2/WkeV7R7IO" "I0dpo3uGAEpCz9eepXLrA5kF35MXuU=").encode() self.assertTrue(bms.verify(msg, p2wpkh, exp_sig)) sig = bms.sign(msg, wif, p2wpkh) self.assertTrue(bms.verify(msg, p2wpkh, sig)) self.assertEqual(bms.serialize(*sig), exp_sig)
def test_p2w_p2sh() -> None: pubkey = "03 a1af804ac108a8a51782198c2d034b28bf90c8803f5a53f76276fa69a4eae77f" h160pubkey, network = hash160_from_key(pubkey) b58addr = p2wpkh_p2sh(pubkey, network) b58addr2 = b58address_from_witness(h160pubkey, network) assert b58addr2 == b58addr scriptPubKey: List[ScriptToken] = [ "OP_DUP", "OP_HASH160", h160pubkey, "OP_EQUALVERIFY", "OP_CHECKSIG", ] h256script = hash256_from_script(scriptPubKey) b58addr = p2wsh_p2sh(scriptPubKey, network) b58addr2 = b58address_from_witness(h256script, network) assert b58addr2 == b58addr err_msg = "invalid witness program length for witness version zero: " with pytest.raises(ValueError, match=err_msg): b58address_from_witness(h256script[:-1], network)
def test_segwit() -> None: msg = "test" wif = "L4xAvhKR35zFcamyHME2ZHfhw5DEyeJvEMovQHQ7DttPTM8NLWCK" b58_p2pkh = base58address.p2pkh(wif) b58_p2wpkh = bech32address.p2wpkh(wif) b58_p2wpkh_p2sh = base58address.p2wpkh_p2sh(wif) # p2pkh base58 address (Core, Electrum, BIP137) exp_sig = "IBFyn+h9m3pWYbB4fBFKlRzBD4eJKojgCIZSNdhLKKHPSV2/WkeV7R7IOI0dpo3uGAEpCz9eepXLrA5kF35MXuU=" assert bms.verify(msg, b58_p2pkh, exp_sig) sig = bms.sign(msg, wif) # no address: p2pkh assumed assert bms.verify(msg, b58_p2pkh, sig) assert bms.encode(*sig) == exp_sig.encode() # p2wpkh-p2sh base58 address (Electrum) assert bms.verify(msg, b58_p2wpkh_p2sh, sig) # p2wpkh bech32 address (Electrum) assert bms.verify(msg, b58_p2wpkh, sig) # p2wpkh-p2sh base58 address (BIP137) # different first letter in sig because of different rf exp_sig = "JBFyn+h9m3pWYbB4fBFKlRzBD4eJKojgCIZSNdhLKKHPSV2/WkeV7R7IOI0dpo3uGAEpCz9eepXLrA5kF35MXuU=" assert bms.verify(msg, b58_p2wpkh_p2sh, exp_sig) sig = bms.sign(msg, wif, b58_p2wpkh_p2sh) assert bms.verify(msg, b58_p2wpkh_p2sh, sig) assert bms.encode(*sig) == exp_sig.encode() # p2wpkh bech32 address (BIP137) # different first letter in sig because of different rf exp_sig = "KBFyn+h9m3pWYbB4fBFKlRzBD4eJKojgCIZSNdhLKKHPSV2/WkeV7R7IOI0dpo3uGAEpCz9eepXLrA5kF35MXuU=" assert bms.verify(msg, b58_p2wpkh, exp_sig) sig = bms.sign(msg, wif, b58_p2wpkh) assert bms.verify(msg, b58_p2wpkh, sig) assert bms.encode(*sig) == exp_sig.encode()
def test_one_prvkey_multiple_addresses() -> None: msg = "Paolo is afraid of ephemeral random numbers" # Compressed WIF wif = b"Kx45GeUBSMPReYQwgXiKhG9FzNXrnCeutJp4yjTd5kKxCitadm3C" addr_p2pkh_compressed = p2pkh(wif) addr_p2wpkh_p2sh = p2wpkh_p2sh(wif) addr_p2wpkh = p2wpkh(wif) # sign with no address sig1 = bms.sign(msg, wif) # True for Bitcoin Core bms.assert_as_valid(msg, addr_p2pkh_compressed, sig1) assert bms.verify(msg, addr_p2pkh_compressed, sig1) # True for Electrum p2wpkh_p2sh bms.assert_as_valid(msg, addr_p2wpkh_p2sh, sig1) assert bms.verify(msg, addr_p2wpkh_p2sh, sig1) # True for Electrum p2wpkh bms.assert_as_valid(msg, addr_p2wpkh, sig1) assert bms.verify(msg, addr_p2wpkh, sig1) # sign with no p2pkh address sig1 = bms.sign(msg, wif, addr_p2pkh_compressed) # True for Bitcoin Core bms.assert_as_valid(msg, addr_p2pkh_compressed, sig1) assert bms.verify(msg, addr_p2pkh_compressed, sig1) # True for Electrum p2wpkh_p2sh bms.assert_as_valid(msg, addr_p2wpkh_p2sh, sig1) assert bms.verify(msg, addr_p2wpkh_p2sh, sig1) # True for Electrum p2wpkh bms.assert_as_valid(msg, addr_p2wpkh, sig1) assert bms.verify(msg, addr_p2wpkh, sig1) err_msg = "invalid recovery flag: " # sign with p2wpkh_p2sh address (BIP137) sig2 = bms.sign(msg, wif, addr_p2wpkh_p2sh) # False for Bitcoin Core with pytest.raises(BTClibValueError, match=err_msg): bms.assert_as_valid(msg, addr_p2pkh_compressed, sig2) assert not bms.verify(msg, addr_p2pkh_compressed, sig2) # True for BIP137 p2wpkh_p2sh bms.assert_as_valid(msg, addr_p2wpkh_p2sh, sig2) assert bms.verify(msg, addr_p2wpkh_p2sh, sig2) # False for BIP137 p2wpkh with pytest.raises(BTClibValueError, match=err_msg): bms.assert_as_valid(msg, addr_p2wpkh, sig2) assert not bms.verify(msg, addr_p2wpkh, sig2) # sign with p2wpkh address (BIP137) sig3 = bms.sign(msg, wif, addr_p2wpkh) # False for Bitcoin Core with pytest.raises(BTClibValueError, match=err_msg): bms.assert_as_valid(msg, addr_p2pkh_compressed, sig3) assert not bms.verify(msg, addr_p2pkh_compressed, sig3) # False for BIP137 p2wpkh_p2sh with pytest.raises(BTClibValueError, match=err_msg): bms.assert_as_valid(msg, addr_p2wpkh_p2sh, sig3) assert not bms.verify(msg, addr_p2wpkh_p2sh, sig3) # True for BIP137 p2wpkh bms.assert_as_valid(msg, addr_p2wpkh, sig3) assert bms.verify(msg, addr_p2wpkh, sig3) # uncompressed WIF / p2pkh address q, network, _ = prvkeyinfo_from_prvkey(wif) wif2 = wif_from_prvkey(q, network, False) addr_p2pkh_uncompressed = p2pkh(wif2) # sign with uncompressed p2pkh sig4 = bms.sign(msg, wif2, addr_p2pkh_uncompressed) # False for Bitcoin Core compressed p2pkh with pytest.raises(BTClibValueError, match="wrong p2pkh address: "): bms.assert_as_valid(msg, addr_p2pkh_compressed, sig4) assert not bms.verify(msg, addr_p2pkh_compressed, sig4) # False for BIP137 p2wpkh_p2sh # FIXME: puzzling error message # it should have been "wrong p2wpkh-p2sh address: " with pytest.raises(BTClibValueError, match="wrong p2pkh address: "): bms.assert_as_valid(msg, addr_p2wpkh_p2sh, sig4) assert not bms.verify(msg, addr_p2wpkh_p2sh, sig4) # False for BIP137 p2wpkh with pytest.raises(BTClibValueError, match=err_msg): bms.assert_as_valid(msg, addr_p2wpkh, sig4) assert not bms.verify(msg, addr_p2wpkh, sig4) # True for Bitcoin Core uncompressed p2pkh bms.assert_as_valid(msg, addr_p2pkh_uncompressed, sig4) assert bms.verify(msg, addr_p2pkh_uncompressed, sig4) # unrelated different wif wif3 = b"KwdMAjGmerYanjeui5SHS7JkmpZvVipYvB2LJGU1ZxJwYvP98617" addr_p2pkh_compressed = p2pkh(wif3) addr_p2wpkh_p2sh = p2wpkh_p2sh(wif3) addr_p2wpkh = p2wpkh(wif3) # False for Bitcoin Core compressed p2pkh with pytest.raises(BTClibValueError, match="wrong p2pkh address: "): bms.assert_as_valid(msg, addr_p2pkh_compressed, sig1) assert not bms.verify(msg, addr_p2pkh_compressed, sig1) # False for BIP137 p2wpkh_p2sh with pytest.raises(BTClibValueError, match="wrong p2wpkh-p2sh address: "): bms.assert_as_valid(msg, addr_p2wpkh_p2sh, sig1) assert not bms.verify(msg, addr_p2wpkh_p2sh, sig1) # False for BIP137 p2wpkh with pytest.raises(BTClibValueError, match="wrong p2wpkh address: "): bms.assert_as_valid(msg, addr_p2wpkh, sig1) assert not bms.verify(msg, addr_p2wpkh, sig1) # FIXME: puzzling error message err_msg = "not a private or compressed public key for mainnet: " with pytest.raises(BTClibValueError, match=err_msg): bms.sign(msg, wif2, addr_p2pkh_compressed) err_msg = "mismatch between private key and address" with pytest.raises(BTClibValueError, match=err_msg): bms.sign(msg, wif, addr_p2pkh_uncompressed)
def test_address_from_wif(self): # uncompressed mainnet wif1 = "5J1geo9kcAUSM6GJJmhYRX1eZEjvos9nFyWwPstVziTVueRJYvW" pubkey, network = pubkey_info_from_prvkey(wif1) b58 = p2pkh(pubkey) self.assertEqual(b58, b'1LPM8SZ4RQDMZymUmVSiSSvrDfj1UZY9ig') self.assertRaises(ValueError, p2wpkh, pubkey) self.assertRaises(ValueError, p2wpkh_p2sh, pubkey) # compressed mainnet wif2 = "Kx621phdUCp6sgEXPSHwhDTrmHeUVrMkm6T95ycJyjyxbDXkr162" pubkey, network = pubkey_info_from_prvkey(wif2) b58 = p2pkh(pubkey) self.assertEqual(b58, b'1HJC7kFvXHepkSzdc8RX6khQKkAyntdfkB') b32 = p2wpkh(pubkey) self.assertEqual(h160_from_b58address( b58)[1:], witness_from_b32address(b32)[1:]) h160 = h160_from_b58address(b58)[1] b = p2wpkh_p2sh(pubkey) self.assertEqual(hash160(b'\x00\x14' + h160), h160_from_b58address(b)[1]) self.assertEqual(prvkey_info_from_prvkey( wif1)[0], prvkey_info_from_prvkey(wif2)[0]) # uncompressed testnet wif1 = "91gGn1HgSap6CbU12F6z3pJri26xzp7Ay1VW6NHCoEayNXwRpu2" pubkey, network = pubkey_info_from_prvkey(wif1) b58 = p2pkh(pubkey, network, None) self.assertEqual(b58, b'mvgbzkCSgKbYgaeG38auUzR7otscEGi8U7') self.assertRaises(ValueError, p2wpkh, pubkey) self.assertRaises(ValueError, p2wpkh_p2sh, pubkey) # compressed testnet wif2 = "cMzLdeGd5vEqxB8B6VFQoRopQ3sLAAvEzDAoQgvX54xwofSWj1fx" pubkey, network = pubkey_info_from_prvkey(wif2) b58 = p2pkh(pubkey, network, None) self.assertEqual(b58, b'n1KSZGmQgB8iSZqv6UVhGkCGUbEdw8Lm3Q') b32 = p2wpkh(pubkey, network) self.assertEqual(h160_from_b58address( b58)[1:], witness_from_b32address(b32)[1:]) h160 = h160_from_b58address(b58)[1] b = p2wpkh_p2sh(pubkey, network) self.assertEqual(hash160(b'\x00\x14' + h160), h160_from_b58address(b)[1]) self.assertEqual(prvkey_info_from_prvkey( wif1)[0], prvkey_info_from_prvkey(wif2)[0]) # uncompressed mainnet, trailing/leading spaces in string wif1 = " 5J1geo9kcAUSM6GJJmhYRX1eZEjvos9nFyWwPstVziTVueRJYvW" pubkey, network = pubkey_info_from_prvkey(wif1) b58 = p2pkh(pubkey) self.assertEqual(b58, b'1LPM8SZ4RQDMZymUmVSiSSvrDfj1UZY9ig') self.assertRaises(ValueError, p2wpkh, pubkey) self.assertRaises(ValueError, p2wpkh_p2sh, pubkey) # compressed mainnet, trailing/leading spaces in string wif2 = "Kx621phdUCp6sgEXPSHwhDTrmHeUVrMkm6T95ycJyjyxbDXkr162 " pubkey, network = pubkey_info_from_prvkey(wif2) b58 = p2pkh(pubkey) self.assertEqual(b58, b'1HJC7kFvXHepkSzdc8RX6khQKkAyntdfkB') b32 = p2wpkh(pubkey) self.assertEqual(h160_from_b58address( b58)[1:], witness_from_b32address(b32)[1:]) h160 = h160_from_b58address(b58)[1] b = p2wpkh_p2sh(pubkey) self.assertEqual(hash160(b'\x00\x14' + h160), h160_from_b58address(b)[1])
from btclib.bech32address import p2wpkh from btclib.bms import encode, sign, verify from btclib.to_prvkey import prvkeyinfo_from_prvkey from btclib.to_pubkey import pubkeyinfo_from_prvkey msg = "Paolo is afraid of ephemeral random numbers" print("\n0. Message:", msg) wif = b"Kx45GeUBSMPReYQwgXiKhG9FzNXrnCeutJp4yjTd5kKxCitadm3C" print("1. Compressed WIF:", wif.decode()) pubkey, network = pubkeyinfo_from_prvkey(wif) print("2. Addresses") address1 = p2pkh(pubkey) print(" p2pkh:", address1.decode()) address2 = p2wpkh_p2sh(pubkey) print("p2wpkh_p2sh:", address2.decode()) address3 = p2wpkh(pubkey) print(" p2wpkh:", address3.decode()) print("\n3. Sign message with no address (or with compressed p2pkh address):") sig1 = sign(msg, wif) print(f"rf1: {sig1[0]}") print(f" r1: {hex(sig1[1]).upper()}") print(f" s1: {hex(sig1[2]).upper()}") bsmsig1 = encode(*sig1) print("4. Serialized signature:") print(bsmsig1.decode()) print("5. Verify signature")
def test_exceptions(self): msg = 'test' wif = 'KwELaABegYxcKApCb3kJR9ymecfZZskL9BzVUkQhsqFiUKftb4tu' pubkey, _ = pubkey_info_from_prvkey(wif) address = base58address.p2pkh(pubkey) exp_sig = b'IHdKsFF1bUrapA8GMoQUbgI+Ad0ZXyX1c/yAZHmJn5hSNBi7J+TrI1615FG3g9JEOPGVvcfDWIFWrg2exLNtoVc=' self.assertTrue(bms.verify(msg, address, exp_sig)) # Invalid recovery flag: 26 _, r, s = bms.deserialize(exp_sig) self.assertRaises(ValueError, bms.serialize, 26, r, s) #bms.serialize(26, r, s) # short exp_sig exp_sig = b'IHdKsFF1bUrapA8GMoQUbgI+Ad0ZXyX1c/yAZHmJn5hNBi7J+TrI1615FG3g9JEOPGVvcfDWIFWrg2exLoVc=' self.assertRaises(ValueError, bms._verify, msg, address, exp_sig) self.assertFalse(bms.verify(msg, address, exp_sig)) # Invalid recovery flag: 26 exp_sig = b'GpNLHqEKSzwXV+KwwBfQthQ848mn5qSkmGDXpqshDuPYJELOnSuRYGQQgBR4PpI+w2tJdD4v+hxElvAaUSqv2eU=' self.assertRaises(ValueError, bms._verify, msg, address, exp_sig) self.assertFalse(bms.verify(msg, address, exp_sig)) #bms._verify(msg, address, exp_sig) # Invalid recovery flag: 66 exp_sig = b'QpNLHqEKSzwXV+KwwBfQthQ848mn5qSkmGDXpqshDuPYJELOnSuRYGQQgBR4PpI+w2tJdD4v+hxElvAaUSqv2eU=' self.assertRaises(ValueError, bms._verify, msg, address, exp_sig) self.assertFalse(bms.verify(msg, address, exp_sig)) #bms._verify(msg, address, exp_sig) # Pubkey mismatch: compressed wif, uncompressed address wif = 'Ky1XfDK2v6wHPazA6ECaD8UctEoShXdchgABjpU9GWGZDxVRDBMJ' address = '19f7adDYqhHSJm2v7igFWZAqxXHj1vUa3T' self.assertRaises(ValueError, bms.sign, msg, wif, address) #bms.sign(msg, wif, address) # Pubkey mismatch: uncompressed wif, compressed address wif = '5JDopdKaxz5bXVYXcAnfno6oeSL8dpipxtU1AhfKe3Z58X48srn' address = '1DAag8qiPLHh6hMFVu9qJQm9ro1HtwuyK5' self.assertRaises(ValueError, bms.sign, msg, wif, address) #bms.sign(msg, wif, address) msg = 'test' wif = 'L4xAvhKR35zFcamyHME2ZHfhw5DEyeJvEMovQHQ7DttPTM8NLWCK' pubkey, _ = pubkey_info_from_prvkey(wif) p2pkh = base58address.p2pkh(pubkey) p2wpkh = bech32address.p2wpkh(pubkey) p2wpkh_p2sh = base58address.p2wpkh_p2sh(pubkey) wif = 'Ky1XfDK2v6wHPazA6ECaD8UctEoShXdchgABjpU9GWGZDxVRDBMJ' # Mismatch between p2pkh address and key pair self.assertRaises(ValueError, bms.sign, msg, wif, p2pkh) # bms.sign(msg, wif, p2pkh) # Mismatch between p2wpkh address and key pair self.assertRaises(ValueError, bms.sign, msg, wif, p2wpkh) # bms.sign(msg, wif, p2wpkh) # Mismatch between p2wpkh_p2sh address and key pair self.assertRaises(ValueError, bms.sign, msg, wif, p2wpkh_p2sh) # bms.sign(msg, wif, p2wpkh_p2sh) # Invalid recovery flag (39) for base58 address exp_sig = b'IHdKsFF1bUrapA8GMoQUbgI+Ad0ZXyX1c/yAZHmJn5hSNBi7J+TrI1615FG3g9JEOPGVvcfDWIFWrg2exLNtoVc=' _, r, s = bms.deserialize(exp_sig) sig = bms.serialize(39, r, s) self.assertRaises(ValueError, bms._verify, msg, p2pkh, sig) #bms._verify(msg, p2pkh, sig) # Invalid recovery flag (35) for bech32 address exp_sig = b'IBFyn+h9m3pWYbB4fBFKlRzBD4eJKojgCIZSNdhLKKHPSV2/WkeV7R7IOI0dpo3uGAEpCz9eepXLrA5kF35MXuU=' _, r, s = bms.deserialize(exp_sig) sig = bms.serialize(35, r, s) self.assertRaises(ValueError, bms._verify, msg, p2wpkh, sig)
def test_testnet_versions(self): # data cross-checked with Electrum and # https://jlopp.github.io/xpub-converter/ # 128 bits raw_entr = bytes.fromhex("6" * 32) # 12 words mnemonic = bip39.mnemonic_from_entropy(raw_entr, "en") seed = bip39.seed_from_mnemonic(mnemonic, "") # p2pkh BIP44 # m / 44h / coin_typeh / accounth / change / address_index path = "m/44h/1h/0h" version = NETWORKS["testnet"]["bip32_prv"] rootprv = rootxprv_from_seed(seed, version) xprv = derive(rootprv, path) xpub = xpub_from_xprv(xprv) exp = "tpubDChqWo2Xi2wNsxyJBE8ipcTJHLKWcqeeNUKBVTpUCNPZkHzHTm3qKAeHqgCou1t8PAY5ZnJ9QDa6zXSZxmjDnhiBpgZ7f6Yv88wEm5HXVbm" self.assertEqual(xpub.decode(), exp) # first addresses xpub_ext = derive(xpub, "./0/0") # external address = p2pkh(xpub_ext) exp_address = b"moutHSzeFWViMNEcvBxKzNCMj2kca8MvE1" self.assertEqual(address, exp_address) xpub_int = derive(xpub, "./1/0") # internal address = p2pkh(xpub_int) exp_address = b"myWcXdNais9ExumnGKnNoJwoihQKfNPG9i" self.assertEqual(address, exp_address) # legacy segwit (p2wsh-p2sh) # m / 49h / coin_typeh / accounth / change / address_index path = "m/49h/1h/0h" version = NETWORKS["testnet"]["slip32_p2wsh_p2sh_prv"] rootprv = rootxprv_from_seed(seed, version) xprv = derive(rootprv, path) xpub = xpub_from_xprv(xprv) exp = "upub5Dj8j7YrwodV68mt58QmNpSzjqjso2WMXEpLGLSvskKccGuXhCh3dTedkzVLAePA617UyXAg2vdswJXTYjU4qjMJaHU79GJVVJCAiy9ezZ2" self.assertEqual(xpub.decode(), exp) # first addresses xpub_ext = derive(xpub, "./0/0") # external address = p2wpkh_p2sh(xpub_ext) exp_address = b"2Mw8tQ6uT6mHhybarVhjgomUhHQJTeV9A2c" self.assertEqual(address, exp_address) xpub_int = derive(xpub, "./1/0") # internal address = p2wpkh_p2sh(xpub_int) exp_address = b"2N872CRJ3E1CzWjfixXr3aeC3hkF5Cz4kWb" self.assertEqual(address, exp_address) # legacy segwit (p2wsh-p2sh) # m / 49h / coin_typeh / accounth / change / address_index path = "m/49h/1h/0h" version = NETWORKS["testnet"]["slip32_p2wpkh_p2sh_prv"] rootprv = rootxprv_from_seed(seed, version) xprv = derive(rootprv, path) xpub = xpub_from_xprv(xprv) exp = "Upub5QdDrMHJWmBrWhwG1nskCtnoTdn91PBwqWU1BbiUFXA2ETUSTc5KiaWZZhSoj5c4KUBTr7Anv92P4U9Dqxd1zDTyQkaWYfmVP2U3Js1W5cG" self.assertEqual(xpub.decode(), exp) # native segwit (p2wpkh) # m / 84h / coin_typeh / accounth / change / address_index path = "m/84h/1h/0h" version = NETWORKS["testnet"]["slip32_p2wpkh_prv"] rootprv = rootxprv_from_seed(seed, version) xprv = derive(rootprv, path) xpub = xpub_from_xprv(xprv) exp = "vpub5ZhJmduYY7M5J2qCJgSW7hunX6zJrr5WuNg2kKt321HseZEYxqJc6Zso47aNXQw3Wf3sA8kppbfsxnLheUNXcL3xhzeBHLNp8fTVBN6DnJF" self.assertEqual(xpub.decode(), exp) # first addresses xpub_ext = derive(xpub, "./0/0") # external # explicit network is required to discriminate from testnet address = p2wpkh(xpub_ext, "regtest") exp_address = b"bcrt1qv8lcnmj09rpdqwgl025h2deygur64z4hqf7me5" self.assertEqual(address, exp_address) xpub_int = derive(xpub, "./1/0") # internal # explicit network is required to discriminate from testnet address = p2wpkh(xpub_int, "regtest") exp_address = b"bcrt1qqhxvky4y6qkwpvdzqjkdafmj20vs5trmt6y8w5" self.assertEqual(address, exp_address) # native segwit (p2wsh) # m / 84h / coin_typeh / accounth / change / address_index path = "m/84h/1h/0h" version = NETWORKS["testnet"]["slip32_p2wsh_prv"] rootprv = rootxprv_from_seed(seed, version) xprv = derive(rootprv, path) xpub = xpub_from_xprv(xprv) exp = "Vpub5kbPtsdz74uSibzaFLuUwnFbEu2a5Cm7DeKhfb9aPn8HGjoTjEgtBgjirpXr5r9wk87r2ikwhp4P5wxTwhXUkpAdYTkagjqp2PjMmGPBESU" self.assertEqual(xpub.decode(), exp)
def test_mainnet_versions(self): # data cross-checked with Electrum and # https://jlopp.github.io/xpub-converter/ # 128 bits raw_entr = bytes.fromhex("6" * 32) # 12 words mnemonic = bip39.mnemonic_from_entropy(raw_entr, "en") seed = bip39.seed_from_mnemonic(mnemonic, "") # p2pkh BIP44 # m / 44h / coin_typeh / accounth / change / address_index path = "m/44h/0h/0h" version = NETWORKS["mainnet"]["bip32_prv"] rootprv = rootxprv_from_seed(seed, version) xprv = derive(rootprv, path) xpub = xpub_from_xprv(xprv) exp = "xpub6C3uWu5Go5q62JzJpbjyCLYRGLYvexFeiepZTsYZ6SRexARkNfjG7GKtQVuGR3KHsyKsAwv7Hz3iNucPp6pfHiLvBczyK1j5CtBtpHB3NKx" self.assertEqual(xpub.decode(), exp) # first addresses xpub_ext = derive(xpub, "./0/0") # external address = p2pkh(xpub_ext) exp_address = b"1DDKKVHoFWGfctyEEJvrusqq6ipEaieGCq" self.assertEqual(address, exp_address) xpub_int = derive(xpub, "./1/0") # internal address = p2pkh(xpub_int) exp_address = b"1FhKoffreKHzhtBMVW9NSsg3ZF148JPGoR" self.assertEqual(address, exp_address) # legacy segwit (p2wsh-p2sh) # m / 49h / coin_typeh / accounth / change / address_index path = "m/49h/0h/0h" version = NETWORKS["mainnet"]["slip32_p2wsh_p2sh_prv"] rootprv = rootxprv_from_seed(seed, version) xprv = derive(rootprv, path) xpub = xpub_from_xprv(xprv) exp = "ypub6YBGdYufCVeoPVmNXfdrWhaBCXsQoLKNetNmD9bPTrKmnKVmiyU8f1uJqwGdmBb8kbAZpHoYfXQTLbWpkXc4skQDAreeCUXdbX9k8vtiHsN" self.assertEqual(xpub.decode(), exp) # first addresses xpub_ext = derive(xpub, "./0/0") # external address = p2wpkh_p2sh(xpub_ext) exp_address = b"3FmNAiTCWe5kPMgc4dtSgEdY8VuaCiJEH8" self.assertEqual(address, exp_address) xpub_int = derive(xpub, "./1/0") # internal address = p2wpkh_p2sh(xpub_int) exp_address = b"34FLgkoRYX5Q5fqiZCZDwsK5GpXxmFuLJN" self.assertEqual(address, exp_address) # legacy segwit (p2wpkh-p2sh) # m / 49h / coin_typeh / accounth / change / address_index path = "m/49h/0h/0h" version = NETWORKS["mainnet"]["slip32_p2wpkh_p2sh_prv"] rootprv = rootxprv_from_seed(seed, version) xprv = derive(rootprv, path) xpub = xpub_from_xprv(xprv) exp = "Ypub6j5Mkne6mTDAp4vkUL6qLmuyvKug1gzxyA2S8QrvqdABQW4gVNrQk8mEeeE7Kcp2z4EYgsofYjnxTm8b3km22EWt1Km3bszdVFRcipc6rXu" self.assertEqual(xpub.decode(), exp) # native segwit (p2wpkh) # m / 84h / coin_typeh / accounth / change / address_index path = "m/84h/0h/0h" version = NETWORKS["mainnet"]["slip32_p2wpkh_prv"] rootprv = rootxprv_from_seed(seed, version) xprv = derive(rootprv, path) xpub = xpub_from_xprv(xprv) exp = "zpub6qg3Uc1BAQkQvcBUYMmZHSzbsshSon3FvJ8yvH3ZZMjFNvJkwSji8UUwghiF3wvpvSvcNWVP8kfUhc2V2RwGp6pTC3ouj6njj956f26TniN" self.assertEqual(xpub.decode(), exp) # first addresses xpub_ext = derive(xpub, "./0/0") # external address = p2wpkh(xpub_ext) exp_address = b"bc1q0hy024867ednvuhy9en4dggflt5w9unw4ztl5a" self.assertEqual(address, exp_address) xpub_int = derive(xpub, "./1/0") # internal address = p2wpkh(xpub_int) exp_address = b"bc1qy4x03jyl88h2zeg7l287xhv2xrwk4c3ztfpjd2" self.assertEqual(address, exp_address) # native segwit (p2wsh) # m / 84h / coin_typeh / accounth / change / address_index path = "m/84h/0h/0h" version = NETWORKS["mainnet"]["slip32_p2wsh_prv"] rootprv = rootxprv_from_seed(seed, version) xprv = derive(rootprv, path) xpub = xpub_from_xprv(xprv) exp = "Zpub72a8bqjcjNJnMBLrV2EY7XLQbfji28irEZneqYK6w8Zf16sfhr7zDbLsVQficP9j9uzbF6VW1y3ypmeFKf6Dxaw82WvK8WFjcsLyEvMNZjF" self.assertEqual(xpub.decode(), exp)
def test_exceptions() -> None: msg = "test" wif = "KwELaABegYxcKApCb3kJR9ymecfZZskL9BzVUkQhsqFiUKftb4tu" address = base58address.p2pkh(wif) exp_sig = "IHdKsFF1bUrapA8GMoQUbgI+Ad0ZXyX1c/yAZHmJn5hSNBi7J+TrI1615FG3g9JEOPGVvcfDWIFWrg2exLNtoVc=" assert bms.verify(msg, address, exp_sig) _, r, s = bms.decode(exp_sig) err_msg = "invalid recovery flag: " with pytest.raises(BTClibValueError, match=err_msg): bms.encode(26, r, s) exp_sig = "IHdKsFF1bUrapA8GMoQUbgI+Ad0ZXyX1c/yAZHmJn5hNBi7J+TrI1615FG3g9JEOPGVvcfDWIFWrg2exLoVc=" err_msg = "wrong signature length: " with pytest.raises(BTClibValueError, match=err_msg): bms.assert_as_valid(msg, address, exp_sig) assert not bms.verify(msg, address, exp_sig) exp_sig = "GpNLHqEKSzwXV+KwwBfQthQ848mn5qSkmGDXpqshDuPYJELOnSuRYGQQgBR4PpI+w2tJdD4v+hxElvAaUSqv2eU=" err_msg = "invalid recovery flag: " with pytest.raises(BTClibValueError, match=err_msg): bms.assert_as_valid(msg, address, exp_sig) assert not bms.verify(msg, address, exp_sig) exp_sig = "QpNLHqEKSzwXV+KwwBfQthQ848mn5qSkmGDXpqshDuPYJELOnSuRYGQQgBR4PpI+w2tJdD4v+hxElvAaUSqv2eU=" with pytest.raises(BTClibValueError, match=err_msg): bms.assert_as_valid(msg, address, exp_sig) assert not bms.verify(msg, address, exp_sig) # compressed wif, uncompressed address wif = "Ky1XfDK2v6wHPazA6ECaD8UctEoShXdchgABjpU9GWGZDxVRDBMJ" address = b"19f7adDYqhHSJm2v7igFWZAqxXHj1vUa3T" err_msg = "mismatch between private key and address" with pytest.raises(BTClibValueError, match=err_msg): bms.sign(msg, wif, address) # uncompressed wif, compressed address wif = "5JDopdKaxz5bXVYXcAnfno6oeSL8dpipxtU1AhfKe3Z58X48srn" address = b"1DAag8qiPLHh6hMFVu9qJQm9ro1HtwuyK5" err_msg = "not a private or compressed public key for mainnet: " # FIXME puzzling error message with pytest.raises(BTClibValueError, match=err_msg): bms.sign(msg, wif, address) msg = "test" wif = "L4xAvhKR35zFcamyHME2ZHfhw5DEyeJvEMovQHQ7DttPTM8NLWCK" b58_p2pkh = base58address.p2pkh(wif) b58_p2wpkh = bech32address.p2wpkh(wif) b58_p2wpkh_p2sh = base58address.p2wpkh_p2sh(wif) wif = "Ky1XfDK2v6wHPazA6ECaD8UctEoShXdchgABjpU9GWGZDxVRDBMJ" err_msg = "mismatch between private key and address" with pytest.raises(BTClibValueError, match=err_msg): bms.sign(msg, wif, b58_p2pkh) with pytest.raises(BTClibValueError, match=err_msg): bms.sign(msg, wif, b58_p2wpkh) with pytest.raises(BTClibValueError, match=err_msg): bms.sign(msg, wif, b58_p2wpkh_p2sh) # Invalid recovery flag (39) for base58 address exp_sig = "IHdKsFF1bUrapA8GMoQUbgI+Ad0ZXyX1c/yAZHmJn5hSNBi7J+TrI1615FG3g9JEOPGVvcfDWIFWrg2exLNtoVc=" _, r, s = bms.decode(exp_sig) sig = bms.encode(39, r, s) err_msg = "invalid recovery flag: " with pytest.raises(BTClibValueError, match=err_msg): bms.assert_as_valid(msg, b58_p2pkh, sig) # Invalid recovery flag (35) for bech32 address exp_sig = "IBFyn+h9m3pWYbB4fBFKlRzBD4eJKojgCIZSNdhLKKHPSV2/WkeV7R7IOI0dpo3uGAEpCz9eepXLrA5kF35MXuU=" _, r, s = bms.decode(exp_sig) sig = bms.encode(35, r, s) err_msg = "invalid recovery flag: " with pytest.raises(BTClibValueError, match=err_msg): bms.assert_as_valid(msg, b58_p2wpkh, sig)