diff --git a/.github/workflows/test_vectors.yml b/.github/workflows/test_vectors.yml index 9352782..b1c93c1 100644 --- a/.github/workflows/test_vectors.yml +++ b/.github/workflows/test_vectors.yml @@ -11,13 +11,10 @@ jobs: kind: ['rust', 'json', 'zcash'] include: - kind: 'rust' - extension: 'rs' name: 'Rust' - kind: 'json' - extension: 'json' name: 'JSON' - kind: 'zcash' - extension: 'json' name: 'Bitcoin-flavoured JSON' fail-fast: false @@ -34,7 +31,7 @@ jobs: run: poetry install --no-root - name: Regenerate test vectors - run: ./regenerate.sh ${{ matrix.kind }} ${{ matrix.extension }} + run: ./regenerate.sh ${{ matrix.kind }} all - name: Verify there are no changes run: git diff; git ls-files --others --exclude-standard; test -z "$(git status --porcelain)" diff --git a/pyproject.toml b/pyproject.toml index a0f9359..bc787b5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -69,3 +69,4 @@ orchard_note_encryption = "zcash_test_vectors.orchard.note_encryption:main" orchard_poseidon = "zcash_test_vectors.orchard.poseidon:main" orchard_poseidon_hash = "zcash_test_vectors.orchard.poseidon:hash_test_vectors" orchard_sinsemilla = "zcash_test_vectors.orchard.sinsemilla:main" +orchard_zip32 = "zcash_test_vectors.orchard.zip32:main" diff --git a/regenerate.sh b/regenerate.sh index 2f6f923..0695b70 100755 --- a/regenerate.sh +++ b/regenerate.sh @@ -1,36 +1,80 @@ #!/usr/bin/env bash -tv_scripts=( - bip_0032 - f4jumble - f4jumble_long - orchard_empty_roots - orchard_generators - orchard_group_hash - orchard_key_components - orchard_map_to_curve - orchard_merkle_tree - orchard_note_encryption - orchard_poseidon - orchard_poseidon_hash - orchard_sinsemilla - sapling_generators - sapling_key_components - sapling_note_encryption - sapling_signatures - sapling_zip32 - sapling_zip32_hard - unified_address - unified_full_viewing_keys - unified_incoming_viewing_keys - zip_0143 - zip_0243 - zip_0244 - zip_0316 - zip_0320) +case "$1" in + "rust" ) + gen_types=(rust) + ;; + "zcash" ) + gen_types=(zcash) + ;; + "json") + gen_types=(json) + ;; + "all") + gen_types=(rust zcash json) + ;; + *) + echo "Unexpected generation type: $1" + exit 1 + ;; +esac -for generator in "${tv_scripts[@]}" +case "$2" in + "all" ) + tv_scripts=( + bip_0032 + f4jumble + f4jumble_long + orchard_empty_roots + orchard_generators + orchard_group_hash + orchard_key_components + orchard_map_to_curve + orchard_merkle_tree + orchard_note_encryption + orchard_poseidon + orchard_poseidon_hash + orchard_sinsemilla + orchard_zip32 + sapling_generators + sapling_key_components + sapling_note_encryption + sapling_signatures + sapling_zip32 + sapling_zip32_hard + unified_address + unified_full_viewing_keys + unified_incoming_viewing_keys + zip_0143 + zip_0243 + zip_0244 + zip_0316 + zip_0320) + ;; + *) + tv_scripts=($2) + ;; +esac + +for gen_type in "${gen_types[@]}" do - echo "# $generator" - poetry run $generator -t $1 >test-vectors/$1/$generator.$2 + echo "Generating $gen_type test vectors..." + case "$gen_type" in + "rust" ) + extension="rs" + ;; + "zcash" ) + extension="json" + ;; + "json") + extension="json" + ;; + esac + + for generator in "${tv_scripts[@]}" + do + echo "# $generator" + poetry run $generator -t $gen_type >test-vectors/$gen_type/$generator.$extension + done + echo "Finished $gen_type." done diff --git a/test-vectors/json/orchard_zip32.json b/test-vectors/json/orchard_zip32.json new file mode 100644 index 0000000..4f19f29 --- /dev/null +++ b/test-vectors/json/orchard_zip32.json @@ -0,0 +1,8 @@ +[ + ["From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/orchard_zip32.py"], + ["sk, c, xsk, fp"], + ["7eee3c1017870990a3dd6891b82f80be8976c1e7dc20d60817a5e88e8b2cd4b8", "ab8b7a00509ef20e469b5292b61d474b7cffcb1657924cda720250ae40526677", "000000000000000000ab8b7a00509ef20e469b5292b61d474b7cffcb1657924cda720250ae405266777eee3c1017870990a3dd6891b82f80be8976c1e7dc20d60817a5e88e8b2cd4b8", "ff4cda5002c8d182058807b84e616b6d339e1bbeecea01650568d891a438e706"], + ["98d703fcb40504c95b3b6ed10ecd50082cff97dfd1dd9aa0913c78f977c962af", "6a041dfb9cfebee97cb1854fdc481cc04f02c9577aa6f13b2c445b80a9669a22", "01ff4cda50010000806a041dfb9cfebee97cb1854fdc481cc04f02c9577aa6f13b2c445b80a9669a2298d703fcb40504c95b3b6ed10ecd50082cff97dfd1dd9aa0913c78f977c962af", "32bbdc921d066f235dc93e913b8fe1fd5b9f7f6a13d56f18ec0d3620d1f7b9a6"], + ["99afd8894baad58784d0ec08f5148ee2c2a17b2b294b08ef9e0a0cf14bcc0920", "6da8b57a36c77ad6412a9dc0115f12aced0ee01c402a0cf0a507cb17fc7bbd1d", "0232bbdc92020000806da8b57a36c77ad6412a9dc0115f12aced0ee01c402a0cf0a507cb17fc7bbd1d99afd8894baad58784d0ec08f5148ee2c2a17b2b294b08ef9e0a0cf14bcc0920", "36a57c4fc5b8b4a3d62f22a5500878f393856b7ecce771ad597ca964b98637d9"], + ["96439ea348a4b2ce4ec7beb4543c70274c8f76495d60c5fa5f018b68f3c32367", "b196e9b5809d76577a8944c3f8c8a83f93f0c8f5ace6e7bc9ce4396c034d93fe", "0336a57c4f03000080b196e9b5809d76577a8944c3f8c8a83f93f0c8f5ace6e7bc9ce4396c034d93fe96439ea348a4b2ce4ec7beb4543c70274c8f76495d60c5fa5f018b68f3c32367", "be1a1b661d2ca319822a32550d6dc488b6571e0cd781d5078b8f7ba366ddd368"] +] diff --git a/test-vectors/rust/orchard_zip32.rs b/test-vectors/rust/orchard_zip32.rs new file mode 100644 index 0000000..381c07f --- /dev/null +++ b/test-vectors/rust/orchard_zip32.rs @@ -0,0 +1,66 @@ + struct TestVector { + sk: [u8; 32], + c: [u8; 32], + xsk: [u8; 73], + fp: [u8; 32], + }; + + // From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/orchard_zip32.py + let test_vectors = vec![ + TestVector { + sk: [ + 0x7e, 0xee, 0x3c, 0x10, 0x17, 0x87, 0x09, 0x90, 0xa3, 0xdd, 0x68, 0x91, 0xb8, 0x2f, 0x80, 0xbe, 0x89, 0x76, 0xc1, 0xe7, 0xdc, 0x20, 0xd6, 0x08, 0x17, 0xa5, 0xe8, 0x8e, 0x8b, 0x2c, 0xd4, 0xb8 + ], + c: [ + 0xab, 0x8b, 0x7a, 0x00, 0x50, 0x9e, 0xf2, 0x0e, 0x46, 0x9b, 0x52, 0x92, 0xb6, 0x1d, 0x47, 0x4b, 0x7c, 0xff, 0xcb, 0x16, 0x57, 0x92, 0x4c, 0xda, 0x72, 0x02, 0x50, 0xae, 0x40, 0x52, 0x66, 0x77 + ], + xsk: [ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xab, 0x8b, 0x7a, 0x00, 0x50, 0x9e, 0xf2, 0x0e, 0x46, 0x9b, 0x52, 0x92, 0xb6, 0x1d, 0x47, 0x4b, 0x7c, 0xff, 0xcb, 0x16, 0x57, 0x92, 0x4c, 0xda, 0x72, 0x02, 0x50, 0xae, 0x40, 0x52, 0x66, 0x77, 0x7e, 0xee, 0x3c, 0x10, 0x17, 0x87, 0x09, 0x90, 0xa3, 0xdd, 0x68, 0x91, 0xb8, 0x2f, 0x80, 0xbe, 0x89, 0x76, 0xc1, 0xe7, 0xdc, 0x20, 0xd6, 0x08, 0x17, 0xa5, 0xe8, 0x8e, 0x8b, 0x2c, 0xd4, 0xb8 + ], + fp: [ + 0xff, 0x4c, 0xda, 0x50, 0x02, 0xc8, 0xd1, 0x82, 0x05, 0x88, 0x07, 0xb8, 0x4e, 0x61, 0x6b, 0x6d, 0x33, 0x9e, 0x1b, 0xbe, 0xec, 0xea, 0x01, 0x65, 0x05, 0x68, 0xd8, 0x91, 0xa4, 0x38, 0xe7, 0x06 + ], + }, + TestVector { + sk: [ + 0x98, 0xd7, 0x03, 0xfc, 0xb4, 0x05, 0x04, 0xc9, 0x5b, 0x3b, 0x6e, 0xd1, 0x0e, 0xcd, 0x50, 0x08, 0x2c, 0xff, 0x97, 0xdf, 0xd1, 0xdd, 0x9a, 0xa0, 0x91, 0x3c, 0x78, 0xf9, 0x77, 0xc9, 0x62, 0xaf + ], + c: [ + 0x6a, 0x04, 0x1d, 0xfb, 0x9c, 0xfe, 0xbe, 0xe9, 0x7c, 0xb1, 0x85, 0x4f, 0xdc, 0x48, 0x1c, 0xc0, 0x4f, 0x02, 0xc9, 0x57, 0x7a, 0xa6, 0xf1, 0x3b, 0x2c, 0x44, 0x5b, 0x80, 0xa9, 0x66, 0x9a, 0x22 + ], + xsk: [ + 0x01, 0xff, 0x4c, 0xda, 0x50, 0x01, 0x00, 0x00, 0x80, 0x6a, 0x04, 0x1d, 0xfb, 0x9c, 0xfe, 0xbe, 0xe9, 0x7c, 0xb1, 0x85, 0x4f, 0xdc, 0x48, 0x1c, 0xc0, 0x4f, 0x02, 0xc9, 0x57, 0x7a, 0xa6, 0xf1, 0x3b, 0x2c, 0x44, 0x5b, 0x80, 0xa9, 0x66, 0x9a, 0x22, 0x98, 0xd7, 0x03, 0xfc, 0xb4, 0x05, 0x04, 0xc9, 0x5b, 0x3b, 0x6e, 0xd1, 0x0e, 0xcd, 0x50, 0x08, 0x2c, 0xff, 0x97, 0xdf, 0xd1, 0xdd, 0x9a, 0xa0, 0x91, 0x3c, 0x78, 0xf9, 0x77, 0xc9, 0x62, 0xaf + ], + fp: [ + 0x32, 0xbb, 0xdc, 0x92, 0x1d, 0x06, 0x6f, 0x23, 0x5d, 0xc9, 0x3e, 0x91, 0x3b, 0x8f, 0xe1, 0xfd, 0x5b, 0x9f, 0x7f, 0x6a, 0x13, 0xd5, 0x6f, 0x18, 0xec, 0x0d, 0x36, 0x20, 0xd1, 0xf7, 0xb9, 0xa6 + ], + }, + TestVector { + sk: [ + 0x99, 0xaf, 0xd8, 0x89, 0x4b, 0xaa, 0xd5, 0x87, 0x84, 0xd0, 0xec, 0x08, 0xf5, 0x14, 0x8e, 0xe2, 0xc2, 0xa1, 0x7b, 0x2b, 0x29, 0x4b, 0x08, 0xef, 0x9e, 0x0a, 0x0c, 0xf1, 0x4b, 0xcc, 0x09, 0x20 + ], + c: [ + 0x6d, 0xa8, 0xb5, 0x7a, 0x36, 0xc7, 0x7a, 0xd6, 0x41, 0x2a, 0x9d, 0xc0, 0x11, 0x5f, 0x12, 0xac, 0xed, 0x0e, 0xe0, 0x1c, 0x40, 0x2a, 0x0c, 0xf0, 0xa5, 0x07, 0xcb, 0x17, 0xfc, 0x7b, 0xbd, 0x1d + ], + xsk: [ + 0x02, 0x32, 0xbb, 0xdc, 0x92, 0x02, 0x00, 0x00, 0x80, 0x6d, 0xa8, 0xb5, 0x7a, 0x36, 0xc7, 0x7a, 0xd6, 0x41, 0x2a, 0x9d, 0xc0, 0x11, 0x5f, 0x12, 0xac, 0xed, 0x0e, 0xe0, 0x1c, 0x40, 0x2a, 0x0c, 0xf0, 0xa5, 0x07, 0xcb, 0x17, 0xfc, 0x7b, 0xbd, 0x1d, 0x99, 0xaf, 0xd8, 0x89, 0x4b, 0xaa, 0xd5, 0x87, 0x84, 0xd0, 0xec, 0x08, 0xf5, 0x14, 0x8e, 0xe2, 0xc2, 0xa1, 0x7b, 0x2b, 0x29, 0x4b, 0x08, 0xef, 0x9e, 0x0a, 0x0c, 0xf1, 0x4b, 0xcc, 0x09, 0x20 + ], + fp: [ + 0x36, 0xa5, 0x7c, 0x4f, 0xc5, 0xb8, 0xb4, 0xa3, 0xd6, 0x2f, 0x22, 0xa5, 0x50, 0x08, 0x78, 0xf3, 0x93, 0x85, 0x6b, 0x7e, 0xcc, 0xe7, 0x71, 0xad, 0x59, 0x7c, 0xa9, 0x64, 0xb9, 0x86, 0x37, 0xd9 + ], + }, + TestVector { + sk: [ + 0x96, 0x43, 0x9e, 0xa3, 0x48, 0xa4, 0xb2, 0xce, 0x4e, 0xc7, 0xbe, 0xb4, 0x54, 0x3c, 0x70, 0x27, 0x4c, 0x8f, 0x76, 0x49, 0x5d, 0x60, 0xc5, 0xfa, 0x5f, 0x01, 0x8b, 0x68, 0xf3, 0xc3, 0x23, 0x67 + ], + c: [ + 0xb1, 0x96, 0xe9, 0xb5, 0x80, 0x9d, 0x76, 0x57, 0x7a, 0x89, 0x44, 0xc3, 0xf8, 0xc8, 0xa8, 0x3f, 0x93, 0xf0, 0xc8, 0xf5, 0xac, 0xe6, 0xe7, 0xbc, 0x9c, 0xe4, 0x39, 0x6c, 0x03, 0x4d, 0x93, 0xfe + ], + xsk: [ + 0x03, 0x36, 0xa5, 0x7c, 0x4f, 0x03, 0x00, 0x00, 0x80, 0xb1, 0x96, 0xe9, 0xb5, 0x80, 0x9d, 0x76, 0x57, 0x7a, 0x89, 0x44, 0xc3, 0xf8, 0xc8, 0xa8, 0x3f, 0x93, 0xf0, 0xc8, 0xf5, 0xac, 0xe6, 0xe7, 0xbc, 0x9c, 0xe4, 0x39, 0x6c, 0x03, 0x4d, 0x93, 0xfe, 0x96, 0x43, 0x9e, 0xa3, 0x48, 0xa4, 0xb2, 0xce, 0x4e, 0xc7, 0xbe, 0xb4, 0x54, 0x3c, 0x70, 0x27, 0x4c, 0x8f, 0x76, 0x49, 0x5d, 0x60, 0xc5, 0xfa, 0x5f, 0x01, 0x8b, 0x68, 0xf3, 0xc3, 0x23, 0x67 + ], + fp: [ + 0xbe, 0x1a, 0x1b, 0x66, 0x1d, 0x2c, 0xa3, 0x19, 0x82, 0x2a, 0x32, 0x55, 0x0d, 0x6d, 0xc4, 0x88, 0xb6, 0x57, 0x1e, 0x0c, 0xd7, 0x81, 0xd5, 0x07, 0x8b, 0x8f, 0x7b, 0xa3, 0x66, 0xdd, 0xd3, 0x68 + ], + }, + ]; diff --git a/test-vectors/zcash/orchard_zip32.json b/test-vectors/zcash/orchard_zip32.json new file mode 100644 index 0000000..1d8cfd9 --- /dev/null +++ b/test-vectors/zcash/orchard_zip32.json @@ -0,0 +1,8 @@ +[ + ["From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/orchard_zip32.py"], + ["sk, c, xsk, fp"], + ["b8d42c8b8ee8a51708d620dce7c17689be802fb89168dda390098717103cee7e", "77665240ae500272da4c925716cbff7c4b471db692529b460ef29e50007a8bab", "000000000000000000ab8b7a00509ef20e469b5292b61d474b7cffcb1657924cda720250ae405266777eee3c1017870990a3dd6891b82f80be8976c1e7dc20d60817a5e88e8b2cd4b8", "06e738a491d868056501eaecbe1b9e336d6b614eb807880582d1c80250da4cff"], + ["af62c977f9783c91a09addd1df97ff2c0850cd0ed16e3b5bc90405b4fc03d798", "229a66a9805b442c3bf1a67a57c9024fc01c48dc4f85b17ce9befe9cfb1d046a", "01ff4cda50010000806a041dfb9cfebee97cb1854fdc481cc04f02c9577aa6f13b2c445b80a9669a2298d703fcb40504c95b3b6ed10ecd50082cff97dfd1dd9aa0913c78f977c962af", "a6b9f7d120360dec186fd5136a7f9f5bfde18f3b913ec95d236f061d92dcbb32"], + ["2009cc4bf10c0a9eef084b292b7ba1c2e28e14f508ecd08487d5aa4b89d8af99", "1dbd7bfc17cb07a5f00c2a401ce00eedac125f11c09d2a41d67ac7367ab5a86d", "0232bbdc92020000806da8b57a36c77ad6412a9dc0115f12aced0ee01c402a0cf0a507cb17fc7bbd1d99afd8894baad58784d0ec08f5148ee2c2a17b2b294b08ef9e0a0cf14bcc0920", "d93786b964a97c59ad71e7cc7e6b8593f3780850a5222fd6a3b4b8c54f7ca536"], + ["6723c3f3688b015ffac5605d49768f4c27703c54b4bec74eceb2a448a39e4396", "fe934d036c39e49cbce7e6acf5c8f0933fa8c8f8c344897a57769d80b5e996b1", "0336a57c4f03000080b196e9b5809d76577a8944c3f8c8a83f93f0c8f5ace6e7bc9ce4396c034d93fe96439ea348a4b2ce4ec7beb4543c70274c8f76495d60c5fa5f018b68f3c32367", "68d3dd66a37b8f8b07d581d70c1e57b688c46d0d55322a8219a32c1d661b1abe"] +] diff --git a/zcash_test_vectors/orchard/zip32.py b/zcash_test_vectors/orchard/zip32.py new file mode 100755 index 0000000..f9c6a60 --- /dev/null +++ b/zcash_test_vectors/orchard/zip32.py @@ -0,0 +1,101 @@ +#!/usr/bin/env python3 +import sys; assert sys.version_info[0] >= 3, "Python 3 required." + +from hashlib import blake2b + +from .key_components import FullViewingKey, ExtendedSpendingKey + +from ..hd_common import hardened +from ..utils import i2leosp +from ..output import render_args, render_tv + + +class DerivedSpendingKey(object): + def __init__(self, extsk, depth=0, parent_tag=i2leosp(32, 0), i=0): + self._extsk = extsk + self._depth = depth + self._parent_tag = parent_tag + self._i = i + + def __eq__(self, other): + return (self._extsk == other._extsk and + self._depth == other._depth and + self._parent_tag == other._parent_tag and + self._i == other._i) + + @classmethod + def master(cls, S): + return cls(ExtendedSpendingKey.master(S)) + + def sk(self): + return self._extsk.data + + def c(self): + return self._extsk.chaincode + + def depth(self): + return self._depth + + def parent_tag(self): + return self._parent_tag + + def i(self): + return self._i + + def fingerprint(self): + fvk = FullViewingKey.from_spending_key(self._extsk) + digest = blake2b(person=b'ZcashOrchardFVFP', digest_size=32) + digest.update(bytes(fvk.ak) + bytes(fvk.nk) + bytes(fvk.rivk)) + return digest.digest() + + def tag(self): + return self.fingerprint()[:4] + + def __bytes__(self): + return (i2leosp(8, self.depth()) + + self.parent_tag() + + i2leosp(32, self.i()) + + self.c() + + self.sk()) + + def child(self, i): + return self.__class__(self._extsk.child(i), self.depth()+1, self.tag(), i) + + +def main(): + args = render_args() + + seed = bytes(range(32)) + m = DerivedSpendingKey.master(seed) + m_1h = m.child(hardened(1)) + m_1h_2h = m_1h.child(hardened(2)) + m_1h_2h_3h = m_1h_2h.child(hardened(3)) + + keys = [m, m_1h, m_1h_2h, m_1h_2h_3h] + + render_tvs(args, keys) + +def render_tvs(args, keys): + test_vectors = [ + {'sk' : k.sk(), + 'c' : k.c(), + 'xsk' : bytes(k), + 'fp' : k.fingerprint(), + } + for k in keys + ] + + render_tv( + args, + 'orchard_zip32', + ( + ('sk', '[u8; 32]'), + ('c', '[u8; 32]'), + ('xsk', '[u8; 73]'), + ('fp', '[u8; 32]'), + ), + test_vectors, + ) + +if __name__ == '__main__': + main()