mirror of
https://github.com/LBRYFoundation/LBRY-Vault.git
synced 2025-08-30 08:51:32 +00:00
follow-up prev: do all checks, and add tests
This commit is contained in:
parent
a987a2bbbe
commit
c744fc4e3d
3 changed files with 100 additions and 8 deletions
|
@ -401,3 +401,26 @@ def root_fp_and_der_prefix_from_xkey(xkey: str) -> Tuple[Optional[str], Optional
|
|||
derivation_prefix = convert_bip32_intpath_to_strpath([child_number_int])
|
||||
root_fingerprint = node.fingerprint.hex()
|
||||
return root_fingerprint, derivation_prefix
|
||||
|
||||
|
||||
def is_xkey_consistent_with_key_origin_info(xkey: str, *,
|
||||
derivation_prefix: str = None,
|
||||
root_fingerprint: str = None) -> bool:
|
||||
bip32node = BIP32Node.from_xkey(xkey)
|
||||
int_path = None
|
||||
if derivation_prefix is not None:
|
||||
int_path = convert_bip32_path_to_list_of_uint32(derivation_prefix)
|
||||
if int_path is not None and len(int_path) != bip32node.depth:
|
||||
return False
|
||||
if bip32node.depth == 0:
|
||||
if bfh(root_fingerprint) != bip32node.calc_fingerprint_of_this_node():
|
||||
return False
|
||||
if bip32node.child_number != bytes(4):
|
||||
return False
|
||||
if int_path is not None and bip32node.depth > 0:
|
||||
if int.from_bytes(bip32node.child_number, 'big') != int_path[-1]:
|
||||
return False
|
||||
if bip32node.depth == 1:
|
||||
if bfh(root_fingerprint) != bip32node.fingerprint:
|
||||
return False
|
||||
return True
|
||||
|
|
|
@ -36,7 +36,7 @@ from .bitcoin import deserialize_privkey, serialize_privkey
|
|||
from .transaction import Transaction, PartialTransaction, PartialTxInput, PartialTxOutput, TxInput
|
||||
from .bip32 import (convert_bip32_path_to_list_of_uint32, BIP32_PRIME,
|
||||
is_xpub, is_xprv, BIP32Node, normalize_bip32_derivation,
|
||||
convert_bip32_intpath_to_strpath)
|
||||
convert_bip32_intpath_to_strpath, is_xkey_consistent_with_key_origin_info)
|
||||
from .ecc import string_to_number
|
||||
from .crypto import (pw_decode, pw_encode, sha256, sha256d, PW_HASH_VERSION_LATEST,
|
||||
SUPPORTED_PW_HASH_VERSIONS, UnsupportedPasswordHashVersion, hash_160)
|
||||
|
@ -468,13 +468,10 @@ class Xpub(MasterPublicKeyMixin):
|
|||
if not (root_fingerprint is None or (is_hex_str(root_fingerprint) and len(root_fingerprint) == 8)):
|
||||
raise Exception("root fp must be 8 hex characters")
|
||||
derivation_prefix = normalize_bip32_derivation(derivation_prefix)
|
||||
calc_root_fp, calc_der_prefix = bip32.root_fp_and_der_prefix_from_xkey(self.xpub)
|
||||
if (calc_root_fp is not None and root_fingerprint is not None
|
||||
and calc_root_fp != root_fingerprint):
|
||||
raise Exception("provided root fp inconsistent with xpub")
|
||||
if (calc_der_prefix is not None and derivation_prefix is not None
|
||||
and calc_der_prefix != derivation_prefix):
|
||||
raise Exception("provided der prefix inconsistent with xpub")
|
||||
if not is_xkey_consistent_with_key_origin_info(self.xpub,
|
||||
derivation_prefix=derivation_prefix,
|
||||
root_fingerprint=root_fingerprint):
|
||||
raise Exception("xpub inconsistent with provided key origin info")
|
||||
if root_fingerprint is not None:
|
||||
self._root_fingerprint = root_fingerprint
|
||||
if derivation_prefix is not None:
|
||||
|
|
|
@ -9,6 +9,7 @@ from electrum.bitcoin import (public_key_to_p2pkh, address_from_private_key,
|
|||
is_compressed_privkey, EncodeBase58Check, DecodeBase58Check,
|
||||
script_num_to_hex, push_script, add_number_to_script, int_to_hex,
|
||||
opcodes, base_encode, base_decode, BitcoinException)
|
||||
from electrum import bip32
|
||||
from electrum.bip32 import (BIP32Node, convert_bip32_intpath_to_strpath,
|
||||
xpub_from_xprv, xpub_type, is_xprv, is_bip32_derivation,
|
||||
is_xpub, convert_bip32_path_to_list_of_uint32,
|
||||
|
@ -457,6 +458,77 @@ class Test_xprv_xpub(ElectrumTestCase):
|
|||
self.assertEqual("m/0/2/1'", normalize_bip32_derivation("m/0/2/-1/"))
|
||||
self.assertEqual("m/0/1'/1'/5'", normalize_bip32_derivation("m/0//-1/1'///5h"))
|
||||
|
||||
def test_is_xkey_consistent_with_key_origin_info(self):
|
||||
### actual data (high depth path)
|
||||
self.assertTrue(bip32.is_xkey_consistent_with_key_origin_info(
|
||||
"Zpub75NQordWKAkaF7utBw95GEodyxqwFdR3idtTqQtrvWkYFeiuYdg5c3Q9L9bLjPLhEahLCTjmmS2YQcXPwr6twYCEJ55k6uhE5JxRqvUowmd",
|
||||
derivation_prefix="m/48'/1'/0'/2'",
|
||||
root_fingerprint="b2768d2f"))
|
||||
# ok to skip args
|
||||
self.assertTrue(bip32.is_xkey_consistent_with_key_origin_info(
|
||||
"Zpub75NQordWKAkaF7utBw95GEodyxqwFdR3idtTqQtrvWkYFeiuYdg5c3Q9L9bLjPLhEahLCTjmmS2YQcXPwr6twYCEJ55k6uhE5JxRqvUowmd",
|
||||
derivation_prefix="m/48'/1'/0'/2'"))
|
||||
self.assertTrue(bip32.is_xkey_consistent_with_key_origin_info(
|
||||
"Zpub75NQordWKAkaF7utBw95GEodyxqwFdR3idtTqQtrvWkYFeiuYdg5c3Q9L9bLjPLhEahLCTjmmS2YQcXPwr6twYCEJ55k6uhE5JxRqvUowmd",
|
||||
root_fingerprint="b2768d2f"))
|
||||
# path changed: wrong depth
|
||||
self.assertFalse(bip32.is_xkey_consistent_with_key_origin_info(
|
||||
"Zpub75NQordWKAkaF7utBw95GEodyxqwFdR3idtTqQtrvWkYFeiuYdg5c3Q9L9bLjPLhEahLCTjmmS2YQcXPwr6twYCEJ55k6uhE5JxRqvUowmd",
|
||||
derivation_prefix="m/48'/0'/2'",
|
||||
root_fingerprint="b2768d2f"))
|
||||
# path changed: wrong child index
|
||||
self.assertFalse(bip32.is_xkey_consistent_with_key_origin_info(
|
||||
"Zpub75NQordWKAkaF7utBw95GEodyxqwFdR3idtTqQtrvWkYFeiuYdg5c3Q9L9bLjPLhEahLCTjmmS2YQcXPwr6twYCEJ55k6uhE5JxRqvUowmd",
|
||||
derivation_prefix="m/48'/1'/0'/3'",
|
||||
root_fingerprint="b2768d2f"))
|
||||
# path changed: but cannot tell
|
||||
self.assertTrue(bip32.is_xkey_consistent_with_key_origin_info(
|
||||
"Zpub75NQordWKAkaF7utBw95GEodyxqwFdR3idtTqQtrvWkYFeiuYdg5c3Q9L9bLjPLhEahLCTjmmS2YQcXPwr6twYCEJ55k6uhE5JxRqvUowmd",
|
||||
derivation_prefix="m/48'/1'/1'/2'",
|
||||
root_fingerprint="b2768d2f"))
|
||||
# fp changed: but cannot tell
|
||||
self.assertTrue(bip32.is_xkey_consistent_with_key_origin_info(
|
||||
"Zpub75NQordWKAkaF7utBw95GEodyxqwFdR3idtTqQtrvWkYFeiuYdg5c3Q9L9bLjPLhEahLCTjmmS2YQcXPwr6twYCEJ55k6uhE5JxRqvUowmd",
|
||||
derivation_prefix="m/48'/1'/0'/2'",
|
||||
root_fingerprint="aaaaaaaa"))
|
||||
|
||||
### actual data (depth=1 path)
|
||||
self.assertTrue(bip32.is_xkey_consistent_with_key_origin_info(
|
||||
"zpub6nsHdRuY92FsMKdbn9BfjBCG6X8pyhCibNP6uDvpnw2cyrVhecvHRMa3Ne8kdJZxjxgwnpbHLkcR4bfnhHy6auHPJyDTQ3kianeuVLdkCYQ",
|
||||
derivation_prefix="m/0'",
|
||||
root_fingerprint="b2e35a7d"))
|
||||
# path changed: wrong depth
|
||||
self.assertFalse(bip32.is_xkey_consistent_with_key_origin_info(
|
||||
"zpub6nsHdRuY92FsMKdbn9BfjBCG6X8pyhCibNP6uDvpnw2cyrVhecvHRMa3Ne8kdJZxjxgwnpbHLkcR4bfnhHy6auHPJyDTQ3kianeuVLdkCYQ",
|
||||
derivation_prefix="m/0'/0'",
|
||||
root_fingerprint="b2e35a7d"))
|
||||
# path changed: wrong child index
|
||||
self.assertFalse(bip32.is_xkey_consistent_with_key_origin_info(
|
||||
"zpub6nsHdRuY92FsMKdbn9BfjBCG6X8pyhCibNP6uDvpnw2cyrVhecvHRMa3Ne8kdJZxjxgwnpbHLkcR4bfnhHy6auHPJyDTQ3kianeuVLdkCYQ",
|
||||
derivation_prefix="m/1'",
|
||||
root_fingerprint="b2e35a7d"))
|
||||
# fp changed: can tell
|
||||
self.assertFalse(bip32.is_xkey_consistent_with_key_origin_info(
|
||||
"zpub6nsHdRuY92FsMKdbn9BfjBCG6X8pyhCibNP6uDvpnw2cyrVhecvHRMa3Ne8kdJZxjxgwnpbHLkcR4bfnhHy6auHPJyDTQ3kianeuVLdkCYQ",
|
||||
derivation_prefix="m/0'",
|
||||
root_fingerprint="aaaaaaaa"))
|
||||
|
||||
### actual data (depth=0 path)
|
||||
self.assertTrue(bip32.is_xkey_consistent_with_key_origin_info(
|
||||
"xpub661MyMwAqRbcFWohJWt7PHsFEJfZAvw9ZxwQoDa4SoMgsDDM1T7WK3u9E4edkC4ugRnZ8E4xDZRpk8Rnts3Nbt97dPwT52CwBdDWroaZf8U",
|
||||
derivation_prefix="m",
|
||||
root_fingerprint="48adc7a0"))
|
||||
# path changed: wrong depth
|
||||
self.assertFalse(bip32.is_xkey_consistent_with_key_origin_info(
|
||||
"xpub661MyMwAqRbcFWohJWt7PHsFEJfZAvw9ZxwQoDa4SoMgsDDM1T7WK3u9E4edkC4ugRnZ8E4xDZRpk8Rnts3Nbt97dPwT52CwBdDWroaZf8U",
|
||||
derivation_prefix="m/0",
|
||||
root_fingerprint="48adc7a0"))
|
||||
# fp changed: can tell
|
||||
self.assertFalse(bip32.is_xkey_consistent_with_key_origin_info(
|
||||
"xpub661MyMwAqRbcFWohJWt7PHsFEJfZAvw9ZxwQoDa4SoMgsDDM1T7WK3u9E4edkC4ugRnZ8E4xDZRpk8Rnts3Nbt97dPwT52CwBdDWroaZf8U",
|
||||
derivation_prefix="m",
|
||||
root_fingerprint="aaaaaaaa"))
|
||||
|
||||
def test_is_all_public_derivation(self):
|
||||
self.assertFalse(is_all_public_derivation("m/0/1'/1'"))
|
||||
self.assertFalse(is_all_public_derivation("m/0/2/1'"))
|
||||
|
|
Loading…
Add table
Reference in a new issue