def test_bip39(): lang = "en" mnem = "abandon abandon atom trust ankle walnut oil across awake bunker divorce abstract" raw_entr = bytes.fromhex("0000003974d093eda670121023cd0000") mnemonic = bip39.mnemonic_from_entropy(raw_entr, lang) assert mnemonic == mnem r = bip39.entropy_from_mnemonic(mnemonic, lang) size = (len(r) + 7) // 8 r = int(r, 2).to_bytes(size, byteorder="big") assert r == raw_entr wrong_mnemonic = mnemonic + " abandon" err_msg = "Wrong number of words: " with pytest.raises(ValueError, match=err_msg): bip39.entropy_from_mnemonic(wrong_mnemonic, lang) wr_m = "abandon abandon atom trust ankle walnut oil across awake bunker divorce oil" err_msg = "invalid checksum: " with pytest.raises(ValueError, match=err_msg): bip39.entropy_from_mnemonic(wr_m, lang) # Invalid number of bits (130) for BIP39 entropy; must be in ... binstr_entropy = "01" * 65 # 130 bits err_msg = "Invalid number of bits for BIP39 entropy: " with pytest.raises(ValueError, match=err_msg): bip39._entropy_checksum(binstr_entropy)
def test_bip39(self): lang = "en" raw_entr = bytes.fromhex("0000003974d093eda670121023cd0000") mnemonic = bip39.mnemonic_from_entropy(raw_entr, lang) self.assertEqual(mnemonic, "abandon abandon atom trust ankle walnut oil across awake bunker divorce abstract") r = bip39.entropy_from_mnemonic(mnemonic, lang) size = (len(r)+7) // 8 r = int(r, 2).to_bytes(size, 'big') self.assertEqual(r, raw_entr) passphrase = '' rootxprv = bip39.rootxprv_from_mnemonic(mnemonic, passphrase, bip32.PRV_VERSION[0]) exp = b'xprv9s21ZrQH143K3ZxBCax3Wu25iWt3yQJjdekBuGrVa5LDAvbLeCT99U59szPSFdnMe5szsWHbFyo8g5nAFowWJnwe8r6DiecBXTVGHG124G1' self.assertEqual(rootxprv, exp) rootxprv2 = bip39.rootxprv_from_entropy(raw_entr, passphrase, lang, bip32.PRV_VERSION[0]) self.assertEqual(rootxprv2, rootxprv) rootxprv = bip39.rootxprv_from_mnemonic(mnemonic, passphrase, bip32.PRV_VERSION[0]) exp = b'xprv9s21ZrQH143K3ZxBCax3Wu25iWt3yQJjdekBuGrVa5LDAvbLeCT99U59szPSFdnMe5szsWHbFyo8g5nAFowWJnwe8r6DiecBXTVGHG124G1' self.assertEqual(rootxprv, exp) rootxprv2 = bip39.rootxprv_from_entropy(raw_entr, passphrase, lang, bip32.PRV_VERSION[0]) self.assertEqual(rootxprv2, rootxprv) # mnemonic with wrong number of bits wrong_mnemonic = mnemonic + " abandon" self.assertRaises(ValueError, bip39.entropy_from_mnemonic, wrong_mnemonic, lang) #bip39_entropy_from_mnemonic(wrong_mnemonic, lang) # invalid mnemonic checksum wrong_mnemonic = "abandon abandon atom trust ankle walnut oil across awake bunker divorce walnut" self.assertRaises(ValueError, bip39.entropy_from_mnemonic, wrong_mnemonic, lang)
def test_bip39(self): lang = "en" raw_entr = bytes.fromhex("0000003974d093eda670121023cd0000") mnemonic = bip39.mnemonic_from_entropy(raw_entr, lang) self.assertEqual( mnemonic, "abandon abandon atom trust ankle walnut oil across awake bunker divorce abstract" ) r = bip39.entropy_from_mnemonic(mnemonic, lang) size = (len(r) + 7) // 8 r = int(r, 2).to_bytes(size, byteorder='big') self.assertEqual(r, raw_entr) # mnemonic with wrong number of words wrong_mnemonic = mnemonic + " abandon" self.assertRaises(ValueError, bip39.entropy_from_mnemonic, wrong_mnemonic, lang) #bip39_entropy_from_mnemonic(wrong_mnemonic, lang) # invalid mnemonic checksum wr_m = "abandon abandon atom trust ankle walnut oil across awake bunker divorce walnut" self.assertRaises(ValueError, bip39.entropy_from_mnemonic, wr_m, lang) #bip39_entropy_from_mnemonic(wrong_mnemonic, lang) # Invalid number of bits (130) for BIP39 entropy; must be in ... binstr_entropy = '01' * 65 # 130 bits self.assertRaises(ValueError, bip39._entropy_checksum, binstr_entropy)
def test_vectors(self): """BIP39 test vectors https://github.com/trezor/python-mnemonic/blob/master/vectors.json """ fname = "bip39_test_vectors.json" filename = path.join(path.dirname(__file__), "test_data", fname) with open(filename, "r") as f: test_vectors = json.load(f)["english"] for test_vector in test_vectors: lang = "en" entropy = bytes.fromhex(test_vector[0]) mnemonic = bip39.mnemonic_from_entropy(entropy, lang) self.assertEqual(mnemonic.split(), test_vector[1].split()) raw_entr = bip39.entropy_from_mnemonic(mnemonic, lang) size = (len(raw_entr) + 7) // 8 raw_entr = int(raw_entr, 2).to_bytes(size, byteorder="big") self.assertEqual(raw_entr, entropy) seed = bip39.seed_from_mnemonic(mnemonic, "TREZOR").hex() self.assertEqual(seed, test_vector[2])
def test_vectors() -> None: """BIP39 test vectors https://github.com/trezor/python-mnemonic/blob/master/vectors.json """ fname = "bip39_test_vectors.json" filename = path.join(path.dirname(__file__), "test_data", fname) with open(filename, "r") as file_: bip39_test_vectors = json.load(file_)["english"] lang = "en" # test_vector[3], i.e. the bip32 master private key, is tested in bip32 for entr, mnemonic, seed, _ in bip39_test_vectors: entropy = bytes.fromhex(entr) # clean up mnemonic from spurious whitespaces mnemonic = " ".join(mnemonic.split()) assert mnemonic == bip39.mnemonic_from_entropy(entropy, lang) assert seed == bip39.seed_from_mnemonic(mnemonic, "TREZOR").hex() raw_entr = bip39.entropy_from_mnemonic(mnemonic, lang) size = (len(raw_entr) + 7) // 8 assert entropy == int(raw_entr, 2).to_bytes(size, byteorder="big")
def test_vectors(self): """BIP39 test vectors https://github.com/trezor/python-mnemonic/blob/master/vectors.json """ filename = "bip39_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)["english"] f.closed for test_vector in test_vectors: lang = "en" test_vector[0] = bytes.fromhex(test_vector[0]) mnemonic = bip39.mnemonic_from_entropy(test_vector[0], lang) self.assertEqual(mnemonic, test_vector[1]) raw_entr = bip39.entropy_from_mnemonic(mnemonic, lang) size = (len(raw_entr) + 7) // 8 raw_entr = int(raw_entr, 2).to_bytes(size, 'big') self.assertEqual(raw_entr, test_vector[0]) seed = bip39.seed_from_mnemonic(mnemonic, "TREZOR").hex() self.assertEqual(seed, test_vector[2])
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_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_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, '') ##### TESTNET # p2pkh BIP44 m / 44' / coin_type' / account' / change / address_index path = "m/44h/1h/0h" version = bip32.TEST_tprv rootprv = bip32.rootxprv_from_seed(seed, version) xprv = bip32.derive(rootprv, path) xpub = bip32.xpub_from_xprv(xprv) exp = b'tpubDChqWo2Xi2wNsxyJBE8ipcTJHLKWcqeeNUKBVTpUCNPZkHzHTm3qKAeHqgCou1t8PAY5ZnJ9QDa6zXSZxmjDnhiBpgZ7f6Yv88wEm5HXVbm' self.assertEqual(xpub, exp) # first addresses xpub_ext = bip32.derive(xpub, "./0/0") # external address = bip32.p2pkh_address_from_xpub(xpub_ext) exp_address = b'moutHSzeFWViMNEcvBxKzNCMj2kca8MvE1' self.assertEqual(address, exp_address) xpub_int = bip32.derive(xpub, "./1/0") # internal address = bip32.p2pkh_address_from_xpub(xpub_int) exp_address = b'myWcXdNais9ExumnGKnNoJwoihQKfNPG9i' self.assertEqual(address, exp_address) # legacy segwit (p2wpkh-p2sh) m / 49'/ coin_type' / account' / change / address_index path = "m/49h/1h/0h" version = bip32.TEST_uprv rootprv = bip32.rootxprv_from_seed(seed, version) xprv = bip32.derive(rootprv, path) xpub = bip32.xpub_from_xprv(xprv) exp = b'upub5Dj8j7YrwodV68mt58QmNpSzjqjso2WMXEpLGLSvskKccGuXhCh3dTedkzVLAePA617UyXAg2vdswJXTYjU4qjMJaHU79GJVVJCAiy9ezZ2' self.assertEqual(xpub, exp) # first addresses xpub_ext = bip32.derive(xpub, "./0/0") # external # TODO: address = bip32.p2pkh_address_from_xpub(xpub_ext) exp_address = b'2Mw8tQ6uT6mHhybarVhjgomUhHQJTeV9A2c' # TODO: self.assertEqual(address, exp_address) xpub_int = bip32.derive(xpub, "./1/0") # internal # TODO: address = bip32.p2pkh_address_from_xpub(xpub_int) exp_address = b'2N872CRJ3E1CzWjfixXr3aeC3hkF5Cz4kWb' # TODO: self.assertEqual(address, exp_address) # multi-sig version version = bip32.TEST_Uprv rootprv = bip32.rootxprv_from_seed(seed, version) xprv = bip32.derive(rootprv, path) xpub = bip32.xpub_from_xprv(xprv) exp = b'Upub5QdDrMHJWmBrWhwG1nskCtnoTdn91PBwqWU1BbiUFXA2ETUSTc5KiaWZZhSoj5c4KUBTr7Anv92P4U9Dqxd1zDTyQkaWYfmVP2U3Js1W5cG' self.assertEqual(xpub, exp) # native segwit (p2wpkh) m / 84'/ coin_type' / account' / change / address_index path = "m/84h/1h/0h" version = bip32.TEST_vprv rootprv = bip32.rootxprv_from_seed(seed, version) xprv = bip32.derive(rootprv, path) xpub = bip32.xpub_from_xprv(xprv) exp = b'vpub5ZhJmduYY7M5J2qCJgSW7hunX6zJrr5WuNg2kKt321HseZEYxqJc6Zso47aNXQw3Wf3sA8kppbfsxnLheUNXcL3xhzeBHLNp8fTVBN6DnJF' self.assertEqual(xpub, exp) # first addresses xpub_ext = bip32.derive(xpub, "./0/0") # external # FIXME: address = bip32.p2pkh_address_from_xpub(xpub_ext) exp_address = b'bcrt1qv8lcnmj09rpdqwgl025h2deygur64z4hqf7me5' # FIXME: self.assertEqual(address, exp_address) xpub_int = bip32.derive(xpub, "./1/0") # internal # FIXME: address = bip32.p2pkh_address_from_xpub(xpub_int) exp_address = b'bcrt1qqhxvky4y6qkwpvdzqjkdafmj20vs5trmt6y8w5' # FIXME: self.assertEqual(address, exp_address) # multi-sig version version = bip32.TEST_Vprv rootprv = bip32.rootxprv_from_seed(seed, version) xprv = bip32.derive(rootprv, path) xpub = bip32.xpub_from_xprv(xprv) exp = b'Vpub5kbPtsdz74uSibzaFLuUwnFbEu2a5Cm7DeKhfb9aPn8HGjoTjEgtBgjirpXr5r9wk87r2ikwhp4P5wxTwhXUkpAdYTkagjqp2PjMmGPBESU' self.assertEqual(xpub, exp) ##### MAINNET # p2pkh BIP44 m / 44' / coin_type' / account' / change / address_index path = "m/44h/0h/0h" version = bip32.MAIN_xprv rootprv = bip32.rootxprv_from_seed(seed, version) xprv = bip32.derive(rootprv, path) xpub = bip32.xpub_from_xprv(xprv) exp = b'xpub6C3uWu5Go5q62JzJpbjyCLYRGLYvexFeiepZTsYZ6SRexARkNfjG7GKtQVuGR3KHsyKsAwv7Hz3iNucPp6pfHiLvBczyK1j5CtBtpHB3NKx' self.assertEqual(xpub, exp) # first addresses xpub_ext = bip32.derive(xpub, "./0/0") # external address = bip32.p2pkh_address_from_xpub(xpub_ext) exp_address = b'1DDKKVHoFWGfctyEEJvrusqq6ipEaieGCq' self.assertEqual(address, exp_address) xpub_int = bip32.derive(xpub, "./1/0") # internal address = bip32.p2pkh_address_from_xpub(xpub_int) exp_address = b'1FhKoffreKHzhtBMVW9NSsg3ZF148JPGoR' self.assertEqual(address, exp_address) # legacy segwit (p2wpkh-p2sh) m / 49'/ coin_type' / account' / change / address_index path = "m/49h/0h/0h" version = bip32.MAIN_yprv rootprv = bip32.rootxprv_from_seed(seed, version) xprv = bip32.derive(rootprv, path) xpub = bip32.xpub_from_xprv(xprv) exp = b'ypub6YBGdYufCVeoPVmNXfdrWhaBCXsQoLKNetNmD9bPTrKmnKVmiyU8f1uJqwGdmBb8kbAZpHoYfXQTLbWpkXc4skQDAreeCUXdbX9k8vtiHsN' self.assertEqual(xpub, exp) # first addresses xpub_ext = bip32.derive(xpub, "./0/0") # external # FIXME: address = bip32.p2pkh_address_from_xpub(xpub_ext) exp_address = b'3FmNAiTCWe5kPMgc4dtSgEdY8VuaCiJEH8' # FIXME: self.assertEqual(address, exp_address) xpub_int = bip32.derive(xpub, "./1/0") # internal # FIXME: address = bip32.p2pkh_address_from_xpub(xpub_int) exp_address = b'34FLgkoRYX5Q5fqiZCZDwsK5GpXxmFuLJN' # FIXME: self.assertEqual(address, exp_address) # multi-sig version version = bip32.MAIN_Yprv rootprv = bip32.rootxprv_from_seed(seed, version) xprv = bip32.derive(rootprv, path) xpub = bip32.xpub_from_xprv(xprv) exp = b'Ypub6j5Mkne6mTDAp4vkUL6qLmuyvKug1gzxyA2S8QrvqdABQW4gVNrQk8mEeeE7Kcp2z4EYgsofYjnxTm8b3km22EWt1Km3bszdVFRcipc6rXu' self.assertEqual(xpub, exp) # native segwit (p2wpkh) m / 84'/ coin_type' / account' / change / address_index path = "m/84h/0h/0h" version = bip32.MAIN_zprv rootprv = bip32.rootxprv_from_seed(seed, version) xprv = bip32.derive(rootprv, path) xpub = bip32.xpub_from_xprv(xprv) exp = b'zpub6qg3Uc1BAQkQvcBUYMmZHSzbsshSon3FvJ8yvH3ZZMjFNvJkwSji8UUwghiF3wvpvSvcNWVP8kfUhc2V2RwGp6pTC3ouj6njj956f26TniN' self.assertEqual(xpub, exp) # first addresses xpub_ext = bip32.derive(xpub, "./0/0") # external # FIXME: address = bip32.p2pkh_address_from_xpub(xpub_ext) exp_address = b'bc1q0hy024867ednvuhy9en4dggflt5w9unw4ztl5a' # FIXME: self.assertEqual(address, exp_address) xpub_int = bip32.derive(xpub, "./1/0") # internal # FIXME: address = bip32.p2pkh_address_from_xpub(xpub_int) exp_address = b'bc1qy4x03jyl88h2zeg7l287xhv2xrwk4c3ztfpjd2' # FIXME: self.assertEqual(address, exp_address) # multi-sig version version = bip32.MAIN_Zprv rootprv = bip32.rootxprv_from_seed(seed, version) xprv = bip32.derive(rootprv, path) xpub = bip32.xpub_from_xprv(xprv) exp = b'Zpub72a8bqjcjNJnMBLrV2EY7XLQbfji28irEZneqYK6w8Zf16sfhr7zDbLsVQficP9j9uzbF6VW1y3ypmeFKf6Dxaw82WvK8WFjcsLyEvMNZjF' self.assertEqual(xpub, exp)
# Copyright (C) 2020 The btclib developers # # This file is part of btclib. It is subject to the license terms in the # LICENSE file found in the top-level directory of this distribution. # # No part of btclib including this file, may be copied, modified, propagated, # or distributed except according to the terms contained in the LICENSE file. import secrets from btclib import bip32, bip39, electrum entropy = secrets.randbits(256) bip39_mnemonic = bip39.mnemonic_from_entropy(entropy) print() print(bip39_mnemonic) rxprv = bip32.mxprv_from_bip39_mnemonic(bip39_mnemonic) rxpub = bip32.xpub_from_xprv(rxprv) # warning: first level should always be hardened # or any (depth=1) child private key would compromise rxprv path = "m/0h" xprv = bip32.derive(rxprv, path) print(path + f" : {xprv!r}") electrum_mnemonic = electrum.mnemonic_from_entropy(entropy) print() print(electrum_mnemonic) mxprv = bip32.mxprv_from_electrum_mnemonic(electrum_mnemonic) mxpub = bip32.xpub_from_xprv(mxprv)
def test_addresses() -> None: # 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") # m / purpose h / coin_type h / account h / change / address_index test_vectors: List[Tuple[str, str, str]] = [ # coin_type = 0 -> mainnet ( "m/44h/0h/0h", "bip32_prv", # p2pkh or p2sh "xpub6C3uWu5Go5q62JzJpbjyCLYRGLYvexFeiepZTsYZ6SRexARkNfjG7GKtQVuGR3KHsyKsAwv7Hz3iNucPp6pfHiLvBczyK1j5CtBtpHB3NKx", ), ( "m/49h/0h/0h", "slip132_p2wpkh_p2sh_prv", # p2wpkh-p2sh (p2sh-wrapped legacy-segwit p2wpkh) "ypub6YBGdYufCVeoPVmNXfdrWhaBCXsQoLKNetNmD9bPTrKmnKVmiyU8f1uJqwGdmBb8kbAZpHoYfXQTLbWpkXc4skQDAreeCUXdbX9k8vtiHsN", ), ( "m/49h/0h/0h", "slip132_p2wsh_p2sh_prv", # p2wsh-p2sh (p2sh-wrapped legacy-segwit p2wsh) "Ypub6j5Mkne6mTDAp4vkUL6qLmuyvKug1gzxyA2S8QrvqdABQW4gVNrQk8mEeeE7Kcp2z4EYgsofYjnxTm8b3km22EWt1Km3bszdVFRcipc6rXu", ), ( "m/84h/0h/0h", "slip132_p2wpkh_prv", # p2wpkh (native-segwit p2wpkh) "zpub6qg3Uc1BAQkQvcBUYMmZHSzbsshSon3FvJ8yvH3ZZMjFNvJkwSji8UUwghiF3wvpvSvcNWVP8kfUhc2V2RwGp6pTC3ouj6njj956f26TniN", ), ( "m/84h/0h/0h", "slip132_p2wsh_prv", # p2wsh (native-segwit p2wsh) "Zpub72a8bqjcjNJnMBLrV2EY7XLQbfji28irEZneqYK6w8Zf16sfhr7zDbLsVQficP9j9uzbF6VW1y3ypmeFKf6Dxaw82WvK8WFjcsLyEvMNZjF", ), # coin_type = 1 -> testnet ( "m/44h/1h/0h", "bip32_prv", # p2pkh BIP44 "tpubDChqWo2Xi2wNsxyJBE8ipcTJHLKWcqeeNUKBVTpUCNPZkHzHTm3qKAeHqgCou1t8PAY5ZnJ9QDa6zXSZxmjDnhiBpgZ7f6Yv88wEm5HXVbm", ), ( "m/49h/1h/0h", "slip132_p2wpkh_p2sh_prv", # p2wpkh-p2sh (p2sh-wrapped legacy-segwit p2wpkh) "upub5Dj8j7YrwodV68mt58QmNpSzjqjso2WMXEpLGLSvskKccGuXhCh3dTedkzVLAePA617UyXAg2vdswJXTYjU4qjMJaHU79GJVVJCAiy9ezZ2", ), ( "m/49h/1h/0h", "slip132_p2wsh_p2sh_prv", # p2wsh-p2sh (p2sh-wrapped legacy-segwit p2wsh) "Upub5QdDrMHJWmBrWhwG1nskCtnoTdn91PBwqWU1BbiUFXA2ETUSTc5KiaWZZhSoj5c4KUBTr7Anv92P4U9Dqxd1zDTyQkaWYfmVP2U3Js1W5cG", ), ( "m/84h/1h/0h", "slip132_p2wpkh_prv", # p2wpkh (native-segwit p2wpkh) "vpub5ZhJmduYY7M5J2qCJgSW7hunX6zJrr5WuNg2kKt321HseZEYxqJc6Zso47aNXQw3Wf3sA8kppbfsxnLheUNXcL3xhzeBHLNp8fTVBN6DnJF", ), ( "m/84h/1h/0h", "slip132_p2wsh_prv", # p2wsh (native-segwit p2wsh) "Vpub5kbPtsdz74uSibzaFLuUwnFbEu2a5Cm7DeKhfb9aPn8HGjoTjEgtBgjirpXr5r9wk87r2ikwhp4P5wxTwhXUkpAdYTkagjqp2PjMmGPBESU", ), ] for der_path, addr_type, mxpub in test_vectors: der_path_elements = der_path.split("/") network = "testnet" if der_path_elements[2] == "1h" else "mainnet" rootprv = bip32.mxprv_from_bip39_mnemonic(mnemonic, "", network) # FIXME: do not ignore version = NETWORKS[network][addr_type] # type: ignore xprv = bip32.derive(rootprv, der_path, version) assert mxpub.encode() == bip32.xpub_from_xprv(xprv) # a non-private version cannot be forced on a private key pub_version = NETWORKS[network]["bip32_pub"] err_msg = "invalid non-private version forced on a private key: " with pytest.raises(ValueError, match=err_msg): bip32.derive(rootprv, der_path, pub_version) # just changing the public version with no derivation does work bip32.derive(mxpub, ".", pub_version) err_msg = "invalid non-public version forced on a public key: " with pytest.raises(ValueError, match=err_msg): bip32.derive(mxpub, ".", version)
def test_zeroleadingbit(self): bip39.mnemonic_from_entropy(secrets.randbits(127), 'en')
def test_zeroleadingbit(): # it should not throw an error bip39.mnemonic_from_entropy(secrets.randbits(127), "en")
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 / 44' / coin_type' / account' / change / address_index path = "m/44h/1h/0h" version = bip32.TEST_tprv rootprv = bip32.rootxprv_from_seed(seed, version) xprv = bip32.derive(rootprv, path) xpub = bip32.xpub_from_xprv(xprv) exp = b'tpubDChqWo2Xi2wNsxyJBE8ipcTJHLKWcqeeNUKBVTpUCNPZkHzHTm3qKAeHqgCou1t8PAY5ZnJ9QDa6zXSZxmjDnhiBpgZ7f6Yv88wEm5HXVbm' self.assertEqual(xpub, exp) # first addresses xpub_ext = bip32.derive(xpub, "./0/0") # external address = bip32.p2pkh_address_from_xpub(xpub_ext) exp_address = b'moutHSzeFWViMNEcvBxKzNCMj2kca8MvE1' self.assertEqual(address, exp_address) xpub_int = bip32.derive(xpub, "./1/0") # internal address = bip32.p2pkh_address_from_xpub(xpub_int) exp_address = b'myWcXdNais9ExumnGKnNoJwoihQKfNPG9i' self.assertEqual(address, exp_address) # legacy segwit (p2wpkh-p2sh) m / 49'/ coin_type' / account' / change / address_index path = "m/49h/1h/0h" version = bip32.TEST_uprv rootprv = bip32.rootxprv_from_seed(seed, version) xprv = bip32.derive(rootprv, path) xpub = bip32.xpub_from_xprv(xprv) exp = b'upub5Dj8j7YrwodV68mt58QmNpSzjqjso2WMXEpLGLSvskKccGuXhCh3dTedkzVLAePA617UyXAg2vdswJXTYjU4qjMJaHU79GJVVJCAiy9ezZ2' self.assertEqual(xpub, exp) # first addresses xpub_ext = bip32.derive(xpub, "./0/0") # external address = bip32.p2wpkh_p2sh_address_from_xpub(xpub_ext) exp_address = b'2Mw8tQ6uT6mHhybarVhjgomUhHQJTeV9A2c' self.assertEqual(address, exp_address) xpub_int = bip32.derive(xpub, "./1/0") # internal address = bip32.p2wpkh_p2sh_address_from_xpub(xpub_int) exp_address = b'2N872CRJ3E1CzWjfixXr3aeC3hkF5Cz4kWb' self.assertEqual(address, exp_address) # legacy segwit (p2wsh-p2sh) m / 49'/ coin_type' / account' / change / address_index path = "m/49h/1h/0h" version = bip32.TEST_Uprv rootprv = bip32.rootxprv_from_seed(seed, version) xprv = bip32.derive(rootprv, path) xpub = bip32.xpub_from_xprv(xprv) exp = b'Upub5QdDrMHJWmBrWhwG1nskCtnoTdn91PBwqWU1BbiUFXA2ETUSTc5KiaWZZhSoj5c4KUBTr7Anv92P4U9Dqxd1zDTyQkaWYfmVP2U3Js1W5cG' self.assertEqual(xpub, exp) # native segwit (p2wpkh) m / 84'/ coin_type' / account' / change / address_index path = "m/84h/1h/0h" version = bip32.TEST_vprv rootprv = bip32.rootxprv_from_seed(seed, version) xprv = bip32.derive(rootprv, path) xpub = bip32.xpub_from_xprv(xprv) exp = b'vpub5ZhJmduYY7M5J2qCJgSW7hunX6zJrr5WuNg2kKt321HseZEYxqJc6Zso47aNXQw3Wf3sA8kppbfsxnLheUNXcL3xhzeBHLNp8fTVBN6DnJF' self.assertEqual(xpub, exp) # first addresses xpub_ext = bip32.derive(xpub, "./0/0") # external address = bip32.p2wpkh_address_from_xpub(xpub_ext) # this is regtest, not testnet!! exp_address = b'bcrt1qv8lcnmj09rpdqwgl025h2deygur64z4hqf7me5' # FIXME: self.assertEqual(address, exp_address) xpub_int = bip32.derive(xpub, "./1/0") # internal address = bip32.p2wpkh_address_from_xpub(xpub_int) # this is regtest, not testnet!! exp_address = b'bcrt1qqhxvky4y6qkwpvdzqjkdafmj20vs5trmt6y8w5' # FIXME: self.assertEqual(address, exp_address) # native segwit (p2wsh) m / 84'/ coin_type' / account' / change / address_index path = "m/84h/1h/0h" version = bip32.TEST_Vprv rootprv = bip32.rootxprv_from_seed(seed, version) xprv = bip32.derive(rootprv, path) xpub = bip32.xpub_from_xprv(xprv) exp = b'Vpub5kbPtsdz74uSibzaFLuUwnFbEu2a5Cm7DeKhfb9aPn8HGjoTjEgtBgjirpXr5r9wk87r2ikwhp4P5wxTwhXUkpAdYTkagjqp2PjMmGPBESU' self.assertEqual(xpub, exp)