Reduce run times of unified_{address, incoming_viewing_keys, full_viewing_keys}.py by over half

by avoiding duplicated work in deriving levels of the key hierarchy above the account level.

Signed-off-by: Daira Hopwood <daira@jacaranda.org>
This commit is contained in:
Daira Hopwood 2022-02-11 16:12:16 +00:00
parent f8a462d859
commit 189cadb357
3 changed files with 62 additions and 53 deletions

View File

@ -25,6 +25,18 @@ def main():
rand = Rand(randbytes(rng)) rand = Rand(randbytes(rng))
seed = bytes(range(32)) seed = bytes(range(32))
t_root_key = bip_0032.ExtendedSecretKey.master(seed)
t_purpose_key = t_root_key.child(hardened(44))
t_coin_key = t_purpose_key.child(hardened(ZCASH_MAIN_COINTYPE))
s_root_key = sapling_zip32.ExtendedSpendingKey.master(seed)
s_purpose_key = s_root_key.child(hardened(32))
s_coin_key = s_purpose_key.child(hardened(ZCASH_MAIN_COINTYPE))
o_root_key = orchard_key_components.ExtendedSpendingKey.master(seed)
o_purpose_key = o_root_key.child(hardened(32))
o_coin_key = o_purpose_key.child(hardened(ZCASH_MAIN_COINTYPE))
test_vectors = [] test_vectors = []
for account in range(0, 20): for account in range(0, 20):
has_t_addr = rand.bool() has_t_addr = rand.bool()
@ -39,25 +51,18 @@ def main():
j = 0 j = 0
has_s_addr = rand.bool() has_s_addr = rand.bool()
if has_s_addr: if has_s_addr:
root_key = sapling_zip32.ExtendedSpendingKey.master(seed) s_account_key = s_coin_key.child(hardened(account))
purpose_key = root_key.child(hardened(32)) j = s_account_key.find_j(0)
coin_key = purpose_key.child(hardened(ZCASH_MAIN_COINTYPE)) sapling_d = s_account_key.diversifier(j)
account_key = coin_key.child(hardened(account)) sapling_pk_d = s_account_key.pk_d(j)
j = account_key.find_j(0)
sapling_d = account_key.diversifier(j)
sapling_pk_d = account_key.pk_d(j)
sapling_raw_addr = sapling_d + bytes(sapling_pk_d) sapling_raw_addr = sapling_d + bytes(sapling_pk_d)
else: else:
sapling_raw_addr = None sapling_raw_addr = None
has_o_addr = (not has_s_addr) or rand.bool() has_o_addr = (not has_s_addr) or rand.bool()
if has_o_addr: if has_o_addr:
root_key = orchard_key_components.ExtendedSpendingKey.master(seed) o_account_key = o_coin_key.child(hardened(account))
purpose_key = root_key.child(hardened(32)) orchard_fvk = orchard_key_components.FullViewingKey.from_spending_key(o_account_key)
coin_key = purpose_key.child(hardened(ZCASH_MAIN_COINTYPE))
account_key = coin_key.child(hardened(account))
orchard_fvk = orchard_key_components.FullViewingKey.from_spending_key(account_key)
orchard_d = orchard_fvk.diversifier(j) orchard_d = orchard_fvk.diversifier(j)
orchard_pk_d = orchard_fvk.pk_d(j) orchard_pk_d = orchard_fvk.pk_d(j)
orchard_raw_addr = orchard_d + bytes(orchard_pk_d) orchard_raw_addr = orchard_d + bytes(orchard_pk_d)
@ -66,14 +71,11 @@ def main():
is_p2pkh = rand.bool() is_p2pkh = rand.bool()
if has_t_addr and is_p2pkh: if has_t_addr and is_p2pkh:
root_key = bip_0032.ExtendedSecretKey.master(seed) t_account_key = t_coin_key.child(hardened(account))
purpose_key = root_key.child(hardened(44)) t_external_key = t_account_key.child(0)
coin_key = purpose_key.child(hardened(ZCASH_MAIN_COINTYPE)) t_index_key = t_account_key.child(j)
account_key = coin_key.child(hardened(account)) t_index_pubkey = t_index_key.public_key()
external_key = account_key.child(0) t_addr = t_index_pubkey.address()
index_key = account_key.child(j)
index_pubkey = index_key.public_key()
t_addr = index_pubkey.address()
# include an unknown item 1/4 of the time # include an unknown item 1/4 of the time
has_unknown_item = rand.bool() and rand.bool() has_unknown_item = rand.bool() and rand.bool()

