rust: Migrate to `zcash_primitives 0.14.0`

This commit is contained in:
Jack Grigg 2024-03-01 19:45:44 +00:00 committed by Sean Bowe
parent 2112e467ee
commit fd675c3205
60 changed files with 966 additions and 999 deletions

View File

@ -17,7 +17,7 @@ jobs:
- uses: dtolnay/rust-toolchain@stable
id: toolchain
- run: rustup override set ${{steps.toolchain.outputs.name}}
- run: cargo install cargo-vet --version ~0.8
- run: cargo install cargo-vet --version ~0.9
- run: cargo vet --locked
cargo-deny:

228
Cargo.lock generated
View File

@ -265,12 +265,6 @@ version = "3.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec"
[[package]]
name = "byte-slice-cast"
version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c"
[[package]]
name = "byteorder"
version = "1.5.0"
@ -540,6 +534,15 @@ dependencies = [
"winapi",
]
[[package]]
name = "document-features"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef5282ad69563b5fc40319526ba27e0e7363d552a896f0297d54f767717f9b95"
dependencies = [
"litrs",
]
[[package]]
name = "ed25519"
version = "2.2.3"
@ -583,12 +586,6 @@ dependencies = [
"byteorder",
]
[[package]]
name = "equivalent"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]]
name = "errno"
version = "0.3.8"
@ -633,13 +630,10 @@ checksum = "27573eac26f4dd11e2b1916c3fe1baa56407c83c71a773a8ba17ec0bca03b6b7"
[[package]]
name = "fixed-hash"
version = "0.7.0"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfcf0ed7fe52a17a03854ec54a9f76d6d84508d1c0e66bc1793301c73fc8493c"
checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534"
dependencies = [
"byteorder",
"rand",
"rustc-hex",
"static_assertions",
]
@ -926,26 +920,6 @@ dependencies = [
"want",
]
[[package]]
name = "impl-codec"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f"
dependencies = [
"parity-scale-codec",
]
[[package]]
name = "impl-trait-for-tuples"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "incrementalmerkletree"
version = "0.5.0"
@ -966,16 +940,6 @@ dependencies = [
"hashbrown 0.12.3",
]
[[package]]
name = "indexmap"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
dependencies = [
"equivalent",
"hashbrown 0.14.3",
]
[[package]]
name = "inout"
version = "0.1.3"
@ -1098,6 +1062,8 @@ dependencies = [
"rand",
"rand_core",
"rayon",
"redjubjub",
"sapling-crypto",
"secp256k1",
"secrecy",
"serde",
@ -1137,6 +1103,12 @@ version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456"
[[package]]
name = "litrs"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5"
[[package]]
name = "log"
version = "0.4.20"
@ -1205,7 +1177,7 @@ checksum = "1d4fa7ce7c4862db464a37b0b31d89bca874562f034bd7993895572783d02950"
dependencies = [
"base64",
"hyper",
"indexmap 1.9.3",
"indexmap",
"ipnet",
"metrics",
"metrics-util",
@ -1369,9 +1341,9 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
[[package]]
name = "orchard"
version = "0.6.0"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d31e68534df32024dcc89a8390ec6d7bef65edd87d91b45cfb481a2eb2d77c5"
checksum = "1fb255c3ffdccd3c84fe9ebed72aef64fdc72e6a3e4180dd411002d47abaad42"
dependencies = [
"aes",
"bitvec",
@ -1394,6 +1366,8 @@ dependencies = [
"subtle",
"tracing",
"zcash_note_encryption",
"zcash_spec",
"zip32",
]
[[package]]
@ -1411,32 +1385,6 @@ dependencies = [
"group",
]
[[package]]
name = "parity-scale-codec"
version = "3.6.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "881331e34fa842a2fb61cc2db9643a8fedc615e47cfcc52597d1af0db9a7e8fe"
dependencies = [
"arrayvec",
"bitvec",
"byte-slice-cast",
"impl-trait-for-tuples",
"parity-scale-codec-derive",
"serde",
]
[[package]]
name = "parity-scale-codec-derive"
version = "3.6.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be30eaf4b0a9fba5336683b38de57bb86d179a35862ba6bfcf57625d006bde5b"
dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "password-hash"
version = "0.3.2"
@ -1570,25 +1518,14 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "primitive-types"
version = "0.11.1"
version = "0.12.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e28720988bff275df1f51b171e1b2a18c30d194c4d2b61defdacecd625a5d94a"
checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2"
dependencies = [
"fixed-hash",
"impl-codec",
"uint",
]
[[package]]
name = "proc-macro-crate"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97dc5fea232fc28d2f597b37c4876b348a40e33f3b02cc975c8d006d78d94b1a"
dependencies = [
"toml_datetime",
"toml_edit",
]
[[package]]
name = "proc-macro2"
version = "1.0.74"
@ -1848,12 +1785,6 @@ version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
[[package]]
name = "rustc-hex"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6"
[[package]]
name = "rustc_version"
version = "0.4.0"
@ -1894,6 +1825,39 @@ version = "1.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c"
[[package]]
name = "sapling-crypto"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d183012062dfdde85f7e3e758328fcf6e9846d8dd3fce35b04d0efcb6677b0e0"
dependencies = [
"aes",
"bellman",
"bitvec",
"blake2b_simd",
"blake2s_simd",
"bls12_381",
"byteorder",
"document-features",
"ff",
"fpe",
"group",
"hex",
"incrementalmerkletree",
"jubjub",
"lazy_static",
"memuse",
"proptest",
"rand",
"rand_core",
"redjubjub",
"subtle",
"tracing",
"zcash_note_encryption",
"zcash_spec",
"zip32",
]
[[package]]
name = "secp256k1"
version = "0.26.0"
@ -2179,23 +2143,6 @@ dependencies = [
"windows-sys 0.48.0",
]
[[package]]
name = "toml_datetime"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b"
[[package]]
name = "toml_edit"
version = "0.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338"
dependencies = [
"indexmap 2.1.0",
"toml_datetime",
"winnow",
]
[[package]]
name = "tower-service"
version = "0.3.2"
@ -2640,15 +2587,6 @@ version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
[[package]]
name = "winnow"
version = "0.5.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97a4882e6b134d6c28953a387571f1acdd3496830d5e36c5e3a1075580ea641c"
dependencies = [
"memchr",
]
[[package]]
name = "wyz"
version = "0.5.1"
@ -2666,9 +2604,9 @@ checksum = "213b7324336b53d2414b2db8537e56544d981803139155afa84f76eeebb7a546"
[[package]]
name = "zcash_address"
version = "0.3.0"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8944af5c206cf2e37020ad54618e1825501b98548d35a638b73e0ec5762df8d5"
checksum = "bce173f1d9ed4f806e310bc3a873301531e7a6dc209928584d6404e3f8228ef4"
dependencies = [
"bech32",
"bs58",
@ -2688,9 +2626,9 @@ dependencies = [
[[package]]
name = "zcash_history"
version = "0.3.0"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb611a28a4e13ac715ee712f4344d6b279b767daf6345dafefb2c4bf582b6679"
checksum = "2fde17bf53792f9c756b313730da14880257d7661b5bfc69d0571c3a7c11a76d"
dependencies = [
"blake2b_simd",
"byteorder",
@ -2712,17 +2650,15 @@ dependencies = [
[[package]]
name = "zcash_primitives"
version = "0.13.0"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d17e4c94ca8d69d2fcf2be97522da5732a580eb2125cda3b150761952f8df8e6"
checksum = "9070e084570bb78aed4f8d71fd6254492e62c87a5d01e084183980e98117092d"
dependencies = [
"aes",
"bip0039",
"bitvec",
"blake2b_simd",
"blake2s_simd",
"bls12_381",
"byteorder",
"document-features",
"equihash",
"ff",
"fpe",
@ -2731,31 +2667,36 @@ dependencies = [
"hex",
"incrementalmerkletree",
"jubjub",
"lazy_static",
"memuse",
"nonempty",
"orchard",
"proptest",
"rand",
"rand_core",
"redjubjub",
"ripemd",
"sapling-crypto",
"secp256k1",
"sha2",
"subtle",
"tracing",
"zcash_address",
"zcash_encoding",
"zcash_note_encryption",
"zcash_spec",
"zip32",
]
[[package]]
name = "zcash_proofs"
version = "0.13.0"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df0c99f65a840ff256c106b28d67d702d9759d206112473d4982c92003262406"
checksum = "b8a02eb1f151d9b9a6e16408d2c55ff440bd2fb232b7377277146d0fa2df9bc8"
dependencies = [
"bellman",
"blake2b_simd",
"bls12_381",
"document-features",
"group",
"home",
"jubjub",
@ -2763,11 +2704,21 @@ dependencies = [
"lazy_static",
"rand_core",
"redjubjub",
"sapling-crypto",
"tracing",
"xdg",
"zcash_primitives",
]
[[package]]
name = "zcash_spec"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7a3bf58b673cb3dacd8ae09ba345998923a197ab0da70d6239d8e8838949e9b"
dependencies = [
"blake2b_simd",
]
[[package]]
name = "zerocopy"
version = "0.7.32"
@ -2807,3 +2758,14 @@ dependencies = [
"quote",
"syn 2.0.46",
]
[[package]]
name = "zip32"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d724a63be4dfb50b7f3617e542984e22e4b4a5b8ca5de91f55613152885e6b22"
dependencies = [
"blake2b_simd",
"memuse",
"subtle",
]

View File

@ -52,19 +52,21 @@ libc = "0.2"
jubjub = "0.10"
memuse = "0.2"
nonempty = "0.7"
orchard = "0.6"
orchard = "0.7"
sapling = { package = "sapling-crypto", version = "0.1", features = ["temporary-zcashd"] }
secp256k1 = "0.26"
subtle = "2.2"
rand_core = "0.6"
redjubjub = "0.7"
tracing = "0.1"
tracing-core = "0.1"
tracing-appender = "0.2"
zcash_address = "0.3"
zcash_encoding = "0.2"
zcash_history = "0.3"
zcash_history = "0.4"
zcash_note_encryption = "0.4"
zcash_primitives = { version = "0.13", features = ["temporary-zcashd", "transparent-inputs"] }
zcash_proofs = { version = "0.13", features = ["directories"] }
zcash_primitives = { version = "0.14", features = ["temporary-zcashd", "transparent-inputs"] }
zcash_proofs = { version = "0.14", features = ["directories"] }
ed25519-zebra = "4"
zeroize = "1.4.2"
wagyu-zcash-parameters = "0.2"
@ -109,7 +111,7 @@ time = { version = "0.3", features = ["formatting", "macros"] }
[dev-dependencies]
incrementalmerkletree = { version = "0.5", features = ["test-dependencies"] }
proptest = "1.0.0"
zcash_primitives = { version = "0.13", features = ["temporary-zcashd", "transparent-inputs", "test-dependencies"] }
zcash_primitives = { version = "0.14", features = ["temporary-zcashd", "transparent-inputs", "test-dependencies"] }
[dependencies.tracing-subscriber]
version = "0.3"

View File

@ -237,7 +237,7 @@ class FinalOrchardRootTest(BitcoinTestFramework):
assert new_treestate["sapling"]["commitments"]["finalRoot"] != treestate["sapling"]["commitments"]["finalRoot"]
assert new_treestate["sapling"]["commitments"]["finalState"] != treestate["sapling"]["commitments"]["finalState"]
assert_equal(len(new_treestate["sapling"]["commitments"]["finalRoot"]), 64)
assert_equal(len(new_treestate["sapling"]["commitments"]["finalState"]), 70)
assert_equal(len(new_treestate["sapling"]["commitments"]["finalState"]), 134)
treestate = new_treestate
# Mine a block with an Orchard shielded recipient and verify the final Orchard root changes

View File

@ -122,8 +122,8 @@ class FinalSaplingRootTest(BitcoinTestFramework):
# Verify there is a Sapling output description (its commitment was added to tree)
result = self.nodes[0].getrawtransaction(mytxid, 1)
assert_equal(len(result["vShieldedOutput"]), 1)
assert_equal(blk["trees"]["sapling"]["size"], 1)
assert_equal(len(result["vShieldedOutput"]), 2) # Non-coinbase bundles are padded
assert_equal(blk["trees"]["sapling"]["size"], 2)
# Since there is a now sapling shielded input in the blockchain,
# the sapling values should have changed
@ -133,7 +133,7 @@ class FinalSaplingRootTest(BitcoinTestFramework):
assert new_treestate["sapling"]["commitments"]["finalRoot"] != treestate["sapling"]["commitments"]["finalRoot"]
assert new_treestate["sapling"]["commitments"]["finalState"] != treestate["sapling"]["commitments"]["finalState"]
assert_equal(len(new_treestate["sapling"]["commitments"]["finalRoot"]), 64)
assert_equal(len(new_treestate["sapling"]["commitments"]["finalState"]), 70)
assert_equal(len(new_treestate["sapling"]["commitments"]["finalState"]), 134)
treestate = new_treestate
# Mine an empty block and verify the final Sapling root does not change
@ -142,7 +142,7 @@ class FinalSaplingRootTest(BitcoinTestFramework):
self.sync_all()
blk = self.nodes[0].getblock("202")
assert_equal(root, blk["finalsaplingroot"])
assert_equal(blk["trees"]["sapling"]["size"], 1)
assert_equal(blk["trees"]["sapling"]["size"], 2)
# Mine a block with a transparent tx and verify the final Sapling root does not change
taddr1 = self.nodes[1].getnewaddress()
@ -171,7 +171,7 @@ class FinalSaplingRootTest(BitcoinTestFramework):
assert_equal(len(blk["tx"]), 2)
assert_equal(self.nodes[0].z_getbalance(zaddr0), Decimal("37.66"))
assert_equal(root, blk["finalsaplingroot"])
assert_equal(blk["trees"]["sapling"]["size"], 1)
assert_equal(blk["trees"]["sapling"]["size"], 2)
new_treestate = self.nodes[0].z_gettreestate(str(-1))
assert_equal(new_treestate["sapling"]["commitments"]["finalRoot"], root)
@ -200,14 +200,14 @@ class FinalSaplingRootTest(BitcoinTestFramework):
# Verify there is a Sapling output description (its commitment was added to tree)
result = self.nodes[0].getrawtransaction(mytxid, 1)
assert_equal(len(result["vShieldedOutput"]), 2) # there is Sapling shielded change
assert_equal(blk["trees"]["sapling"]["size"], 3)
assert_equal(blk["trees"]["sapling"]["size"], 4)
new_treestate = self.nodes[0].z_gettreestate(str(-1))
assert_equal(new_treestate["sprout"], treestate["sprout"])
assert new_treestate["sapling"]["commitments"]["finalRoot"] != treestate["sapling"]["commitments"]["finalRoot"]
assert new_treestate["sapling"]["commitments"]["finalState"] != treestate["sapling"]["commitments"]["finalState"]
assert_equal(len(new_treestate["sapling"]["commitments"]["finalRoot"]), 64)
assert_equal(len(new_treestate["sapling"]["commitments"]["finalState"]), 136)
assert_equal(len(new_treestate["sapling"]["commitments"]["finalState"]), 200)
treestate = new_treestate
# Mine a block with a Sapling shielded sender and transparent recipient.
@ -221,16 +221,19 @@ class FinalSaplingRootTest(BitcoinTestFramework):
self.nodes[0].generate(1)
self.sync_all()
assert_equal(len(self.nodes[0].getblock("206")["tx"]), 2)
blk = self.nodes[0].getblock("206")
assert_equal(len(blk["tx"]), 2)
assert_equal(mytxid, blk["tx"][1])
assert_equal(self.nodes[0].z_getbalance(taddr2), Decimal("2.34"))
assert_equal(self.nodes[1].z_getbalance(saplingAddr1), 0)
# Verify the final Sapling root changes (because the Sapling bundle was padded
# with 2 dummy outputs).
blk = self.nodes[0].getblock("206")
print(self.nodes[0].getrawtransaction(blk["tx"][0]))
print(self.nodes[0].getrawtransaction(blk["tx"][1]))
root = blk["finalsaplingroot"]
assert root != self.nodes[0].getblock("205")["finalsaplingroot"]
assert_equal(blk["trees"]["sapling"]["size"], 5)
assert_equal(blk["trees"]["sapling"]["size"], 6)
# Verify there are two Sapling output descriptions.
result = self.nodes[0].getrawtransaction(mytxid, 1)
@ -241,7 +244,7 @@ class FinalSaplingRootTest(BitcoinTestFramework):
assert new_treestate["sapling"]["commitments"]["finalRoot"] != treestate["sapling"]["commitments"]["finalRoot"]
assert new_treestate["sapling"]["commitments"]["finalState"] != treestate["sapling"]["commitments"]["finalState"]
assert_equal(len(new_treestate["sapling"]["commitments"]["finalRoot"]), 64)
assert_equal(len(new_treestate["sapling"]["commitments"]["finalState"]), 138)
assert_equal(len(new_treestate["sapling"]["commitments"]["finalState"]), 202)
treestate = new_treestate
# Activate NU5; more testing should be added once we can mine orchard transactions.

View File

@ -2634,6 +2634,12 @@ user-id = 1244 # ebfull
start = "2022-10-19"
end = "2024-09-21"
[[trusted.sapling-crypto]]
criteria = ["safe-to-deploy", "crypto-reviewed", "license-reviewed"]
user-id = 6289 # str4d
start = "2024-01-26"
end = "2025-03-18"
[[trusted.windows-sys]]
criteria = "safe-to-deploy"
user-id = 64539 # Kenny Kerr (kennykerr)
@ -2694,6 +2700,12 @@ user-id = 1244 # ebfull
start = "2022-10-19"
end = "2024-09-21"
[[trusted.zcash_address]]
criteria = "safe-to-deploy"
user-id = 6289 # str4d
start = "2021-03-07"
end = "2025-03-18"
[[trusted.zcash_encoding]]
criteria = "safe-to-deploy"
user-id = 1244 # ebfull
@ -2706,6 +2718,12 @@ user-id = 1244 # ebfull
start = "2020-03-04"
end = "2024-09-21"
[[trusted.zcash_history]]
criteria = "safe-to-deploy"
user-id = 6289 # str4d
start = "2024-03-01"
end = "2025-03-18"
[[trusted.zcash_note_encryption]]
criteria = ["safe-to-deploy", "crypto-reviewed"]
user-id = 169181 # Kris Nuttycombe (nuttycom)
@ -2729,3 +2747,15 @@ criteria = ["safe-to-deploy", "crypto-reviewed", "license-reviewed"]
user-id = 6289 # str4d
start = "2021-03-26"
end = "2024-09-21"
[[trusted.zcash_spec]]
criteria = ["safe-to-deploy", "crypto-reviewed", "license-reviewed"]
user-id = 6289 # str4d
start = "2023-12-07"
end = "2025-03-18"
[[trusted.zip32]]
criteria = "safe-to-deploy"
user-id = 6289 # str4d
start = "2023-12-06"
end = "2025-03-18"

View File

@ -2,7 +2,7 @@
# cargo-vet config file
[cargo-vet]
version = "0.8"
version = "0.9"
[imports.bytecode-alliance]
url = "https://raw.githubusercontent.com/bytecodealliance/wasmtime/main/supply-chain/audits.toml"
@ -91,10 +91,6 @@ criteria = "safe-to-deploy"
version = "0.5.0"
criteria = "safe-to-deploy"
[[exemptions.byte-slice-cast]]
version = "1.2.1"
criteria = "safe-to-deploy"
[[exemptions.byteorder]]
version = "1.4.3"
criteria = "safe-to-deploy"
@ -195,16 +191,12 @@ criteria = "safe-to-deploy"
version = "3.0.0"
criteria = "safe-to-deploy"
[[exemptions.equivalent]]
version = "1.0.0"
criteria = "safe-to-deploy"
[[exemptions.ff]]
version = "0.12.0"
criteria = "safe-to-deploy"
[[exemptions.fixed-hash]]
version = "0.7.0"
version = "0.8.0"
criteria = "safe-to-deploy"
[[exemptions.fpe]]
@ -279,22 +271,10 @@ criteria = "safe-to-deploy"
version = "0.14.25"
criteria = "safe-to-deploy"
[[exemptions.impl-codec]]
version = "0.6.0"
criteria = "safe-to-deploy"
[[exemptions.impl-trait-for-tuples]]
version = "0.2.2"
criteria = "safe-to-deploy"
[[exemptions.indexmap]]
version = "1.8.1"
criteria = "safe-to-deploy"
[[exemptions.indexmap]]
version = "2.0.0"
criteria = "safe-to-deploy"
[[exemptions.ipnet]]
version = "2.5.0"
criteria = "safe-to-deploy"
@ -363,10 +343,6 @@ criteria = "safe-to-deploy"
version = "0.26.1"
criteria = "safe-to-deploy"
[[exemptions.nom]]
version = "7.1.1"
criteria = "safe-to-deploy"
[[exemptions.nonempty]]
version = "0.7.0"
criteria = "safe-to-deploy"
@ -387,14 +363,6 @@ criteria = "safe-to-deploy"
version = "0.22.0"
criteria = "safe-to-deploy"
[[exemptions.parity-scale-codec]]
version = "3.6.1"
criteria = "safe-to-deploy"
[[exemptions.parity-scale-codec-derive]]
version = "3.6.5"
criteria = "safe-to-deploy"
[[exemptions.password-hash]]
version = "0.3.2"
criteria = "safe-to-deploy"
@ -444,11 +412,7 @@ version = "0.2.16"
criteria = "safe-to-deploy"
[[exemptions.primitive-types]]
version = "0.11.1"
criteria = "safe-to-deploy"
[[exemptions.proc-macro-crate]]
version = "1.2.1"
version = "0.12.2"
criteria = "safe-to-deploy"
[[exemptions.proptest]]
@ -515,10 +479,6 @@ criteria = "safe-to-deploy"
version = "0.1.3"
criteria = "safe-to-deploy"
[[exemptions.rustc-hex]]
version = "2.1.0"
criteria = "safe-to-deploy"
[[exemptions.rustix]]
version = "0.38.28"
criteria = "safe-to-deploy"
@ -579,10 +539,6 @@ criteria = "safe-to-deploy"
version = "0.7.3"
criteria = "safe-to-deploy"
[[exemptions.static_assertions]]
version = "1.1.0"
criteria = "safe-to-deploy"
[[exemptions.subtle]]
version = "2.4.1"
criteria = "safe-to-deploy"
@ -611,10 +567,6 @@ criteria = "safe-to-deploy"
version = "1.35.0"
criteria = "safe-to-deploy"
[[exemptions.toml_edit]]
version = "0.19.15"
criteria = "safe-to-deploy"
[[exemptions.tower-service]]
version = "0.3.2"
criteria = "safe-to-deploy"
@ -691,10 +643,6 @@ criteria = "safe-to-deploy"
version = "0.4.0"
criteria = "safe-to-deploy"
[[exemptions.winnow]]
version = "0.5.31"
criteria = "safe-to-deploy"
[[exemptions.wyz]]
version = "0.5.0"
criteria = "safe-to-deploy"

View File

@ -52,8 +52,14 @@ user-id = 6289
user-login = "str4d"
[[publisher.orchard]]
version = "0.6.0"
when = "2023-09-08"
version = "0.7.1"
when = "2024-02-29"
user-id = 6289
user-login = "str4d"
[[publisher.sapling-crypto]]
version = "0.1.1"
when = "2024-02-15"
user-id = 6289
user-login = "str4d"
@ -184,10 +190,10 @@ user-login = "kennykerr"
user-name = "Kenny Kerr"
[[publisher.zcash_address]]
version = "0.3.0"
when = "2023-06-06"
user-id = 1244
user-login = "ebfull"
version = "0.3.1"
when = "2024-01-12"
user-id = 6289
user-login = "str4d"
[[publisher.zcash_encoding]]
version = "0.2.0"
@ -196,10 +202,10 @@ user-id = 1244
user-login = "ebfull"
[[publisher.zcash_history]]
version = "0.3.0"
when = "2022-05-11"
user-id = 1244
user-login = "ebfull"
version = "0.4.0"
when = "2024-03-01"
user-id = 6289
user-login = "str4d"
[[publisher.zcash_note_encryption]]
version = "0.4.0"
@ -209,14 +215,26 @@ user-login = "nuttycom"
user-name = "Kris Nuttycombe"
[[publisher.zcash_primitives]]
version = "0.13.0"
when = "2023-09-25"
version = "0.14.0"
when = "2024-03-01"
user-id = 6289
user-login = "str4d"
[[publisher.zcash_proofs]]
version = "0.13.0"
when = "2023-09-25"
version = "0.14.0"
when = "2024-03-01"
user-id = 6289
user-login = "str4d"
[[publisher.zcash_spec]]
version = "0.1.0"
when = "2023-12-07"
user-id = 6289
user-login = "str4d"
[[publisher.zip32]]
version = "0.1.0"
when = "2023-12-06"
user-id = 6289
user-login = "str4d"
@ -466,6 +484,12 @@ criteria = "safe-to-deploy"
version = "0.1.4"
notes = "I always really enjoy reading eliza's code, she left perfect comments at every use of unsafe."
[[audits.bytecode-alliance.audits.static_assertions]]
who = "Andrew Brown <andrew.brown@intel.com>"
criteria = "safe-to-deploy"
version = "1.1.0"
notes = "No dependencies and completely a compile-time crate as advertised. Uses `unsafe` in one module as a compile-time check only: `mem::transmute` and `ptr::write` are wrapped in an impossible-to-run closure."
[[audits.bytecode-alliance.audits.tempfile]]
who = "Pat Hickey <phickey@fastly.com>"
criteria = "safe-to-deploy"
@ -553,12 +577,6 @@ criteria = "safe-to-deploy"
version = "1.0.40"
notes = "Found no unsafe or ambient capabilities used"
[[audits.embark-studios.audits.toml_datetime]]
who = "Johan Andersson <opensource@embark-studios.com>"
criteria = "safe-to-deploy"
delta = "0.6.1 -> 0.6.2"
notes = "No notable changes"
[[audits.embark-studios.audits.valuable]]
who = "Johan Andersson <opensource@embark-studios.com>"
criteria = "safe-to-deploy"
@ -597,6 +615,15 @@ are made about the safety of either of those libraries. :)
"""
aggregated-from = "https://chromium.googlesource.com/chromiumos/third_party/rust_crates/+/refs/heads/main/cargo-vet/audits.toml?format=TEXT"
[[audits.google.audits.nom]]
who = "danakj@chromium.org"
criteria = "safe-to-deploy"
version = "7.1.3"
notes = """
Reviewed in https://chromium-review.googlesource.com/c/chromium/src/+/5046153
"""
aggregated-from = "https://chromium.googlesource.com/chromium/src/+/main/third_party/rust/chromium_crates_io/supply-chain/audits.toml?format=TEXT"
[[audits.google.audits.pin-project-lite]]
who = "David Koloski <dkoloski@google.com>"
criteria = "safe-to-deploy"
@ -1034,6 +1061,12 @@ criteria = "safe-to-deploy"
delta = "0.10.3 -> 0.10.6"
aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml"
[[audits.mozilla.audits.document-features]]
who = "Erich Gubler <erichdongubler@gmail.com>"
criteria = "safe-to-deploy"
version = "0.2.8"
aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml"
[[audits.mozilla.audits.either]]
who = "Mike Hommey <mh+mozilla@glandium.org>"
criteria = "safe-to-deploy"
@ -1109,6 +1142,12 @@ version = "1.4.0"
notes = "I have read over the macros, and audited the unsafe code."
aggregated-from = "https://raw.githubusercontent.com/mozilla/cargo-vet/main/supply-chain/audits.toml"
[[audits.mozilla.audits.litrs]]
who = "Erich Gubler <erichdongubler@gmail.com>"
criteria = "safe-to-deploy"
version = "0.4.1"
aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml"
[[audits.mozilla.audits.log]]
who = "Mike Hommey <mh+mozilla@glandium.org>"
criteria = "safe-to-deploy"
@ -1128,12 +1167,6 @@ criteria = "safe-to-deploy"
version = "0.4.1"
aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml"
[[audits.mozilla.audits.nom]]
who = "Mike Hommey <mh+mozilla@glandium.org>"
criteria = "safe-to-deploy"
delta = "7.1.1 -> 7.1.3"
aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml"
[[audits.mozilla.audits.num-bigint]]
who = "Josh Stone <jistone@redhat.com>"
criteria = "safe-to-deploy"

View File

@ -325,6 +325,8 @@ TEST(ChecktransactionTests, BadTxnsTxouttotalToolargeOutputs) {
CheckTransactionWithoutProofVerification(tx, state);
}
// TODO: The new Sapling bundle API prevents us from constructing this case.
/*
TEST(ChecktransactionTests, ValueBalanceNonZero) {
CMutableTransaction mtx = GetValidTransaction(NetworkUpgradeInfo[Consensus::UPGRADE_SAPLING].nBranchId);
mtx.saplingBundle = sapling::test_only_invalid_bundle(0, 0, 10);
@ -333,8 +335,9 @@ TEST(ChecktransactionTests, ValueBalanceNonZero) {
MockCValidationState state;
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-valuebalance-nonzero", false, "")).Times(1);
CheckTransactionWithoutProofVerification(tx, state);
EXPECT_FALSE(CheckTransactionWithoutProofVerification(tx, state));
}
*/
TEST(ChecktransactionTests, ValueBalanceOverflowsTotal) {
CMutableTransaction mtx = GetValidTransaction(NetworkUpgradeInfo[Consensus::UPGRADE_SAPLING].nBranchId);
@ -1152,7 +1155,8 @@ TEST(ChecktransactionTests, HeartwoodAcceptsSaplingShieldedCoinbase) {
RegtestActivateHeartwood(false, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
auto chainparams = Params();
auto builder = sapling::new_builder(*chainparams.RustNetwork(), 10);
auto saplingAnchor = SaplingMerkleTree::empty_root().GetRawBytes();
auto builder = sapling::new_builder(*chainparams.RustNetwork(), 10, saplingAnchor, true);
builder->add_recipient(
uint256().GetRawBytes(),
libzcash::SaplingSpendingKey::random().default_address().GetRawBytes(),
@ -1167,7 +1171,7 @@ TEST(ChecktransactionTests, HeartwoodAcceptsSaplingShieldedCoinbase) {
mtx.vin.resize(1);
mtx.vin[0].prevout.SetNull();
mtx.vJoinSplit.resize(0);
mtx.saplingBundle = sapling::apply_bundle_signatures(sapling::build_bundle(std::move(builder), 10), {});
mtx.saplingBundle = sapling::apply_bundle_signatures(sapling::build_bundle(std::move(builder)), {});
auto outputs = mtx.saplingBundle.GetDetails().outputs();
auto& odesc = outputs[0];
@ -1256,10 +1260,12 @@ TEST(ChecktransactionTests, HeartwoodEnforcesSaplingRulesOnShieldedCoinbase) {
mtx.vin[0].prevout.SetNull();
mtx.vin[0].scriptSig << 123;
mtx.vJoinSplit.resize(0);
mtx.saplingBundle = sapling::test_only_invalid_bundle(0, 0, -1000);
mtx.saplingBundle = sapling::test_only_invalid_bundle(0, 1, -1000);
// Coinbase transaction should fail non-contextual checks with no shielded
// outputs and non-zero valueBalanceSapling.
// TODO: The new Sapling bundle API prevents us from constructing this case.
/*
{
CTransaction tx(mtx);
EXPECT_TRUE(tx.IsCoinBase());
@ -1268,15 +1274,17 @@ TEST(ChecktransactionTests, HeartwoodEnforcesSaplingRulesOnShieldedCoinbase) {
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-valuebalance-nonzero", false, "")).Times(1);
EXPECT_FALSE(CheckTransactionWithoutProofVerification(tx, state));
}
*/
// Add a Sapling output.
auto builder = sapling::new_builder(*chainparams.RustNetwork(), 10);
auto saplingAnchor = SaplingMerkleTree::empty_root().GetRawBytes();
auto builder = sapling::new_builder(*chainparams.RustNetwork(), 10, saplingAnchor, true);
builder->add_recipient(
uint256().GetRawBytes(),
libzcash::SaplingSpendingKey::random().default_address().GetRawBytes(),
1000,
libzcash::Memo::ToBytes(std::nullopt));
mtx.saplingBundle = sapling::apply_bundle_signatures(sapling::build_bundle(std::move(builder), 10), {});
mtx.saplingBundle = sapling::apply_bundle_signatures(sapling::build_bundle(std::move(builder)), {});
CTransaction tx(mtx);
EXPECT_TRUE(tx.IsCoinBase());
@ -1376,9 +1384,15 @@ TEST(ChecktransactionTests, InvalidOrchardShieldedCoinbase) {
mtx.nConsensusBranchId = NetworkUpgradeInfo[Consensus::UPGRADE_NU5].nBranchId;
// Make it an invalid shielded coinbase, by creating an all-dummy Orchard bundle.
RawHDSeed seed(32, 0);
auto to = libzcash::OrchardSpendingKey::ForAccount(seed, 133, 0)
.ToFullViewingKey()
.GetChangeAddress();
mtx.vin.resize(1);
mtx.vin[0].prevout.SetNull();
mtx.orchardBundle = orchard::Builder(false, true, uint256())
auto builder = orchard::Builder(true, uint256());
builder.AddOutput(std::nullopt, to, 0, std::nullopt);
mtx.orchardBundle = builder
.Build().value()
.ProveAndSign({}, uint256()).value();
@ -1405,7 +1419,7 @@ TEST(ChecktransactionTests, NU5AcceptsOrchardShieldedCoinbase) {
auto chainparams = Params();
uint256 orchardAnchor;
auto builder = orchard::Builder(false, true, orchardAnchor);
auto builder = orchard::Builder(true, orchardAnchor);
// Shielded coinbase outputs must be recoverable with an all-zeroes ovk.
RawHDSeed rawSeed(32, 0);
@ -1527,7 +1541,7 @@ TEST(ChecktransactionTests, NU5EnforcesOrchardRulesOnShieldedCoinbase) {
auto chainparams = Params();
uint256 orchardAnchor;
auto builder = orchard::Builder(false, true, orchardAnchor);
auto builder = orchard::Builder(true, orchardAnchor);
// Shielded coinbase outputs must be recoverable with an all-zeroes ovk.
RawHDSeed rawSeed(32, 0);

View File

@ -448,11 +448,14 @@ public:
mutableTxV5.saplingBundle = sapling::test_only_invalid_bundle(1, 0, 0);
saplingNullifier = uint256::FromRawBytes(mutableTxV5.saplingBundle.GetDetails().spends()[0].nullifier());
// The Orchard bundle builder always pads to two Actions, so we can just
// use an empty builder to create a dummy Orchard bundle.
RawHDSeed seed(32, 0);
auto to = libzcash::OrchardSpendingKey::ForAccount(seed, 133, 0)
.ToFullViewingKey()
.GetChangeAddress();
uint256 orchardAnchor;
uint256 dataToBeSigned;
auto builder = orchard::Builder(true, true, orchardAnchor);
auto builder = orchard::Builder(false, orchardAnchor);
builder.AddOutput(std::nullopt, to, 0, std::nullopt);
mutableTxV5.orchardBundle = builder.Build().value().ProveAndSign({}, dataToBeSigned).value();
orchardNullifier = mutableTxV5.orchardBundle.GetNullifiers().at(0);

View File

@ -23,7 +23,7 @@ TEST(RecursiveDynamicUsageTests, TestTransactionTransparent)
auto scriptPubKey = GetScriptForDestination(tsk.GetPubKey().GetID());
CTxDestination taddr = tsk.GetPubKey().GetID();
auto builder = TransactionBuilder(Params(), 1, std::nullopt, &keystore);
auto builder = TransactionBuilder(Params(), 1, std::nullopt, SaplingMerkleTree::empty_root(), &keystore);
builder.SetFee(10000);
builder.AddTransparentInput(
COutPoint(uint256S("7777777777777777777777777777777777777777777777777777777777777777"), 0),
@ -64,7 +64,7 @@ TEST(RecursiveDynamicUsageTests, TestTransactionSaplingToSapling)
auto pa = extfvk.DefaultAddress();
auto testNote = GetTestSaplingNote(pa, 50000);
auto builder = TransactionBuilder(Params(), 1, std::nullopt);
auto builder = TransactionBuilder(Params(), 1, std::nullopt, testNote.tree.root());
builder.SetFee(10000);
builder.AddSaplingSpend(sk, testNote.note, testNote.tree.witness());
builder.AddSaplingOutput(fvk.ovk, pa, 5000, {});
@ -73,7 +73,7 @@ TEST(RecursiveDynamicUsageTests, TestTransactionSaplingToSapling)
// 1 vShieldedSpend + 2 vShieldedOutput
EXPECT_EQ(1, tx.GetSaplingSpendsCount());
EXPECT_EQ(2, tx.GetSaplingOutputsCount());
EXPECT_EQ(400 + 2520, RecursiveDynamicUsage(tx));
EXPECT_EQ(400 + 32 + 2520, RecursiveDynamicUsage(tx));
RegtestDeactivateSapling();
}
@ -89,7 +89,7 @@ TEST(RecursiveDynamicUsageTests, TestTransactionTransparentToSapling)
auto scriptPubKey = GetScriptForDestination(tsk.GetPubKey().GetID());
auto sk = libzcash::SaplingSpendingKey::random();
auto builder = TransactionBuilder(Params(), 1, std::nullopt, &keystore);
auto builder = TransactionBuilder(Params(), 1, std::nullopt, SaplingMerkleTree::empty_root(), &keystore);
builder.SetFee(10000);
builder.AddTransparentInput(
COutPoint(uint256S("7777777777777777777777777777777777777777777777777777777777777777"), 0),
@ -97,10 +97,10 @@ TEST(RecursiveDynamicUsageTests, TestTransactionTransparentToSapling)
builder.AddSaplingOutput(sk.full_viewing_key().ovk, sk.default_address(), 40000, {});
auto tx = builder.Build().GetTxOrThrow();
// 1 vin + 1 vShieldedOutput
// 1 vin + 2 vShieldedOutput
EXPECT_EQ(0, tx.GetSaplingSpendsCount());
EXPECT_EQ(1, tx.GetSaplingOutputsCount());
EXPECT_EQ((96 + 128) + 1200, RecursiveDynamicUsage(tx));
EXPECT_EQ(2, tx.GetSaplingOutputsCount());
EXPECT_EQ((96 + 128) + 2280, RecursiveDynamicUsage(tx));
RegtestDeactivateSapling();
}
@ -117,7 +117,7 @@ TEST(RecursiveDynamicUsageTests, TestTransactionSaplingToTransparent)
auto sk = GetTestMasterSaplingSpendingKey();
auto testNote = GetTestSaplingNote(sk.ToXFVK().DefaultAddress(), 50000);
auto builder = TransactionBuilder(Params(), 1, std::nullopt, &keystore);
auto builder = TransactionBuilder(Params(), 1, std::nullopt, testNote.tree.root(), &keystore);
builder.SetFee(10000);
builder.AddSaplingSpend(sk, testNote.note, testNote.tree.witness());
builder.AddTransparentOutput(taddr, 40000);
@ -126,7 +126,7 @@ TEST(RecursiveDynamicUsageTests, TestTransactionSaplingToTransparent)
// 1 vShieldedSpend + 2 vShieldedOutput + 1 vout
EXPECT_EQ(1, tx.GetSaplingSpendsCount());
EXPECT_EQ(2, tx.GetSaplingOutputsCount());
EXPECT_EQ(400 + 2520 + 64, RecursiveDynamicUsage(tx));
EXPECT_EQ(400 + 2520 + 64 + 32, RecursiveDynamicUsage(tx));
RegtestDeactivateSapling();
}

View File

@ -20,7 +20,7 @@ TEST(Keys, EncodeAndDecodeSapling)
auto m = GetTestMasterSaplingSpendingKey();
for (uint32_t i = 0; i < 1000; i++) {
auto sk = m.Derive(i);
auto sk = m.Derive(i | HARDENED_KEY_LIMIT);
{
std::string sk_string = keyIO.EncodeSpendingKey(sk);
EXPECT_EQ(

View File

@ -124,7 +124,7 @@ TEST(MempoolLimitTests, MempoolCostAndEvictionWeight)
// Default fee
{
auto builder = TransactionBuilder(Params(), 1, std::nullopt);
auto builder = TransactionBuilder(Params(), 1, std::nullopt, testNote.tree.root());
builder.AddSaplingSpend(sk, testNote.note, testNote.tree.witness());
builder.AddSaplingOutput(fvk.ovk, pa, 25000, {});
@ -135,7 +135,7 @@ TEST(MempoolLimitTests, MempoolCostAndEvictionWeight)
// Lower than standard fee
{
auto builder = TransactionBuilder(Params(), 1, std::nullopt);
auto builder = TransactionBuilder(Params(), 1, std::nullopt, testNote.tree.root());
builder.AddSaplingSpend(sk, testNote.note, testNote.tree.witness());
builder.AddSaplingOutput(fvk.ovk, pa, 25000, {});
static_assert(MINIMUM_FEE == 10000);
@ -148,7 +148,7 @@ TEST(MempoolLimitTests, MempoolCostAndEvictionWeight)
// Larger Tx
{
auto builder = TransactionBuilder(Params(), 1, std::nullopt);
auto builder = TransactionBuilder(Params(), 1, std::nullopt, testNote.tree.root());
builder.AddSaplingSpend(sk, testNote.note, testNote.tree.witness());
for (int i = 0; i < 10; i++) {
builder.AddSaplingOutput(fvk.ovk, pa, 1000, {});

View File

@ -40,7 +40,7 @@ TEST(TransactionBuilder, TransparentToSapling)
// Create a shielding transaction from transparent to Sapling
// 0.00005 t-ZEC in, 0.00004 z-ZEC out, default fee
auto builder = TransactionBuilder(Params(), 1, std::nullopt, &keystore);
auto builder = TransactionBuilder(Params(), 1, std::nullopt, SaplingMerkleTree::empty_root(), &keystore);
builder.AddTransparentInput(COutPoint(uint256S("1234"), 0), scriptPubKey, 5000);
builder.AddSaplingOutput(fvk_from.ovk, pk, 4000, {});
auto tx = builder.Build().GetTxOrThrow();
@ -49,7 +49,7 @@ TEST(TransactionBuilder, TransparentToSapling)
EXPECT_EQ(tx.vout.size(), 0);
EXPECT_EQ(tx.vJoinSplit.size(), 0);
EXPECT_EQ(tx.GetSaplingSpendsCount(), 0);
EXPECT_EQ(tx.GetSaplingOutputsCount(), 1);
EXPECT_EQ(tx.GetSaplingOutputsCount(), 2);
EXPECT_EQ(tx.GetValueBalanceSapling(), -4000);
CValidationState state;
@ -74,7 +74,7 @@ TEST(TransactionBuilder, SaplingToSapling) {
// Create a Sapling-only transaction
// 0.00004 z-ZEC in, 0.000025 z-ZEC out, default fee, 0.000005 z-ZEC change
auto builder = TransactionBuilder(Params(), 2, std::nullopt);
auto builder = TransactionBuilder(Params(), 2, std::nullopt, testNote.tree.root());
builder.AddSaplingSpend(sk, testNote.note, testNote.tree.witness());
// Check that trying to add a different anchor fails
@ -119,7 +119,7 @@ TEST(TransactionBuilder, SaplingToSprout) {
// - 0.00004 Sapling-ZEC in - 0.000025 Sprout-ZEC out
// - 0.000005 Sapling-ZEC change
// - default t-ZEC fee
auto builder = TransactionBuilder(Params(), 2, std::nullopt, nullptr);
auto builder = TransactionBuilder(Params(), 2, std::nullopt, testNote.tree.root(), nullptr);
builder.AddSaplingSpend(sk, testNote.note, testNote.tree.witness());
builder.AddSproutOutput(sproutAddr, 2500, std::nullopt);
auto tx = builder.Build().GetTxOrThrow();
@ -173,7 +173,7 @@ TEST(TransactionBuilder, SproutToSproutAndSapling) {
// - 0.00005 Sprout-ZEC change
// - 0.00005 Sapling-ZEC out
// - 0.00005 t-ZEC fee
auto builder = TransactionBuilder(Params(), 2, std::nullopt, nullptr, &view);
auto builder = TransactionBuilder(Params(), 2, std::nullopt, SaplingMerkleTree::empty_root(), nullptr, &view);
builder.SetFee(5000);
builder.AddSproutInput(sproutSk, sproutNote, sproutWitness);
builder.AddSproutOutput(sproutAddr, 6000, std::nullopt);
@ -193,7 +193,7 @@ TEST(TransactionBuilder, SproutToSproutAndSapling) {
EXPECT_EQ(tx.vJoinSplit[2].vpub_old, 0);
EXPECT_EQ(tx.vJoinSplit[2].vpub_new, 10000);
EXPECT_EQ(tx.GetSaplingSpendsCount(), 0);
EXPECT_EQ(tx.GetSaplingOutputsCount(), 1);
EXPECT_EQ(tx.GetSaplingOutputsCount(), 2);
EXPECT_EQ(tx.GetValueBalanceSapling(), -5000);
CValidationState state;
@ -247,7 +247,7 @@ TEST(TransactionBuilder, TransparentToOrchard)
// Create a shielding transaction from transparent to Orchard
// 0.00005 t-ZEC in, 0.00004 z-ZEC out, default fee
auto builder = TransactionBuilder(Params(), 1, orchardAnchor, &keystore);
auto builder = TransactionBuilder(Params(), 1, orchardAnchor, SaplingMerkleTree::empty_root(), &keystore);
builder.AddTransparentInput(COutPoint(uint256S("1234"), 0), scriptPubKey, 5000);
builder.AddOrchardOutput(std::nullopt, recipient, 4000, std::nullopt);
auto maybeTx = builder.Build();
@ -279,7 +279,7 @@ TEST(TransactionBuilder, ThrowsOnTransparentInputWithoutKeyStore)
SelectParams(CBaseChainParams::REGTEST);
const Consensus::Params& consensusParams = Params().GetConsensus();
auto builder = TransactionBuilder(Params(), 1, std::nullopt);
auto builder = TransactionBuilder(Params(), 1, std::nullopt, SaplingMerkleTree::empty_root());
ASSERT_THROW(builder.AddTransparentInput(COutPoint(), CScript(), 1), std::runtime_error);
}
@ -290,7 +290,7 @@ TEST(TransactionBuilder, RejectsInvalidTransparentOutput)
// Default CTxDestination type is an invalid address
CTxDestination taddr;
auto builder = TransactionBuilder(Params(), 1, std::nullopt);
auto builder = TransactionBuilder(Params(), 1, std::nullopt, SaplingMerkleTree::empty_root());
ASSERT_THROW(builder.AddTransparentOutput(taddr, 50), UniValue);
}
@ -317,13 +317,13 @@ TEST(TransactionBuilder, FailsWithNegativeChange)
// Fail if there is only a Sapling output
// 0.00005 z-ZEC out, default fee
auto builder = TransactionBuilder(Params(), 1, std::nullopt);
auto builder = TransactionBuilder(Params(), 1, std::nullopt, testNote.tree.root());
builder.AddSaplingOutput(fvk.ovk, pa, 5000, {});
EXPECT_EQ("Change cannot be negative: -0.00006 ZEC", builder.Build().GetError());
// Fail if there is only a transparent output
// 0.00005 t-ZEC out, default fee
builder = TransactionBuilder(Params(), 1, std::nullopt, &keystore);
builder = TransactionBuilder(Params(), 1, std::nullopt, testNote.tree.root(), &keystore);
builder.AddTransparentOutput(taddr, 5000);
EXPECT_EQ("Change cannot be negative: -0.00006 ZEC", builder.Build().GetError());
@ -368,17 +368,18 @@ TEST(TransactionBuilder, ChangeOutput)
auto scriptPubKey = GetScriptForDestination(tkeyid);
auto fakeCoin = COutPoint(uint256S("7777777777777777777777777777777777777777777777777777777777777777"), 0);
auto saplingAnchor = SaplingMerkleTree::empty_root();
// No change address and no Sapling spends
{
auto builder = TransactionBuilder(Params(), 1, std::nullopt, &keystore);
auto builder = TransactionBuilder(Params(), 1, std::nullopt, saplingAnchor, &keystore);
builder.AddTransparentInput(fakeCoin, scriptPubKey, 2500);
EXPECT_EQ("Could not determine change address", builder.Build().GetError());
}
// Change to the same address as the first Sapling spend
{
auto builder = TransactionBuilder(Params(), 1, std::nullopt, &keystore);
auto builder = TransactionBuilder(Params(), 1, std::nullopt, testNote.tree.root(), &keystore);
builder.AddTransparentInput(fakeCoin, scriptPubKey, 2500);
builder.AddSaplingSpend(sk, testNote.note, testNote.tree.witness());
auto tx = builder.Build().GetTxOrThrow();
@ -393,7 +394,7 @@ TEST(TransactionBuilder, ChangeOutput)
// Change to a Sapling address
{
auto builder = TransactionBuilder(Params(), 1, std::nullopt, &keystore);
auto builder = TransactionBuilder(Params(), 1, std::nullopt, saplingAnchor, &keystore);
builder.AddTransparentInput(fakeCoin, scriptPubKey, 2500);
builder.SendChangeTo(zChangeAddr, fvkOut.ovk);
auto tx = builder.Build().GetTxOrThrow();
@ -402,13 +403,13 @@ TEST(TransactionBuilder, ChangeOutput)
EXPECT_EQ(tx.vout.size(), 0);
EXPECT_EQ(tx.vJoinSplit.size(), 0);
EXPECT_EQ(tx.GetSaplingSpendsCount(), 0);
EXPECT_EQ(tx.GetSaplingOutputsCount(), 1);
EXPECT_EQ(tx.GetSaplingOutputsCount(), 2);
EXPECT_EQ(tx.GetValueBalanceSapling(), -1500);
}
// Change to a transparent address
{
auto builder = TransactionBuilder(Params(), 1, std::nullopt, &keystore);
auto builder = TransactionBuilder(Params(), 1, std::nullopt, saplingAnchor, &keystore);
builder.AddTransparentInput(fakeCoin, scriptPubKey, 2500);
builder.SendChangeTo(tkeyid, {});
auto tx = builder.Build().GetTxOrThrow();
@ -442,7 +443,7 @@ TEST(TransactionBuilder, SetFee)
// Default fee
{
auto builder = TransactionBuilder(Params(), 1, std::nullopt);
auto builder = TransactionBuilder(Params(), 1, std::nullopt, testNote.tree.root());
builder.AddSaplingSpend(sk, testNote.note, testNote.tree.witness());
builder.AddSaplingOutput(fvk.ovk, pa, 25000, {});
auto tx = builder.Build().GetTxOrThrow();
@ -458,7 +459,7 @@ TEST(TransactionBuilder, SetFee)
// Configured fee
{
auto builder = TransactionBuilder(Params(), 1, std::nullopt);
auto builder = TransactionBuilder(Params(), 1, std::nullopt, testNote.tree.root());
builder.AddSaplingSpend(sk, testNote.note, testNote.tree.witness());
builder.AddSaplingOutput(fvk.ovk, pa, 25000, {});
builder.SetFee(20000);
@ -487,7 +488,8 @@ TEST(TransactionBuilder, CheckSaplingTxVersion)
auto pk = sk.ToXFVK().DefaultAddress();
// Cannot add Sapling outputs to a non-Sapling transaction
auto builder = TransactionBuilder(Params(), 1, std::nullopt);
SaplingMerkleTree tree;
auto builder = TransactionBuilder(Params(), 1, std::nullopt, tree.root());
try {
builder.AddSaplingOutput(uint256(), pk, 12345, {});
} catch (std::runtime_error const & err) {
@ -498,7 +500,6 @@ TEST(TransactionBuilder, CheckSaplingTxVersion)
// Cannot add Sapling spends to a non-Sapling transaction
libzcash::SaplingNote note(pk, 50000, libzcash::Zip212Enabled::BeforeZip212);
SaplingMerkleTree tree;
try {
builder.AddSaplingSpend(sk, note, tree.witness());
} catch (std::runtime_error const & err) {

View File

@ -208,7 +208,7 @@ TEST(Validation, ContextualCheckInputsDetectsOldBranchId) {
// Create a transparent transaction that spends the coin, targeting
// a height during the Overwinter epoch.
auto builder = TransactionBuilder(params, 15, std::nullopt, &keystore);
auto builder = TransactionBuilder(params, 15, std::nullopt, SaplingMerkleTree::empty_root(), &keystore);
builder.AddTransparentInput(utxo, scriptPubKey, coinValue);
builder.AddTransparentOutput(destination, 4000);
auto tx = builder.Build().GetTxOrThrow();

View File

@ -3,7 +3,7 @@
#include <zcash/address/zip32.h>
// From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/sapling_zip32.py
// From https://github.com/zcash/zcash-test-vectors/blob/master/zcash_test_vectors/sapling/zip32.py
// Sapling consistently uses little-endian encoding, but uint256S takes its input in
// big-endian byte order, so the test vectors below are byte-reversed.
TEST(ZIP32, TestVectors) {
@ -35,102 +35,95 @@ TEST(ZIP32, TestVectors) {
m.ToXFVK().DefaultAddress().d,
testing::ElementsAreArray({ 0xd8, 0x62, 0x1b, 0x98, 0x1c, 0xf3, 0x00, 0xe9, 0xd4, 0xcc, 0x89 }));
auto m_1 = m.Derive(1);
EXPECT_EQ(m_1.depth, 1);
EXPECT_EQ(m_1.parentFVKTag, 0x3a71c214);
EXPECT_EQ(m_1.childIndex, 1);
auto m_1h = m.Derive(1 | HARDENED_KEY_LIMIT);
EXPECT_EQ(m_1h.depth, 1);
EXPECT_EQ(m_1h.parentFVKTag, 0x3a71c214);
EXPECT_EQ(m_1h.childIndex, 1 | HARDENED_KEY_LIMIT);
EXPECT_EQ(
m_1.chaincode,
uint256S("e6bcda05678a43fad229334ef0b795a590e7c50590baf0d9b9031a690c114701"));
m_1h.chaincode,
uint256S("dbaeca68fd2ef8b45ec23ee91bd694aa2759e010c668bb3e066b20a845aacc6f"));
EXPECT_EQ(
m_1.expsk.ask,
uint256S("0c357a2655b4b8d761794095df5cb402d3ba4a428cf6a88e7c2816a597c12b28"));
m_1h.expsk.ask,
uint256S("04bd31e1a6218db693ff0802f029043ec20f3b0b8b148cdc04be7afb2ee9f7d5"));
EXPECT_EQ(
m_1.expsk.nsk,
uint256S("01ba6bff1018fd4eac04da7e3f2c6be9c229e662c5c4d1d6fc1ecafd8829a3e7"));
m_1h.expsk.nsk,
uint256S("0a75e557f6fcbf672e0134d4ec2d51a3f358659b4b5c46f303e6cb22687c2a37"));
EXPECT_EQ(
m_1.expsk.ovk,
uint256S("7474a4c518551bd82f14a7f7365a8ffa403c50cfeffedf026ada8688fc81135f"));
m_1h.expsk.ovk,
uint256S("691c33ec470a1697ca37ceb237bb7f1691d2a833543514cf1f8c343319763025"));
EXPECT_EQ(
m_1.dk,
uint256S("dcb4c170d878510e96c4a74192d7eecde9c9912b00b99a12ec91d7a232e84de0"));
m_1h.dk,
uint256S("26d53444cbe2e9929f619d810a0d05ae0deece0a72c3a7e3df9a5fd60f4088f2"));
EXPECT_THAT(
m_1.ToXFVK().DefaultAddress().d,
testing::ElementsAreArray({ 0x8b, 0x41, 0x38, 0x32, 0x0d, 0xfa, 0xfd, 0x7b, 0x39, 0x97, 0x81 }));
m_1h.ToXFVK().DefaultAddress().d,
testing::ElementsAreArray({ 0xbc, 0xc3, 0x23, 0xe8, 0xda, 0x39, 0xb4, 0x96, 0xc0, 0x50, 0x51 }));
auto m_1_2h = m_1.Derive(2 | HARDENED_KEY_LIMIT);
EXPECT_EQ(m_1_2h.depth, 2);
EXPECT_EQ(m_1_2h.parentFVKTag, 0x079e99db);
EXPECT_EQ(m_1_2h.childIndex, 2 | HARDENED_KEY_LIMIT);
auto m_1h_2h = m_1h.Derive(2 | HARDENED_KEY_LIMIT);
EXPECT_EQ(m_1h_2h.depth, 2);
EXPECT_EQ(m_1h_2h.parentFVKTag, 0xcb238476);
EXPECT_EQ(m_1h_2h.childIndex, 2 | HARDENED_KEY_LIMIT);
EXPECT_EQ(
m_1_2h.chaincode,
uint256S("35d4a883737742ca41a4baa92323bdb3c93dcb3b462a26b039971bedf415ce97"));
m_1h_2h.chaincode,
uint256S("daf7be6f80503ab34f14f236da9de2cf540ae3c100f520607980d0756c087944"));
EXPECT_EQ(
m_1_2h.expsk.ask,
uint256S("0dc6e4fe846bda925c82e632980434e17b51dac81fc4821fa71334ee3c11e88b"));
m_1h_2h.expsk.ask,
uint256S("06512f33a6f9ae4b42fd71f9cfa08d3727522dd3089cad596fc3139eb65df37f"));
EXPECT_EQ(
m_1_2h.expsk.nsk,
uint256S("0c99a63a275c1c66734761cfb9c62fe9bd1b953f579123d3d0e769c59d057837"));
m_1h_2h.expsk.nsk,
uint256S("00debf5999f564a3e05a0d418cf40714399a32c1bdc98ba2eb4439a0e46e9c77"));
EXPECT_EQ(
m_1_2h.expsk.ovk,
uint256S("bc1328fc5eb693e18875c5149d06953b11d39447ebd6e38c023c22962e1881cf"));
m_1h_2h.expsk.ovk,
uint256S("ac85619305763dc29b67b75e305e5323bda7d6a530736a88417f90bf0171fcd9"));
EXPECT_EQ(
m_1_2h.dk,
uint256S("377bb062dce7e0dcd8a0054d0ca4b4d1481b3710bfa1df12ca46ff9e9fa1eda3"));
m_1h_2h.dk,
uint256S("d148325ff6faa682558de97a9fec61dd8dc10a96d0cd214bc531e0869a9e69e4"));
EXPECT_THAT(
m_1_2h.ToXFVK().DefaultAddress().d,
testing::ElementsAreArray({ 0xe8, 0xd0, 0x37, 0x93, 0xcd, 0xd2, 0xba, 0xcc, 0x9c, 0x70, 0x41 }));
m_1h_2h.ToXFVK().DefaultAddress().d,
testing::ElementsAreArray({ 0x98, 0x82, 0x40, 0xce, 0xa4, 0xdb, 0xc3, 0x0a, 0x73, 0x75, 0x50 }));
auto m_1_2hv = m_1_2h.ToXFVK();
auto m_1_2hv = m_1h_2h.ToXFVK();
EXPECT_EQ(m_1_2hv.depth, 2);
EXPECT_EQ(m_1_2hv.parentFVKTag, 0x079e99db);
EXPECT_EQ(m_1_2hv.parentFVKTag, 0xcb238476);
EXPECT_EQ(m_1_2hv.childIndex, 2 | HARDENED_KEY_LIMIT);
EXPECT_EQ(
m_1_2hv.chaincode,
uint256S("35d4a883737742ca41a4baa92323bdb3c93dcb3b462a26b039971bedf415ce97"));
uint256S("daf7be6f80503ab34f14f236da9de2cf540ae3c100f520607980d0756c087944"));
EXPECT_EQ(
m_1_2hv.fvk.ak,
uint256S("4138cffdf7200e52d4e9f4384481b4a4c4d070493a5e401e4ffa850f5a92c5a6"));
uint256S("4eab7275725c76ee4247ae8d941d4b53682e39da641785e097377144953f859a"));
EXPECT_EQ(
m_1_2hv.fvk.nk,
uint256S("11eee22577304f660cc036bc84b3fc88d1ec50ae8a4d657beb6b211659304e30"));
uint256S("be4f5d4f36018511d23a1b9a9c87af8c6dbd20212da84121c1ce884f8aa266f1"));
EXPECT_EQ(
m_1_2hv.fvk.ovk,
uint256S("bc1328fc5eb693e18875c5149d06953b11d39447ebd6e38c023c22962e1881cf"));
uint256S("ac85619305763dc29b67b75e305e5323bda7d6a530736a88417f90bf0171fcd9"));
EXPECT_EQ(
m_1_2hv.dk,
uint256S("377bb062dce7e0dcd8a0054d0ca4b4d1481b3710bfa1df12ca46ff9e9fa1eda3"));
EXPECT_EQ(m_1_2hv.DefaultAddress(), m_1_2h.ToXFVK().DefaultAddress());
uint256S("d148325ff6faa682558de97a9fec61dd8dc10a96d0cd214bc531e0869a9e69e4"));
EXPECT_EQ(m_1_2hv.DefaultAddress(), m_1h_2h.ToXFVK().DefaultAddress());
// Hardened derivation from an xfvk fails
EXPECT_FALSE(m_1_2hv.Derive(3 | HARDENED_KEY_LIMIT));
// Non-hardened derivation succeeds
auto maybe_m_1_2hv_3 = m_1_2hv.Derive(3);
EXPECT_TRUE(maybe_m_1_2hv_3);
auto m_1_2hv_3 = maybe_m_1_2hv_3.value();
EXPECT_EQ(m_1_2hv_3.depth, 3);
EXPECT_EQ(m_1_2hv_3.parentFVKTag, 0x7583c148);
EXPECT_EQ(m_1_2hv_3.childIndex, 3);
auto m_1h_2h_3h = m_1h_2h.Derive(3 | HARDENED_KEY_LIMIT);
EXPECT_EQ(m_1h_2h_3h.depth, 3);
EXPECT_EQ(m_1h_2h_3h.parentFVKTag, 0x2b2ddc0b);
EXPECT_EQ(m_1h_2h_3h.childIndex, 3 | HARDENED_KEY_LIMIT);
EXPECT_EQ(
m_1_2hv_3.chaincode,
uint256S("e8e7d6a74a5a1c05be41baec7998d91f7b3603a4c0af495b0d43ba81cf7b938d"));
m_1h_2h_3h.chaincode,
uint256S("4bc7bd5b38fcbdb259be013bef298c8de263e4c32ccb2bcdd2ce90762d01dc33"));
EXPECT_EQ(
m_1_2hv_3.fvk.ak,
uint256S("a3a697bdda9d648d32a97553de4754b2fac866d726d3f2c436259c507bc585b1"));
m_1h_2h_3h.expsk.ask,
uint256S("07afec4df829ace083d68145103c50692f331c4690cf52f13759e3214dd29345"));
EXPECT_EQ(
m_1_2hv_3.fvk.nk,
uint256S("4f66c0814b769963f3bf1bc001270b50edabb27de042fc8a5607d2029e0488db"));
m_1h_2h_3h.expsk.nsk,
uint256S("0bbba7ff6efab6fbabb5b727ed3d55e40efa0de858f8c0e357503f12c27ec81a"));
EXPECT_EQ(
m_1_2hv_3.fvk.ovk,
uint256S("f61a699934dc78441324ef628b4b4721611571e8ee3bd591eb3d4b1cfae0b969"));
m_1h_2h_3h.expsk.ovk,
uint256S("e39e4b1b9c5c1b31988beffb515522a95de718afa880e36c9d2ebef20cea361e"));
EXPECT_EQ(
m_1_2hv_3.dk,
uint256S("6ee53b1261f2c9c0f7359ab236f87b52a0f1b0ce43305cdad92ebb63c350cbbe"));
m_1h_2h_3h.dk,
uint256S("6abb7b109c7270edaa3a36dc140d3f70bf8cd271b69d606f5aadf3a4596cfc57"));
EXPECT_THAT(
m_1_2hv_3.DefaultAddress().d,
testing::ElementsAreArray({ 0x03, 0x0f, 0xfb, 0x26, 0x3a, 0x93, 0x9e, 0x23, 0x0e, 0x96, 0xdd }));
m_1h_2h_3h.ToXFVK().DefaultAddress().d,
testing::ElementsAreArray({ 0x5a, 0x75, 0xbe, 0x14, 0x00, 0x53, 0x0b, 0x4b, 0x7a, 0xdd, 0x52 }));
}
TEST(ZIP32, ParseHDKeypathAccount) {

View File

@ -79,9 +79,15 @@ template<> void AppendRandomLeaf(OrchardMerkleFrontier &tree) {
// fortunately the tests only require that the tree root change.
// TODO: Remove the need to create proofs by having a testing-only way to
// append a random leaf to OrchardMerkleFrontier.
RawHDSeed seed(32, 0);
auto to = libzcash::OrchardSpendingKey::ForAccount(seed, 133, 0)
.ToFullViewingKey()
.GetChangeAddress();
uint256 orchardAnchor;
uint256 dataToBeSigned;
auto builder = orchard::Builder(true, true, orchardAnchor);
// TODO: Create bundle.
auto builder = orchard::Builder(false, orchardAnchor);
builder.AddOutput(std::nullopt, to, 0, std::nullopt);
auto bundle = builder.Build().value().ProveAndSign({}, dataToBeSigned).value();
tree.AppendBundle(bundle);
}

View File

@ -173,7 +173,7 @@ public:
void ComputeBindingSig(rust::Box<sapling::Builder> saplingBuilder, std::optional<orchard::UnauthorizedBundle> orchardBundle) const {
auto consensusBranchId = CurrentEpochBranchId(nHeight, chainparams.GetConsensus());
auto saplingBundle = sapling::build_bundle(std::move(saplingBuilder), nHeight);
auto saplingBundle = sapling::build_bundle(std::move(saplingBuilder));
// Empty output script.
uint256 dataToBeSigned;
@ -213,13 +213,14 @@ public:
// Create Orchard output
void operator()(const libzcash::OrchardRawAddress &to) const {
auto saplingBuilder = sapling::new_builder(*chainparams.RustNetwork(), nHeight);
std::array<uint8_t, 32> saplingAnchor;
auto saplingBuilder = sapling::new_builder(*chainparams.RustNetwork(), nHeight, saplingAnchor, true);
// `enableSpends` must be set to `false` for coinbase transactions. This
// means the Orchard anchor is unconstrained, so we set it to the empty
// tree root via a null (all zeroes) uint256.
uint256 orchardAnchor;
auto builder = orchard::Builder(false, true, orchardAnchor);
auto builder = orchard::Builder(true, orchardAnchor);
// Shielded coinbase outputs must be recoverable with an all-zeroes ovk.
uint256 ovk;
@ -249,7 +250,8 @@ public:
// Create Sapling output
void operator()(const libzcash::SaplingPaymentAddress &pa) const {
auto saplingBuilder = sapling::new_builder(*chainparams.RustNetwork(), nHeight);
std::array<uint8_t, 32> saplingAnchor;
auto saplingBuilder = sapling::new_builder(*chainparams.RustNetwork(), nHeight, saplingAnchor, true);
auto miner_reward = SetFoundersRewardAndGetMinerValue(*saplingBuilder);
@ -265,7 +267,8 @@ public:
// Create transparent output
void operator()(const boost::shared_ptr<CReserveScript> &coinbaseScript) const {
// Add the FR output and fetch the miner's output value.
auto saplingBuilder = sapling::new_builder(*chainparams.RustNetwork(), nHeight);
std::array<uint8_t, 32> saplingAnchor;
auto saplingBuilder = sapling::new_builder(*chainparams.RustNetwork(), nHeight, saplingAnchor, true);
// Miner output will be vout[0]; Founders' Reward & funding stream outputs
// will follow.

View File

@ -9,7 +9,7 @@ use serde::{
use zcash_primitives::{
consensus::Network,
legacy::Script,
transaction::components::{transparent, Amount, TxOut},
transaction::components::{amount::NonNegativeAmount, transparent, TxOut},
zip32::AccountId,
};
@ -67,7 +67,9 @@ impl<'de> Visitor<'de> for JsonAccountIdVisitor {
{
u32::try_from(v)
.map_err(|_| E::custom(format!("u32 out of range: {}", v)))
.map(AccountId::from)
.and_then(|a| {
AccountId::try_from(a).map_err(|e| E::custom(format!("AccountId invalid: {}", e)))
})
.map(JsonAccountId)
}
@ -77,7 +79,9 @@ impl<'de> Visitor<'de> for JsonAccountIdVisitor {
{
u32::try_from(v)
.map_err(|_| E::custom(format!("u32 out of range: {}", v)))
.map(AccountId::from)
.and_then(|a| {
AccountId::try_from(a).map_err(|e| E::custom(format!("AccountId invalid: {}", e)))
})
.map(JsonAccountId)
}
@ -87,7 +91,9 @@ impl<'de> Visitor<'de> for JsonAccountIdVisitor {
{
u32::try_from(v)
.map_err(|_| E::custom(format!("u32 out of range: {}", v)))
.map(AccountId::from)
.and_then(|a| {
AccountId::try_from(a).map_err(|e| E::custom(format!("AccountId invalid: {}", e)))
})
.map(JsonAccountId)
}
@ -97,7 +103,9 @@ impl<'de> Visitor<'de> for JsonAccountIdVisitor {
{
u32::try_from(v)
.map_err(|_| E::custom(format!("u32 out of range: {}", v)))
.map(AccountId::from)
.and_then(|a| {
AccountId::try_from(a).map_err(|e| E::custom(format!("AccountId invalid: {}", e)))
})
.map(JsonAccountId)
}
}
@ -162,7 +170,7 @@ impl fmt::Display for ZUint256 {
}
#[derive(Clone, Debug)]
struct ZOutputValue(Amount);
struct ZOutputValue(NonNegativeAmount);
struct ZOutputValueVisitor;
@ -177,9 +185,11 @@ impl<'de> Visitor<'de> for ZOutputValueVisitor {
where
E: serde::de::Error,
{
Amount::from_u64(v).map(ZOutputValue).map_err(|()| {
serde::de::Error::invalid_type(Unexpected::Unsigned(v), &"a valid zatoshi amount")
})
NonNegativeAmount::from_u64(v)
.map(ZOutputValue)
.map_err(|()| {
serde::de::Error::invalid_type(Unexpected::Unsigned(v), &"a valid zatoshi amount")
})
}
}

View File

@ -36,7 +36,7 @@ pub(crate) fn inspect_mnemonic(
let orchard_fvk = match orchard::keys::SpendingKey::from_zip32_seed(
&seed,
network.coin_type(),
account.into(),
account,
) {
Ok(sk) => Some(orchard::keys::FullViewingKey::from(&sk)),
Err(e) => {
@ -49,13 +49,13 @@ pub(crate) fn inspect_mnemonic(
};
eprintln!(" - Sapling:");
let sapling_master = zip32::ExtendedSpendingKey::master(&seed);
let sapling_extsk = zip32::ExtendedSpendingKey::from_path(
let sapling_master = sapling::zip32::ExtendedSpendingKey::master(&seed);
let sapling_extsk = sapling::zip32::ExtendedSpendingKey::from_path(
&sapling_master,
&[
zip32::ChildIndex::Hardened(32),
zip32::ChildIndex::Hardened(network.coin_type()),
zip32::ChildIndex::Hardened(account.into()),
zip32::ChildIndex::hardened(32),
zip32::ChildIndex::hardened(network.coin_type()),
account.into(),
],
);
#[allow(deprecated)]
@ -106,8 +106,8 @@ pub(crate) fn inspect_mnemonic(
Ok(addr) => eprintln!(
" - Default address: {}",
match addr {
TransparentAddress::PublicKey(data) => ZcashAddress::from_transparent_p2pkh(addr_net, data),
TransparentAddress::Script(_) => unreachable!(),
TransparentAddress::PublicKeyHash(data) => ZcashAddress::from_transparent_p2pkh(addr_net, data),
TransparentAddress::ScriptHash(_) => unreachable!(),
}.encode(),
),
Err(e) => eprintln!(

View File

@ -98,8 +98,9 @@ fn inspect_bytes(bytes: Vec<u8>, context: Option<Context>) {
block::inspect(&block, context);
} else if let Some(header) = complete(&bytes, |r| BlockHeader::read(r)) {
block::inspect_header(&header, context);
} else if let Some(tx) = complete(&bytes, |r| Transaction::read(r, BranchId::Sprout)) {
} else if let Some(tx) = complete(&bytes, |r| Transaction::read(r, BranchId::Nu5)) {
// TODO: Take the branch ID used above from the context if present.
// https://github.com/zcash/zcash/issues/6831
transaction::inspect(tx, context);
} else {
// It's not a known variable-length format. check fixed-length data formats.

View File

@ -6,6 +6,7 @@ use std::{
use bellman::groth16;
use group::GroupEncoding;
use orchard::note_encryption::OrchardDomain;
use sapling::{note_encryption::SaplingDomain, SaplingVerificationContext};
use secp256k1::{Secp256k1, VerifyOnly};
use zcash_address::{
unified::{self, Encoding},
@ -14,18 +15,16 @@ use zcash_address::{
use zcash_note_encryption::try_output_recovery_with_ovk;
#[allow(deprecated)]
use zcash_primitives::{
consensus::BlockHeight,
consensus::{sapling_zip212_enforcement, BlockHeight},
legacy::{keys::pubkey_to_address, Script, TransparentAddress},
memo::{Memo, MemoBytes},
sapling::note_encryption::SaplingDomain,
transaction::{
components::{sapling, transparent, Amount},
components::{amount::NonNegativeAmount, transparent},
sighash::{signature_hash, SignableInput, TransparentAuthorizingContext},
txid::TxIdDigester,
Authorization, Transaction, TransactionData, TxId, TxVersion,
},
};
use zcash_proofs::sapling::SaplingVerificationContext;
use crate::{
context::{Context, ZTxOut},
@ -106,7 +105,7 @@ impl transparent::Authorization for TransparentAuth {
}
impl TransparentAuthorizingContext for TransparentAuth {
fn input_amounts(&self) -> Vec<Amount> {
fn input_amounts(&self) -> Vec<NonNegativeAmount> {
self.all_prev_outputs
.iter()
.map(|prevout| prevout.value)
@ -143,7 +142,7 @@ pub(crate) struct PrecomputedAuth;
impl Authorization for PrecomputedAuth {
type TransparentAuth = TransparentAuth;
type SaplingAuth = sapling::Authorized;
type SaplingAuth = sapling::bundle::Authorized;
type OrchardAuth = orchard::bundle::Authorized;
}
@ -231,7 +230,7 @@ pub(crate) fn inspect(tx: Transaction, context: Option<Context>) {
txin.prevout.n()
);
match coin.recipient_address() {
Some(addr @ TransparentAddress::PublicKey(_)) => {
Some(addr @ TransparentAddress::PublicKeyHash(_)) => {
// Format is [sig_and_type_len] || sig || [hash_type] || [pubkey_len] || pubkey
// where [x] encodes a single byte.
let sig_and_type_len = txin.script_sig.0.first().map(|l| *l as usize);
@ -311,7 +310,7 @@ pub(crate) fn inspect(tx: Transaction, context: Option<Context>) {
}
}
// TODO: Check P2SH structure.
Some(TransparentAddress::Script(_)) => {
Some(TransparentAddress::ScriptHash(_)) => {
eprintln!(" 🔎 \"transparentcoins\"[{}] is a P2SH coin.", i);
}
// TODO: Check arbitrary scripts.
@ -376,7 +375,7 @@ pub(crate) fn inspect(tx: Transaction, context: Option<Context>) {
assert!(!(bundle.shielded_spends().is_empty() && bundle.shielded_outputs().is_empty()));
// TODO: Separate into checking proofs, signatures, and other structural details.
let mut ctx = SaplingVerificationContext::new(true);
let mut ctx = SaplingVerificationContext::new();
if !bundle.shielded_spends().is_empty() {
eprintln!(" - {} Sapling Spend(s)", bundle.shielded_spends().len());
@ -386,7 +385,7 @@ pub(crate) fn inspect(tx: Transaction, context: Option<Context>) {
spend.cv(),
*spend.anchor(),
&spend.nullifier().0,
spend.rk().clone(),
*spend.rk(),
sighash.as_ref(),
*spend.spend_auth_sig(),
groth16::Proof::read(&spend.zkproof()[..]).unwrap(),
@ -411,8 +410,11 @@ pub(crate) fn inspect(tx: Transaction, context: Option<Context>) {
.and_then(|ctx| ctx.network().zip(ctx.addr_network()))
{
if let Some((note, addr, memo)) = try_output_recovery_with_ovk(
&SaplingDomain::for_height(params, height.unwrap()),
&zcash_primitives::keys::OutgoingViewingKey([0; 32]),
&SaplingDomain::new(sapling_zip212_enforcement(
&params,
height.unwrap(),
)),
&sapling::keys::OutgoingViewingKey([0; 32]),
output,
output.cv(),
output.out_ciphertext(),
@ -426,6 +428,7 @@ pub(crate) fn inspect(tx: Transaction, context: Option<Context>) {
eprintln!(" - {}", zaddr);
eprintln!(" - {}", render_value(note.value().inner()));
}
let memo = MemoBytes::from_bytes(&memo).expect("correct length");
eprintln!(" - {}", render_memo(memo));
} else {
eprintln!(

View File

@ -35,8 +35,7 @@ void orchard_spend_info_free(OrchardSpendInfoPtr* ptr);
///
/// If `anchor` is `null`, the root of the empty Orchard commitment tree is used.
OrchardBuilderPtr* orchard_builder_new(
bool spends_enabled,
bool outputs_enabled,
bool coinbase,
const unsigned char* anchor);
/// Frees an Orchard builder returned from `orchard_builder_new`.

View File

@ -9,7 +9,6 @@ use zcash_address::{
unified::{self, Container, Encoding},
Network, ToAddress, TryFromAddress, ZcashAddress,
};
use zcash_primitives::sapling;
pub type UnifiedAddressObj = NonNull<c_void>;
pub type AddOrchardReceiverCb =

View File

@ -185,11 +185,15 @@ pub(crate) mod ffi {
type SaplingBuilder;
#[cxx_name = "new_builder"]
fn new_sapling_builder(network: &Network, height: u32) -> Box<SaplingBuilder>;
fn new_sapling_builder(
network: &Network,
height: u32,
anchor: [u8; 32],
coinbase: bool,
) -> Result<Box<SaplingBuilder>>;
fn add_spend(
self: &mut SaplingBuilder,
extsk: &[u8],
diversifier: [u8; 11],
recipient: [u8; 43],
value: u64,
rcm: [u8; 32],
@ -205,7 +209,6 @@ pub(crate) mod ffi {
#[cxx_name = "build_bundle"]
fn build_sapling_bundle(
builder: Box<SaplingBuilder>,
target_height: u32,
) -> Result<Box<SaplingUnauthorizedBundle>>;
#[cxx_name = "UnauthorizedBundle"]

View File

@ -6,8 +6,8 @@ use incrementalmerkletree::Hashable;
use libc::size_t;
use orchard::keys::SpendingKey;
use orchard::{
builder::{Builder, InProgress, Unauthorized, Unproven},
bundle::{Authorized, Flags},
builder::{Builder, BundleType, InProgress, Unauthorized, Unproven},
bundle::Authorized,
keys::{FullViewingKey, OutgoingViewingKey},
tree::{MerkleHashOrchard, MerklePath},
value::NoteValue,
@ -18,7 +18,7 @@ use tracing::error;
use zcash_primitives::{
consensus::BranchId,
transaction::{
components::{sapling, Amount},
components::Amount,
sighash::{signature_hash, SignableInput},
txid::TxIdDigester,
Authorization, Transaction, TransactionData,
@ -55,18 +55,16 @@ pub extern "C" fn orchard_spend_info_free(spend_info: *mut OrchardSpendInfo) {
}
#[no_mangle]
pub extern "C" fn orchard_builder_new(
spends_enabled: bool,
outputs_enabled: bool,
anchor: *const [u8; 32],
) -> *mut Builder {
pub extern "C" fn orchard_builder_new(coinbase: bool, anchor: *const [u8; 32]) -> *mut Builder {
let bundle_type = if coinbase {
BundleType::Coinbase
} else {
BundleType::DEFAULT
};
let anchor = unsafe { anchor.as_ref() }
.map(|a| orchard::Anchor::from_bytes(*a).unwrap())
.unwrap_or_else(|| MerkleHashOrchard::empty_root(32.into()).into());
Box::into_raw(Box::new(Builder::new(
Flags::from_parts(spends_enabled, outputs_enabled),
anchor,
)))
Box::into_raw(Box::new(Builder::new(bundle_type, anchor)))
}
#[no_mangle]
@ -106,7 +104,7 @@ pub extern "C" fn orchard_builder_add_recipient(
let value = NoteValue::from_raw(value);
let memo = unsafe { memo.as_ref() }.copied();
match builder.add_recipient(ovk, *recipient, value, memo) {
match builder.add_output(ovk, *recipient, value, memo) {
Ok(()) => true,
Err(e) => {
error!("Failed to add Orchard recipient: {}", e);
@ -132,8 +130,15 @@ pub extern "C" fn orchard_builder_build(
}
let builder = unsafe { Box::from_raw(builder) };
match builder.build(OsRng) {
Ok(bundle) => Box::into_raw(Box::new(bundle)),
match builder.build::<Amount>(OsRng) {
Ok(Some((bundle, _))) => Box::into_raw(Box::new(bundle)),
Ok(None) => {
// The C++ side only calls `orchard_builder_build` when it expects the
// resulting bundle to be non-empty (either at least one Orchard output for
// coinbase transactions, or a potentially-empty bundle that gets padded).
error!("Tried to build empty Orchard bundle");
ptr::null_mut()
}
Err(e) => {
error!("Failed to build Orchard bundle: {:?}", e);
ptr::null_mut()
@ -232,7 +237,8 @@ pub(crate) fn shielded_signature_digest(
struct Signable {}
impl Authorization for Signable {
type TransparentAuth = TransparentAuth;
type SaplingAuth = sapling::builder::Unauthorized;
type SaplingAuth =
sapling::builder::InProgress<sapling::builder::Proven, sapling::builder::Unsigned>;
type OrchardAuth = InProgress<Unproven, Unauthorized>;
}

View File

@ -5,12 +5,9 @@ use std::io::{self, Read, Write};
use bridgetree::{BridgeTree, Checkpoint, MerkleBridge};
use incrementalmerkletree::{Address, Hashable, Level, Position};
use zcash_encoding::{Optional, Vector};
use zcash_primitives::{
merkle_tree::{
read_address, read_leu64_usize, read_nonempty_frontier_v1, read_position, write_address,
write_nonempty_frontier_v1, write_position, write_usize_leu64, HashSer,
},
sapling::NOTE_COMMITMENT_TREE_DEPTH,
use zcash_primitives::merkle_tree::{
read_address, read_leu64_usize, read_nonempty_frontier_v1, read_position, write_address,
write_nonempty_frontier_v1, write_position, write_usize_leu64, HashSer,
};
pub const SER_V1: u8 = 1;
@ -252,9 +249,9 @@ pub fn write_checkpoint_v3<W: Write>(
/// ids should always be treated as opaque, totally ordered identifiers without additional
/// semantics.
#[allow(clippy::redundant_closure)]
pub fn read_tree<H: Hashable + HashSer + Ord + Clone, R: Read>(
pub fn read_tree<H: Hashable + HashSer + Ord + Clone, const DEPTH: u8, R: Read>(
mut reader: R,
) -> io::Result<BridgeTree<H, u32, NOTE_COMMITMENT_TREE_DEPTH>> {
) -> io::Result<BridgeTree<H, u32, DEPTH>> {
let tree_version = reader.read_u8()?;
let prior_bridges = Vector::read(&mut reader, |r| read_bridge(r, tree_version))?;
let current_bridge = Optional::read(&mut reader, |r| read_bridge(r, tree_version))?;
@ -309,9 +306,9 @@ pub fn read_tree<H: Hashable + HashSer + Ord + Clone, R: Read>(
})
}
pub fn write_tree<H: Hashable + HashSer + Ord, W: Write>(
pub fn write_tree<H: Hashable + HashSer + Ord, const DEPTH: u8, W: Write>(
mut writer: W,
tree: &BridgeTree<H, u32, NOTE_COMMITMENT_TREE_DEPTH>,
tree: &BridgeTree<H, u32, DEPTH>,
) -> io::Result<()> {
writer.write_u8(SER_V3)?;
Vector::write(&mut writer, tree.prior_bridges(), |w, b| write_bridge(w, b))?;

View File

@ -2,8 +2,8 @@ use std::ffi::OsString;
use std::path::PathBuf;
use std::sync::Once;
use bellman::groth16::Parameters;
use bls12_381::Bls12;
use sapling::circuit::{OutputParameters, SpendParameters};
use tracing::info;
use crate::{
@ -51,17 +51,18 @@ fn zksnark_params(sprout_path: String, load_proving_keys: bool) {
// Load params
let (sapling_spend_params, sapling_output_params) = {
let (spend_buf, output_buf) = wagyu_zcash_parameters::load_sapling_parameters();
let spend_params = Parameters::<Bls12>::read(&spend_buf[..], false)
.expect("couldn't deserialize Sapling spend parameters");
let output_params = Parameters::<Bls12>::read(&output_buf[..], false)
.expect("couldn't deserialize Sapling spend parameters");
(spend_params, output_params)
(
SpendParameters::read(&spend_buf[..], false)
.expect("Failed to read Sapling Spend parameters"),
OutputParameters::read(&output_buf[..], false)
.expect("Failed to read Sapling Output parameters"),
)
};
// We need to clone these because we aren't necessarily storing the proving
// parameters in memory.
let sapling_spend_vk = sapling_spend_params.vk.clone();
let sapling_output_vk = sapling_output_params.vk.clone();
let sapling_spend_vk = sapling_spend_params.verifying_key();
let sapling_output_vk = sapling_output_params.verifying_key();
// Generate Orchard parameters.
info!(target: "main", "Loading Orchard parameters");

View File

@ -19,7 +19,10 @@
// See https://github.com/rust-lang/rfcs/pull/2585 for more background.
#![allow(clippy::not_unsafe_ptr_arg_deref)]
use bellman::groth16::{self, Parameters, PreparedVerifyingKey};
use ::sapling::circuit::{
OutputParameters, OutputVerifyingKey, SpendParameters, SpendVerifyingKey,
};
use bellman::groth16::PreparedVerifyingKey;
use bls12_381::Bls12;
use std::path::PathBuf;
use subtle::CtOption;
@ -61,12 +64,12 @@ mod test_harness_ffi;
#[cfg(test)]
mod tests;
static mut SAPLING_SPEND_VK: Option<groth16::VerifyingKey<Bls12>> = None;
static mut SAPLING_OUTPUT_VK: Option<groth16::VerifyingKey<Bls12>> = None;
static mut SAPLING_SPEND_VK: Option<SpendVerifyingKey> = None;
static mut SAPLING_OUTPUT_VK: Option<OutputVerifyingKey> = None;
static mut SPROUT_GROTH16_VK: Option<PreparedVerifyingKey<Bls12>> = None;
static mut SAPLING_SPEND_PARAMS: Option<Parameters<Bls12>> = None;
static mut SAPLING_OUTPUT_PARAMS: Option<Parameters<Bls12>> = None;
static mut SAPLING_SPEND_PARAMS: Option<SpendParameters> = None;
static mut SAPLING_OUTPUT_PARAMS: Option<OutputParameters> = None;
static mut SPROUT_GROTH16_PARAMS_PATH: Option<PathBuf> = None;
static mut ORCHARD_PK: Option<orchard::circuit::ProvingKey> = None;

View File

@ -5,9 +5,9 @@ use incrementalmerkletree::{
Hashable, Level,
};
use orchard::tree::MerkleHashOrchard;
use zcash_primitives::{
merkle_tree::{read_frontier_v1, write_commitment_tree, write_frontier_v1, HashSer},
sapling::NOTE_COMMITMENT_TREE_DEPTH,
use sapling::NOTE_COMMITMENT_TREE_DEPTH;
use zcash_primitives::merkle_tree::{
read_frontier_v1, write_commitment_tree, write_frontier_v1, HashSer,
};
use crate::{bridge::ffi, orchard_bundle, streams::CppStream, wallet::Wallet};

View File

@ -1,19 +1,15 @@
use std::convert::TryInto;
use sapling::{
keys::OutgoingViewingKey,
note_encryption::{PreparedIncomingViewingKey, SaplingDomain},
value::ValueCommitment,
SaplingIvk,
};
use zcash_note_encryption::{
try_output_recovery_with_ovk, Domain, EphemeralKeyBytes, ShieldedOutput, ENC_CIPHERTEXT_SIZE,
};
use zcash_primitives::{
consensus::BlockHeight,
keys::OutgoingViewingKey,
memo::MemoBytes,
sapling::{
self,
note_encryption::{PreparedIncomingViewingKey, SaplingDomain},
value::ValueCommitment,
SaplingIvk,
},
};
use zcash_primitives::consensus::{sapling_zip212_enforcement, BlockHeight};
use crate::{bridge::ffi::SaplingShieldedOutput, params::Network};
@ -35,10 +31,9 @@ pub(crate) fn try_sapling_note_decryption(
.ok_or("Invalid Sapling ivk passed to wallet::try_sapling_note_decryption()")?;
let (note, recipient, memo) = sapling::note_encryption::try_sapling_note_decryption(
network,
BlockHeight::from_u32(height),
&ivk,
&output,
sapling_zip212_enforcement(network, BlockHeight::from_u32(height)),
)
.ok_or("Decryption failed")?;
@ -64,7 +59,10 @@ pub(crate) fn try_sapling_output_recovery(
ovk: [u8; 32],
output: SaplingShieldedOutput,
) -> Result<Box<DecryptedSaplingOutput>, &'static str> {
let domain = SaplingDomain::for_height(*network, BlockHeight::from_u32(height));
let domain = SaplingDomain::new(sapling_zip212_enforcement(
network,
BlockHeight::from_u32(height),
));
let cv = Option::from(ValueCommitment::from_bytes_not_small_order(&output.cv))
.ok_or("Invalid output.cv passed to wallet::try_sapling_note_decryption()")?;
@ -94,12 +92,12 @@ pub(crate) fn parse_and_prepare_sapling_ivk(
.into()
}
impl ShieldedOutput<SaplingDomain<Network>, ENC_CIPHERTEXT_SIZE> for SaplingShieldedOutput {
impl ShieldedOutput<SaplingDomain, ENC_CIPHERTEXT_SIZE> for SaplingShieldedOutput {
fn ephemeral_key(&self) -> EphemeralKeyBytes {
EphemeralKeyBytes(self.ephemeral_key)
}
fn cmstar_bytes(&self) -> <SaplingDomain<Network> as Domain>::ExtractedCommitmentBytes {
fn cmstar_bytes(&self) -> <SaplingDomain as Domain>::ExtractedCommitmentBytes {
self.cmu
}
@ -112,7 +110,7 @@ impl ShieldedOutput<SaplingDomain<Network>, ENC_CIPHERTEXT_SIZE> for SaplingShie
pub(crate) struct DecryptedSaplingOutput {
note: sapling::Note,
recipient: sapling::PaymentAddress,
memo: MemoBytes,
memo: [u8; 512],
}
impl DecryptedSaplingOutput {
@ -140,6 +138,6 @@ impl DecryptedSaplingOutput {
}
pub(crate) fn memo(&self) -> [u8; 512] {
*self.memo.as_array()
self.memo
}
}

View File

@ -1,3 +1,4 @@
use std::convert::TryInto;
use std::io::{Read, Write};
use std::slice;
use tracing::error;
@ -160,7 +161,7 @@ pub extern "C" fn orchard_incoming_viewing_key_decrypt_diversifier(
match key.diversifier_index(addr) {
Some(j) => {
j_ret.copy_from_slice(j.to_bytes());
j_ret.copy_from_slice(j.as_bytes());
true
}
None => false,
@ -327,7 +328,8 @@ pub extern "C" fn orchard_spending_key_for_account(
account_id: u32,
) -> *mut SpendingKey {
let seed = unsafe { slice::from_raw_parts(seed, seed_len) };
SpendingKey::from_zip32_seed(seed, bip44_coin_type, account_id)
let account = account_id.try_into().expect("account_id should be a u31");
SpendingKey::from_zip32_seed(seed, bip44_coin_type, account)
.map(|key| Box::into_raw(Box::new(key)))
.unwrap_or(std::ptr::null_mut())
}

View File

@ -2,37 +2,35 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or https://www.opensource.org/licenses/mit-license.php .
use std::convert::TryInto;
use std::io::{self, Read, Write};
use std::convert::{TryFrom, TryInto};
use std::io;
use std::mem;
use bellman::groth16::{prepare_verifying_key, Proof};
use bellman::groth16::Proof;
use bls12_381::Bls12;
use group::GroupEncoding;
use incrementalmerkletree::MerklePath;
use memuse::DynamicUsage;
use rand_core::OsRng;
use zcash_encoding::Vector;
use rand_core::{OsRng, RngCore};
use sapling::{
builder::BundleType,
circuit::{self, OutputParameters, SpendParameters},
keys::{OutgoingViewingKey, SpendAuthorizingKey},
note::ExtractedNoteCommitment,
prover::{OutputProver, SpendProver},
value::{NoteValue, ValueCommitTrapdoor, ValueCommitment},
zip32::ExtendedSpendingKey,
Anchor, Diversifier, MerklePath, Note, PaymentAddress, ProofGenerationKey, Rseed,
SaplingVerificationContext,
};
use zcash_primitives::{
keys::OutgoingViewingKey,
consensus::sapling_zip212_enforcement,
memo::MemoBytes,
merkle_tree::merkle_path_from_slice,
sapling::{
note::ExtractedNoteCommitment,
prover::TxProver,
redjubjub::{self, Signature},
value::{NoteValue, ValueCommitment},
Diversifier, Node, Note, PaymentAddress, ProofGenerationKey, Rseed,
NOTE_COMMITMENT_TREE_DEPTH,
},
transaction::{
components::{sapling, Amount},
components::{sapling as sapling_serialization, Amount},
txid::{BlockTxCommitmentDigester, TxIdDigester},
Authorized, Transaction, TransactionDigest,
},
zip32::ExtendedSpendingKey,
};
use zcash_proofs::sapling::{
self as sapling_proofs, SaplingProvingContext, SaplingVerificationContext,
};
use super::GROTH_PROOF_SIZE;
@ -50,10 +48,10 @@ mod zip32;
const SAPLING_TREE_DEPTH: usize = 32;
pub(crate) struct Spend(sapling::SpendDescription<sapling::Authorized>);
pub(crate) struct Spend(sapling::bundle::SpendDescription<sapling::bundle::Authorized>);
pub(crate) fn parse_v4_sapling_spend(bytes: &[u8]) -> Result<Box<Spend>, String> {
sapling::SpendDescription::read(&mut io::Cursor::new(bytes))
sapling_serialization::temporary_zcashd_read_spend_v4(&mut io::Cursor::new(bytes))
.map(Spend)
.map(Box::new)
.map_err(|e| format!("{}", e))
@ -73,7 +71,7 @@ impl Spend {
}
pub(crate) fn rk(&self) -> [u8; 32] {
self.0.rk().0.to_bytes()
(*self.0.rk()).into()
}
pub(crate) fn zkproof(&self) -> [u8; 192] {
@ -81,19 +79,14 @@ impl Spend {
}
pub(crate) fn spend_auth_sig(&self) -> [u8; 64] {
let mut ret = [0; 64];
self.0
.spend_auth_sig()
.write(&mut ret[..])
.expect("correct length");
ret
(*self.0.spend_auth_sig()).into()
}
}
pub(crate) struct Output(sapling::OutputDescription<[u8; 192]>);
pub(crate) struct Output(sapling::bundle::OutputDescription<[u8; 192]>);
pub(crate) fn parse_v4_sapling_output(bytes: &[u8]) -> Result<Box<Output>, String> {
sapling::OutputDescription::read(&mut io::Cursor::new(bytes))
sapling_serialization::temporary_zcashd_read_output_v4(&mut io::Cursor::new(bytes))
.map(Output)
.map(Box::new)
.map_err(|e| format!("{}", e))
@ -125,14 +118,13 @@ impl Output {
}
pub(crate) fn serialize_v4(&self, writer: &mut CppStream<'_>) -> Result<(), String> {
self.0
.write_v4(writer)
sapling_serialization::temporary_zcashd_write_output_v4(writer, &self.0)
.map_err(|e| format!("Failed to write v4 Sapling Output Description: {}", e))
}
}
#[derive(Clone)]
pub(crate) struct Bundle(pub(crate) Option<sapling::Bundle<sapling::Authorized>>);
pub(crate) struct Bundle(pub(crate) Option<sapling::Bundle<sapling::bundle::Authorized, Amount>>);
pub(crate) fn none_sapling_bundle() -> Box<Bundle> {
Box::new(Bundle(None))
@ -159,37 +151,15 @@ impl Bundle {
pub(crate) fn serialize_v4_components(
&self,
mut writer: &mut CppStream<'_>,
writer: &mut CppStream<'_>,
has_sapling: bool,
) -> Result<(), String> {
if has_sapling {
let mut write_v4 = || {
writer.write_all(
&self
.0
.as_ref()
.map_or(Amount::zero(), |b| *b.value_balance())
.to_i64_le_bytes(),
)?;
Vector::write(
&mut writer,
self.0.as_ref().map_or(&[], |b| b.shielded_spends()),
|w, e| e.write_v4(w),
)?;
Vector::write(
&mut writer,
self.0.as_ref().map_or(&[], |b| b.shielded_outputs()),
|w, e| e.write_v4(w),
)
};
write_v4().map_err(|e| format!("{}", e))?;
} else if self.0.is_some() {
return Err(
"Sapling components may not be present if Sapling is not active.".to_string(),
);
}
Ok(())
sapling_serialization::temporary_zcashd_write_v4_components(
writer,
self.0.as_ref(),
has_sapling,
)
.map_err(|e| format!("{}", e))
}
/// Serializes an authorized Sapling bundle to the given stream.
@ -200,7 +170,7 @@ impl Bundle {
.map_err(|e| format!("Failed to serialize Sapling bundle: {}", e))
}
pub(crate) fn inner(&self) -> Option<&sapling::Bundle<sapling::Authorized>> {
pub(crate) fn inner(&self) -> Option<&sapling::Bundle<sapling::bundle::Authorized, Amount>> {
self.0.as_ref()
}
@ -264,14 +234,11 @@ impl Bundle {
///
/// Panics if the bundle is not present.
pub(crate) fn binding_sig(&self) -> [u8; 64] {
let mut ret = [0; 64];
self.inner()
.expect("Bundle actions should have been checked to be non-empty")
.authorization()
.binding_sig
.write(&mut ret[..])
.expect("correct length");
ret
.into()
}
fn commitment<D: TransactionDigest<Authorized>>(&self, digester: D) -> D::SaplingDigest {
@ -281,8 +248,8 @@ impl Bundle {
pub(crate) struct BundleAssembler {
value_balance: Amount,
shielded_spends: Vec<sapling::SpendDescription<sapling::Authorized>>,
shielded_outputs: Vec<sapling::OutputDescription<[u8; 192]>>, // GROTH_PROOF_SIZE
shielded_spends: Vec<sapling::bundle::SpendDescription<sapling::bundle::Authorized>>,
shielded_outputs: Vec<sapling::bundle::OutputDescription<[u8; 192]>>, // GROTH_PROOF_SIZE
}
pub(crate) fn new_bundle_assembler() -> Box<BundleAssembler> {
@ -303,27 +270,11 @@ pub(crate) fn parse_v4_sapling_components(
impl BundleAssembler {
pub(crate) fn parse_v4_components(
mut reader: &mut CppStream<'_>,
reader: &mut CppStream<'_>,
has_sapling: bool,
) -> io::Result<Box<Self>> {
let (value_balance, shielded_spends, shielded_outputs) = if has_sapling {
let vb = {
let mut tmp = [0; 8];
reader.read_exact(&mut tmp)?;
Amount::from_i64_le_bytes(tmp).map_err(|_| {
io::Error::new(io::ErrorKind::InvalidData, "valueBalance out of range")
})?
};
#[allow(clippy::redundant_closure)]
let ss: Vec<sapling::SpendDescription<sapling::Authorized>> =
Vector::read(&mut reader, |r| sapling::SpendDescription::read(r))?;
#[allow(clippy::redundant_closure)]
let so: Vec<sapling::OutputDescription<sapling::GrothProofBytes>> =
Vector::read(&mut reader, |r| sapling::OutputDescription::read(r))?;
(vb, ss, so)
} else {
(Amount::zero(), vec![], vec![])
};
let (value_balance, shielded_spends, shielded_outputs) =
sapling_serialization::temporary_zcashd_read_v4_components(reader, has_sapling)?;
Ok(Box::new(Self {
value_balance,
@ -342,125 +293,119 @@ pub(crate) fn finish_bundle_assembly(
assembler: Box<BundleAssembler>,
binding_sig: [u8; 64],
) -> Box<Bundle> {
let binding_sig = redjubjub::Signature::read(&binding_sig[..]).expect("parsed elsewhere");
let binding_sig = redjubjub::Signature::from(binding_sig);
Box::new(Bundle(Some(sapling::Bundle::temporary_zcashd_from_parts(
Box::new(Bundle(sapling::Bundle::from_parts(
assembler.shielded_spends,
assembler.shielded_outputs,
assembler.value_balance,
sapling::Authorized { binding_sig },
))))
sapling::bundle::Authorized { binding_sig },
)))
}
pub(crate) struct StaticTxProver;
impl TxProver for StaticTxProver {
type SaplingProvingContext = SaplingProvingContext;
impl SpendProver for StaticTxProver {
type Proof = Proof<Bls12>;
fn new_sapling_proving_context(&self) -> Self::SaplingProvingContext {
SaplingProvingContext::new()
}
fn spend_proof(
&self,
ctx: &mut Self::SaplingProvingContext,
fn prepare_circuit(
proof_generation_key: ProofGenerationKey,
diversifier: Diversifier,
rseed: Rseed,
ar: jubjub::Fr,
value: u64,
value: NoteValue,
alpha: jubjub::Fr,
rcv: ValueCommitTrapdoor,
anchor: bls12_381::Scalar,
merkle_path: MerklePath<Node, NOTE_COMMITMENT_TREE_DEPTH>,
) -> Result<
(
[u8; GROTH_PROOF_SIZE],
ValueCommitment,
redjubjub::PublicKey,
),
(),
> {
let (proof, cv, rk) = ctx.spend_proof(
merkle_path: MerklePath,
) -> Option<circuit::Spend> {
SpendParameters::prepare_circuit(
proof_generation_key,
diversifier,
rseed,
ar,
value,
alpha,
rcv,
anchor,
merkle_path,
unsafe { SAPLING_SPEND_PARAMS.as_ref() }
.expect("Parameters not loaded: SAPLING_SPEND_PARAMS should have been initialized"),
&prepare_verifying_key(
unsafe { SAPLING_SPEND_VK.as_ref() }
.expect("Parameters not loaded: SAPLING_SPEND_VK should have been initialized"),
),
)?;
let mut zkproof = [0u8; GROTH_PROOF_SIZE];
proof
.write(&mut zkproof[..])
.expect("should be able to serialize a proof");
Ok((zkproof, cv, rk))
)
}
fn output_proof(
&self,
ctx: &mut Self::SaplingProvingContext,
esk: jubjub::Fr,
payment_address: PaymentAddress,
rcm: jubjub::Fr,
value: u64,
) -> ([u8; GROTH_PROOF_SIZE], ValueCommitment) {
let (proof, cv) = ctx.output_proof(
esk,
payment_address,
rcm,
value,
unsafe { SAPLING_OUTPUT_PARAMS.as_ref() }.expect(
"Parameters not loaded: SAPLING_OUTPUT_PARAMS should have been initialized",
),
);
let mut zkproof = [0u8; GROTH_PROOF_SIZE];
proof
.write(&mut zkproof[..])
.expect("should be able to serialize a proof");
(zkproof, cv)
fn create_proof<R: RngCore>(&self, circuit: circuit::Spend, rng: &mut R) -> Self::Proof {
unsafe { SAPLING_SPEND_PARAMS.as_ref() }
.expect("Parameters not loaded: SAPLING_SPEND_PARAMS should have been initialized")
.create_proof(circuit, rng)
}
fn binding_sig(
&self,
ctx: &mut Self::SaplingProvingContext,
value_balance: zcash_primitives::transaction::components::Amount,
sighash: &[u8; 32],
) -> Result<redjubjub::Signature, ()> {
ctx.binding_sig(value_balance, sighash)
fn encode_proof(proof: Self::Proof) -> sapling::bundle::GrothProofBytes {
SpendParameters::encode_proof(proof)
}
}
pub(crate) struct SaplingBuilder(sapling::builder::SaplingBuilder<Network>);
impl OutputProver for StaticTxProver {
type Proof = Proof<Bls12>;
pub(crate) fn new_sapling_builder(network: &Network, target_height: u32) -> Box<SaplingBuilder> {
Box::new(SaplingBuilder(sapling::builder::SaplingBuilder::new(
*network,
target_height.into(),
)))
fn prepare_circuit(
esk: jubjub::Fr,
payment_address: PaymentAddress,
rcm: jubjub::Fr,
value: NoteValue,
rcv: ValueCommitTrapdoor,
) -> circuit::Output {
OutputParameters::prepare_circuit(esk, payment_address, rcm, value, rcv)
}
fn create_proof<R: RngCore>(&self, circuit: circuit::Output, rng: &mut R) -> Self::Proof {
unsafe { SAPLING_OUTPUT_PARAMS.as_ref() }
.expect("Parameters not loaded: SAPLING_OUTPUT_PARAMS should have been initialized")
.create_proof(circuit, rng)
}
fn encode_proof(proof: Self::Proof) -> sapling::bundle::GrothProofBytes {
OutputParameters::encode_proof(proof)
}
}
pub(crate) struct SaplingBuilder {
builder: sapling::builder::Builder,
signing_keys: Vec<SpendAuthorizingKey>,
}
pub(crate) fn new_sapling_builder(
network: &Network,
target_height: u32,
anchor: [u8; 32],
coinbase: bool,
) -> Result<Box<SaplingBuilder>, String> {
let bundle_type = if coinbase {
BundleType::Coinbase
} else {
BundleType::DEFAULT
};
let anchor = Option::from(Anchor::from_bytes(anchor))
.ok_or_else(|| "Invalid Sapling anchor".to_owned())?;
Ok(Box::new(SaplingBuilder {
builder: sapling::builder::Builder::new(
sapling_zip212_enforcement(network, target_height.into()),
bundle_type,
anchor,
),
signing_keys: vec![],
}))
}
#[allow(clippy::boxed_local)]
pub(crate) fn build_sapling_bundle(
builder: Box<SaplingBuilder>,
target_height: u32,
) -> Result<Box<SaplingUnauthorizedBundle>, String> {
builder.build(target_height).map(Box::new)
builder.build().map(Box::new)
}
impl SaplingBuilder {
pub(crate) fn add_spend(
&mut self,
extsk: &[u8],
diversifier: [u8; 11],
recipient: [u8; 43],
value: u64,
rcm: [u8; 32],
@ -468,7 +413,6 @@ impl SaplingBuilder {
) -> Result<(), String> {
let extsk =
ExtendedSpendingKey::from_bytes(extsk).map_err(|_| "Invalid ExtSK".to_owned())?;
let diversifier = Diversifier(diversifier);
let recipient =
PaymentAddress::from_bytes(&recipient).ok_or("Invalid recipient address")?;
let value = NoteValue::from_raw(value);
@ -481,9 +425,12 @@ impl SaplingBuilder {
let merkle_path = merkle_path_from_slice(&merkle_path)
.map_err(|e| format!("Invalid Sapling Merkle path: {}", e))?;
self.0
.add_spend(OsRng, extsk, diversifier, note, merkle_path)
.map_err(|e| format!("Failed to add Sapling spend: {}", e))
self.builder
.add_spend(&extsk, note, merkle_path)
.map_err(|e| format!("Failed to add Sapling spend: {}", e))?;
self.signing_keys.push(extsk.expsk.ask);
Ok(())
}
pub(crate) fn add_recipient(
@ -496,28 +443,39 @@ impl SaplingBuilder {
let ovk = Some(OutgoingViewingKey(ovk));
let to = PaymentAddress::from_bytes(&to).ok_or("Invalid recipient address")?;
let value = NoteValue::from_raw(value);
let memo = MemoBytes::from_bytes(&memo).map_err(|e| format!("Invalid memo: {}", e))?;
let _ = MemoBytes::from_bytes(&memo).map_err(|e| format!("Invalid memo: {}", e))?;
self.0
.add_output(OsRng, ovk, to, value, memo)
self.builder
.add_output(ovk, to, value, Some(memo))
.map_err(|e| format!("Failed to add Sapling recipient: {}", e))
}
fn build(self, target_height: u32) -> Result<SaplingUnauthorizedBundle, String> {
fn build(self) -> Result<SaplingUnauthorizedBundle, String> {
let Self {
builder,
signing_keys,
} = self;
let prover = crate::sapling::StaticTxProver;
let mut ctx = prover.new_sapling_proving_context();
let rng = OsRng;
let bundle = self
.0
.build(&prover, &mut ctx, rng, target_height.into(), None)
.map_err(|e| format!("Failed to build Sapling bundle: {}", e))?;
Ok(SaplingUnauthorizedBundle { bundle, ctx })
let bundle = builder
.build::<StaticTxProver, StaticTxProver, _, Amount>(rng)
.map_err(|e| format!("Failed to build Sapling bundle: {}", e))?
.map(|(bundle, _)| bundle.create_proofs(&prover, &prover, rng, ()));
Ok(SaplingUnauthorizedBundle {
bundle,
signing_keys,
})
}
}
pub(crate) struct SaplingUnauthorizedBundle {
pub(crate) bundle: Option<sapling::Bundle<sapling::builder::Unauthorized>>,
ctx: SaplingProvingContext,
pub(crate) bundle: Option<
sapling::Bundle<
sapling::builder::InProgress<sapling::builder::Proven, sapling::builder::Unsigned>,
Amount,
>,
>,
signing_keys: Vec<SpendAuthorizingKey>,
}
pub(crate) fn apply_sapling_bundle_signatures(
@ -529,12 +487,14 @@ pub(crate) fn apply_sapling_bundle_signatures(
impl SaplingUnauthorizedBundle {
fn apply_signatures(self, sighash_bytes: [u8; 32]) -> Result<crate::sapling::Bundle, String> {
let SaplingUnauthorizedBundle { bundle, mut ctx } = self;
let SaplingUnauthorizedBundle {
bundle,
signing_keys,
} = self;
let authorized = if let Some(bundle) = bundle {
let prover = crate::sapling::StaticTxProver;
let (authorized, _) = bundle
.apply_signatures(&prover, &mut ctx, &mut OsRng, &sighash_bytes)
let authorized = bundle
.apply_signatures(OsRng, sighash_bytes, &signing_keys)
.map_err(|e| format!("Failed to apply signatures to Sapling bundle: {}", e))?;
Some(authorized)
} else {
@ -548,10 +508,7 @@ impl SaplingUnauthorizedBundle {
pub(crate) struct Verifier(SaplingVerificationContext);
pub(crate) fn init_verifier() -> Box<Verifier> {
// We consider ZIP 216 active all of the time because blocks prior to NU5
// activation (on mainnet and testnet) did not contain Sapling transactions
// that violated its canonicity rule.
Box::new(Verifier(SaplingVerificationContext::new(true)))
Box::new(Verifier(SaplingVerificationContext::new()))
}
impl Verifier {
@ -580,16 +537,13 @@ impl Verifier {
};
// Deserialize rk
let rk = match redjubjub::PublicKey::read(&rk[..]) {
let rk = match redjubjub::VerificationKey::try_from(*rk) {
Ok(p) => p,
Err(_) => return false,
};
// Deserialize the signature
let spend_auth_sig = match Signature::read(&spend_auth_sig[..]) {
Ok(sig) => sig,
Err(_) => return false,
};
let spend_auth_sig = redjubjub::Signature::from(*spend_auth_sig);
// Deserialize the proof
let zkproof = match Proof::read(&zkproof[..]) {
@ -605,10 +559,9 @@ impl Verifier {
sighash_value,
spend_auth_sig,
zkproof,
&prepare_verifying_key(
unsafe { SAPLING_SPEND_VK.as_ref() }
.expect("Parameters not loaded: SAPLING_SPEND_VK should have been initialized"),
),
&unsafe { SAPLING_SPEND_VK.as_ref() }
.expect("Parameters not loaded: SAPLING_SPEND_VK should have been initialized")
.prepare(),
)
}
@ -648,11 +601,9 @@ impl Verifier {
cmu,
epk,
zkproof,
&prepare_verifying_key(
unsafe { SAPLING_OUTPUT_VK.as_ref() }.expect(
"Parameters not loaded: SAPLING_OUTPUT_VK should have been initialized",
),
),
&unsafe { SAPLING_OUTPUT_VK.as_ref() }
.expect("Parameters not loaded: SAPLING_OUTPUT_VK should have been initialized")
.prepare(),
)
}
@ -668,10 +619,7 @@ impl Verifier {
};
// Deserialize the signature
let binding_sig = match Signature::read(&binding_sig[..]) {
Ok(sig) => sig,
Err(_) => return false,
};
let binding_sig = redjubjub::Signature::from(*binding_sig);
self.0
.final_check(value_balance, sighash_value, binding_sig)
@ -679,7 +627,7 @@ impl Verifier {
}
struct BatchValidatorInner {
validator: sapling_proofs::BatchValidator,
validator: sapling::BatchValidator,
queued_entries: CacheEntries,
}
@ -687,7 +635,7 @@ pub(crate) struct BatchValidator(Option<BatchValidatorInner>);
pub(crate) fn init_batch_validator(cache_store: bool) -> Box<BatchValidator> {
Box::new(BatchValidator(Some(BatchValidatorInner {
validator: sapling_proofs::BatchValidator::new(),
validator: sapling::BatchValidator::new(),
queued_entries: CacheEntries::new(cache_store),
})))
}

View File

@ -5,16 +5,14 @@ use group::{cofactor::CofactorGroup, GroupEncoding};
use incrementalmerkletree::Hashable;
use rand_core::{OsRng, RngCore};
use zcash_primitives::{
use sapling::{
constants::{CRH_IVK_PERSONALIZATION, PROOF_GENERATION_KEY_GENERATOR, SPENDING_KEY_GENERATOR},
merkle_tree::HashSer,
sapling::{
merkle_hash,
note::{ExtractedNoteCommitment, NoteCommitment},
value::NoteValue,
Diversifier, Node, Note, NullifierDerivingKey, PaymentAddress, Rseed,
},
merkle_hash,
note::{ExtractedNoteCommitment, NoteCommitment},
value::NoteValue,
Diversifier, Node, Note, NullifierDerivingKey, PaymentAddress, Rseed,
};
use zcash_primitives::merkle_tree::HashSer;
use crate::de_ct;

View File

@ -1,7 +1,9 @@
use zcash_primitives::{
sapling::{keys::FullViewingKey, Diversifier},
zip32::{self, sapling_address, sapling_derive_internal_fvk, sapling_find_address},
use sapling::{
keys::FullViewingKey,
zip32::{sapling_address, sapling_derive_internal_fvk, sapling_find_address},
Diversifier,
};
use zcash_primitives::zip32;
#[cxx::bridge]
mod ffi {
@ -20,7 +22,6 @@ mod ffi {
fn xsk_master(seed: &[u8]) -> [u8; 169];
fn xsk_derive(xsk_parent: &[u8; 169], i: u32) -> [u8; 169];
fn xsk_derive_internal(xsk_external: &[u8; 169]) -> [u8; 169];
fn xfvk_derive(xfvk_parent: &[u8; 169], i: u32) -> Result<[u8; 169]>;
fn derive_internal_fvk(fvk: &[u8; 96], dk: [u8; 32]) -> FfiFullViewingKey;
fn address(fvk: &[u8; 96], dk: [u8; 32], j: [u8; 11]) -> Result<[u8; 43]>;
fn find_address(fvk: &[u8; 96], dk: [u8; 32], j: [u8; 11]) -> Result<FfiPaymentAddress>;
@ -30,7 +31,7 @@ mod ffi {
/// Derives the master ExtendedSpendingKey from a seed.
fn xsk_master(seed: &[u8]) -> [u8; 169] {
let xsk = zip32::ExtendedSpendingKey::master(seed);
let xsk = sapling::zip32::ExtendedSpendingKey::master(seed);
let mut xsk_master = [0; 169];
xsk.write(&mut xsk_master[..])
@ -40,9 +41,9 @@ fn xsk_master(seed: &[u8]) -> [u8; 169] {
/// Derive a child ExtendedSpendingKey from a parent.
fn xsk_derive(xsk_parent: &[u8; 169], i: u32) -> [u8; 169] {
let xsk_parent =
zip32::ExtendedSpendingKey::read(&xsk_parent[..]).expect("valid ExtendedSpendingKey");
let i = zip32::ChildIndex::from_index(i);
let xsk_parent = sapling::zip32::ExtendedSpendingKey::read(&xsk_parent[..])
.expect("valid ExtendedSpendingKey");
let i = zip32::ChildIndex::from_index(i).expect("non-hardened derivation is unsupported");
let xsk = xsk_parent.derive_child(i);
@ -55,8 +56,8 @@ fn xsk_derive(xsk_parent: &[u8; 169], i: u32) -> [u8; 169] {
/// Derive the Sapling internal spending key from the external extended
/// spending key
fn xsk_derive_internal(xsk_external: &[u8; 169]) -> [u8; 169] {
let xsk_external =
zip32::ExtendedSpendingKey::read(&xsk_external[..]).expect("valid ExtendedSpendingKey");
let xsk_external = sapling::zip32::ExtendedSpendingKey::read(&xsk_external[..])
.expect("valid ExtendedSpendingKey");
let xsk_internal = xsk_external.derive_internal();
@ -67,26 +68,10 @@ fn xsk_derive_internal(xsk_external: &[u8; 169]) -> [u8; 169] {
xsk_internal_ret
}
/// Derive a child ExtendedFullViewingKey from a parent.
fn xfvk_derive(xfvk_parent: &[u8; 169], i: u32) -> Result<[u8; 169], String> {
let xfvk_parent = zip32::ExtendedFullViewingKey::read(&xfvk_parent[..])
.expect("valid ExtendedFullViewingKey");
let i = zip32::ChildIndex::from_index(i);
let xfvk = xfvk_parent
.derive_child(i)
.map_err(|()| "Cannot derive hardened xfvk".to_string())?;
let mut xfvk_i = [0; 169];
xfvk.write(&mut xfvk_i[..])
.expect("should be able to serialize an ExtendedFullViewingKey");
Ok(xfvk_i)
}
/// Derive the Sapling internal full viewing key from the corresponding external full viewing key
fn derive_internal_fvk(fvk: &[u8; 96], dk: [u8; 32]) -> ffi::FfiFullViewingKey {
let fvk = FullViewingKey::read(&fvk[..]).expect("valid Sapling FullViewingKey");
let dk = zip32::sapling::DiversifierKey::from_bytes(dk);
let dk = sapling::zip32::DiversifierKey::from_bytes(dk);
let (fvk_internal, dk_internal) = sapling_derive_internal_fvk(&fvk, &dk);
@ -99,8 +84,8 @@ fn derive_internal_fvk(fvk: &[u8; 96], dk: [u8; 32]) -> ffi::FfiFullViewingKey {
/// Derive a PaymentAddress from an ExtendedFullViewingKey.
fn address(fvk: &[u8; 96], dk: [u8; 32], j: [u8; 11]) -> Result<[u8; 43], String> {
let fvk = FullViewingKey::read(&fvk[..]).expect("valid Sapling FullViewingKey");
let dk = zip32::sapling::DiversifierKey::from_bytes(dk);
let j = zip32::DiversifierIndex(j);
let dk = sapling::zip32::DiversifierKey::from_bytes(dk);
let j = zip32::DiversifierIndex::from(j);
sapling_address(&fvk, &dk, j)
.ok_or_else(|| "Diversifier index does not produce a valid diversifier".to_string())
@ -114,21 +99,21 @@ fn find_address(
j: [u8; 11],
) -> Result<ffi::FfiPaymentAddress, String> {
let fvk = FullViewingKey::read(&fvk[..]).expect("valid Sapling FullViewingKey");
let dk = zip32::sapling::DiversifierKey::from_bytes(dk);
let j = zip32::DiversifierIndex(j);
let dk = sapling::zip32::DiversifierKey::from_bytes(dk);
let j = zip32::DiversifierIndex::from(j);
sapling_find_address(&fvk, &dk, j)
.ok_or_else(|| "No valid diversifiers at or above given index".to_string())
.map(|(j, addr)| ffi::FfiPaymentAddress {
j: j.0,
j: *j.as_bytes(),
addr: addr.to_bytes(),
})
}
fn diversifier_index(dk: [u8; 32], d: [u8; 11]) -> [u8; 11] {
let dk = zip32::sapling::DiversifierKey::from_bytes(dk);
let dk = sapling::zip32::DiversifierKey::from_bytes(dk);
let diversifier = Diversifier(d);
let j = dk.diversifier_index(&diversifier);
j.0
*j.as_bytes()
}

View File

@ -1,10 +1,10 @@
use std::convert::TryFrom;
use group::{ff::Field, Group, GroupEncoding};
use rand::{thread_rng, Rng};
use sapling::value::ValueCommitment;
use zcash_note_encryption::EphemeralKeyBytes;
use zcash_primitives::{
sapling::{self, redjubjub, value::ValueCommitment},
transaction::components::{sapling as sapling_tx, Amount},
};
use zcash_primitives::transaction::components::Amount;
pub(crate) fn test_only_invalid_sapling_bundle(
spends: usize,
@ -27,14 +27,17 @@ pub(crate) fn test_only_invalid_sapling_bundle(
.unwrap();
let anchor = jubjub::Base::random(&mut rng);
let nullifier = sapling::Nullifier(rng.gen());
let rk = redjubjub::PublicKey(jubjub::ExtendedPoint::random(&mut rng));
let rk = redjubjub::VerificationKey::try_from(
jubjub::ExtendedPoint::random(&mut rng).to_bytes(),
)
.unwrap();
let zkproof = gen_array(&mut rng);
let spend_auth_sig = {
let tmp = gen_array::<_, 64>(&mut rng);
redjubjub::Signature::read(&tmp[..]).unwrap()
redjubjub::Signature::from(tmp)
};
sapling_tx::SpendDescription::temporary_zcashd_from_parts(
sapling::bundle::SpendDescription::from_parts(
cv,
anchor,
nullifier,
@ -61,7 +64,7 @@ pub(crate) fn test_only_invalid_sapling_bundle(
let out_ciphertext = gen_array(&mut rng);
let zkproof = gen_array(&mut rng);
sapling_tx::OutputDescription::temporary_zcashd_from_parts(
sapling::bundle::OutputDescription::from_parts(
cv,
cmu,
ephemeral_key,
@ -74,16 +77,16 @@ pub(crate) fn test_only_invalid_sapling_bundle(
let binding_sig = {
let tmp = gen_array::<_, 64>(&mut rng);
redjubjub::Signature::read(&tmp[..]).unwrap()
redjubjub::Signature::from(tmp)
};
let bundle = sapling_tx::Bundle::temporary_zcashd_from_parts(
let bundle = sapling::Bundle::from_parts(
spends,
outputs,
Amount::from_i64(value_balance).unwrap(),
sapling_tx::Authorized { binding_sig },
sapling::bundle::Authorized { binding_sig },
);
Box::new(crate::sapling::Bundle(Some(bundle)))
Box::new(crate::sapling::Bundle(bundle))
}
pub(crate) fn test_only_replace_sapling_nullifier(
@ -92,18 +95,18 @@ pub(crate) fn test_only_replace_sapling_nullifier(
nullifier: [u8; 32],
) {
if let Some(bundle) = bundle.0.as_mut() {
*bundle = sapling_tx::Bundle::temporary_zcashd_from_parts(
*bundle = sapling::Bundle::from_parts(
bundle
.shielded_spends()
.iter()
.enumerate()
.map(|(i, spend)| {
if i == spend_index {
sapling_tx::SpendDescription::temporary_zcashd_from_parts(
sapling::bundle::SpendDescription::from_parts(
spend.cv().clone(),
*spend.anchor(),
sapling::Nullifier(nullifier),
spend.rk().clone(),
*spend.rk(),
*spend.zkproof(),
*spend.spend_auth_sig(),
)
@ -116,6 +119,7 @@ pub(crate) fn test_only_replace_sapling_nullifier(
*bundle.value_balance(),
*bundle.authorization(),
)
.expect("Prior bundle was valid");
}
}
@ -127,7 +131,7 @@ pub(crate) fn test_only_replace_sapling_output_parts(
out_ciphertext: [u8; 80],
) {
if let Some(bundle) = bundle.0.as_mut() {
*bundle = sapling_tx::Bundle::temporary_zcashd_from_parts(
*bundle = sapling::Bundle::from_parts(
bundle.shielded_spends().to_vec(),
bundle
.shielded_outputs()
@ -135,7 +139,7 @@ pub(crate) fn test_only_replace_sapling_output_parts(
.enumerate()
.map(|(i, output)| {
if i == output_index {
sapling_tx::OutputDescription::temporary_zcashd_from_parts(
sapling::bundle::OutputDescription::from_parts(
output.cv().clone(),
sapling::note::ExtractedNoteCommitment::from_bytes(&cmu).unwrap(),
output.ephemeral_key().clone(),
@ -151,5 +155,6 @@ pub(crate) fn test_only_replace_sapling_output_parts(
*bundle.value_balance(),
*bundle.authorization(),
)
.expect("Prior bundle was valid");
}
}

View File

@ -1,7 +1,7 @@
use group::GroupEncoding;
use zcash_primitives::{
constants::SPENDING_KEY_GENERATOR,
sapling::{Diversifier, Nullifier, ProofGenerationKey, Rseed},
use sapling::{
constants::SPENDING_KEY_GENERATOR, keys::SpendValidatingKey, value::NoteValue, Diversifier,
Nullifier, ProofGenerationKey, Rseed,
};
use crate::sapling::spec::{ask_to_ak, check_diversifier, crh_ivk, ivk_to_pkd, nsk_to_nk};
@ -661,7 +661,10 @@ fn key_components() {
assert_eq!(&ak, &tv.ak);
}
let pgk = ProofGenerationKey { ak, nsk };
let pgk = ProofGenerationKey {
ak: SpendValidatingKey::temporary_zcash_from_bytes(&ak.to_bytes()).unwrap(),
nsk,
};
let fvk = pgk.to_viewing_key();
assert_eq!(&fvk.nk.0.to_bytes(), &tv.nk);
{
@ -686,7 +689,7 @@ fn key_components() {
}
let note_r = jubjub::Scalar::from_bytes(&tv.note_r).unwrap();
let note = addr.create_note(tv.note_v, Rseed::BeforeZip212(note_r));
let note = addr.create_note(NoteValue::from_raw(tv.note_v), Rseed::BeforeZip212(note_r));
assert_eq!(&note.cmu().to_bytes(), &tv.note_cm);
assert_eq!(note.nf(&fvk.nk, tv.note_pos), Nullifier(tv.note_nf));

View File

@ -1,5 +1,5 @@
use group::GroupEncoding;
use zcash_primitives::constants::{
use sapling::constants::{
NOTE_COMMITMENT_RANDOMNESS_GENERATOR, NULLIFIER_POSITION_GENERATOR,
PROOF_GENERATION_KEY_GENERATOR, SPENDING_KEY_GENERATOR, VALUE_COMMITMENT_RANDOMNESS_GENERATOR,
VALUE_COMMITMENT_VALUE_GENERATOR,

View File

@ -1,7 +1,4 @@
use zcash_primitives::{
constants::SPENDING_KEY_GENERATOR,
sapling::redjubjub::{PrivateKey, PublicKey, Signature},
};
use std::convert::TryFrom;
#[test]
fn redjubjub_signatures() {
@ -16,7 +13,7 @@ fn redjubjub_signatures() {
rsig: [u8; 64],
}
// From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/sapling_signatures.py
// From https://github.com/zcash/zcash-test-vectors/blob/master/zcash_test_vectors/sapling/redjubjub.py
let test_vectors = vec![
TestVector {
sk: [
@ -50,18 +47,18 @@ fn redjubjub_signatures() {
0x00, 0x00, 0x00, 0x00,
],
sig: [
0xea, 0xa0, 0x57, 0x47, 0x6b, 0x4a, 0xb4, 0x82, 0x28, 0x8b, 0x93, 0xdf, 0x8f, 0xe0,
0xc5, 0xce, 0x9d, 0x78, 0x83, 0x67, 0xf2, 0xbe, 0x55, 0x1b, 0x7f, 0x7a, 0x82, 0xa6,
0xdb, 0x36, 0x04, 0x68, 0xde, 0xb9, 0xa7, 0xb7, 0xaf, 0xaa, 0xdf, 0xec, 0xa6, 0xf4,
0x81, 0x19, 0x3d, 0xc6, 0x57, 0x57, 0x47, 0xf6, 0x0a, 0x1a, 0x8a, 0x48, 0xff, 0x0a,
0xd7, 0x0c, 0xf8, 0xcb, 0x8d, 0x52, 0x8e, 0x08,
0xdc, 0xa3, 0xbb, 0x2c, 0xb8, 0xf0, 0x48, 0xcc, 0xab, 0x10, 0xae, 0xd7, 0x75, 0x46,
0xc1, 0xdb, 0xb1, 0x0c, 0xc4, 0xfb, 0x15, 0xab, 0x02, 0xac, 0xae, 0xf9, 0x44, 0xdd,
0xab, 0x8b, 0x67, 0x22, 0x54, 0x5f, 0xda, 0x4c, 0x62, 0x04, 0x6d, 0x69, 0xd9, 0x8f,
0x92, 0x2f, 0x4e, 0x8c, 0x21, 0x0b, 0xc4, 0x7b, 0x4f, 0xdd, 0xe0, 0xa1, 0x94, 0x71,
0x79, 0x80, 0x4c, 0x1a, 0xce, 0x56, 0x90, 0x05,
],
rsig: [
0xd5, 0x6f, 0x0d, 0x91, 0xaf, 0x42, 0x4e, 0x1f, 0x1c, 0x7f, 0xb8, 0x6b, 0xa4, 0xee,
0xd1, 0x43, 0xcc, 0x16, 0x66, 0x0c, 0x5f, 0xe8, 0xd7, 0xdc, 0x0d, 0x28, 0x4b, 0xcf,
0x65, 0xa0, 0x89, 0xe9, 0x8b, 0x56, 0x1f, 0x9f, 0x20, 0x1a, 0x63, 0x3d, 0x70, 0x0c,
0xd3, 0x98, 0x1e, 0x8c, 0xac, 0x07, 0xb5, 0xa8, 0x7e, 0xfa, 0x61, 0x86, 0x06, 0x2d,
0xd8, 0xe5, 0xd6, 0x32, 0x5e, 0x7b, 0x82, 0x02,
0x70, 0xc2, 0x84, 0x50, 0x4e, 0x90, 0xf0, 0x00, 0x8e, 0x8e, 0xd2, 0x20, 0x8f, 0x49,
0x69, 0x72, 0x7a, 0x41, 0x5e, 0xc3, 0x10, 0x2c, 0x29, 0x9e, 0x39, 0x8b, 0x6c, 0x16,
0x57, 0x2b, 0xd9, 0x64, 0x3e, 0xe1, 0x01, 0x17, 0x66, 0x68, 0x1e, 0x40, 0x6e, 0xe6,
0xbe, 0xe3, 0xd0, 0x3e, 0xe8, 0xf2, 0x71, 0x76, 0xe3, 0x2f, 0xba, 0xbd, 0xde, 0xd2,
0x0b, 0x0d, 0x17, 0x86, 0xa4, 0xee, 0x18, 0x01,
],
},
TestVector {
@ -96,18 +93,18 @@ fn redjubjub_signatures() {
0x01, 0x01, 0x01, 0x01,
],
sig: [
0x22, 0x35, 0x54, 0x94, 0xa8, 0x31, 0x6a, 0xb1, 0x34, 0x73, 0xf5, 0x5e, 0x62, 0x66,
0xb2, 0xfb, 0x41, 0x97, 0x31, 0x5e, 0xac, 0x62, 0xf8, 0x2c, 0xc7, 0x3d, 0xca, 0xca,
0x19, 0x90, 0x90, 0xf1, 0x5b, 0xe1, 0x98, 0xce, 0x7d, 0x3f, 0x9f, 0xc8, 0xff, 0xf5,
0x50, 0xe1, 0x08, 0x81, 0xec, 0x49, 0xff, 0x27, 0x36, 0x9e, 0x7d, 0x4f, 0xd9, 0x64,
0x01, 0x53, 0x49, 0x2a, 0x0a, 0x06, 0x25, 0x08,
0xb5, 0xa1, 0xf3, 0x2d, 0x3d, 0x50, 0xfc, 0x73, 0x8b, 0x5c, 0x3b, 0x4e, 0x99, 0x60,
0x72, 0x9c, 0xe4, 0x31, 0x6b, 0xa7, 0x72, 0x1a, 0x12, 0x68, 0x66, 0x04, 0xfe, 0xba,
0x6b, 0xd7, 0x48, 0x45, 0x00, 0x70, 0xcb, 0x92, 0x24, 0x06, 0xfd, 0xfc, 0x5d, 0x60,
0xde, 0xa9, 0xbe, 0x3a, 0x52, 0x6a, 0x16, 0xcf, 0xeb, 0x87, 0x77, 0x79, 0xfb, 0x78,
0x2d, 0x5d, 0x41, 0x39, 0x5b, 0x45, 0x5f, 0x04,
],
rsig: [
0xf4, 0xb8, 0x94, 0xba, 0x84, 0xce, 0x1e, 0xc3, 0x8a, 0x63, 0x15, 0x2f, 0xc4, 0x09,
0xf9, 0x47, 0xd6, 0x1a, 0xbb, 0x1f, 0x48, 0x91, 0x63, 0x6b, 0xc3, 0xee, 0x19, 0xef,
0x6d, 0x4b, 0x30, 0xc0, 0xfd, 0x22, 0x86, 0x6b, 0x84, 0xff, 0xbc, 0x7e, 0x2a, 0x78,
0xc4, 0x3f, 0x57, 0x83, 0xd2, 0xd2, 0xea, 0xd0, 0x78, 0x59, 0x55, 0x03, 0x74, 0x43,
0xc2, 0xf4, 0xd5, 0x2f, 0x78, 0x5e, 0xee, 0x07,
0x5a, 0x5a, 0x20, 0xd2, 0x00, 0xef, 0xdd, 0xd4, 0x98, 0xdf, 0xae, 0x2a, 0x9e, 0xf8,
0xcf, 0x01, 0x28, 0x1a, 0x89, 0x19, 0x01, 0x8a, 0x82, 0x4c, 0xc7, 0xa4, 0x98, 0x3b,
0x9a, 0x0d, 0x4a, 0x06, 0xff, 0x17, 0x20, 0x79, 0xe0, 0x13, 0xd4, 0x2a, 0x2a, 0x3a,
0x88, 0xa6, 0x52, 0x0c, 0x86, 0xfc, 0xe3, 0xb9, 0x8e, 0x1e, 0xfa, 0xa3, 0x25, 0x83,
0x2a, 0x6a, 0x56, 0x58, 0xd8, 0xdd, 0x7c, 0x0a,
],
},
TestVector {
@ -142,18 +139,18 @@ fn redjubjub_signatures() {
0x02, 0x02, 0x02, 0x02,
],
sig: [
0xdd, 0x65, 0x21, 0x01, 0x4d, 0xff, 0x70, 0x6e, 0x3a, 0x38, 0x52, 0x7a, 0x86, 0xb6,
0xc1, 0x6e, 0x94, 0x14, 0x80, 0xe7, 0x33, 0xef, 0xf7, 0x9e, 0xbe, 0x0c, 0x43, 0x03,
0x79, 0xd7, 0x57, 0x04, 0x9d, 0xb7, 0x90, 0xcd, 0x5e, 0x14, 0x44, 0x7c, 0x38, 0x6f,
0x5f, 0xcb, 0x41, 0x9f, 0x27, 0xc4, 0x41, 0x3f, 0x35, 0x88, 0xfa, 0x21, 0x42, 0xd2,
0xcf, 0xba, 0xed, 0x08, 0x2c, 0xc6, 0xdb, 0x07,
0x1f, 0x3e, 0x8a, 0x94, 0x31, 0x0c, 0x20, 0x71, 0xa7, 0x0f, 0x9d, 0xf5, 0xe7, 0x9a,
0xa9, 0xe8, 0x48, 0x5d, 0xec, 0xcb, 0x17, 0x8b, 0xdf, 0xf9, 0x80, 0x5f, 0xcb, 0xe6,
0xf7, 0xd5, 0x51, 0xee, 0xe3, 0xc3, 0x54, 0x2c, 0xa7, 0x5c, 0x9d, 0x8d, 0x4a, 0xdc,
0x54, 0xd7, 0x2c, 0x3d, 0xbe, 0x28, 0x62, 0x6d, 0x20, 0x78, 0x5b, 0xb7, 0xf5, 0x88,
0xc1, 0xa5, 0x82, 0xb8, 0x93, 0xdb, 0xb6, 0x01,
],
rsig: [
0xd8, 0x94, 0x45, 0xcb, 0x9b, 0xd1, 0x03, 0x35, 0x69, 0x23, 0x1d, 0xd6, 0x28, 0xaa,
0x62, 0x81, 0x09, 0xfe, 0x93, 0x50, 0x2b, 0xf2, 0x2f, 0x9a, 0x5f, 0x37, 0xb1, 0x4e,
0x51, 0x7f, 0x9a, 0x20, 0x54, 0xae, 0xe3, 0xc8, 0x1b, 0x60, 0xb3, 0xf0, 0x55, 0x1e,
0x32, 0xf7, 0x93, 0x5a, 0xbc, 0x2f, 0x37, 0xb9, 0x9a, 0xb3, 0xec, 0x99, 0x68, 0x02,
0xef, 0xd6, 0x50, 0x69, 0xe1, 0x28, 0x12, 0x08,
0xd1, 0x36, 0x21, 0x4c, 0x5d, 0x52, 0x8e, 0xa3, 0xd4, 0xcb, 0x7b, 0x63, 0x1a, 0x6b,
0xb0, 0x36, 0x06, 0x49, 0x73, 0xa1, 0x08, 0xb7, 0x33, 0xa5, 0xe3, 0xa4, 0x52, 0xab,
0x52, 0xa6, 0x59, 0xe5, 0x67, 0xcb, 0x55, 0xd2, 0x64, 0x4e, 0x74, 0xb6, 0xe8, 0x42,
0x6f, 0x2a, 0x7d, 0xd2, 0xa0, 0x4d, 0x2d, 0xda, 0x49, 0x35, 0xcc, 0x38, 0x20, 0xb7,
0x7a, 0x9c, 0x1a, 0xb6, 0x19, 0x86, 0x3c, 0x05,
],
},
TestVector {
@ -188,18 +185,18 @@ fn redjubjub_signatures() {
0x03, 0x03, 0x03, 0x03,
],
sig: [
0x72, 0x79, 0xa7, 0x5c, 0x01, 0x36, 0x75, 0xb3, 0x29, 0x84, 0xe5, 0xc7, 0x3a, 0x98,
0x91, 0xeb, 0xf0, 0xb2, 0x29, 0xb1, 0x6e, 0x62, 0x35, 0xba, 0x36, 0xdf, 0xa1, 0xb5,
0xa1, 0x0c, 0x5e, 0x44, 0x57, 0x81, 0x91, 0x89, 0x7c, 0x06, 0xb8, 0x52, 0x4a, 0x26,
0x74, 0xaa, 0x7a, 0x0c, 0x8c, 0x23, 0x5f, 0x52, 0xd3, 0x3a, 0xc9, 0x2c, 0x70, 0x56,
0xb2, 0xbe, 0x95, 0x3c, 0x3f, 0xaa, 0x3d, 0x07,
0x12, 0xc7, 0x8d, 0xdd, 0x20, 0xd3, 0x0a, 0x61, 0xf8, 0x93, 0x0c, 0x6f, 0xe0, 0x85,
0x0f, 0xd1, 0x12, 0xbb, 0x7b, 0xe8, 0x8b, 0x12, 0x38, 0xea, 0x33, 0xd6, 0xbe, 0xf8,
0x81, 0xc1, 0x02, 0xd1, 0x04, 0xaa, 0x36, 0x54, 0x4a, 0x78, 0x47, 0x1c, 0x9e, 0x28,
0x42, 0xe6, 0xfd, 0x42, 0x55, 0x83, 0x46, 0xcf, 0xf4, 0x31, 0x27, 0x03, 0x26, 0x66,
0xeb, 0x11, 0x6f, 0x44, 0x2a, 0x28, 0x48, 0x0c,
],
rsig: [
0xaa, 0xd4, 0x82, 0x8c, 0xb3, 0x42, 0xcf, 0x09, 0xb0, 0x0e, 0x30, 0x2c, 0xbb, 0xe7,
0xcc, 0x3e, 0x95, 0xfe, 0x1f, 0xf8, 0x28, 0x74, 0x8e, 0x5f, 0x5b, 0xc6, 0x9c, 0xbf,
0xde, 0x6e, 0x27, 0x22, 0xd7, 0x64, 0x35, 0x68, 0x7e, 0x85, 0x0c, 0xd3, 0x07, 0xa9,
0xc1, 0x82, 0xec, 0x10, 0xe6, 0x88, 0x1d, 0xd6, 0x5e, 0xed, 0xc1, 0x1f, 0xa7, 0xb4,
0x6d, 0xe3, 0xa7, 0x19, 0x59, 0xce, 0xc0, 0x02,
0x01, 0xba, 0xaa, 0x26, 0x27, 0x4c, 0x14, 0x9a, 0xcf, 0x12, 0xe1, 0xcc, 0xf5, 0x50,
0x7d, 0x56, 0x79, 0x04, 0x82, 0xf0, 0x67, 0xe5, 0xc9, 0x2b, 0x32, 0x19, 0xad, 0x6b,
0xf9, 0x11, 0x18, 0xcc, 0x3f, 0xce, 0x8d, 0x2a, 0x23, 0x19, 0x8a, 0x3b, 0x29, 0x0a,
0x7b, 0xf6, 0x8c, 0x2a, 0xc0, 0x7b, 0x5d, 0x90, 0x62, 0xb9, 0xf8, 0x68, 0x66, 0x2b,
0xb2, 0x52, 0x49, 0x12, 0xd4, 0x85, 0x6e, 0x0c,
],
},
TestVector {
@ -234,18 +231,18 @@ fn redjubjub_signatures() {
0x04, 0x04, 0x04, 0x04,
],
sig: [
0x51, 0x23, 0xb3, 0x1f, 0x84, 0xaf, 0x0c, 0x35, 0x5e, 0x13, 0xe7, 0x8a, 0x64, 0xd7,
0xa3, 0xcd, 0xfd, 0x6b, 0xdf, 0xfd, 0xc7, 0x33, 0x38, 0xd9, 0x31, 0x7f, 0x73, 0x43,
0x91, 0xa5, 0x5a, 0xe6, 0x25, 0x8f, 0x69, 0x80, 0xb9, 0xc7, 0xd1, 0x90, 0xcf, 0xa3,
0x65, 0x81, 0xa9, 0xa4, 0x7a, 0x86, 0x3f, 0xd3, 0xbf, 0x76, 0x59, 0x42, 0x22, 0x95,
0xb7, 0x5f, 0xd1, 0x22, 0xc3, 0xdd, 0x8a, 0x05,
0x77, 0x4a, 0xc4, 0x67, 0x3f, 0x09, 0xf3, 0xac, 0x57, 0x89, 0xb2, 0x86, 0xb5, 0xee,
0xcb, 0xed, 0xb2, 0x57, 0x23, 0x4e, 0x8c, 0xdf, 0xd9, 0x3f, 0x02, 0x89, 0x09, 0x78,
0xa6, 0xbb, 0xa6, 0x11, 0x69, 0xed, 0x48, 0xf9, 0xe1, 0xc9, 0xfd, 0x13, 0x19, 0xbd,
0x33, 0x0d, 0x2c, 0xf5, 0xb4, 0x91, 0x01, 0x0d, 0x69, 0xb0, 0x43, 0xf4, 0x64, 0x8b,
0xff, 0x55, 0x41, 0x62, 0xc6, 0xa6, 0xdc, 0x09,
],
rsig: [
0x5b, 0xae, 0x25, 0x4f, 0xbd, 0xed, 0x60, 0x7a, 0x5c, 0x48, 0xb5, 0x30, 0x29, 0xf5,
0x9b, 0xa7, 0x06, 0x32, 0x48, 0x79, 0xaa, 0x18, 0xd9, 0xc4, 0x73, 0x19, 0x00, 0x4b,
0xe0, 0x2c, 0xec, 0xe0, 0xb8, 0xbb, 0x02, 0x4a, 0x7a, 0xab, 0xaa, 0x0a, 0x64, 0x0f,
0x3a, 0x54, 0xdc, 0xda, 0xf2, 0x11, 0x31, 0x46, 0x9a, 0x50, 0x06, 0xbe, 0x27, 0x81,
0xa5, 0x67, 0xff, 0xa6, 0x50, 0x3a, 0x35, 0x03,
0x7c, 0x6c, 0x49, 0x8d, 0xe0, 0x01, 0x78, 0x61, 0x09, 0xb3, 0x03, 0xa4, 0xc5, 0xdc,
0xb7, 0xfd, 0x07, 0x57, 0x50, 0xa0, 0xb9, 0xdf, 0x5e, 0x1e, 0x2a, 0x8e, 0x75, 0x47,
0xb7, 0xed, 0x70, 0xcc, 0x0b, 0x56, 0xa5, 0xbf, 0xa9, 0x65, 0x78, 0x43, 0xef, 0xd8,
0x9c, 0x66, 0xa8, 0x4f, 0x41, 0xd2, 0xb1, 0xb5, 0x07, 0x51, 0x19, 0x6b, 0x1e, 0x8c,
0x0c, 0x44, 0x98, 0x60, 0x06, 0x96, 0xa4, 0x04,
],
},
TestVector {
@ -280,18 +277,18 @@ fn redjubjub_signatures() {
0x05, 0x05, 0x05, 0x05,
],
sig: [
0xdc, 0x18, 0xc8, 0x8d, 0x96, 0x44, 0x42, 0x40, 0x6d, 0x65, 0x0a, 0xa2, 0xff, 0xbd,
0x83, 0xd1, 0x13, 0xbf, 0x6a, 0x19, 0xda, 0x78, 0xf2, 0x66, 0x5b, 0x29, 0x4f, 0xa5,
0xfa, 0x45, 0x0b, 0x92, 0x81, 0xa0, 0x7e, 0x32, 0x0c, 0x1a, 0xa3, 0x1d, 0x32, 0x44,
0x9e, 0x00, 0xc5, 0xc3, 0x2d, 0xb2, 0xf4, 0x13, 0xdf, 0x0b, 0x63, 0xd0, 0x72, 0x8f,
0xa4, 0x09, 0x41, 0xa8, 0xda, 0x02, 0x4f, 0x01,
0x9a, 0x25, 0x42, 0x9f, 0x3e, 0xfd, 0x9b, 0x2f, 0x7d, 0xe2, 0x9e, 0x45, 0x12, 0x8d,
0xd7, 0xb7, 0x60, 0xf0, 0x50, 0x8c, 0xd9, 0x58, 0x21, 0x82, 0xab, 0xaf, 0x53, 0xdd,
0x76, 0xc0, 0x34, 0x2c, 0xe4, 0x1b, 0x4a, 0xcf, 0x8e, 0x0a, 0x48, 0x24, 0xe4, 0x11,
0x08, 0xc2, 0x02, 0x65, 0x73, 0x11, 0x4b, 0x60, 0xbe, 0xec, 0xb1, 0x74, 0x01, 0x2a,
0x2b, 0xdb, 0xee, 0xcb, 0xaa, 0x00, 0xb5, 0x06,
],
rsig: [
0x59, 0xe2, 0xe8, 0x18, 0x76, 0x6c, 0x50, 0xfc, 0x8f, 0x38, 0x40, 0xb2, 0x72, 0xaf,
0x9a, 0xd9, 0x47, 0x56, 0xc8, 0x41, 0x32, 0x95, 0xfc, 0x79, 0x5f, 0xaf, 0xbc, 0xc0,
0x71, 0x8e, 0x6c, 0x08, 0x16, 0x9a, 0x00, 0xd5, 0x83, 0x02, 0x77, 0x2a, 0x28, 0x28,
0x43, 0xe8, 0x88, 0xd9, 0x81, 0xfa, 0x04, 0x79, 0x5d, 0x01, 0x4c, 0xf9, 0xc8, 0xcd,
0xb9, 0x07, 0xff, 0x1b, 0x43, 0x0d, 0x92, 0x00,
0xcf, 0xf5, 0x83, 0x57, 0x13, 0xbe, 0x07, 0xfb, 0xe1, 0x25, 0xbb, 0xf2, 0x7a, 0x63,
0x6a, 0xdd, 0x13, 0x1c, 0x90, 0x81, 0x71, 0x6c, 0x52, 0xfd, 0xa8, 0x75, 0x42, 0x6d,
0x03, 0x98, 0x2c, 0xd2, 0x7e, 0xbd, 0x14, 0xb4, 0x22, 0x7b, 0x83, 0x96, 0x15, 0xfd,
0x03, 0x71, 0xbf, 0xdb, 0x8a, 0x30, 0xab, 0xdd, 0xff, 0x74, 0xd7, 0x95, 0xf3, 0xe2,
0x7d, 0x1d, 0x47, 0xc6, 0x29, 0x46, 0x9b, 0x08,
],
},
TestVector {
@ -326,18 +323,18 @@ fn redjubjub_signatures() {
0x06, 0x06, 0x06, 0x06,
],
sig: [
0x9a, 0xf6, 0xf2, 0x80, 0x0f, 0x4b, 0x80, 0xf7, 0x93, 0xbe, 0x64, 0x8a, 0x43, 0x9f,
0x86, 0xe5, 0x7d, 0xa1, 0xb9, 0x19, 0x99, 0x9e, 0x41, 0x91, 0x09, 0x99, 0xd4, 0x2e,
0xd0, 0xf3, 0x89, 0x6d, 0xb7, 0x6e, 0x06, 0x38, 0x8b, 0x27, 0x2c, 0x99, 0x85, 0x8b,
0x55, 0x04, 0xd0, 0x2e, 0xc6, 0xb4, 0xd5, 0x25, 0xb8, 0x71, 0x38, 0x10, 0x50, 0x5f,
0x4f, 0xc0, 0x31, 0x08, 0x3a, 0x14, 0xbf, 0x09,
0xbb, 0xe0, 0x23, 0x59, 0x87, 0xc6, 0xe0, 0xec, 0x68, 0x6d, 0xdb, 0x8a, 0x65, 0x72,
0x66, 0xad, 0x60, 0x5f, 0x7b, 0x75, 0x95, 0x5b, 0xb0, 0xe8, 0x02, 0xf8, 0x81, 0x64,
0xa0, 0xff, 0xe1, 0x0c, 0x3b, 0x73, 0x85, 0x04, 0xab, 0xb3, 0xd1, 0x05, 0x62, 0xb9,
0x27, 0xb3, 0xd2, 0x9f, 0xe9, 0xb0, 0xd3, 0x56, 0x28, 0x6a, 0xea, 0xe5, 0xa2, 0xac,
0x9e, 0x43, 0x5f, 0x20, 0x79, 0x1a, 0xf8, 0x00,
],
rsig: [
0x3f, 0x7d, 0x50, 0x71, 0xb8, 0x76, 0x17, 0x49, 0x05, 0x71, 0xa8, 0xbe, 0x91, 0x74,
0x9e, 0x69, 0xf6, 0xbc, 0xba, 0x5a, 0xb6, 0x26, 0xe4, 0x2f, 0xf9, 0x2d, 0x0d, 0x7d,
0xab, 0x73, 0xf3, 0x03, 0x61, 0xe5, 0xa2, 0x24, 0x99, 0x8e, 0x1f, 0x5e, 0xa1, 0xe5,
0xf8, 0x68, 0x9a, 0x06, 0xa2, 0x77, 0x48, 0xbf, 0x74, 0x19, 0x63, 0xef, 0x51, 0x33,
0x22, 0xf4, 0xa1, 0xba, 0x99, 0xaa, 0x36, 0x03,
0x6d, 0xe3, 0x2b, 0x54, 0x15, 0xd7, 0x7a, 0x90, 0x5f, 0x09, 0x03, 0x90, 0x2a, 0x11,
0x7e, 0xda, 0x79, 0x3c, 0x70, 0x8e, 0x23, 0xa5, 0x42, 0x45, 0xba, 0x8a, 0x8d, 0x1f,
0xe0, 0x26, 0x75, 0x23, 0x23, 0x15, 0x65, 0xe0, 0x57, 0x09, 0xae, 0xd9, 0x6c, 0x22,
0x1f, 0xb1, 0xf3, 0xd0, 0x42, 0x04, 0x35, 0x03, 0xff, 0x33, 0x85, 0x85, 0xa9, 0xbb,
0x98, 0x9c, 0x9d, 0xd4, 0x30, 0xd6, 0xd6, 0x0b,
],
},
TestVector {
@ -372,18 +369,18 @@ fn redjubjub_signatures() {
0x07, 0x07, 0x07, 0x07,
],
sig: [
0x64, 0x59, 0x67, 0x6a, 0x94, 0x16, 0x34, 0xec, 0xb6, 0x1e, 0x59, 0xb7, 0x9a, 0x98,
0xab, 0xe5, 0x87, 0x6f, 0x35, 0x6f, 0x72, 0x8a, 0xa0, 0x9e, 0x0c, 0xca, 0x9e, 0xfe,
0x05, 0x76, 0x1a, 0x33, 0x09, 0xaa, 0x88, 0xb2, 0xfa, 0x0e, 0xe2, 0xd0, 0x4c, 0x1c,
0x46, 0xe9, 0xf2, 0xa0, 0x48, 0xd5, 0x9d, 0x55, 0x65, 0xaf, 0xa6, 0xc3, 0xf1, 0x5b,
0xce, 0x70, 0x8d, 0xaa, 0xab, 0x7b, 0x34, 0x0e,
0x44, 0x6d, 0x67, 0x7c, 0x4c, 0xfe, 0xfd, 0x02, 0x4b, 0x0a, 0xeb, 0x37, 0xa5, 0x98,
0xcc, 0x2e, 0xb3, 0xd2, 0x9b, 0x02, 0x94, 0xfe, 0x5b, 0xb6, 0x97, 0x8e, 0x8b, 0x43,
0xd3, 0x2b, 0x2e, 0x4f, 0x09, 0x56, 0xac, 0xd1, 0x3e, 0x7e, 0x3a, 0x63, 0xa1, 0x8f,
0xca, 0x32, 0xd6, 0xab, 0x94, 0xb9, 0x4e, 0xd0, 0x33, 0xe9, 0xa1, 0x0f, 0xc5, 0x69,
0x28, 0xbc, 0x8a, 0x0f, 0x4f, 0x8e, 0x95, 0x00,
],
rsig: [
0xc9, 0x66, 0x84, 0xec, 0x7e, 0xa6, 0x0b, 0xde, 0x87, 0x88, 0x22, 0xdd, 0xca, 0xf6,
0xb8, 0xb0, 0xbd, 0x31, 0x98, 0x51, 0x54, 0xdf, 0x9a, 0xd4, 0xf6, 0x90, 0x7d, 0xf8,
0xfe, 0xd9, 0x5c, 0x1d, 0x84, 0xfe, 0x67, 0xe6, 0x78, 0x75, 0xa5, 0x39, 0x55, 0x0e,
0xb2, 0x51, 0x4f, 0x19, 0x3b, 0x8e, 0xd4, 0x57, 0x25, 0x6c, 0x8d, 0x30, 0x28, 0x1d,
0x6f, 0x8b, 0xb9, 0x54, 0x49, 0x24, 0xca, 0x0c,
0x8d, 0xe0, 0x41, 0xe7, 0x09, 0xdb, 0x62, 0x4a, 0xe2, 0xbe, 0x16, 0x48, 0xb6, 0x62,
0x23, 0x9c, 0xde, 0xdf, 0x85, 0xec, 0xd3, 0x82, 0x26, 0x8b, 0x0e, 0x35, 0x54, 0xbf,
0xa0, 0xf2, 0x08, 0x1c, 0xd6, 0x41, 0xbc, 0xa0, 0x40, 0x78, 0xaa, 0x89, 0xf7, 0xdd,
0x25, 0x40, 0x58, 0x7c, 0xed, 0x6b, 0x45, 0x89, 0x16, 0xb1, 0x3e, 0x4b, 0x6a, 0x36,
0x30, 0xda, 0x69, 0x76, 0x46, 0xdb, 0xbf, 0x09,
],
},
TestVector {
@ -418,18 +415,18 @@ fn redjubjub_signatures() {
0x08, 0x08, 0x08, 0x08,
],
sig: [
0x24, 0x93, 0x2c, 0x1f, 0xaa, 0x01, 0x63, 0xca, 0x9a, 0x7f, 0xcd, 0xe4, 0x76, 0x11,
0x29, 0xd2, 0xe5, 0xe9, 0x9c, 0xf5, 0xef, 0xa2, 0x5d, 0x27, 0x04, 0x58, 0x8e, 0x1c,
0x75, 0x67, 0x7b, 0x5e, 0xeb, 0xe4, 0x55, 0x04, 0x8d, 0x7c, 0xe1, 0xb0, 0xd2, 0x01,
0x27, 0x53, 0xf7, 0x1b, 0x27, 0x25, 0x01, 0x2e, 0xe1, 0x85, 0x49, 0x28, 0x73, 0x18,
0xf9, 0xcd, 0x73, 0xf0, 0x7f, 0x0f, 0xb5, 0x02,
0x99, 0x35, 0x80, 0xef, 0x93, 0x34, 0x9a, 0x1c, 0x9e, 0xe9, 0x60, 0xca, 0x3e, 0x7c,
0xd0, 0x4c, 0x13, 0xb4, 0xa0, 0xec, 0x4f, 0xd1, 0x80, 0x53, 0xa1, 0x9c, 0xff, 0x77,
0x63, 0x62, 0x09, 0x65, 0xfb, 0xee, 0x96, 0xc1, 0x64, 0x72, 0x30, 0xe3, 0x73, 0xcb,
0x82, 0xb8, 0x1d, 0x00, 0x03, 0x92, 0x23, 0xd3, 0x0b, 0x39, 0x3e, 0xd1, 0x72, 0xc9,
0xb3, 0xc5, 0x63, 0xc6, 0x11, 0x79, 0x22, 0x05,
],
rsig: [
0xf7, 0xfa, 0x26, 0xca, 0x22, 0xf3, 0x86, 0xc4, 0x3c, 0x19, 0x1a, 0x0b, 0x3e, 0xa6,
0x57, 0x7e, 0x8e, 0xea, 0xa3, 0xf3, 0x6b, 0x9b, 0xd1, 0xa3, 0xac, 0x3d, 0xf6, 0xf8,
0x83, 0xa3, 0xff, 0xdb, 0x31, 0x32, 0x0b, 0xde, 0x62, 0x7f, 0xf4, 0x6f, 0xc2, 0x26,
0x4a, 0x32, 0x63, 0xb9, 0xab, 0x67, 0x12, 0x3b, 0xa5, 0xe1, 0x08, 0x43, 0x20, 0xd9,
0x10, 0xb3, 0x94, 0xef, 0x8c, 0x65, 0xba, 0x09,
0xcc, 0x7a, 0xae, 0x1c, 0xed, 0xad, 0x2d, 0x7f, 0x6c, 0xe0, 0x4c, 0x19, 0xc5, 0xa5,
0xb6, 0xb7, 0xa6, 0xa0, 0x82, 0x78, 0x5c, 0x54, 0x0c, 0x14, 0xf6, 0x30, 0x9b, 0x06,
0x4d, 0x1f, 0xfa, 0x68, 0x17, 0x29, 0x53, 0xfb, 0xa0, 0xc2, 0xfc, 0xfb, 0x87, 0x5c,
0xa7, 0xf7, 0xea, 0x98, 0xef, 0x55, 0xa0, 0x40, 0x2f, 0xd5, 0x29, 0xcf, 0xcd, 0xdf,
0x99, 0x6c, 0xa2, 0xb8, 0xca, 0x89, 0x90, 0x0a,
],
},
TestVector {
@ -464,47 +461,37 @@ fn redjubjub_signatures() {
0x09, 0x09, 0x09, 0x09,
],
sig: [
0x64, 0xab, 0xd1, 0x25, 0xbf, 0xc4, 0xc6, 0x54, 0xfa, 0xf2, 0xb6, 0xdd, 0x75, 0x3e,
0xc6, 0x90, 0x22, 0x4d, 0xbc, 0xab, 0x8c, 0xd6, 0x32, 0xdd, 0x59, 0x3c, 0x91, 0xce,
0x3a, 0xb0, 0xbc, 0xad, 0xca, 0x92, 0x76, 0x34, 0x02, 0x1c, 0x31, 0x47, 0x6c, 0x78,
0xc5, 0xac, 0x7c, 0xcc, 0xab, 0xbd, 0x6f, 0x92, 0x7d, 0xf2, 0x05, 0xea, 0xa7, 0x07,
0xcc, 0x00, 0xd4, 0x7d, 0x39, 0xf3, 0xe4, 0x0c,
0xce, 0x90, 0xdd, 0xf4, 0xaf, 0x21, 0xaa, 0xc4, 0xd9, 0x41, 0x93, 0xea, 0x16, 0xff,
0x35, 0xcd, 0x93, 0x79, 0x20, 0x4e, 0x7d, 0x8f, 0xf4, 0xc0, 0xf5, 0x41, 0x17, 0xab,
0xb1, 0x6b, 0x7c, 0x85, 0xa0, 0xb1, 0x97, 0xcf, 0x13, 0xab, 0x14, 0xd7, 0xc3, 0xba,
0x68, 0x01, 0x0a, 0xb8, 0x05, 0x12, 0x25, 0x91, 0x3b, 0xdb, 0xc3, 0x9a, 0x51, 0xf6,
0x03, 0x7a, 0xfc, 0x6c, 0xee, 0xcb, 0x0b, 0x06,
],
rsig: [
0xeb, 0x7a, 0x06, 0x5d, 0x75, 0xf8, 0x45, 0xdc, 0x09, 0x41, 0xb7, 0x09, 0xc0, 0xb1,
0x49, 0xea, 0xfd, 0x80, 0x5e, 0xa5, 0x8f, 0x38, 0x0b, 0x92, 0xb9, 0xd3, 0x10, 0x8a,
0x56, 0x1b, 0xda, 0x17, 0x85, 0xdf, 0x8f, 0x10, 0x1e, 0x0e, 0x14, 0x0f, 0xca, 0xee,
0x99, 0xb7, 0xdb, 0xb7, 0xdf, 0xbf, 0x7e, 0x61, 0xf3, 0xa1, 0x2f, 0x46, 0x09, 0x50,
0x69, 0xe0, 0x6e, 0x88, 0x96, 0xa9, 0xe4, 0x04,
0xa8, 0x47, 0x74, 0x2e, 0x94, 0x01, 0xcf, 0x22, 0x39, 0x21, 0x3d, 0xc8, 0x81, 0x3e,
0x97, 0x72, 0xe9, 0x7a, 0xf8, 0xd6, 0x7a, 0xdf, 0xfe, 0xab, 0xc8, 0xe6, 0x7f, 0x5d,
0x2d, 0x90, 0xd0, 0xb4, 0x1b, 0xc2, 0x5b, 0x05, 0xf9, 0x4a, 0xce, 0x16, 0x8a, 0xec,
0xc6, 0x58, 0x3e, 0x18, 0xf7, 0x63, 0x74, 0x92, 0xf3, 0x7a, 0x9c, 0xa3, 0x00, 0x20,
0x2b, 0xc0, 0x65, 0xab, 0xd3, 0x80, 0xec, 0x00,
],
},
];
for tv in test_vectors {
let sk = PrivateKey::read(&tv.sk[..]).unwrap();
let vk = PublicKey::read(&tv.vk[..]).unwrap();
let rvk = PublicKey::read(&tv.rvk[..]).unwrap();
let sig = Signature::read(&tv.sig[..]).unwrap();
let rsig = Signature::read(&tv.rsig[..]).unwrap();
let sk = redjubjub::SigningKey::try_from(tv.sk).unwrap();
let vk = redjubjub::VerificationKey::try_from(tv.vk).unwrap();
let rvk = redjubjub::VerificationKey::try_from(tv.rvk).unwrap();
let sig = redjubjub::Signature::from(tv.sig);
let rsig = redjubjub::Signature::from(tv.rsig);
let alpha = jubjub::Scalar::from_bytes(&tv.alpha).unwrap();
{
let mut vec = Vec::new();
sk.randomize(alpha).write(&mut vec).unwrap();
assert_eq!(&vec, &tv.rsk);
}
{
let mut vec = Vec::new();
vk.randomize(alpha, SPENDING_KEY_GENERATOR)
.write(&mut vec)
.unwrap();
assert_eq!(&vec, &tv.rvk);
}
assert_eq!(<[u8; 32]>::from(sk.randomize(&alpha)), tv.rsk);
assert_eq!(<[u8; 32]>::from(vk.randomize(&alpha)), tv.rvk);
assert!(vk.verify(&tv.m, &sig, SPENDING_KEY_GENERATOR));
assert!(rvk.verify(&tv.m, &rsig, SPENDING_KEY_GENERATOR));
assert!(!vk.verify(&tv.m, &rsig, SPENDING_KEY_GENERATOR));
assert!(!rvk.verify(&tv.m, &sig, SPENDING_KEY_GENERATOR));
assert_eq!(vk.verify(&tv.m, &sig), Ok(()));
assert_eq!(rvk.verify(&tv.m, &rsig), Ok(()));
assert!(matches!(vk.verify(&tv.m, &rsig), Err(_)));
assert!(matches!(rvk.verify(&tv.m, &sig), Err(_)));
}
}

View File

@ -6,11 +6,12 @@ use blake2b_simd::Hash;
use libc::{c_uchar, size_t};
use tracing::error;
use zcash_encoding::Vector;
use zcash_primitives::transaction::components::amount::NonNegativeAmount;
use zcash_primitives::{
consensus::BranchId,
legacy::Script,
transaction::{
components::{sapling, transparent, Amount},
components::transparent,
sighash::{SignableInput, TransparentAuthorizingContext},
sighash_v5::v5_signature_hash,
txid::TxIdDigester,
@ -69,7 +70,7 @@ impl transparent::Authorization for TransparentAuth {
}
impl TransparentAuthorizingContext for TransparentAuth {
fn input_amounts(&self) -> Vec<Amount> {
fn input_amounts(&self) -> Vec<NonNegativeAmount> {
self.all_prev_outputs
.iter()
.map(|prevout| prevout.value)
@ -148,7 +149,7 @@ pub(crate) struct PrecomputedAuth;
impl Authorization for PrecomputedAuth {
type TransparentAuth = TransparentAuth;
type SaplingAuth = sapling::Authorized;
type SaplingAuth = sapling::bundle::Authorized;
type OrchardAuth = orchard::bundle::Authorized;
}

View File

@ -50,9 +50,7 @@ pub extern "C" fn unified_full_viewing_key_parse(
Fvk::Sapling(data) => {
// The last 32 bytes is the diversifier key, which is opaque.
// The remaining 96 bytes should be a valid Sapling FVK.
if zcash_primitives::sapling::keys::FullViewingKey::read(&data[..96])
.is_err()
{
if sapling::keys::FullViewingKey::read(&data[..96]).is_err() {
error!("Unified FVK contains invalid Sapling FVK");
return std::ptr::null_mut();
}

View File

@ -13,7 +13,6 @@ use zcash_encoding::{Optional, Vector};
use zcash_primitives::{
consensus::BlockHeight,
merkle_tree::{read_position, write_position},
sapling::NOTE_COMMITMENT_TREE_DEPTH,
transaction::{components::Amount, TxId},
};
@ -150,7 +149,8 @@ pub struct Wallet {
nullifiers: BTreeMap<Nullifier, OutPoint>,
/// The incremental Merkle tree used to track note commitments and witnesses for notes
/// belonging to the wallet.
commitment_tree: BridgeTree<MerkleHashOrchard, u32, NOTE_COMMITMENT_TREE_DEPTH>,
// TODO: Replace this with an `orchard` crate constant (they happen to be the same).
commitment_tree: BridgeTree<MerkleHashOrchard, u32, { sapling::NOTE_COMMITMENT_TREE_DEPTH }>,
/// The block height at which the last checkpoint was created, if any.
last_checkpoint: Option<BlockHeight>,
/// The block height and transaction index of the note most recently added to
@ -1370,7 +1370,10 @@ pub extern "C" fn orchard_wallet_load_note_commitment_tree(
#[no_mangle]
pub extern "C" fn orchard_wallet_init_from_frontier(
wallet: *mut Wallet,
frontier: *const bridgetree::Frontier<MerkleHashOrchard, NOTE_COMMITMENT_TREE_DEPTH>,
frontier: *const bridgetree::Frontier<
MerkleHashOrchard,
{ sapling::NOTE_COMMITMENT_TREE_DEPTH },
>,
) -> bool {
let wallet = unsafe { wallet.as_mut() }.expect("Wallet pointer may not be null.");
let frontier = unsafe { frontier.as_ref() }.expect("Wallet pointer may not be null.");

View File

@ -10,15 +10,12 @@ use std::sync::{
use crossbeam_channel as channel;
use memuse::DynamicUsage;
use sapling::{bundle::GrothProofBytes, note_encryption::SaplingDomain};
use zcash_note_encryption::{batch, BatchDomain, Domain, ShieldedOutput, ENC_CIPHERTEXT_SIZE};
use zcash_primitives::{
block::BlockHash,
consensus,
sapling::note_encryption::SaplingDomain,
transaction::{
components::{sapling::GrothProofBytes, OutputDescription},
Transaction, TxId,
},
transaction::{components::OutputDescription, Transaction, TxId},
};
use crate::{bridge::ffi, note_encryption::parse_and_prepare_sapling_ivk, params::Network};
@ -38,7 +35,7 @@ trait OutputDomain: BatchDomain {
const KIND: &'static str;
}
impl<P: consensus::Parameters> OutputDomain for SaplingDomain<P> {
impl OutputDomain for SaplingDomain {
const KIND: &'static str = "sapling";
}
@ -550,7 +547,7 @@ where
}
type SaplingRunner =
BatchRunner<[u8; 32], SaplingDomain<Network>, OutputDescription<GrothProofBytes>, WithUsage>;
BatchRunner<[u8; 32], SaplingDomain, OutputDescription<GrothProofBytes>, WithUsage>;
/// A batch scanner for the `zcashd` wallet.
pub(crate) struct BatchScanner {
@ -622,7 +619,7 @@ impl BatchScanner {
runner.add_outputs(
block_tag,
txid,
|| SaplingDomain::for_height(params, height),
|| SaplingDomain::new(consensus::sapling_zip212_enforcement(&params, height)),
bundle.shielded_outputs(),
);
}
@ -671,7 +668,7 @@ impl BatchScanner {
}
pub(crate) struct BatchResult {
sapling: HashMap<(TxId, usize), DecryptedNote<[u8; 32], SaplingDomain<Network>>>,
sapling: HashMap<(TxId, usize), DecryptedNote<[u8; 32], SaplingDomain>>,
}
impl BatchResult {

View File

@ -306,9 +306,10 @@ public:
// The Orchard bundle builder always pads to two Actions, so we can just
// use an empty builder to create a dummy Orchard bundle.
// TODO: With the new BundleType::DEFAULT this is no longer true. Fix this.
uint256 orchardAnchor;
uint256 dataToBeSigned;
auto builder = orchard::Builder(true, true, orchardAnchor);
auto builder = orchard::Builder(false, orchardAnchor);
mutableTx.orchardBundle = builder.Build().value().ProveAndSign({}, dataToBeSigned).value();
orchardNullifier = mutableTx.orchardBundle.GetNullifiers()[0];
@ -340,7 +341,7 @@ template<> void AppendRandomLeaf(OrchardMerkleFrontier &tree) {
// append a random leaf to OrchardMerkleFrontier.
uint256 orchardAnchor;
uint256 dataToBeSigned;
auto builder = orchard::Builder(true, true, orchardAnchor);
auto builder = orchard::Builder(false, orchardAnchor);
auto bundle = builder.Build().value().ProveAndSign({}, dataToBeSigned).value();
tree.AppendBundle(bundle);
}

View File

@ -206,7 +206,7 @@ BOOST_AUTO_TEST_CASE(zs_address_test)
KeyIO keyIO(Params());
for (uint32_t i = 0; i < 1000; i++) {
auto sk = m.Derive(i);
auto sk = m.Derive(i | HARDENED_KEY_LIMIT);
{
std::string sk_string = keyIO.EncodeSpendingKey(sk);
BOOST_CHECK(sk_string.compare(0, 27, Params().Bech32HRP(CChainParams::SAPLING_EXTENDED_SPEND_KEY)) == 0);

View File

@ -48,11 +48,10 @@ uint256 ProduceShieldedSignatureHash(
namespace orchard {
Builder::Builder(
bool spendsEnabled,
bool outputsEnabled,
bool coinbase,
uint256 anchor) : inner(nullptr, orchard_builder_free)
{
inner.reset(orchard_builder_new(spendsEnabled, outputsEnabled, anchor.IsNull() ? nullptr : anchor.begin()));
inner.reset(orchard_builder_new(coinbase, anchor.IsNull() ? nullptr : anchor.begin()));
}
bool Builder::AddSpend(orchard::SpendInfo spendInfo)
@ -209,6 +208,7 @@ TransactionBuilder::TransactionBuilder(
const CChainParams& params,
int nHeight,
std::optional<uint256> orchardAnchor,
uint256 saplingAnchor,
const CKeyStore* keystore,
const CCoinsViewCache* coinsView,
CCriticalSection* cs_coinsView) :
@ -218,7 +218,8 @@ TransactionBuilder::TransactionBuilder(
coinsView(coinsView),
cs_coinsView(cs_coinsView),
orchardAnchor(orchardAnchor),
saplingBuilder(sapling::new_builder(*params.RustNetwork(), nHeight))
saplingAnchor(saplingAnchor),
saplingBuilder(sapling::new_builder(*params.RustNetwork(), nHeight, saplingAnchor.ToRawBytes(), false))
{
mtx = CreateNewContextualCMutableTransaction(
consensusParams, nHeight,
@ -226,7 +227,7 @@ TransactionBuilder::TransactionBuilder(
// Ignore the Orchard anchor if we can't use it yet.
if (orchardAnchor.has_value() && mtx.nVersion >= ZIP225_MIN_TX_VERSION) {
orchardBuilder = orchard::Builder(true, true, orchardAnchor.value());
orchardBuilder = orchard::Builder(false, orchardAnchor.value());
}
}
@ -329,7 +330,6 @@ void TransactionBuilder::AddSaplingSpend(
saplingBuilder->add_spend(
{reinterpret_cast<uint8_t*>(ssExtSk.data()), ssExtSk.size()},
note.d,
recipient.GetRawBytes(),
note.value(),
note.rcm().GetRawBytes(),
@ -525,7 +525,7 @@ TransactionBuilderResult TransactionBuilder::Build()
std::optional<rust::Box<sapling::UnauthorizedBundle>> maybeSaplingBundle;
try {
maybeSaplingBundle = sapling::build_bundle(std::move(saplingBuilder), nHeight);
maybeSaplingBundle = sapling::build_bundle(std::move(saplingBuilder));
} catch (rust::Error e) {
return TransactionBuilderResult("Failed to build Sapling bundle: " + std::string(e.what()));
}

View File

@ -91,7 +91,7 @@ private:
Builder() : inner(nullptr, orchard_builder_free), hasActions(false) { }
public:
Builder(bool spendsEnabled, bool outputsEnabled, uint256 anchor);
Builder(bool coinbase, uint256 anchor);
// Builder should never be copied
Builder(const Builder&) = delete;
@ -242,6 +242,7 @@ private:
std::optional<uint256> orchardAnchor;
std::optional<orchard::Builder> orchardBuilder;
CAmount valueBalanceOrchard = 0;
uint256 saplingAnchor;
rust::Box<sapling::Builder> saplingBuilder;
CAmount valueBalanceSapling = 0;
@ -268,6 +269,7 @@ public:
const CChainParams& params,
int nHeight,
std::optional<uint256> orchardAnchor,
uint256 saplingAnchor,
const CKeyStore* keyStore = nullptr,
const CCoinsViewCache* coinsView = nullptr,
CCriticalSection* cs_coinsView = nullptr);
@ -286,6 +288,7 @@ public:
orchardAnchor(std::move(builder.orchardAnchor)),
orchardBuilder(std::move(builder.orchardBuilder)),
valueBalanceOrchard(std::move(builder.valueBalanceOrchard)),
saplingAnchor(std::move(builder.saplingAnchor)),
saplingBuilder(std::move(builder.saplingBuilder)),
valueBalanceSapling(std::move(builder.valueBalanceSapling)),
orchardSpendingKeys(std::move(orchardSpendingKeys)),
@ -308,8 +311,10 @@ public:
cs_coinsView = std::move(builder.cs_coinsView);
mtx = std::move(builder.mtx);
fee = std::move(builder.fee);
orchardAnchor = std::move(builder.orchardAnchor);
orchardBuilder = std::move(builder.orchardBuilder);
valueBalanceOrchard = std::move(builder.valueBalanceOrchard);
saplingAnchor = std::move(builder.saplingAnchor);
saplingBuilder = std::move(builder.saplingBuilder);
valueBalanceSapling = std::move(builder.valueBalanceSapling);
orchardSpendingKeys = std::move(builder.orchardSpendingKeys),

View File

@ -352,8 +352,9 @@ CWalletTx GetValidSaplingReceive(const CChainParams& params,
// To zaddr
auto fvk = sk.expsk.full_viewing_key();
auto pa = sk.ToXFVK().DefaultAddress();
auto saplingAnchor = SaplingMerkleTree::empty_root();
auto builder = TransactionBuilder(params, 1, std::nullopt, &keyStore);
auto builder = TransactionBuilder(params, 1, std::nullopt, saplingAnchor, &keyStore);
builder.SetFee(0);
builder.AddTransparentInput(COutPoint(), scriptPubKey, value);
builder.AddSaplingOutput(fvk.ovk, pa, value, {});

View File

@ -16,7 +16,8 @@
const int MIGRATION_EXPIRY_DELTA = 450;
AsyncRPCOperation_saplingmigration::AsyncRPCOperation_saplingmigration(int targetHeight) : targetHeight_(targetHeight) {}
AsyncRPCOperation_saplingmigration::AsyncRPCOperation_saplingmigration(int targetHeight, uint256 saplingAnchor) :
targetHeight_(targetHeight), saplingAnchor_(saplingAnchor) {}
AsyncRPCOperation_saplingmigration::~AsyncRPCOperation_saplingmigration() {}
@ -112,7 +113,14 @@ bool AsyncRPCOperation_saplingmigration::main_impl() {
CCoinsViewCache coinsView(pcoinsTip);
do {
CAmount amountToSend = chooseAmount(availableFunds);
auto builder = TransactionBuilder(Params(), targetHeight_, std::nullopt, pwalletMain, &coinsView, &cs_main);
auto builder = TransactionBuilder(
Params(),
targetHeight_,
std::nullopt,
saplingAnchor_,
pwalletMain,
&coinsView,
&cs_main);
builder.SetExpiryHeight(targetHeight_ + MIGRATION_EXPIRY_DELTA);
LogPrint("zrpcunsafe", "%s: Beginning creating transaction with Sapling output amount=%s\n", getId(), FormatMoney(amountToSend - LEGACY_DEFAULT_FEE));
std::vector<SproutNoteEntry> fromNotes;

View File

@ -9,7 +9,7 @@
class AsyncRPCOperation_saplingmigration : public AsyncRPCOperation
{
public:
AsyncRPCOperation_saplingmigration(int targetHeight);
AsyncRPCOperation_saplingmigration(int targetHeight, uint256 saplingAnchor);
virtual ~AsyncRPCOperation_saplingmigration();
// We don't want to be copied or moved around
@ -28,6 +28,7 @@ public:
private:
int targetHeight_;
uint256 saplingAnchor_;
bool main_impl();

View File

@ -32,7 +32,7 @@ CTransaction FakeOrchardTx(const OrchardSpendingKey& sk, libzcash::diversifier_i
// Create a shielding transaction from transparent to Orchard
// 0.0005 t-ZEC in, 0.0004 z-ZEC out, 0.0001 fee
auto builder = TransactionBuilder(Params(), 1, orchardAnchor, &keystore);
auto builder = TransactionBuilder(Params(), 1, orchardAnchor, SaplingMerkleTree::empty_root(), &keystore);
builder.SetFee(10000);
builder.AddTransparentInput(COutPoint(uint256S("1234"), 0), scriptPubKey, 50000);
builder.AddOrchardOutput(std::nullopt, recipient, 40000, std::nullopt);
@ -129,7 +129,7 @@ TEST(TransactionBuilder, OrchardToOrchard) {
// Create an Orchard-only transaction
// 0.0004 z-ZEC in, 0.00025 z-ZEC out, default fee, 0.00014 z-ZEC change
auto builder = TransactionBuilder(Params(), 2, orchardAnchor);
auto builder = TransactionBuilder(Params(), 2, orchardAnchor, SaplingMerkleTree::empty_root());
EXPECT_TRUE(builder.AddOrchardSpend(sk, std::move(spendInfo[0].second)));
builder.AddOrchardOutput(std::nullopt, recipient, 25000, std::nullopt);
auto maybeTx = builder.Build();

View File

@ -330,65 +330,77 @@ TEST(WalletRPCTests, RPCZsendmanyTaddrToSapling)
ss >> tx;
ASSERT_NE(tx.GetSaplingOutputsCount(), 0);
auto outputs = tx.GetSaplingOutputs();
auto enc_ciphertext = outputs[0].enc_ciphertext();
auto out_ciphertext = outputs[0].out_ciphertext();
auto cv = outputs[0].cv();
auto cmu = outputs[0].cmu();
auto ephemeral_key = outputs[0].ephemeral_key();
// We shouldn't be able to decrypt with the empty ovk
EXPECT_THROW(wallet::try_sapling_output_recovery(
*rustNetwork,
nextBlockHeight,
uint256().GetRawBytes(),
{
cv,
cmu,
ephemeral_key,
enc_ciphertext,
out_ciphertext,
}), rust::Error);
// We shouldn't be able to decrypt with a random ovk
EXPECT_THROW(wallet::try_sapling_output_recovery(
*rustNetwork,
nextBlockHeight,
random_uint256().GetRawBytes(),
{
cv,
cmu,
ephemeral_key,
enc_ciphertext,
out_ciphertext,
}), rust::Error);
auto accountKey = pwalletMain->GetLegacyAccountKey().ToAccountPubKey();
auto ovks = accountKey.GetOVKsForShielding();
// We should not be able to decrypt with the internal change OVK for shielding
EXPECT_THROW(wallet::try_sapling_output_recovery(
*rustNetwork,
nextBlockHeight,
ovks.first.GetRawBytes(),
{
cv,
cmu,
ephemeral_key,
enc_ciphertext,
out_ciphertext,
}), rust::Error);
// We should be able to decrypt with the external OVK for shielding
EXPECT_NO_THROW(wallet::try_sapling_output_recovery(
*rustNetwork,
nextBlockHeight,
ovks.second.GetRawBytes(),
{
cv,
cmu,
ephemeral_key,
enc_ciphertext,
out_ciphertext,
}));
auto extDecryptSucceeded = 0;
auto extDecryptFailed = 0;
for (auto& output: tx.GetSaplingOutputs()) {
auto enc_ciphertext = output.enc_ciphertext();
auto out_ciphertext = output.out_ciphertext();
auto cv = output.cv();
auto cmu = output.cmu();
auto ephemeral_key = output.ephemeral_key();
// We shouldn't be able to decrypt with the empty ovk
EXPECT_THROW(wallet::try_sapling_output_recovery(
*rustNetwork,
nextBlockHeight,
uint256().GetRawBytes(),
{
cv,
cmu,
ephemeral_key,
enc_ciphertext,
out_ciphertext,
}), rust::Error);
// We shouldn't be able to decrypt with a random ovk
EXPECT_THROW(wallet::try_sapling_output_recovery(
*rustNetwork,
nextBlockHeight,
random_uint256().GetRawBytes(),
{
cv,
cmu,
ephemeral_key,
enc_ciphertext,
out_ciphertext,
}), rust::Error);
// We should not be able to decrypt with the internal change OVK for shielding
EXPECT_THROW(wallet::try_sapling_output_recovery(
*rustNetwork,
nextBlockHeight,
ovks.first.GetRawBytes(),
{
cv,
cmu,
ephemeral_key,
enc_ciphertext,
out_ciphertext,
}), rust::Error);
// We should be able to decrypt one of the outputs with the external OVK for shielding.
try {
wallet::try_sapling_output_recovery(
*rustNetwork,
nextBlockHeight,
ovks.second.GetRawBytes(),
{
cv,
cmu,
ephemeral_key,
enc_ciphertext,
out_ciphertext,
});
extDecryptSucceeded += 1;
} catch (...) {
extDecryptFailed += 1;
}
}
EXPECT_EQ(extDecryptSucceeded, 1);
EXPECT_EQ(extDecryptFailed, 1);
// Tear down
chainActive.SetTip(NULL);

View File

@ -421,13 +421,14 @@ TEST(WalletTests, SetSaplingNoteAddrsInCWalletTx) {
auto cm = note.cmu().value();
SaplingMerkleTree tree;
tree.append(cm);
auto anchor = tree.root();
auto witness = tree.witness();
auto nf = note.nullifier(fvk, witness.position());
ASSERT_TRUE(nf);
uint256 nullifier = nf.value();
auto builder = TransactionBuilder(Params(), 1, std::nullopt);
auto builder = TransactionBuilder(Params(), 1, std::nullopt, anchor);
builder.AddSaplingSpend(sk, note, witness);
builder.AddSaplingOutput(fvk.ovk, pk, 50000, {});
builder.SetFee(0);
@ -564,7 +565,7 @@ TEST(WalletTests, FindMySaplingNotes) {
auto testNote = GetTestSaplingNote(pa, 50000);
// Generate transaction
auto builder = TransactionBuilder(Params(), 1, std::nullopt);
auto builder = TransactionBuilder(Params(), 1, std::nullopt, testNote.tree.root());
builder.AddSaplingSpend(sk, testNote.note, testNote.tree.witness());
builder.AddSaplingOutput(extfvk.fvk.ovk, pa, 25000, {});
auto tx = builder.Build().GetTxOrThrow();
@ -708,10 +709,11 @@ TEST(WalletTests, GetConflictedSaplingNotes) {
MerkleFrontiers frontiers;
frontiers.sapling.append(cm);
auto anchor = frontiers.sapling.root();
auto witness = frontiers.sapling.witness();
// Generate tx to create output note B
auto builder = TransactionBuilder(Params(), 1, std::nullopt);
auto builder = TransactionBuilder(Params(), 1, std::nullopt, anchor);
builder.AddSaplingSpend(sk, note, witness);
builder.AddSaplingOutput(extfvk.fvk.ovk, pk, 35000, {});
auto tx = builder.Build().GetTxOrThrow();
@ -758,13 +760,13 @@ TEST(WalletTests, GetConflictedSaplingNotes) {
auto nullifier2 = maybe_nf.value();
// Create transaction to spend note B
auto builder2 = TransactionBuilder(Params(), 2, std::nullopt);
auto builder2 = TransactionBuilder(Params(), 2, std::nullopt, spend_note_witness.root());
builder2.AddSaplingSpend(sk, note2, spend_note_witness);
builder2.AddSaplingOutput(extfvk.fvk.ovk, pk, 2000, {});
auto tx2 = builder2.Build().GetTxOrThrow();
// Create conflicting transaction which also spends note B
auto builder3 = TransactionBuilder(Params(), 2, std::nullopt);
auto builder3 = TransactionBuilder(Params(), 2, std::nullopt, spend_note_witness.root());
builder3.AddSaplingSpend(sk, note2, spend_note_witness);
builder3.AddSaplingOutput(extfvk.fvk.ovk, pk, 1999, {});
auto tx3 = builder3.Build().GetTxOrThrow();
@ -822,7 +824,7 @@ TEST(WalletTests, GetConflictedOrchardNotes) {
auto scriptPubKey = GetScriptForDestination(tkeyid);
// Generate a bundle containing output note A.
auto builder = TransactionBuilder(Params(), 1, orchardAnchor, &keystore);
auto builder = TransactionBuilder(Params(), 1, orchardAnchor, SaplingMerkleTree::empty_root(), &keystore);
builder.AddTransparentInput(COutPoint(uint256(), 0), scriptPubKey, 5000);
builder.AddOrchardOutput(std::nullopt, recipient, 4000, {});
auto maybeTx = builder.Build();
@ -876,7 +878,7 @@ TEST(WalletTests, GetConflictedOrchardNotes) {
auto recipient2 = ivk.Address(j2);
// Generate tx to spend note A
auto builder2 = TransactionBuilder(Params(), 2, orchardTree.root());
auto builder2 = TransactionBuilder(Params(), 2, orchardTree.root(), SaplingMerkleTree::empty_root());
auto noteToSpend = std::move(wallet.GetOrchardSpendInfo(orchardEntries, 1, orchardTree.root())[0]);
builder2.AddOrchardSpend(std::move(noteToSpend.first), std::move(noteToSpend.second));
auto maybeTx2 = builder2.Build();
@ -890,7 +892,7 @@ TEST(WalletTests, GetConflictedOrchardNotes) {
// Generate conflicting tx to spend note A
auto noteToSpend2 = std::move(wallet.GetOrchardSpendInfo(orchardEntries, 1, orchardTree.root())[0]);
auto builder3 = TransactionBuilder(Params(), 2, orchardTree.root());
auto builder3 = TransactionBuilder(Params(), 2, orchardTree.root(), SaplingMerkleTree::empty_root());
builder3.AddOrchardSpend(std::move(noteToSpend2.first), std::move(noteToSpend2.second));
auto maybeTx3 = builder3.Build();
EXPECT_TRUE(maybeTx3.IsTx());
@ -992,7 +994,7 @@ TEST(WalletTests, SaplingNullifierIsSpent) {
auto testNote = GetTestSaplingNote(pa, 50000);
// Generate transaction
auto builder = TransactionBuilder(Params(), 1, std::nullopt);
auto builder = TransactionBuilder(Params(), 1, std::nullopt, testNote.tree.root());
builder.AddSaplingSpend(sk, testNote.note, testNote.tree.witness());
builder.AddSaplingOutput(extfvk.fvk.ovk, pa, 25000, {});
auto tx = builder.Build().GetTxOrThrow();
@ -1079,7 +1081,7 @@ TEST(WalletTests, NavigateFromSaplingNullifierToNote) {
auto testNote = GetTestSaplingNote(pa, 50000);
// Generate transaction
auto builder = TransactionBuilder(Params(), 1, std::nullopt);
auto builder = TransactionBuilder(Params(), 1, std::nullopt, testNote.tree.root());
builder.AddSaplingSpend(sk, testNote.note, testNote.tree.witness());
builder.AddSaplingOutput(extfvk.fvk.ovk, pa, 25000, {});
auto tx = builder.Build().GetTxOrThrow();
@ -1214,10 +1216,11 @@ TEST(WalletTests, SpentSaplingNoteIsFromMe) {
auto cm = note.cmu().value();
MerkleFrontiers frontiers;
frontiers.sapling.append(cm);
auto anchor = frontiers.sapling.root();
auto witness = frontiers.sapling.witness();
// Generate transaction, which sends funds to note B
auto builder = TransactionBuilder(Params(), 1, std::nullopt);
auto builder = TransactionBuilder(Params(), 1, std::nullopt, anchor);
builder.AddSaplingSpend(sk, note, witness);
builder.AddSaplingOutput(extfvk.fvk.ovk, pk, 25000, {});
auto tx = builder.Build().GetTxOrThrow();
@ -1278,7 +1281,7 @@ TEST(WalletTests, SpentSaplingNoteIsFromMe) {
auto nullifier2 = maybe_nf.value();
// Create transaction to spend note B
auto builder2 = TransactionBuilder(Params(), 2, std::nullopt);
auto builder2 = TransactionBuilder(Params(), 2, std::nullopt, spend_note_witness.root());
builder2.AddSaplingSpend(sk, note2, spend_note_witness);
builder2.AddSaplingOutput(extfvk.fvk.ovk, pk, 12500, {});
auto tx2 = builder2.Build().GetTxOrThrow();
@ -2046,13 +2049,13 @@ TEST(WalletTests, UpdatedSaplingNoteData) {
auto m = GetTestMasterSaplingSpendingKey();
// Generate dummy Sapling address
auto sk = m.Derive(0);
auto sk = m.Derive(0 | HARDENED_KEY_LIMIT);
auto expsk = sk.expsk;
auto extfvk = sk.ToXFVK();
auto pa = extfvk.DefaultAddress();
// Generate dummy recipient Sapling address
auto sk2 = m.Derive(1);
auto sk2 = m.Derive(1 | HARDENED_KEY_LIMIT);
auto expsk2 = sk2.expsk;
auto extfvk2 = sk2.ToXFVK();
auto pa2 = extfvk2.DefaultAddress();
@ -2060,7 +2063,7 @@ TEST(WalletTests, UpdatedSaplingNoteData) {
auto testNote = GetTestSaplingNote(pa, 50000);
// Generate transaction
auto builder = TransactionBuilder(Params(), 1, std::nullopt);
auto builder = TransactionBuilder(Params(), 1, std::nullopt, testNote.tree.root());
builder.AddSaplingSpend(sk, testNote.note, testNote.tree.witness());
builder.AddSaplingOutput(extfvk.fvk.ovk, pa2, 25000, {});
auto tx = builder.Build().GetTxOrThrow();
@ -2223,7 +2226,7 @@ TEST(WalletTests, MarkAffectedSaplingTransactionsDirty) {
// Generate shielding tx from transparent to Sapling
// 0.0005 t-ZEC in, 0.0004 z-ZEC out, default fee
auto builder = TransactionBuilder(Params(), 1, std::nullopt, &keystore);
auto builder = TransactionBuilder(Params(), 1, std::nullopt, SaplingMerkleTree::empty_root(), &keystore);
builder.AddTransparentInput(
COutPoint(uint256S("7777777777777777777777777777777777777777777777777777777777777777"), 0),
scriptPubKey, 5000);
@ -2234,7 +2237,7 @@ TEST(WalletTests, MarkAffectedSaplingTransactionsDirty) {
EXPECT_EQ(tx1.vout.size(), 0);
EXPECT_EQ(tx1.vJoinSplit.size(), 0);
EXPECT_EQ(tx1.GetSaplingSpendsCount(), 0);
EXPECT_EQ(tx1.GetSaplingOutputsCount(), 1);
EXPECT_EQ(tx1.GetSaplingOutputsCount(), 2);
EXPECT_EQ(tx1.GetValueBalanceSapling(), -4000);
CWalletTx wtx {&wallet, tx1};
@ -2269,17 +2272,23 @@ TEST(WalletTests, MarkAffectedSaplingTransactionsDirty) {
wtx = wallet.mapWallet[hash];
// Prepare to spend the note that was just created
auto maybe_pt = wtx.DecryptSaplingNote(Params(), SaplingOutPoint(hash, 0));
auto outpt = SaplingOutPoint(hash, 0);
auto maybe_pt = wtx.DecryptSaplingNote(Params(), outpt);
if (!static_cast<bool>(maybe_pt)) {
outpt = SaplingOutPoint(hash, 1);
maybe_pt = wtx.DecryptSaplingNote(Params(), outpt);
}
ASSERT_EQ(static_cast<bool>(maybe_pt), true);
auto maybe_note = maybe_pt.value().first.note(ivk);
ASSERT_EQ(static_cast<bool>(maybe_note), true);
auto note = maybe_note.value();
auto anchor = frontiers.sapling.root();
auto witness = frontiers.sapling.witness();
auto witness = wtx.mapSaplingNoteData[outpt].witnesses.back();
ASSERT_EQ(anchor, witness.root());
// Create a Sapling-only transaction
// 0.0004 z-ZEC in, 0.00025 z-ZEC out, default fee, 0.00005 z-ZEC change
auto builder2 = TransactionBuilder(Params(), 2, std::nullopt);
auto builder2 = TransactionBuilder(Params(), 2, std::nullopt, anchor);
builder2.AddSaplingSpend(sk, note, witness);
builder2.AddSaplingOutput(extfvk.fvk.ovk, pk, 2500, {});
auto tx2 = builder2.Build().GetTxOrThrow();

View File

@ -48,7 +48,7 @@ TEST(WalletZkeysTest, StoreAndLoadSaplingZkeys) {
// manually add new spending key to wallet
auto m = libzcash::SaplingExtendedSpendingKey::Master(seed);
auto sk = m.Derive(0);
auto sk = m.Derive(0 | HARDENED_KEY_LIMIT);
ASSERT_TRUE(wallet.AddSaplingZKey(sk));
// verify wallet did add it
@ -88,7 +88,7 @@ TEST(WalletZkeysTest, StoreAndLoadSaplingZkeys) {
EXPECT_TRUE(wallet.HaveSaplingIncomingViewingKey(dpa));
// Load a third key into the wallet
auto sk2 = m.Derive(1);
auto sk2 = m.Derive(1 | HARDENED_KEY_LIMIT);
ASSERT_TRUE(wallet.LoadSaplingZKey(sk2));
// attach metadata to this third key

View File

@ -691,7 +691,7 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_importexport)
BOOST_CHECK_EQUAL(retValue.get_str(), testKey);
// create a random Sapling key locally; split between IVKs and spending keys.
auto testSaplingSpendingKey = m.Derive(i);
auto testSaplingSpendingKey = m.Derive(i | HARDENED_KEY_LIMIT);
auto testSaplingPaymentAddress = testSaplingSpendingKey.ToXFVK().DefaultAddress();
if (i % 2 == 0) {
std::string testSaplingAddr = keyIO.EncodePaymentAddress(testSaplingPaymentAddress);
@ -1204,7 +1204,7 @@ BOOST_AUTO_TEST_CASE(rpc_z_sendmany_parameters)
// Mutable tx containing contextual information we need to build tx
UniValue retValue = CallRPC("getblockcount");
int nHeight = retValue.get_int();
TransactionBuilder builder(Params(), nHeight + 1, std::nullopt, pwalletMain);
TransactionBuilder builder(Params(), nHeight + 1, std::nullopt, SaplingMerkleTree::empty_root(), pwalletMain);
}
BOOST_AUTO_TEST_CASE(asyncrpcoperation_sign_send_raw_transaction) {

View File

@ -1481,7 +1481,11 @@ void CWallet::RunSaplingMigration(int blockHeight) {
lastOperation->cancel();
}
pendingSaplingMigrationTxs.clear();
std::shared_ptr<AsyncRPCOperation> operation(new AsyncRPCOperation_saplingmigration(blockHeight + 5));
auto targetHeight = blockHeight + 5;
auto anchorBlockIndex = chainActive[blockHeight - 5];
assert(anchorBlockIndex != nullptr);
auto saplingAnchor = anchorBlockIndex->hashFinalSaplingRoot;
std::shared_ptr<AsyncRPCOperation> operation(new AsyncRPCOperation_saplingmigration(targetHeight, saplingAnchor));
saplingMigrationOperationId = operation->getId();
q->addOperation(operation);
} else if (blockHeight % 500 == 499) {

View File

@ -937,9 +937,6 @@ TransactionBuilderResult TransactionEffects::ApproveAndBuild(
orchardAnchor = anchorBlockIndex->hashFinalOrchardRoot;
}
auto builder = TransactionBuilder(params, nextBlockHeight, orchardAnchor, &wallet);
builder.SetFee(fee);
// Track the total of notes that we've added to the builder. This
// shouldn't strictly be necessary, given `spendable.LimitToAmount`
CAmount totalSpend = 0;
@ -984,6 +981,9 @@ TransactionBuilderResult TransactionEffects::ApproveAndBuild(
}
}
auto builder = TransactionBuilder(params, nextBlockHeight, orchardAnchor, saplingAnchor, &wallet);
builder.SetFee(fee);
// Add Orchard spends
for (size_t i = 0; i < orchardSpendInfo.size(); i++) {
auto spendInfo = std::move(orchardSpendInfo[i]);

View File

@ -55,28 +55,6 @@ std::optional<uint32_t> diversifier_index_t::ToTransparentChildIndex() const {
}
}
//
// SaplingExtendedFullViewingKey
//
std::optional<SaplingExtendedFullViewingKey> SaplingExtendedFullViewingKey::Derive(uint32_t i) const
{
CDataStream ss_p(SER_NETWORK, PROTOCOL_VERSION);
ss_p << *this;
std::array<unsigned char, ZIP32_XFVK_SIZE> p_bytes;
std::copy(ss_p.begin(), ss_p.end(), p_bytes.begin());
try {
auto i_bytes = sapling::zip32::xfvk_derive(p_bytes, i);
CDataStream ss_i(i_bytes, SER_NETWORK, PROTOCOL_VERSION);
SaplingExtendedFullViewingKey xfvk_i;
ss_i >> xfvk_i;
return xfvk_i;
} catch (rust::Error) {
return std::nullopt;
}
}
//
// SaplingDiversifiableFullViewingKey
//
@ -173,6 +151,10 @@ SaplingExtendedSpendingKey SaplingExtendedSpendingKey::Master(const HDSeed& seed
SaplingExtendedSpendingKey SaplingExtendedSpendingKey::Derive(uint32_t i) const
{
if (i < HARDENED_KEY_LIMIT) {
throw std::runtime_error("non-hardened derivation is unsupported");
}
CDataStream ss_p(SER_NETWORK, PROTOCOL_VERSION);
ss_p << *this;
std::array<unsigned char, ZIP32_XSK_SIZE> p_bytes;

View File

@ -257,8 +257,6 @@ public:
READWRITE(dk);
}
std::optional<SaplingExtendedFullViewingKey> Derive(uint32_t i) const;
friend inline bool operator==(const SaplingExtendedFullViewingKey& a, const SaplingExtendedFullViewingKey& b) {
return (
a.depth == b.depth &&

View File

@ -759,6 +759,7 @@ double benchmark_create_sapling_spend()
auto maybe_cmu = note.cmu();
tree.append(maybe_cmu.value());
auto witness = tree.witness();
auto anchor = tree.root().GetRawBytes();
CDataStream ssExtSk(SER_NETWORK, PROTOCOL_VERSION);
ssExtSk << sk;
@ -769,10 +770,9 @@ double benchmark_create_sapling_spend()
std::move(ss.begin(), ss.end(), witnessChars.begin());
auto nHeight = Params().GetConsensus().vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight;
auto builder = sapling::new_builder(*Params().RustNetwork(), nHeight);
auto builder = sapling::new_builder(*Params().RustNetwork(), nHeight, anchor, false);
builder->add_spend(
{reinterpret_cast<uint8_t*>(ssExtSk.data()), ssExtSk.size()},
note.d,
address.GetRawBytes(),
note.value(),
note.rcm().GetRawBytes(),
@ -781,7 +781,7 @@ double benchmark_create_sapling_spend()
struct timeval tv_start;
timer_start(tv_start);
auto result = sapling::build_bundle(std::move(builder), nHeight);
auto result = sapling::build_bundle(std::move(builder));
double t = timer_stop(tv_start);
return t;
@ -791,9 +791,10 @@ double benchmark_create_sapling_output()
{
auto sk = libzcash::SaplingSpendingKey::random();
auto address = sk.default_address();
auto anchor = SaplingMerkleTree::empty_root().GetRawBytes();
auto nHeight = Params().GetConsensus().vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight;
auto builder = sapling::new_builder(*Params().RustNetwork(), nHeight);
auto builder = sapling::new_builder(*Params().RustNetwork(), nHeight, anchor, false);
builder->add_recipient(
uint256().GetRawBytes(),
address.GetRawBytes(),
@ -803,7 +804,7 @@ double benchmark_create_sapling_output()
struct timeval tv_start;
timer_start(tv_start);
auto result = sapling::build_bundle(std::move(builder), nHeight);
auto result = sapling::build_bundle(std::move(builder));
double t = timer_stop(tv_start);
return t;