def test_crack(self): parent_xpub = b'xpub6BabMgRo8rKHfpAb8waRM5vj2AneD4kDMsJhm7jpBDHSJvrFAjHJHU5hM43YgsuJVUVHWacAcTsgnyRptfMdMP8b28LYfqGocGdKCFjhQMV' child_xprv = b'xprv9xkG88dGyiurKbVbPH1kjdYrA8poBBBXa53RKuRGJXyruuoJUDd8e4m6poiz7rV8Z4NoM5AJNcPHN6aj8wRFt5CWvF8VPfQCrDUcLU5tcTm' parent_xprv = bip32.crack(parent_xpub, child_xprv) self.assertEqual(bip32.xpub_from_xprv(parent_xprv), parent_xpub) index = bip32.child_index(child_xprv) self.assertEqual(bip32.ckd(parent_xprv, index), child_xprv) path = [index] self.assertEqual(bip32.derive(parent_xprv, path), child_xprv) # extended parent key is not a public one self.assertRaises(ValueError, bip32.crack, parent_xprv, child_xprv) #bip32.crack(parent_xprv, child_xprv) # extended child key is not a private one self.assertRaises(ValueError, bip32.crack, parent_xpub, parent_xpub) #bip32.crack(parent_xpub, parent_xpub) # wrong child/parent depth relation child_xpub = bip32.xpub_from_xprv(child_xprv) self.assertRaises(ValueError, bip32.crack, child_xpub, child_xprv) #bip32.crack(child_xpub, child_xprv) # not a child for the provided parent child0_xprv = bip32.ckd(parent_xprv, 0) grandchild_xprv = bip32.ckd(child0_xprv, 0) self.assertRaises(ValueError, bip32.crack, child_xpub, grandchild_xprv) #bip32.crack(child_xpub, grandchild_xprv) # hardened derivation hardened_child_xprv = bip32.ckd(parent_xprv, 0x80000000) self.assertRaises(ValueError, bip32.crack, parent_xpub, hardened_child_xprv)
def test_crack(): parent_xpub = "xpub6BabMgRo8rKHfpAb8waRM5vj2AneD4kDMsJhm7jpBDHSJvrFAjHJHU5hM43YgsuJVUVHWacAcTsgnyRptfMdMP8b28LYfqGocGdKCFjhQMV" child_xprv = "xprv9xkG88dGyiurKbVbPH1kjdYrA8poBBBXa53RKuRGJXyruuoJUDd8e4m6poiz7rV8Z4NoM5AJNcPHN6aj8wRFt5CWvF8VPfQCrDUcLU5tcTm" parent_xprv = crack_prvkey(parent_xpub, child_xprv) assert xpub_from_xprv(parent_xprv).decode() == parent_xpub # same check with XKeyDict parent_xprv = crack_prvkey(deserialize(parent_xpub), deserialize(child_xprv)) assert xpub_from_xprv(parent_xprv).decode() == parent_xpub errmsg = "extended parent key is not a public key: " with pytest.raises(ValueError, match=errmsg): crack_prvkey(parent_xprv, child_xprv) errmsg = "extended child key is not a private key: " with pytest.raises(ValueError, match=errmsg): crack_prvkey(parent_xpub, parent_xpub) child_xpub = xpub_from_xprv(child_xprv) with pytest.raises(ValueError, match="not a parent's child: wrong depths"): crack_prvkey(child_xpub, child_xprv) child0_xprv = derive(parent_xprv, 0) grandchild_xprv = derive(child0_xprv, 0) errmsg = "not a parent's child: wrong parent fingerprint" with pytest.raises(ValueError, match=errmsg): crack_prvkey(child_xpub, grandchild_xprv) hardened_child_xprv = derive(parent_xprv, 0x80000000) with pytest.raises(ValueError, match="hardened child derivation"): crack_prvkey(parent_xpub, hardened_child_xprv)
def test_crack(self): parent_xpub = b'xpub6BabMgRo8rKHfpAb8waRM5vj2AneD4kDMsJhm7jpBDHSJvrFAjHJHU5hM43YgsuJVUVHWacAcTsgnyRptfMdMP8b28LYfqGocGdKCFjhQMV' child_xprv = b'xprv9xkG88dGyiurKbVbPH1kjdYrA8poBBBXa53RKuRGJXyruuoJUDd8e4m6poiz7rV8Z4NoM5AJNcPHN6aj8wRFt5CWvF8VPfQCrDUcLU5tcTm' parent_xprv = crack_prvkey(parent_xpub, child_xprv) self.assertEqual(xpub_from_xprv(parent_xprv), parent_xpub) # same check with XKeyDict parent_xprv = crack_prvkey(deserialize(parent_xpub), deserialize(child_xprv)) self.assertEqual(xpub_from_xprv(parent_xprv), parent_xpub) # extended parent key is not a public one self.assertRaises(ValueError, crack_prvkey, parent_xprv, child_xprv) #crack_prvkey(parent_xprv, child_xprv) # extended child key is not a private one self.assertRaises(ValueError, crack_prvkey, parent_xpub, parent_xpub) #crack_prvkey(parent_xpub, parent_xpub) # wrong child/parent depth relation child_xpub = xpub_from_xprv(child_xprv) self.assertRaises(ValueError, crack_prvkey, child_xpub, child_xprv) #crack_prvkey(child_xpub, child_xprv) # not a child for the provided parent child0_xprv = derive(parent_xprv, 0) grandchild_xprv = derive(child0_xprv, 0) self.assertRaises(ValueError, crack_prvkey, child_xpub, grandchild_xprv) #crack_prvkey(child_xpub, grandchild_xprv) # hardened derivation hardened_child_xprv = derive(parent_xprv, 0x80000000) self.assertRaises(ValueError, crack_prvkey, parent_xpub, hardened_child_xprv)
def test_exceptions() -> None: with pytest.raises(ValueError, match="not a private or public key: "): # invalid checksum xprv = "xppp9s21ZrQH143K2oxHiQ5f7D7WYgXD9h6HAXDBuMoozDGGiYHWsq7TLBj2yvGuHTLSPCaFmUyN1v3fJRiY2A4YuNSrqQMPVLZKt76goL6LP7L" p2pkh(xprv) xpub = "xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy" with pytest.raises(ValueError, match="not a private key: "): bip32.xpub_from_xprv(xpub) xpub_dict = bip32.deserialize(xpub) xpub_dict = bip32.deserialize(xpub_dict) xpub_dict["chain_code"] = (xpub_dict["chain_code"])[:-1] with pytest.raises(ValueError, match="invalid chain code length: "): xpub_dict = bip32.deserialize(xpub_dict) xpub_dict = bip32.deserialize(xpub) xpub_dict[ "chain_code"] = "length is 32 but not a chaincode" # type: ignore with pytest.raises(ValueError, match="invalid chain code"): xpub_dict = bip32.deserialize(xpub_dict) seed = "5b56c417303faa3fcba7e57400e120a0" with pytest.raises(ValueError, match="unknown private key version: "): version = b"\x04\x88\xAD\xE5" bip32.rootxprv_from_seed(seed, version) with pytest.raises(ValueError, match="too many bits for seed: "): bip32.rootxprv_from_seed(seed * 5) with pytest.raises(ValueError, match="too few bits for seed: "): bip32.rootxprv_from_seed(seed[:-2])
def test_testnet(self): # bitcoin core derivation style rootxprv = b'tprv8ZgxMBicQKsPe3g3HwF9xxTLiyc5tNyEtjhBBAk29YA3MTQUqULrmg7aj9qTKNfieuu2HryQ6tGVHse9x7ANFGs3f4HgypMc5nSSoxwf7TK' # m/0'/0'/51' addr1 = b'mfXYCCsvWPgeCv8ZYGqcubpNLYy5nYHbbj' indexes = [0x80000000, 0x80000000, 0x80000000 + 51] addr = bip32.p2pkh_address_from_xpub( bip32.xpub_from_xprv(bip32.derive(rootxprv, indexes))) self.assertEqual(addr, addr1) path = "m/0'/0'/51'" addr = bip32.p2pkh_address_from_xpub( bip32.xpub_from_xprv(bip32.derive(rootxprv, path))) self.assertEqual(addr, addr1) # m/0'/1'/150' addr2 = b'mfaUnRFxVvf55uD1P3zWXpprN1EJcKcGrb' indexes = [0x80000000, 0x80000000 + 1, 0x80000000 + 150] addr = bip32.p2pkh_address_from_xpub( bip32.xpub_from_xprv(bip32.derive(rootxprv, indexes))) self.assertEqual(addr, addr2) path = "m/0'/1'/150'" addr = bip32.p2pkh_address_from_xpub( bip32.xpub_from_xprv(bip32.derive(rootxprv, path))) self.assertEqual(addr, addr2)
def test_vector3(self): """BIP32 test vector 3 https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki """ xkey_version = _PRV_VERSIONS[0] seed = "4b381541583be4423346c643850da4b320e46a87ae3d2a4e6da11eba819cd4acba45d239319ac14f863b8d5ab5a0d0c64d2e8a1e7d1457df2e5a3c51c73235be" rootxprv = rootxprv_from_seed(seed, xkey_version) self.assertEqual( rootxprv, b"xprv9s21ZrQH143K25QhxbucbDDuQ4naNntJRi4KUfWT7xo4EKsHt2QJDu7KXp1A3u7Bi1j8ph3EGsZ9Xvz9dGuVrtHHs7pXeTzjuxBrCmmhgC6" ) rootxpub = xpub_from_xprv(rootxprv) # neutering self.assertEqual( rootxpub, b"xpub661MyMwAqRbcEZVB4dScxMAdx6d4nFc9nvyvH3v4gJL378CSRZiYmhRoP7mBy6gSPSCYk6SzXPTf3ND1cZAceL7SfJ1Z3GC8vBgp2epUt13" ) xprv = rootxprv xpub = rootxpub xprv = derive(xprv, ".") # private relative self.assertEqual( xprv, b"xprv9s21ZrQH143K25QhxbucbDDuQ4naNntJRi4KUfWT7xo4EKsHt2QJDu7KXp1A3u7Bi1j8ph3EGsZ9Xvz9dGuVrtHHs7pXeTzjuxBrCmmhgC6" ) xprv = derive(rootxprv, "m") # private absolute self.assertEqual( xprv, b"xprv9s21ZrQH143K25QhxbucbDDuQ4naNntJRi4KUfWT7xo4EKsHt2QJDu7KXp1A3u7Bi1j8ph3EGsZ9Xvz9dGuVrtHHs7pXeTzjuxBrCmmhgC6" ) xpub = derive(xpub, ".") # public relative self.assertEqual( xpub, b"xpub661MyMwAqRbcEZVB4dScxMAdx6d4nFc9nvyvH3v4gJL378CSRZiYmhRoP7mBy6gSPSCYk6SzXPTf3ND1cZAceL7SfJ1Z3GC8vBgp2epUt13" ) xpub = derive(rootxpub, "m") # public absolute self.assertEqual( xpub, b"xpub661MyMwAqRbcEZVB4dScxMAdx6d4nFc9nvyvH3v4gJL378CSRZiYmhRoP7mBy6gSPSCYk6SzXPTf3ND1cZAceL7SfJ1Z3GC8vBgp2epUt13" ) xprv = derive(xprv, "./0'") # private relative self.assertEqual( xprv, b"xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L" ) xprv = derive(rootxprv, "m/0'") # private absolute self.assertEqual( xprv, b"xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L" ) xpub = xpub_from_xprv(xprv) # neutering self.assertEqual( xpub, b"xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y" )
def test_slip32(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" passphrase = "" path = "m/44'/0'/0'" prv = b"xprv9xpXFhFpqdQK3TmytPBqXtGSwS3DLjojFhTGht8gwAAii8py5X6pxeBnQ6ehJiyJ6nDjWGJfZ95WxByFXVkDxHXrqu53WCRGypk2ttuqncb" pub = b"xpub6BosfCnifzxcFwrSzQiqu2DBVTshkCXacvNsWGYJVVhhawA7d4R5WSWGFNbi8Aw6ZRc1brxMyWMzG3DSSSSoekkudhUd9yLb6qx39T9nMdj" address = b"1LqBGSKuX5yYUonjxT5qGfpUsXKYYWeabA" rxprv = bip32.rootxprv_from_bip39mnemonic(mnemonic, passphrase, MAIN_xprv) mprv = bip32.derive(rxprv, path) self.assertEqual(mprv, prv) mpub = bip32.xpub_from_xprv(mprv) self.assertEqual(mpub, pub) pub = bip32.derive(mpub, "./0/0") addr = slip32.address_from_xpub(pub) self.assertEqual(address, addr) path = "m/49'/0'/0'" prv = b"yprvAHwhK6RbpuS3dgCYHM5jc2ZvEKd7Bi61u9FVhYMpgMSuZS613T1xxQeKTffhrHY79hZ5PsskBjcc6C2V7DrnsMsNaGDaWev3GLRQRgV7hxF" pub = b"ypub6Ww3ibxVfGzLrAH1PNcjyAWenMTbbAosGNB6VvmSEgytSER9azLDWCxoJwW7Ke7icmizBMXrzBx9979FfaHxHcrArf3zbeJJJUZPf663zsP" address = b"37VucYSaXLCAsxYyAPfbSi9eh4iEcbShgf" rxprv = bip32.rootxprv_from_bip39mnemonic(mnemonic, passphrase, MAIN_yprv) mprv = bip32.derive(rxprv, path) self.assertEqual(mprv, prv) mpub = bip32.xpub_from_xprv(mprv) self.assertEqual(mpub, pub) pub = bip32.derive(mpub, "./0/0") addr = slip32.address_from_xpub(pub) self.assertEqual(address, addr) addr = base58address.p2wpkh_p2sh_from_xpub(pub) self.assertEqual(address, addr) path = "m/84'/0'/0'" prv = b"zprvAdG4iTXWBoARxkkzNpNh8r6Qag3irQB8PzEMkAFeTRXxHpbF9z4QgEvBRmfvqWvGp42t42nvgGpNgYSJA9iefm1yYNZKEm7z6qUWCroSQnE" pub = b"zpub6rFR7y4Q2AijBEqTUquhVz398htDFrtymD9xYYfG1m4wAcvPhXNfE3EfH1r1ADqtfSdVCToUG868RvUUkgDKf31mGDtKsAYz2oz2AGutZYs" address = b"bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu" rxprv = bip32.rootxprv_from_bip39mnemonic(mnemonic, passphrase, MAIN_zprv) mprv = bip32.derive(rxprv, path) self.assertEqual(mprv, prv) mpub = bip32.xpub_from_xprv(mprv) self.assertEqual(mpub, pub) pub = bip32.derive(mpub, "./0/0") addr = slip32.address_from_xpub(pub) self.assertEqual(address, addr)
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_vectors(): fname = "electrum_test_vectors.json" filename = path.join(path.dirname(__file__), "test_data", fname) with open(filename, "r") as f: test_vectors = json.load(f) lang = "en" for test_vector in test_vectors: mnemonic = test_vector[0] passphrase = test_vector[1] mxprv = test_vector[2] mxpub = test_vector[3] address = test_vector[4] # "./0/0" if mnemonic != "": mxprv2 = bip32.mxprv_from_electrum_mnemonic(mnemonic, passphrase) assert mxprv2 == mxprv.encode() eversion, mnemonic = electrum.version_from_mnemonic(mnemonic) entr = int(electrum.entropy_from_mnemonic(mnemonic, lang), 2) mnem = electrum.mnemonic_from_entropy(entr, eversion, lang) assert mnem == mnemonic if mxprv != "": mxpub2 = bip32.xpub_from_xprv(mxprv) assert mxpub2 == mxpub.encode() xpub = bip32.derive(mxpub, "./0/0") address2 = slip32.address_from_xpub(xpub).decode("ascii") assert address2 == address
def test_serialize(self): xprv = b"xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi" xprv_dict = deserialize(xprv) xpr2 = serialize(xprv_dict) self.assertEqual(xpr2, xprv) # private key not in [1, n-1] inv_key = (ec.n).to_bytes(ec.nsize, 'big') decoded_key = b58decode(xprv, 78) xkey = b58encode(decoded_key[:46] + inv_key) self.assertRaises(ValueError, deserialize, xkey) # deserialize(xkey) xpub = xpub_from_xprv(xprv) xpub2 = xpub_from_xprv(deserialize(xprv)) self.assertEqual(xpub, xpub2)
def test_serialization() -> None: xkey = "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi" xkey_data = BIP32KeyData.deserialize(xkey) decoded_key = b58decode(xkey, 78) assert xkey_data.version == decoded_key[:4] assert xkey_data.depth == decoded_key[4] assert xkey_data.parent_fingerprint == decoded_key[5:9] assert xkey_data.index == int.from_bytes(decoded_key[9:13], "big") assert xkey_data.chain_code == decoded_key[13:45] assert xkey_data.key == decoded_key[45:] assert xkey_data.serialize().decode("ascii") == xkey xpub = xpub_from_xprv(xkey) xpub2 = xpub_from_xprv(xkey_data) assert xpub == xpub2
def test_slip32(self): # xkey is not a public one xprv = b'xprv9s21ZrQH143K2ZP8tyNiUtgoezZosUkw9hhir2JFzDhcUWKz8qFYk3cxdgSFoCMzt8E2Ubi1nXw71TLhwgCfzqFHfM5Snv4zboSebePRmLS' self.assertRaises(ValueError, slip32.address_from_xpub, xprv) address = slip32.address_from_xkey(xprv) xpub = bip32.xpub_from_xprv(xprv) address2 = slip32.address_from_xpub(xpub) self.assertEqual(address, address2)
def test_derive_exceptions() -> None: # root key, zero depth rootmxprv = "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi" xprv = bip32.derive(rootmxprv, b"\x80\x00\x00\x00") xprv = bip32.derive(xprv, ".") # FIXME: this failure shoud be required # errmsg = "public derivation at depth one level" # with pytest.raises(UserWarning, match=errmsg): # bip32.deserialize(bip32.derive(rootmxprv, 0)) for der_path in ("", "/1"): with pytest.raises(ValueError, match="empty derivation path root: must be m or ."): bip32.derive(xprv, der_path) for der_path in (";/0", "invalid index", "800000"): with pytest.raises(ValueError, match="invalid derivation path root: "): bip32.derive(xprv, der_path) with pytest.raises(ValueError, match="derivation path depth greater than 255: "): bip32.derive(xprv, "." + 256 * "/0") errmsg = "absolute derivation path for non-root master key" with pytest.raises(ValueError, match=errmsg): bip32.derive(xprv, "m / 44 h/0h/1h/0/10") with pytest.raises(ValueError, match="index must be 4-bytes, not "): bip32.derive(xprv, b"\x00" * 5) errmsg = "int too big to convert" for index in (256**4, 0x8000000000): with pytest.raises(OverflowError, match=errmsg): bip32.derive(xprv, index) errmsg = "derivation path final depth greater than 255: " with pytest.raises(ValueError, match=errmsg): bip32.derive(xprv, "." + 255 * "/0") rootxprv = "xprv9s21ZrQH143K2ZP8tyNiUtgoezZosUkw9hhir2JFzDhcUWKz8qFYk3cxdgSFoCMzt8E2Ubi1nXw71TLhwgCfzqFHfM5Snv4zboSebePRmLS" temp = b58decode(rootxprv) bad_xprv = b58encode(temp[0:45] + b"\x02" + temp[46:], 78) errmsg = "invalid private key prefix: " with pytest.raises(ValueError, match=errmsg): bip32.derive(bad_xprv, 0x80000000) xpub = bip32.xpub_from_xprv(rootxprv) temp = b58decode(xpub) bad_xpub = b58encode(temp[0:45] + b"\x00" + temp[46:], 78) errmsg = "invalid public key prefix: " with pytest.raises(ValueError, match=errmsg): bip32.derive(bad_xpub, 0x80000000) errmsg = "hardened derivation from public key" with pytest.raises(ValueError, match=errmsg): bip32.derive(xpub, 0x80000000)
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_bips_pr905() -> None: "https://github.com/bitcoin/bips/pull/905" seed = "57fb1e450b8afb95c62afbcd49e4100d6790e0822b8905608679180ac34ca0bd45bf7ccc6c5f5218236d0eb93afc78bd117b9f02a6b7df258ea182dfaef5aad7" xroot = rootxprv_from_seed(seed) der_path = "m/44H/60H/0H" xprv = b"xprv9yqXG1Cns3YEQi6fsCJ7NGV5sHPiyZcbgLVst61dbLYyn7qy1G9aFtRmaYp481ounqnVf9Go2ymQ4gmxZLEwYSRhU868aDk4ZxzGvqHJVhe" assert derive(xroot, der_path) == xprv xpub = b"xpub6CpsfWjghR6XdCB8yDq7jQRpRKEDP2LT3ZRUgURF9g5xevB7YoTpogkFRqq5nQtVSN8YCMZo2CD8u4zCaxRv85ctCWmzEi9gQ5DBhBFaTNo" assert xpub_from_xprv(xprv) == xpub
def test_slip132() -> None: # xkey is not a public one xprv = b"xprv9s21ZrQH143K2ZP8tyNiUtgoezZosUkw9hhir2JFzDhcUWKz8qFYk3cxdgSFoCMzt8E2Ubi1nXw71TLhwgCfzqFHfM5Snv4zboSebePRmLS" err_msg = "not a public key: " with pytest.raises(ValueError, match=err_msg): slip132.address_from_xpub(xprv) address = slip132.address_from_xkey(xprv) xpub = bip32.xpub_from_xprv(xprv) address2 = slip132.address_from_xpub(xpub) assert address == address2
def test_deserialize(): xprv = "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi" xprv_dict = deserialize(xprv) decoded_key = b58decode(xprv, 78) assert xprv_dict["version"] == decoded_key[:4] assert xprv_dict["depth"] == decoded_key[4] assert xprv_dict["parent_fingerprint"] == decoded_key[5:9] assert xprv_dict["index"] == decoded_key[9:13] assert xprv_dict["chain_code"] == decoded_key[13:45] assert xprv_dict["key"] == decoded_key[45:] # no harm in deserializing again an already deserialized key xprv_dict = deserialize(xprv_dict) xpr2 = serialize(xprv_dict) assert xpr2.decode(), xprv xpub = xpub_from_xprv(xprv) xpub2 = xpub_from_xprv(deserialize(xprv)) assert xpub == xpub2
def test_testnet(self): # bitcoin core derivation style rootxprv = "tprv8ZgxMBicQKsPe3g3HwF9xxTLiyc5tNyEtjhBBAk29YA3MTQUqULrmg7aj9qTKNfieuu2HryQ6tGVHse9x7ANFGs3f4HgypMc5nSSoxwf7TK" # m / 0h / 0h / 51h addr1 = b"mfXYCCsvWPgeCv8ZYGqcubpNLYy5nYHbbj" indexes = [0x80000000, 0x80000000, 0x80000000 + 51] addr = p2pkh(xpub_from_xprv(derive(rootxprv, indexes))) self.assertEqual(addr, addr1) path = "m/0h/0h/51h" addr = p2pkh(xpub_from_xprv(derive(rootxprv, path))) self.assertEqual(addr, addr1) # m / 0h / 1h / 150h addr2 = b"mfaUnRFxVvf55uD1P3zWXpprN1EJcKcGrb" indexes = [0x80000000, 0x80000000 + 1, 0x80000000 + 150] addr = p2pkh(xpub_from_xprv(derive(rootxprv, indexes))) self.assertEqual(addr, addr2) path = "m/0h/1h/150h" addr = p2pkh(xpub_from_xprv(derive(rootxprv, path))) self.assertEqual(addr, addr2)
def test_derive_from_account() -> None: seed = "bfc4cbaad0ff131aa97fa30a48d09ae7df914bcc083af1e07793cd0a7c61a03f65d622848209ad3366a419f4718a80ec9037df107d8d12c19b83202de00a40ad" rmxprv = bip32.rootxprv_from_seed(seed) der_path = "m / 44 h / 0 h" mxpub = bip32.xpub_from_xprv(bip32.derive(rmxprv, der_path)) test_vectors = [ [0, 0], [0, 1], [0, 2], [1, 0], [1, 1], [1, 2], ] for branch, index in test_vectors: full_path = der_path + f"/{branch}/{index}" addr = p2pkh(bip32.derive(rmxprv, full_path)).decode() assert addr == p2pkh(bip32.derive_from_account(mxpub, branch, index)).decode() errmsg = "invalid private derivation at branch level" with pytest.raises(ValueError, match=errmsg): bip32.derive_from_account(mxpub, 0x80000000, 0, True) errmsg = "invalid branch: " with pytest.raises(ValueError, match=errmsg): bip32.derive_from_account(mxpub, 2, 0) errmsg = "invalid private derivation at address index level" with pytest.raises(ValueError, match=errmsg): bip32.derive_from_account(mxpub, 0, 0x80000000) der_path = "m / 44 h / 0" mxpub = bip32.xpub_from_xprv(bip32.derive(rmxprv, der_path)) errmsg = "public derivation at account level" with pytest.raises(UserWarning, match=errmsg): bip32.derive_from_account(mxpub, 0, 0)
def test_fingerprint(self): xprv = b"xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi" f = fingerprint(xprv) child_key = derive(xprv, b'\x00\x00\x00\x00') pf = deserialize(child_key)['parent_fingerprint'] self.assertEqual(f, pf) xpub = xpub_from_xprv(xprv) f = fingerprint(xpub) self.assertEqual(f, pf) child_key2 = derive(deserialize(xprv), 0) self.assertEqual(child_key2, child_key)
def test_p2pkh_from_wif(self): seed = b"00" * 32 # better be random rxprv = bip32.rootxprv_from_seed(seed) path = "m/0h/0h/12" xprv = bip32.derive(rxprv, path) wif = wif_from_xprv(xprv) self.assertEqual( wif, b'KyLk7s6Z1FtgYEVp3bPckPVnXvLUWNCcVL6wNt3gaT96EmzTKZwP') address = p2pkh_from_wif(wif) xpub = bip32.xpub_from_xprv(xprv) address2 = slip32.address_from_xpub(xpub) self.assertEqual(address, address2) self.assertRaises(ValueError, wif_from_xprv, xpub)
def test_bip32_vectors(): """BIP32 test vectors https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki """ filename = path.join(data_folder, "bip32_test_vectors.json") with open(filename, "r") as f: test_vectors = json.load(f) for seed in test_vectors: mxprv = rootxprv_from_seed(seed) for der_path, xpub, xprv in test_vectors[seed]: assert xprv == derive(mxprv, der_path).decode() assert xpub == xpub_from_xprv(xprv).decode()
def test_bip32_vectors(self): """BIP32 test vector 3 https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki """ fname = "bip32_test_vectors.json" filename = path.join(path.dirname(__file__), "test_data", fname) with open(filename, "r") as f: test_vectors = json.load(f) for seed in test_vectors: mxprv = rootxprv_from_seed(seed) for der_path, xpub, xprv in test_vectors[seed]: self.assertEqual(xprv, derive(mxprv, der_path).decode()) self.assertEqual(xpub, xpub_from_xprv(xprv).decode())
def test_p2pkh_from_wif() -> None: seed = b"00" * 32 # better be a documented test case rxprv = bip32.rootxprv_from_seed(seed) path = "m/0h/0h/12" xprv = bip32.derive(rxprv, path) wif = wif_from_prvkey(xprv) assert wif == b"KyLk7s6Z1FtgYEVp3bPckPVnXvLUWNCcVL6wNt3gaT96EmzTKZwP" pubkey, _ = pubkeyinfo_from_prvkey(wif) address = p2pkh(pubkey) xpub = bip32.xpub_from_xprv(xprv) address2 = slip132.address_from_xpub(xpub) assert address == address2 err_msg = "not a private key: " with pytest.raises(ValueError, match=err_msg): wif_from_prvkey(xpub)
def test_p2pkh_from_wif() -> None: seed = b"\x00" * 32 # better be a documented test case rxprv = bip32.rootxprv_from_seed(seed) path = "m/0h/0h/12" xprv = bip32.derive(rxprv, path) wif = wif_from_prvkey(xprv) assert wif == b"L2L1dqRmkmVtwStNf5wg8nnGaRn3buoQr721XShM4VwDbTcn9bpm" pubkey, _ = pubkeyinfo_from_prvkey(wif) address = p2pkh(pubkey) xpub = bip32.xpub_from_xprv(xprv) address2 = slip132.address_from_xpub(xpub) assert address == address2 err_msg = "not a private key: " with pytest.raises(ValueError, match=err_msg): wif_from_prvkey(xpub)
def test_derive_exceptions() -> None: # root key, zero depth rootmxprv = "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi" xprv = derive(rootmxprv, bytes.fromhex("80000000")) xprv = derive(xprv, "m") for der_path in ("", "/1", "800000"): derive(xprv, der_path) err_msg = "invalid literal for int" for der_path in (";/0", "invalid index"): with pytest.raises(ValueError, match=err_msg): derive(xprv, der_path) with pytest.raises(BTClibValueError, match="depth greater than 255: "): derive(xprv, "m" + 256 * "/0") with pytest.raises(BTClibValueError, match="index is not a multiple of 4-bytes: "): derive(xprv, b"\x00" * 5) for index in (256**4, 0x8000000000): with pytest.raises(BTClibValueError, match="invalid index: "): derive(xprv, index) err_msg = "final depth greater than 255: " with pytest.raises(BTClibValueError, match=err_msg): derive(xprv, "m" + 255 * "/0") rootxprv = "xprv9s21ZrQH143K2ZP8tyNiUtgoezZosUkw9hhir2JFzDhcUWKz8qFYk3cxdgSFoCMzt8E2Ubi1nXw71TLhwgCfzqFHfM5Snv4zboSebePRmLS" temp = b58decode(rootxprv) bad_xprv = b58encode(temp[0:45] + b"\x02" + temp[46:], 78) err_msg = "invalid private key prefix: " with pytest.raises(BTClibValueError, match=err_msg): derive(bad_xprv, 0x80000000) xpub = xpub_from_xprv(rootxprv) temp = b58decode(xpub) bad_xpub = b58encode(temp[0:45] + b"\x00" + temp[46:], 78) err_msg = r"invalid public key prefix not in \(0x02, 0x03\): " with pytest.raises(BTClibValueError, match=err_msg): derive(bad_xpub, 0x80000000) err_msg = "hardened derivation from public key" with pytest.raises(BTClibValueError, match=err_msg): derive(xpub, 0x80000000)
def test_vectors(self): fname = "electrum_test_vectors.json" filename = path.join(path.dirname(__file__), "test_data", fname) with open(filename, "r") as f: test_vectors = json.load(f) lang = "en" for test_vector in test_vectors: mnemonic = test_vector[0] passphrase = test_vector[1] mxprv = test_vector[2] mxpub = test_vector[3] address = test_vector[4] # "./0/0" if mnemonic != "": mxprv2 = bip32.mxprv_from_electrum_mnemonic( mnemonic, passphrase) self.assertEqual(mxprv2, mxprv.encode()) eversion, mnemonic = electrum.version_from_mnemonic(mnemonic) entr = int(electrum.entropy_from_mnemonic(mnemonic, lang), 2) mnem = electrum.mnemonic_from_entropy(entr, eversion, lang) self.assertEqual(mnem, mnemonic) if mxprv != "": mxpub2 = bip32.xpub_from_xprv(mxprv) self.assertEqual(mxpub2, mxpub.encode()) xpub = bip32.derive(mxpub, "./0/0") address2 = slip32.address_from_xpub(xpub).decode("ascii") self.assertEqual(address2, address) # version 2fa_segwit mnemonic = ("slender flight session office noodle hand " "couple option office wait uniform morning") self.assertEqual("2fa_segwit", electrum.version_from_mnemonic(mnemonic)[0]) # version 2fa mnemonic = ("history recycle company awful donor fold " "beef nominee hard bleak bracket six") self.assertEqual("2fa", electrum.version_from_mnemonic(mnemonic)[0])
def test_vectors(self): filename = "electrum_test_vectors.json" path_to_filename = path.join(path.dirname(__file__), "./data/", filename) with open(path_to_filename, 'r') as f: test_vectors = json.load(f) f.closed lang = "en" for test_vector in test_vectors: mnemonic = test_vector[0] passphrase = test_vector[1] mxprv = test_vector[2] mxpub = test_vector[3] address = test_vector[4] # "./0/0" if mnemonic != "": mxprv2 = electrum.masterxprv_from_mnemonic( mnemonic, passphrase) self.assertEqual(mxprv2.decode(), mxprv) eversion = electrum.version_from_mnemonic(mnemonic) entr = int(electrum.entropy_from_mnemonic(mnemonic, lang), 2) mnem = electrum.mnemonic_from_entropy(eversion, entr, lang) self.assertEqual(mnem, mnemonic) if mxprv != "": mxpub2 = bip32.xpub_from_xprv(mxprv) self.assertEqual(mxpub2.decode(), mxpub) xpub = bip32.derive(mxpub, "./0/0") address2 = bip32.address_from_xpub(xpub).decode() self.assertEqual(address2, address) # version 2fa_segwit mnemonic = "slender flight session office noodle hand couple option office wait uniform morning" self.assertEqual("2fa_segwit", electrum.version_from_mnemonic(mnemonic)) # version 2fa mnemonic = "history recycle company awful donor fold beef nominee hard bleak bracket six" self.assertEqual("2fa", electrum.version_from_mnemonic(mnemonic))
def test_vectors() -> None: fname = "electrum_test_vectors.json" filename = path.join(path.dirname(__file__), "test_data", fname) with open(filename, "r") as f: test_vectors = json.load(f) lang = "en" for mnemonic, passphrase, rmxprv, rmxpub, address in test_vectors: if mnemonic != "": mxprv2 = bip32.mxprv_from_electrum_mnemonic(mnemonic, passphrase) assert mxprv2 == rmxprv.encode() eversion, mnemonic = electrum.version_from_mnemonic(mnemonic) entr = int(electrum.entropy_from_mnemonic(mnemonic, lang), 2) mnem = electrum.mnemonic_from_entropy(entr, eversion, lang) assert mnem == mnemonic assert rmxpub.encode() == bip32.xpub_from_xprv(rmxprv) xprv = bip32.derive(rmxprv, "m/0h/0") address2 = slip132.address_from_xkey(xprv).decode("ascii") assert address2 == address
def test_vectors(self): filename = "electrum_test_vectors.json" path_to_filename = os.path.join(os.path.dirname(__file__), "./data/", filename) with open(path_to_filename, 'r') as f: test_vectors = json.load(f) f.closed for test_vector in test_vectors: version = test_vector[0] mnemonic = test_vector[1] passphrase = test_vector[2] mpub = test_vector[3] xversion = bip32.PRV[0] #FIXME: version / xversion mprv = electrum.mprv_from_mnemonic(mnemonic, passphrase, xversion) mpub2 = bip32.xpub_from_xprv(mprv).decode() self.assertEqual(mpub2, mpub) lang = "en" entropy = int(electrum.entropy_from_mnemonic(mnemonic, lang), 2) mnem = electrum.mnemonic_from_raw_entropy(entropy, lang, version) self.assertEqual(mnem, mnemonic)