View File

@ -20,6 +20,18 @@ def main():
rand = Rand(randbytes(rng)) rand = Rand(randbytes(rng))
seed = bytes(range(32)) seed = bytes(range(32))
t_root_key = bip_0032.ExtendedSecretKey.master(seed)
t_purpose_key = t_root_key.child(hardened(44))
t_coin_key = t_purpose_key.child(hardened(ZCASH_MAIN_COINTYPE))
s_root_key = sapling_zip32.ExtendedSpendingKey.master(seed)
s_purpose_key = s_root_key.child(hardened(32))
s_coin_key = s_purpose_key.child(hardened(ZCASH_MAIN_COINTYPE))
o_root_key = orchard_key_components.ExtendedSpendingKey.master(seed)
o_purpose_key = o_root_key.child(hardened(32))
o_coin_key = o_purpose_key.child(hardened(ZCASH_MAIN_COINTYPE))
test_vectors = [] test_vectors = []
for account in range(0, 20): for account in range(0, 20):
has_t_key = rand.bool() has_t_key = rand.bool()
@ -30,21 +42,15 @@ def main():
# "However, the [Transparent P2PKH] FVK uses the key at the Account level, i.e. # "However, the [Transparent P2PKH] FVK uses the key at the Account level, i.e.
# at path m/44'/coin_type'/account', while the IVK uses the external (non-change) # at path m/44'/coin_type'/account', while the IVK uses the external (non-change)
# child key at the Change level, i.e. at path m/44'/coin_type'/account'/0." # child key at the Change level, i.e. at path m/44'/coin_type'/account'/0."
root_key = bip_0032.ExtendedSecretKey.master(seed) t_account_key = t_coin_key.child(hardened(account))
purpose_key = root_key.child(hardened(44)) t_key_bytes = bytes(t_account_key.public_key())
coin_key = purpose_key.child(hardened(ZCASH_MAIN_COINTYPE))
account_key = coin_key.child(hardened(account))
t_key_bytes = bytes(account_key.public_key())
else: else:
t_key_bytes = None t_key_bytes = None
has_s_key = rand.bool() has_s_key = rand.bool()
if has_s_key: if has_s_key:
root_key = sapling_zip32.ExtendedSpendingKey.master(seed) s_account_key = s_coin_key.child(hardened(account))
purpose_key = root_key.child(hardened(32)) sapling_fvk = s_account_key.to_extended_fvk()
coin_key = purpose_key.child(hardened(ZCASH_MAIN_COINTYPE))
account_key = coin_key.child(hardened(account))
sapling_fvk = account_key.to_extended_fvk()
sapling_fvk_bytes = b"".join([ sapling_fvk_bytes = b"".join([
bytes(sapling_fvk.ak()), bytes(sapling_fvk.ak()),
bytes(sapling_fvk.nk()), bytes(sapling_fvk.nk()),
@ -56,11 +62,8 @@ def main():
has_o_key = (not has_s_key) or rand.bool() has_o_key = (not has_s_key) or rand.bool()
if has_o_key: if has_o_key:
root_key = orchard_key_components.ExtendedSpendingKey.master(seed) o_account_key = o_coin_key.child(hardened(account))
purpose_key = root_key.child(hardened(32)) orchard_fvk = orchard_key_components.FullViewingKey.from_spending_key(o_account_key)
coin_key = purpose_key.child(hardened(ZCASH_MAIN_COINTYPE))
account_key = coin_key.child(hardened(account))
orchard_fvk = orchard_key_components.FullViewingKey.from_spending_key(account_key)
orchard_fvk_bytes = b"".join([ orchard_fvk_bytes = b"".join([
bytes(orchard_fvk.ak), bytes(orchard_fvk.ak),
bytes(orchard_fvk.nk), bytes(orchard_fvk.nk),

View File

@ -20,6 +20,18 @@ def main():
rand = Rand(randbytes(rng)) rand = Rand(randbytes(rng))
seed = bytes(range(32)) seed = bytes(range(32))
t_root_key = bip_0032.ExtendedSecretKey.master(seed)
t_purpose_key = t_root_key.child(hardened(44))
t_coin_key = t_purpose_key.child(hardened(ZCASH_MAIN_COINTYPE))
s_root_key = sapling_zip32.ExtendedSpendingKey.master(seed)
s_purpose_key = s_root_key.child(hardened(32))
s_coin_key = s_purpose_key.child(hardened(ZCASH_MAIN_COINTYPE))
o_root_key = orchard_key_components.ExtendedSpendingKey.master(seed)
o_purpose_key = o_root_key.child(hardened(32))
o_coin_key = o_purpose_key.child(hardened(ZCASH_MAIN_COINTYPE))
test_vectors = [] test_vectors = []
for account in range(0, 20): for account in range(0, 20):
has_t_key = rand.bool() has_t_key = rand.bool()
@ -30,34 +42,26 @@ def main():
# "However, the [Transparent P2PKH] FVK uses the key at the Account level, i.e. # "However, the [Transparent P2PKH] FVK uses the key at the Account level, i.e.
# at path m/44'/coin_type'/account', while the IVK uses the external (non-change) # at path m/44'/coin_type'/account', while the IVK uses the external (non-change)
# child key at the Change level, i.e. at path m/44'/coin_type'/account'/0." # child key at the Change level, i.e. at path m/44'/coin_type'/account'/0."
root_key = bip_0032.ExtendedSecretKey.master(seed) t_account_key = t_coin_key.child(hardened(account))
purpose_key = root_key.child(hardened(44)) t_external_key = t_account_key.child(0)
coin_key = purpose_key.child(hardened(ZCASH_MAIN_COINTYPE)) t_key_bytes = bytes(t_external_key.public_key())
account_key = coin_key.child(hardened(account))
external_key = account_key.child(0)
t_key_bytes = bytes(external_key.public_key())
else: else:
t_key_bytes = None t_key_bytes = None
has_s_key = rand.bool() has_s_key = rand.bool()
if has_s_key: if has_s_key:
root_key = sapling_zip32.ExtendedSpendingKey.master(seed) s_account_key = s_coin_key.child(hardened(account))
purpose_key = root_key.child(hardened(32)) sapling_fvk = s_account_key.to_extended_fvk()
coin_key = purpose_key.child(hardened(ZCASH_MAIN_COINTYPE)) sapling_dk = sapling_fvk.dk()
account_key = coin_key.child(hardened(account)) sapling_ivk = sapling_fvk.ivk()
sapling_dk = account_key.to_extended_fvk().dk()
sapling_ivk = account_key.ivk()
sapling_ivk_bytes = bytes(sapling_dk) + bytes(sapling_ivk) sapling_ivk_bytes = bytes(sapling_dk) + bytes(sapling_ivk)
else: else:
sapling_ivk_bytes = None sapling_ivk_bytes = None
has_o_key = (not has_s_key) or rand.bool() has_o_key = (not has_s_key) or rand.bool()
if has_o_key: if has_o_key:
root_key = orchard_key_components.ExtendedSpendingKey.master(seed) o_account_key = o_coin_key.child(hardened(account))
purpose_key = root_key.child(hardened(32)) orchard_fvk = orchard_key_components.FullViewingKey.from_spending_key(o_account_key)
coin_key = purpose_key.child(hardened(ZCASH_MAIN_COINTYPE))
account_key = coin_key.child(hardened(account))
orchard_fvk = orchard_key_components.FullViewingKey.from_spending_key(account_key)
orchard_dk = orchard_fvk.dk orchard_dk = orchard_fvk.dk
orchard_ivk = orchard_fvk.ivk() orchard_ivk = orchard_fvk.ivk()
orchard_ivk_bytes = bytes(orchard_dk) + bytes(orchard_ivk) orchard_ivk_bytes = bytes(orchard_dk) + bytes(orchard_ivk)