Add PCZT commands
This commit is contained in:
parent
472362363b
commit
ff072fb1a6
|
@ -348,6 +348,15 @@ dependencies = [
|
|||
"bytemuck",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atomic-polyfill"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4"
|
||||
dependencies = [
|
||||
"critical-section",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atomic-waker"
|
||||
version = "1.1.2"
|
||||
|
@ -504,6 +513,9 @@ checksum = "aa13fae8b6255872fd86f7faf4b41168661d7d78609f7bfe6771b85c6739a15b"
|
|||
dependencies = [
|
||||
"bs58",
|
||||
"hmac",
|
||||
"k256",
|
||||
"once_cell",
|
||||
"pbkdf2",
|
||||
"rand_core",
|
||||
"ripemd",
|
||||
"secp256k1",
|
||||
|
@ -794,6 +806,12 @@ dependencies = [
|
|||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cobs"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67ba02a97a2bd10f4b59b25c7973101c79642302776489e030cd13cdab09ed15"
|
||||
|
||||
[[package]]
|
||||
name = "compact_str"
|
||||
version = "0.8.0"
|
||||
|
@ -871,6 +889,12 @@ dependencies = [
|
|||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "critical-section"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b"
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.5.13"
|
||||
|
@ -1383,6 +1407,18 @@ dependencies = [
|
|||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "embedded-io"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced"
|
||||
|
||||
[[package]]
|
||||
name = "embedded-io"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d"
|
||||
|
||||
[[package]]
|
||||
name = "enum-ordinalize"
|
||||
version = "3.1.15"
|
||||
|
@ -1399,7 +1435,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "equihash"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=e0f04e6c7749751e7f590b2c25275f1fa3421d50#e0f04e6c7749751e7f590b2c25275f1fa3421d50"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=1e274c892a11cd15f643f08ffa579166d60180bb#1e274c892a11cd15f643f08ffa579166d60180bb"
|
||||
dependencies = [
|
||||
"blake2b_simd",
|
||||
"byteorder",
|
||||
|
@ -1435,7 +1471,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "f4jumble"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=e0f04e6c7749751e7f590b2c25275f1fa3421d50#e0f04e6c7749751e7f590b2c25275f1fa3421d50"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=1e274c892a11cd15f643f08ffa579166d60180bb#1e274c892a11cd15f643f08ffa579166d60180bb"
|
||||
dependencies = [
|
||||
"blake2b_simd",
|
||||
]
|
||||
|
@ -1766,6 +1802,18 @@ dependencies = [
|
|||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getset"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f636605b743120a8d32ed92fc27b6cde1a769f8f936c065151eb66f88ded513c"
|
||||
dependencies = [
|
||||
"proc-macro-error2",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.90",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.31.1"
|
||||
|
@ -1869,6 +1917,15 @@ dependencies = [
|
|||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hash32"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.12.3"
|
||||
|
@ -1907,6 +1964,20 @@ dependencies = [
|
|||
"hashbrown 0.14.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heapless"
|
||||
version = "0.7.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f"
|
||||
dependencies = [
|
||||
"atomic-polyfill",
|
||||
"hash32",
|
||||
"rustc_version",
|
||||
"serde",
|
||||
"spin 0.9.8",
|
||||
"stable_deref_trait",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
|
@ -2351,6 +2422,18 @@ dependencies = [
|
|||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "k256"
|
||||
version = "0.13.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"ecdsa",
|
||||
"elliptic-curve",
|
||||
"sha2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "keccak"
|
||||
version = "0.1.5"
|
||||
|
@ -2768,14 +2851,14 @@ checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
|
|||
[[package]]
|
||||
name = "orchard"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4f18e997fa121de5c73e95cdc7e8512ae43b7de38904aeea5e5713cc48f3c0ba"
|
||||
source = "git+https://github.com/zcash/orchard.git?rev=bcd08e1d23e70c42a338f3e3f79d6f4c0c219805#bcd08e1d23e70c42a338f3e3f79d6f4c0c219805"
|
||||
dependencies = [
|
||||
"aes",
|
||||
"bitvec",
|
||||
"blake2b_simd",
|
||||
"ff",
|
||||
"fpe",
|
||||
"getset",
|
||||
"group",
|
||||
"halo2_gadgets",
|
||||
"halo2_proofs",
|
||||
|
@ -2930,6 +3013,31 @@ dependencies = [
|
|||
"password-hash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pczt"
|
||||
version = "0.0.0"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=1e274c892a11cd15f643f08ffa579166d60180bb#1e274c892a11cd15f643f08ffa579166d60180bb"
|
||||
dependencies = [
|
||||
"blake2b_simd",
|
||||
"bls12_381",
|
||||
"ff",
|
||||
"getset",
|
||||
"jubjub",
|
||||
"nonempty",
|
||||
"orchard",
|
||||
"pasta_curves",
|
||||
"postcard",
|
||||
"rand_core",
|
||||
"redjubjub",
|
||||
"sapling-crypto",
|
||||
"secp256k1",
|
||||
"serde",
|
||||
"serde_with",
|
||||
"zcash_note_encryption",
|
||||
"zcash_primitives",
|
||||
"zcash_protocol",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pem-rfc7468"
|
||||
version = "0.7.0"
|
||||
|
@ -3082,6 +3190,19 @@ dependencies = [
|
|||
"thiserror 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "postcard"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "170a2601f67cc9dba8edd8c4870b15f71a6a2dc196daec8c83f72b59dff628a8"
|
||||
dependencies = [
|
||||
"cobs",
|
||||
"embedded-io 0.4.0",
|
||||
"embedded-io 0.6.1",
|
||||
"heapless",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "powerfmt"
|
||||
version = "0.2.0"
|
||||
|
@ -3785,8 +3906,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "sapling-crypto"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cfff8cfce16aeb38da50b8e2ed33c9018f30552beff2210c266662a021b17f38"
|
||||
source = "git+https://github.com/zcash/sapling-crypto.git?rev=29cff9683cdf2f0c522ff3224081dfb4fbc80248#29cff9683cdf2f0c522ff3224081dfb4fbc80248"
|
||||
dependencies = [
|
||||
"aes",
|
||||
"bellman",
|
||||
|
@ -3798,6 +3918,7 @@ dependencies = [
|
|||
"document-features",
|
||||
"ff",
|
||||
"fpe",
|
||||
"getset",
|
||||
"group",
|
||||
"hex",
|
||||
"incrementalmerkletree",
|
||||
|
@ -4209,6 +4330,9 @@ name = "spin"
|
|||
version = "0.9.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spki"
|
||||
|
@ -4261,6 +4385,12 @@ dependencies = [
|
|||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stable_deref_trait"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
|
||||
|
||||
[[package]]
|
||||
name = "static_assertions"
|
||||
version = "1.1.0"
|
||||
|
@ -5709,6 +5839,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -6153,11 +6284,12 @@ checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
|
|||
[[package]]
|
||||
name = "zcash_address"
|
||||
version = "0.6.0"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=e0f04e6c7749751e7f590b2c25275f1fa3421d50#e0f04e6c7749751e7f590b2c25275f1fa3421d50"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=1e274c892a11cd15f643f08ffa579166d60180bb#1e274c892a11cd15f643f08ffa579166d60180bb"
|
||||
dependencies = [
|
||||
"bech32",
|
||||
"bs58",
|
||||
"f4jumble",
|
||||
"serde",
|
||||
"zcash_encoding",
|
||||
"zcash_protocol",
|
||||
]
|
||||
|
@ -6165,7 +6297,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "zcash_client_backend"
|
||||
version = "0.15.0"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=e0f04e6c7749751e7f590b2c25275f1fa3421d50#e0f04e6c7749751e7f590b2c25275f1fa3421d50"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=1e274c892a11cd15f643f08ffa579166d60180bb#1e274c892a11cd15f643f08ffa579166d60180bb"
|
||||
dependencies = [
|
||||
"arti-client",
|
||||
"base64 0.22.1",
|
||||
|
@ -6189,7 +6321,9 @@ dependencies = [
|
|||
"nonempty",
|
||||
"orchard",
|
||||
"pasta_curves",
|
||||
"pczt",
|
||||
"percent-encoding",
|
||||
"postcard",
|
||||
"prost",
|
||||
"rand",
|
||||
"rand_core",
|
||||
|
@ -6225,7 +6359,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "zcash_client_sqlite"
|
||||
version = "0.13.0"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=e0f04e6c7749751e7f590b2c25275f1fa3421d50#e0f04e6c7749751e7f590b2c25275f1fa3421d50"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=1e274c892a11cd15f643f08ffa579166d60180bb#1e274c892a11cd15f643f08ffa579166d60180bb"
|
||||
dependencies = [
|
||||
"bip32",
|
||||
"bs58",
|
||||
|
@ -6244,6 +6378,7 @@ dependencies = [
|
|||
"schemerz",
|
||||
"schemerz-rusqlite",
|
||||
"secrecy 0.8.0",
|
||||
"serde",
|
||||
"shardtree",
|
||||
"static_assertions",
|
||||
"subtle",
|
||||
|
@ -6262,7 +6397,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "zcash_encoding"
|
||||
version = "0.2.1"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=e0f04e6c7749751e7f590b2c25275f1fa3421d50#e0f04e6c7749751e7f590b2c25275f1fa3421d50"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=1e274c892a11cd15f643f08ffa579166d60180bb#1e274c892a11cd15f643f08ffa579166d60180bb"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"nonempty",
|
||||
|
@ -6271,7 +6406,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "zcash_keys"
|
||||
version = "0.5.0"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=e0f04e6c7749751e7f590b2c25275f1fa3421d50#e0f04e6c7749751e7f590b2c25275f1fa3421d50"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=1e274c892a11cd15f643f08ffa579166d60180bb#1e274c892a11cd15f643f08ffa579166d60180bb"
|
||||
dependencies = [
|
||||
"bech32",
|
||||
"bip32",
|
||||
|
@ -6312,7 +6447,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "zcash_primitives"
|
||||
version = "0.20.0"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=e0f04e6c7749751e7f590b2c25275f1fa3421d50#e0f04e6c7749751e7f590b2c25275f1fa3421d50"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=1e274c892a11cd15f643f08ffa579166d60180bb#1e274c892a11cd15f643f08ffa579166d60180bb"
|
||||
dependencies = [
|
||||
"aes",
|
||||
"bip32",
|
||||
|
@ -6323,6 +6458,7 @@ dependencies = [
|
|||
"equihash",
|
||||
"ff",
|
||||
"fpe",
|
||||
"getset",
|
||||
"group",
|
||||
"hex",
|
||||
"incrementalmerkletree",
|
||||
|
@ -6350,7 +6486,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "zcash_proofs"
|
||||
version = "0.20.0"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=e0f04e6c7749751e7f590b2c25275f1fa3421d50#e0f04e6c7749751e7f590b2c25275f1fa3421d50"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=1e274c892a11cd15f643f08ffa579166d60180bb#1e274c892a11cd15f643f08ffa579166d60180bb"
|
||||
dependencies = [
|
||||
"bellman",
|
||||
"blake2b_simd",
|
||||
|
@ -6372,7 +6508,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "zcash_protocol"
|
||||
version = "0.4.1"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=e0f04e6c7749751e7f590b2c25275f1fa3421d50#e0f04e6c7749751e7f590b2c25275f1fa3421d50"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=1e274c892a11cd15f643f08ffa579166d60180bb#1e274c892a11cd15f643f08ffa579166d60180bb"
|
||||
dependencies = [
|
||||
"document-features",
|
||||
"memuse",
|
||||
|
@ -6394,12 +6530,15 @@ dependencies = [
|
|||
"age",
|
||||
"anyhow",
|
||||
"bip0039",
|
||||
"bip32",
|
||||
"crossterm",
|
||||
"futures-util",
|
||||
"gumdrop",
|
||||
"hex",
|
||||
"iso_currency",
|
||||
"jubjub",
|
||||
"orchard",
|
||||
"pczt",
|
||||
"prost",
|
||||
"ratatui",
|
||||
"rayon",
|
||||
|
@ -6486,7 +6625,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "zip321"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=e0f04e6c7749751e7f590b2c25275f1fa3421d50#e0f04e6c7749751e7f590b2c25275f1fa3421d50"
|
||||
source = "git+https://github.com/zcash/librustzcash.git?rev=1e274c892a11cd15f643f08ffa579166d60180bb#1e274c892a11cd15f643f08ffa579166d60180bb"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"nom",
|
||||
|
|
26
Cargo.toml
26
Cargo.toml
|
@ -9,9 +9,11 @@ publish = false
|
|||
[dependencies]
|
||||
anyhow = "1"
|
||||
bip0039 = { version = "0.12", features = ["std", "all-languages"] }
|
||||
bip32 = "0.5"
|
||||
futures-util = "0.3"
|
||||
gumdrop = "0.8"
|
||||
hex = "0.4"
|
||||
jubjub = "0.10"
|
||||
prost = "0.13"
|
||||
rayon = "1.7"
|
||||
rusqlite = { version = "0.32", features = ["time"] }
|
||||
|
@ -27,10 +29,11 @@ tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt"] }
|
|||
uuid = "1"
|
||||
|
||||
orchard = { version = "0.10", default-features = false }
|
||||
pczt = "0.0"
|
||||
sapling = { package = "sapling-crypto", version = "0.3" }
|
||||
zcash_address = "0.6"
|
||||
zcash_client_backend = { version = "0.15", features = ["lightwalletd-tonic-tls-webpki-roots", "orchard", "tor"] }
|
||||
zcash_client_sqlite = { version = "0.13", features = ["unstable", "orchard"] }
|
||||
zcash_client_backend = { version = "0.15", features = ["lightwalletd-tonic-tls-webpki-roots", "orchard", "pczt", "tor"] }
|
||||
zcash_client_sqlite = { version = "0.13", features = ["unstable", "orchard", "serde"] }
|
||||
zcash_keys = { version = "0.5", features = ["unstable", "orchard"] }
|
||||
zcash_primitives = "0.20"
|
||||
zcash_proofs = "0.20"
|
||||
|
@ -66,11 +69,14 @@ tui = [
|
|||
]
|
||||
|
||||
[patch.crates-io]
|
||||
zcash_address = { git = "https://github.com/zcash/librustzcash.git", rev = "e0f04e6c7749751e7f590b2c25275f1fa3421d50" }
|
||||
zcash_client_backend = { git = "https://github.com/zcash/librustzcash.git", rev = "e0f04e6c7749751e7f590b2c25275f1fa3421d50" }
|
||||
zcash_client_sqlite = { git = "https://github.com/zcash/librustzcash.git", rev = "e0f04e6c7749751e7f590b2c25275f1fa3421d50" }
|
||||
zcash_keys = { git = "https://github.com/zcash/librustzcash.git", rev = "e0f04e6c7749751e7f590b2c25275f1fa3421d50" }
|
||||
zcash_primitives = { git = "https://github.com/zcash/librustzcash.git", rev = "e0f04e6c7749751e7f590b2c25275f1fa3421d50" }
|
||||
zcash_proofs = { git = "https://github.com/zcash/librustzcash.git", rev = "e0f04e6c7749751e7f590b2c25275f1fa3421d50" }
|
||||
zcash_protocol = { git = "https://github.com/zcash/librustzcash.git", rev = "e0f04e6c7749751e7f590b2c25275f1fa3421d50" }
|
||||
zip321 = { git = "https://github.com/zcash/librustzcash.git", rev = "e0f04e6c7749751e7f590b2c25275f1fa3421d50" }
|
||||
orchard = { git = "https://github.com/zcash/orchard.git", rev = "bcd08e1d23e70c42a338f3e3f79d6f4c0c219805" }
|
||||
pczt = { git = "https://github.com/zcash/librustzcash.git", rev = "1e274c892a11cd15f643f08ffa579166d60180bb" }
|
||||
sapling-crypto = { git = "https://github.com/zcash/sapling-crypto.git", rev = "29cff9683cdf2f0c522ff3224081dfb4fbc80248" }
|
||||
zcash_address = { git = "https://github.com/zcash/librustzcash.git", rev = "1e274c892a11cd15f643f08ffa579166d60180bb" }
|
||||
zcash_client_backend = { git = "https://github.com/zcash/librustzcash.git", rev = "1e274c892a11cd15f643f08ffa579166d60180bb" }
|
||||
zcash_client_sqlite = { git = "https://github.com/zcash/librustzcash.git", rev = "1e274c892a11cd15f643f08ffa579166d60180bb" }
|
||||
zcash_keys = { git = "https://github.com/zcash/librustzcash.git", rev = "1e274c892a11cd15f643f08ffa579166d60180bb" }
|
||||
zcash_primitives = { git = "https://github.com/zcash/librustzcash.git", rev = "1e274c892a11cd15f643f08ffa579166d60180bb" }
|
||||
zcash_proofs = { git = "https://github.com/zcash/librustzcash.git", rev = "1e274c892a11cd15f643f08ffa579166d60180bb" }
|
||||
zcash_protocol = { git = "https://github.com/zcash/librustzcash.git", rev = "1e274c892a11cd15f643f08ffa579166d60180bb" }
|
||||
zip321 = { git = "https://github.com/zcash/librustzcash.git", rev = "1e274c892a11cd15f643f08ffa579166d60180bb" }
|
||||
|
|
|
@ -7,6 +7,7 @@ pub(crate) mod list_accounts;
|
|||
pub(crate) mod list_addresses;
|
||||
pub(crate) mod list_tx;
|
||||
pub(crate) mod list_unspent;
|
||||
pub(crate) mod pczt;
|
||||
pub(crate) mod propose;
|
||||
pub(crate) mod reset;
|
||||
pub(crate) mod send;
|
||||
|
|
|
@ -28,7 +28,7 @@ impl Command {
|
|||
println!("Account {}", self.account_id);
|
||||
let (ua, _) = account
|
||||
.uivk()
|
||||
.default_address(UnifiedAddressRequest::all().unwrap())?;
|
||||
.default_address(UnifiedAddressRequest::all())?;
|
||||
println!(" Default Address: {}", ua.encode(¶ms));
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
use gumdrop::Options;
|
||||
|
||||
pub(crate) mod combine;
|
||||
pub(crate) mod create;
|
||||
pub(crate) mod prove;
|
||||
pub(crate) mod send;
|
||||
pub(crate) mod sign;
|
||||
|
||||
#[derive(Debug, Options)]
|
||||
pub(crate) enum Command {
|
||||
#[options(help = "create a PCZT")]
|
||||
Create(create::Command),
|
||||
#[options(help = "create proofs for a PCZT")]
|
||||
Prove(prove::Command),
|
||||
#[options(help = "apply signatures to a PCZT")]
|
||||
Sign(sign::Command),
|
||||
#[options(help = "combine two PCZTs")]
|
||||
Combine(combine::Command),
|
||||
#[options(help = "extract a finished transaction and send it")]
|
||||
Send(send::Command),
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
use anyhow::anyhow;
|
||||
use gumdrop::Options;
|
||||
use pczt::{roles::combiner::Combiner, Pczt};
|
||||
use tokio::{
|
||||
fs::File,
|
||||
io::{stdout, AsyncReadExt, AsyncWriteExt},
|
||||
};
|
||||
|
||||
// Options accepted for the `pczt combine` command
|
||||
#[derive(Debug, Options)]
|
||||
pub(crate) struct Command {
|
||||
#[options(help = "a list of PCZT files to combine")]
|
||||
input: Vec<PathBuf>,
|
||||
}
|
||||
|
||||
impl Command {
|
||||
pub(crate) async fn run(self) -> Result<(), anyhow::Error> {
|
||||
let mut pczts = vec![];
|
||||
for f in self.input {
|
||||
let mut f = File::open(f).await?;
|
||||
|
||||
let mut buf = vec![];
|
||||
f.read_to_end(&mut buf).await?;
|
||||
|
||||
let pczt = Pczt::parse(&buf).map_err(|e| anyhow!("Failed to read PCZT: {:?}", e))?;
|
||||
|
||||
pczts.push(pczt);
|
||||
}
|
||||
|
||||
let pczt = Combiner::new(pczts)
|
||||
.combine()
|
||||
.map_err(|e| anyhow!("Failed to combine PCZTs: {:?}", e))?;
|
||||
|
||||
stdout().write_all(&pczt.serialize()).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
#![allow(deprecated)]
|
||||
use std::{num::NonZeroUsize, str::FromStr};
|
||||
|
||||
use anyhow::anyhow;
|
||||
use gumdrop::Options;
|
||||
|
||||
use tokio::io::{stdout, AsyncWriteExt};
|
||||
use zcash_address::ZcashAddress;
|
||||
use zcash_client_backend::{
|
||||
data_api::{
|
||||
wallet::{
|
||||
create_pczt_from_proposal, input_selection::GreedyInputSelector, propose_transfer,
|
||||
},
|
||||
WalletRead,
|
||||
},
|
||||
fees::{standard::MultiOutputChangeStrategy, DustOutputPolicy, SplitPolicy, StandardFeeRule},
|
||||
wallet::OvkPolicy,
|
||||
ShieldedProtocol,
|
||||
};
|
||||
use zcash_client_sqlite::WalletDb;
|
||||
use zcash_protocol::{
|
||||
memo::{Memo, MemoBytes},
|
||||
value::Zatoshis,
|
||||
};
|
||||
use zip321::{Payment, TransactionRequest};
|
||||
|
||||
use crate::{config::WalletConfig, data::get_db_paths, error, MIN_CONFIRMATIONS};
|
||||
|
||||
// Options accepted for the `pczt create` command
|
||||
#[derive(Debug, Options)]
|
||||
pub(crate) struct Command {
|
||||
#[options(
|
||||
required,
|
||||
help = "the recipient's Unified, Sapling or transparent address"
|
||||
)]
|
||||
address: String,
|
||||
|
||||
#[options(required, help = "the amount in zatoshis")]
|
||||
value: u64,
|
||||
|
||||
#[options(help = "a memo to send to the recipient")]
|
||||
memo: Option<String>,
|
||||
|
||||
#[options(
|
||||
help = "note management: the number of notes to maintain in the wallet",
|
||||
default = "4"
|
||||
)]
|
||||
target_note_count: usize,
|
||||
|
||||
#[options(
|
||||
help = "note management: the minimum allowed value for split change amounts",
|
||||
default = "10000000"
|
||||
)]
|
||||
min_split_output_value: u64,
|
||||
}
|
||||
|
||||
impl Command {
|
||||
pub(crate) async fn run(self, wallet_dir: Option<String>) -> Result<(), anyhow::Error> {
|
||||
let config = WalletConfig::read(wallet_dir.as_ref())?;
|
||||
let params = config.network();
|
||||
|
||||
let (_, db_data) = get_db_paths(wallet_dir.as_ref());
|
||||
let mut db_data = WalletDb::for_path(db_data, params)?;
|
||||
let account_id = *db_data
|
||||
.get_account_ids()?
|
||||
.first()
|
||||
.ok_or(anyhow!("Wallet has no accounts"))?;
|
||||
|
||||
// Create the PCZT.
|
||||
let change_strategy = MultiOutputChangeStrategy::new(
|
||||
StandardFeeRule::Zip317,
|
||||
None,
|
||||
ShieldedProtocol::Orchard,
|
||||
DustOutputPolicy::default(),
|
||||
SplitPolicy::with_min_output_value(
|
||||
NonZeroUsize::new(self.target_note_count)
|
||||
.ok_or(anyhow!("target note count must be nonzero"))?,
|
||||
Zatoshis::from_u64(self.min_split_output_value)?,
|
||||
),
|
||||
);
|
||||
let input_selector = GreedyInputSelector::new();
|
||||
|
||||
let request = TransactionRequest::new(vec![Payment::new(
|
||||
ZcashAddress::from_str(&self.address).map_err(|_| error::Error::InvalidRecipient)?,
|
||||
Zatoshis::from_u64(self.value).map_err(|_| error::Error::InvalidAmount)?,
|
||||
self.memo
|
||||
.map(|memo| Memo::from_str(&memo))
|
||||
.transpose()?
|
||||
.map(MemoBytes::from),
|
||||
None,
|
||||
None,
|
||||
vec![],
|
||||
)
|
||||
.ok_or_else(|| anyhow!("Invalid memo"))?])
|
||||
.map_err(error::Error::from)?;
|
||||
|
||||
let proposal = propose_transfer(
|
||||
&mut db_data,
|
||||
¶ms,
|
||||
account_id,
|
||||
&input_selector,
|
||||
&change_strategy,
|
||||
request,
|
||||
MIN_CONFIRMATIONS,
|
||||
)
|
||||
.map_err(error::Error::from)?;
|
||||
|
||||
let pczt = create_pczt_from_proposal(
|
||||
&mut db_data,
|
||||
¶ms,
|
||||
account_id,
|
||||
OvkPolicy::Sender,
|
||||
&proposal,
|
||||
)
|
||||
.map_err(error::Error::from)?;
|
||||
|
||||
stdout().write_all(&pczt.serialize()).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -0,0 +1,198 @@
|
|||
use anyhow::anyhow;
|
||||
use gumdrop::Options;
|
||||
use pczt::{
|
||||
roles::{prover::Prover, updater::Updater},
|
||||
Pczt,
|
||||
};
|
||||
use sapling::ProofGenerationKey;
|
||||
use secrecy::ExposeSecret;
|
||||
use tokio::io::{stdin, stdout, AsyncReadExt, AsyncWriteExt};
|
||||
use zcash_keys::keys::UnifiedSpendingKey;
|
||||
use zcash_proofs::prover::LocalTxProver;
|
||||
use zcash_protocol::consensus::{NetworkConstants, Parameters};
|
||||
use zip32::fingerprint::SeedFingerprint;
|
||||
|
||||
use crate::config::WalletConfig;
|
||||
|
||||
// Options accepted for the `pczt prove` command
|
||||
#[derive(Debug, Options)]
|
||||
pub(crate) struct Command {
|
||||
#[options(
|
||||
help = "hex encoding of the Sapling proof generation key",
|
||||
parse(try_from_str = "hex::decode")
|
||||
)]
|
||||
sapling_proof_generation_key: Option<Vec<u8>>,
|
||||
|
||||
#[options(
|
||||
help = "age identity file to decrypt the mnemonic phrase with for deriving the Sapling proof generation key"
|
||||
)]
|
||||
identity: Option<String>,
|
||||
}
|
||||
|
||||
impl Command {
|
||||
pub(crate) async fn run(self, wallet_dir: Option<String>) -> Result<(), anyhow::Error> {
|
||||
let mut buf = vec![];
|
||||
stdin().read_to_end(&mut buf).await?;
|
||||
|
||||
let pczt = Pczt::parse(&buf).map_err(|e| anyhow!("Failed to read PCZT: {:?}", e))?;
|
||||
|
||||
// If we have Sapling spends, we need Sapling proof generation keys.
|
||||
let pczt = if !pczt.sapling().spends().is_empty() {
|
||||
enum PgkSource {
|
||||
Provided(ProofGenerationKey),
|
||||
Wallet {
|
||||
config: WalletConfig,
|
||||
seed_fp: SeedFingerprint,
|
||||
},
|
||||
}
|
||||
|
||||
impl PgkSource {
|
||||
fn proof_generation_key(
|
||||
&self,
|
||||
derivation: Option<([u8; 32], Vec<zip32::ChildIndex>)>,
|
||||
) -> anyhow::Result<ProofGenerationKey> {
|
||||
match self {
|
||||
PgkSource::Provided(proof_generation_key) => {
|
||||
Ok(proof_generation_key.clone())
|
||||
}
|
||||
PgkSource::Wallet { config, seed_fp } => {
|
||||
if let Some((seed_fingerprint, derivation_path)) = derivation {
|
||||
let params = config.network();
|
||||
|
||||
if seed_fingerprint == seed_fp.to_bytes()
|
||||
&& derivation_path.len() == 3
|
||||
&& derivation_path[0] == zip32::ChildIndex::hardened(32)
|
||||
&& derivation_path[1]
|
||||
== zip32::ChildIndex::hardened(
|
||||
params.network_type().coin_type(),
|
||||
)
|
||||
{
|
||||
let account_index = zip32::AccountId::try_from(
|
||||
derivation_path[2].index() - (1 << 31),
|
||||
)
|
||||
.expect("valid");
|
||||
|
||||
let usk = UnifiedSpendingKey::from_seed(
|
||||
¶ms,
|
||||
config
|
||||
.seed()
|
||||
.ok_or(anyhow!(
|
||||
"Seed must be present to enable signing"
|
||||
))?
|
||||
.expose_secret(),
|
||||
account_index,
|
||||
)?;
|
||||
|
||||
Ok(usk.sapling().expsk.proof_generation_key())
|
||||
} else {
|
||||
Err(anyhow!(
|
||||
"Invalid ZIP 32 derivation path for PCZT Sapling spend"
|
||||
))
|
||||
}
|
||||
} else {
|
||||
Err(anyhow!(
|
||||
"Missing ZIP 32 derivation path for PCZT Sapling spend"
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let pkg_source = match (self.sapling_proof_generation_key, self.identity) {
|
||||
(Some(proof_generation_key), _) => {
|
||||
if proof_generation_key.len() == 64 {
|
||||
Ok(PgkSource::Provided(sapling::keys::ProofGenerationKey {
|
||||
ak: sapling::keys::SpendValidatingKey::temporary_zcash_from_bytes(
|
||||
&proof_generation_key[..32],
|
||||
)
|
||||
.ok_or_else(|| anyhow!("Invalid Sapling proof generation key"))?,
|
||||
nsk: jubjub::Scalar::from_bytes(
|
||||
&proof_generation_key[32..].try_into().unwrap(),
|
||||
)
|
||||
.into_option()
|
||||
.ok_or_else(|| anyhow!("Invalid Sapling proof generation key"))?,
|
||||
}))
|
||||
} else {
|
||||
Err(anyhow!("Invalid Sapling proof generation key"))
|
||||
}
|
||||
}
|
||||
(None, Some(identity)) => {
|
||||
// Try to load it from the wallet config.
|
||||
let mut config = WalletConfig::read(wallet_dir.as_ref())?;
|
||||
|
||||
// Decrypt the mnemonic to access the seed.
|
||||
let identities = age::IdentityFile::from_file(identity)?.into_identities()?;
|
||||
config.decrypt(identities.iter().map(|i| i.as_ref() as _))?;
|
||||
|
||||
// Cache the seed fingerprint for matching.
|
||||
let seed = config
|
||||
.seed()
|
||||
.ok_or(anyhow!("Seed must be present to enable signing"))?
|
||||
.expose_secret();
|
||||
let seed_fingerprint = SeedFingerprint::from_seed(seed)
|
||||
.ok_or_else(|| anyhow!("Invalid seed length"))?;
|
||||
|
||||
Ok(PgkSource::Wallet {
|
||||
config,
|
||||
seed_fp: seed_fingerprint,
|
||||
})
|
||||
}
|
||||
(None, None) => Err(anyhow!(
|
||||
"Cannot create Sapling proofs without a proof generation key"
|
||||
)),
|
||||
}?;
|
||||
|
||||
// Add Sapling proof generation key.
|
||||
Updater::new(pczt)
|
||||
.update_sapling_with(|mut updater| {
|
||||
let non_dummy_spends = updater
|
||||
.bundle()
|
||||
.spends()
|
||||
.iter()
|
||||
.enumerate()
|
||||
// Dummy spends will already have a proof generation key.
|
||||
.filter(|(_, spend)| spend.proof_generation_key().is_none())
|
||||
.map(|(index, spend)| {
|
||||
(
|
||||
index,
|
||||
spend
|
||||
.zip32_derivation()
|
||||
.as_ref()
|
||||
.map(|d| (*d.seed_fingerprint(), d.derivation_path().clone())),
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Assume all non-dummy spent notes are from the same account.
|
||||
for (index, derivation) in non_dummy_spends {
|
||||
updater.update_spend_with(index, |mut spend_updater| {
|
||||
spend_updater.set_proof_generation_key(
|
||||
pkg_source.proof_generation_key(derivation).unwrap(),
|
||||
)
|
||||
})?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.map_err(|e| anyhow!("Failed to add Sapling proof generation key: {:?}", e))?
|
||||
.finish()
|
||||
} else {
|
||||
pczt
|
||||
};
|
||||
|
||||
let prover =
|
||||
LocalTxProver::with_default_location().ok_or(anyhow!("Missing Sapling parameters"))?;
|
||||
|
||||
let pczt = Prover::new(pczt)
|
||||
.create_orchard_proof(&orchard::circuit::ProvingKey::build())
|
||||
.map_err(|e| anyhow!("Failed to create Orchard proof: {:?}", e))?
|
||||
.create_sapling_proofs(&prover, &prover)
|
||||
.map_err(|e| anyhow!("Failed to create Sapling proofs: {:?}", e))?
|
||||
.finish();
|
||||
|
||||
stdout().write_all(&pczt.serialize()).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
use anyhow::anyhow;
|
||||
use gumdrop::Options;
|
||||
|
||||
use pczt::Pczt;
|
||||
use tokio::io::{stdin, AsyncReadExt};
|
||||
use zcash_client_backend::{
|
||||
data_api::{wallet::extract_and_store_transaction_from_pczt, WalletRead},
|
||||
proto::service,
|
||||
};
|
||||
use zcash_client_sqlite::WalletDb;
|
||||
use zcash_proofs::prover::LocalTxProver;
|
||||
|
||||
use crate::{
|
||||
config::WalletConfig,
|
||||
data::get_db_paths,
|
||||
error,
|
||||
remote::{tor_client, Servers},
|
||||
};
|
||||
|
||||
// Options accepted for the `pczt send` command
|
||||
#[derive(Debug, Options)]
|
||||
pub(crate) struct Command {
|
||||
#[options(
|
||||
help = "the server to send via (default is \"ecc\")",
|
||||
default = "ecc",
|
||||
parse(try_from_str = "Servers::parse")
|
||||
)]
|
||||
server: Servers,
|
||||
|
||||
#[options(help = "disable connections via TOR")]
|
||||
disable_tor: bool,
|
||||
}
|
||||
|
||||
impl Command {
|
||||
pub(crate) async fn run(self, wallet_dir: Option<String>) -> Result<(), anyhow::Error> {
|
||||
let config = WalletConfig::read(wallet_dir.as_ref())?;
|
||||
let params = config.network();
|
||||
|
||||
let (_, db_data) = get_db_paths(wallet_dir.as_ref());
|
||||
let mut db_data = WalletDb::for_path(db_data, params)?;
|
||||
|
||||
let server = self.server.pick(params)?;
|
||||
let mut client = if self.disable_tor {
|
||||
server.connect_direct().await?
|
||||
} else {
|
||||
server.connect(|| tor_client(wallet_dir.as_ref())).await?
|
||||
};
|
||||
|
||||
let mut buf = vec![];
|
||||
stdin().read_to_end(&mut buf).await?;
|
||||
|
||||
let pczt = Pczt::parse(&buf).map_err(|e| anyhow!("Failed to read PCZT: {:?}", e))?;
|
||||
|
||||
let prover =
|
||||
LocalTxProver::with_default_location().ok_or(anyhow!("Missing Sapling parameters"))?;
|
||||
let (spend_vk, output_vk) = prover.verifying_keys();
|
||||
|
||||
let txid = extract_and_store_transaction_from_pczt::<_, ()>(
|
||||
&mut db_data,
|
||||
pczt,
|
||||
&spend_vk,
|
||||
&output_vk,
|
||||
&orchard::circuit::VerifyingKey::build(),
|
||||
)
|
||||
.map_err(|e| anyhow!("Failed to extract and store transaction from PCZT: {:?}", e))?;
|
||||
|
||||
// Send the transaction.
|
||||
println!("Sending transaction...");
|
||||
let (txid, raw_tx) = db_data
|
||||
.get_transaction(txid)?
|
||||
.map(|tx| {
|
||||
let mut raw_tx = service::RawTransaction::default();
|
||||
tx.write(&mut raw_tx.data).unwrap();
|
||||
(tx.txid(), raw_tx)
|
||||
})
|
||||
.ok_or(anyhow!("Transaction not found for id {:?}", txid))?;
|
||||
let response = client.send_transaction(raw_tx).await?.into_inner();
|
||||
|
||||
if response.error_code != 0 {
|
||||
Err(error::Error::SendFailed {
|
||||
code: response.error_code,
|
||||
reason: response.error_message,
|
||||
}
|
||||
.into())
|
||||
} else {
|
||||
println!("{}", txid);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,206 @@
|
|||
use std::collections::BTreeMap;
|
||||
|
||||
use anyhow::anyhow;
|
||||
use gumdrop::Options;
|
||||
use pczt::{
|
||||
roles::{signer::Signer, updater::Updater},
|
||||
Pczt,
|
||||
};
|
||||
use secrecy::ExposeSecret;
|
||||
use tokio::io::{stdin, stdout, AsyncReadExt, AsyncWriteExt};
|
||||
use zcash_keys::keys::UnifiedSpendingKey;
|
||||
use zcash_primitives::legacy::keys::{NonHardenedChildIndex, TransparentKeyScope};
|
||||
use zcash_protocol::consensus::{NetworkConstants, Parameters};
|
||||
use zip32::fingerprint::SeedFingerprint;
|
||||
|
||||
use crate::config::WalletConfig;
|
||||
|
||||
// Options accepted for the `pczt sign` command
|
||||
#[derive(Debug, Options)]
|
||||
pub(crate) struct Command {
|
||||
#[options(help = "age identity file to decrypt the mnemonic phrase with")]
|
||||
identity: String,
|
||||
}
|
||||
|
||||
impl Command {
|
||||
pub(crate) async fn run(self, wallet_dir: Option<String>) -> Result<(), anyhow::Error> {
|
||||
let mut config = WalletConfig::read(wallet_dir.as_ref())?;
|
||||
let params = config.network();
|
||||
|
||||
let mut buf = vec![];
|
||||
stdin().read_to_end(&mut buf).await?;
|
||||
|
||||
let pczt = Pczt::parse(&buf).map_err(|e| anyhow!("Failed to read PCZT: {:?}", e))?;
|
||||
|
||||
// Decrypt the mnemonic to access the seed.
|
||||
let identities = age::IdentityFile::from_file(self.identity)?.into_identities()?;
|
||||
config.decrypt(identities.iter().map(|i| i.as_ref() as _))?;
|
||||
|
||||
let seed = config
|
||||
.seed()
|
||||
.ok_or(anyhow!("Seed must be present to enable signing"))?
|
||||
.expose_secret();
|
||||
let seed_fp =
|
||||
SeedFingerprint::from_seed(seed).ok_or_else(|| anyhow!("Invalid seed length"))?;
|
||||
|
||||
// Find all the spends matching our seed. For now as a hack, we use the Updater
|
||||
// role to access the bundle data we need.
|
||||
enum KeyRef {
|
||||
Orchard {
|
||||
index: usize,
|
||||
},
|
||||
Sapling {
|
||||
index: usize,
|
||||
},
|
||||
Transparent {
|
||||
index: usize,
|
||||
scope: TransparentKeyScope,
|
||||
address_index: NonHardenedChildIndex,
|
||||
},
|
||||
}
|
||||
let mut keys = BTreeMap::<zip32::AccountId, Vec<KeyRef>>::new();
|
||||
let pczt = Updater::new(pczt)
|
||||
.update_orchard_with(|updater| {
|
||||
for (index, action) in updater.bundle().actions().iter().enumerate() {
|
||||
if let Some(derivation) = action.spend().zip32_derivation() {
|
||||
if derivation.seed_fingerprint() == &seed_fp.to_bytes()
|
||||
&& derivation.derivation_path().len() == 3
|
||||
&& derivation.derivation_path()[0] == zip32::ChildIndex::hardened(32)
|
||||
&& derivation.derivation_path()[1]
|
||||
== zip32::ChildIndex::hardened(params.network_type().coin_type())
|
||||
{
|
||||
let account_index = zip32::AccountId::try_from(
|
||||
derivation.derivation_path()[2].index() - (1 << 31),
|
||||
)
|
||||
.expect("valid");
|
||||
|
||||
keys.entry(account_index)
|
||||
.or_default()
|
||||
.push(KeyRef::Orchard { index });
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
.expect("no errors")
|
||||
.update_sapling_with(|updater| {
|
||||
for (index, spend) in updater.bundle().spends().iter().enumerate() {
|
||||
if let Some(derivation) = spend.zip32_derivation() {
|
||||
if derivation.seed_fingerprint() == &seed_fp.to_bytes()
|
||||
&& derivation.derivation_path().len() == 3
|
||||
&& derivation.derivation_path()[0] == zip32::ChildIndex::hardened(32)
|
||||
&& derivation.derivation_path()[1]
|
||||
== zip32::ChildIndex::hardened(params.network_type().coin_type())
|
||||
{
|
||||
let account_index = zip32::AccountId::try_from(
|
||||
derivation.derivation_path()[2].index() - (1 << 31),
|
||||
)
|
||||
.expect("valid");
|
||||
|
||||
keys.entry(account_index)
|
||||
.or_default()
|
||||
.push(KeyRef::Sapling { index });
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
.expect("no errors")
|
||||
.update_transparent_with(|updater| {
|
||||
for (index, input) in updater.bundle().inputs().iter().enumerate() {
|
||||
for derivation in input.bip32_derivation().values() {
|
||||
if derivation.seed_fingerprint() == &seed_fp.to_bytes()
|
||||
&& derivation.derivation_path().len() == 5
|
||||
&& derivation.derivation_path()[0]
|
||||
== bip32::ChildNumber::new(32, true).expect("valid")
|
||||
&& derivation.derivation_path()[1]
|
||||
== bip32::ChildNumber::new(params.network_type().coin_type(), true)
|
||||
.expect("valid")
|
||||
&& derivation.derivation_path()[2].is_hardened()
|
||||
&& !derivation.derivation_path()[3].is_hardened()
|
||||
&& !derivation.derivation_path()[4].is_hardened()
|
||||
{
|
||||
let account_index = zip32::AccountId::try_from(
|
||||
derivation.derivation_path()[2].index() - (1 << 31),
|
||||
)
|
||||
.expect("valid");
|
||||
|
||||
let scope = TransparentKeyScope::custom(
|
||||
derivation.derivation_path()[3].index(),
|
||||
)
|
||||
.expect("valid");
|
||||
let address_index = NonHardenedChildIndex::from_index(
|
||||
derivation.derivation_path()[4].index(),
|
||||
)
|
||||
.expect("valid");
|
||||
|
||||
keys.entry(account_index)
|
||||
.or_default()
|
||||
.push(KeyRef::Transparent {
|
||||
index,
|
||||
scope,
|
||||
address_index,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
.expect("no errors")
|
||||
.finish();
|
||||
|
||||
let mut signer =
|
||||
Signer::new(pczt).map_err(|e| anyhow!("Failed to initialize Signer: {:?}", e))?;
|
||||
for (account_index, spends) in keys {
|
||||
let usk = UnifiedSpendingKey::from_seed(¶ms, seed, account_index)?;
|
||||
for keyref in spends {
|
||||
match keyref {
|
||||
KeyRef::Orchard { index } => {
|
||||
signer
|
||||
.sign_orchard(
|
||||
index,
|
||||
&orchard::keys::SpendAuthorizingKey::from(usk.orchard()),
|
||||
)
|
||||
.map_err(|e| {
|
||||
anyhow!("Failed to sign Orchard spend {index}: {:?}", e)
|
||||
})?;
|
||||
}
|
||||
KeyRef::Sapling { index } => {
|
||||
signer
|
||||
.sign_sapling(index, &usk.sapling().expsk.ask)
|
||||
.map_err(|e| {
|
||||
anyhow!("Failed to sign Sapling spend {index}: {:?}", e)
|
||||
})?;
|
||||
}
|
||||
KeyRef::Transparent {
|
||||
index,
|
||||
scope,
|
||||
address_index,
|
||||
} => signer
|
||||
.sign_transparent(
|
||||
index,
|
||||
&usk.transparent()
|
||||
.derive_secret_key(scope, address_index)
|
||||
.map_err(|e| {
|
||||
anyhow!(
|
||||
"Failed to derive transparent key at .../{:?}/{:?}: {:?}",
|
||||
scope,
|
||||
address_index,
|
||||
e,
|
||||
)
|
||||
})?,
|
||||
)
|
||||
.map_err(|e| {
|
||||
anyhow!("Failed to sign transparent input {index}: {:?}", e)
|
||||
})?,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let pczt = signer.finish();
|
||||
|
||||
stdout().write_all(&pczt.serialize()).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
12
src/main.rs
12
src/main.rs
|
@ -78,6 +78,9 @@ enum Command {
|
|||
|
||||
#[options(help = "send funds to the given address")]
|
||||
Send(commands::send::Command),
|
||||
|
||||
#[options(help = "send funds using PCZTs")]
|
||||
Pczt(commands::pczt::Command),
|
||||
}
|
||||
|
||||
fn main() -> Result<(), anyhow::Error> {
|
||||
|
@ -151,7 +154,14 @@ fn main() -> Result<(), anyhow::Error> {
|
|||
Some(Command::ListUnspent(command)) => command.run(opts.wallet_dir),
|
||||
Some(Command::Propose(command)) => command.run(opts.wallet_dir).await,
|
||||
Some(Command::Send(command)) => command.run(opts.wallet_dir).await,
|
||||
_ => Ok(()),
|
||||
Some(Command::Pczt(command)) => match command {
|
||||
commands::pczt::Command::Create(command) => command.run(opts.wallet_dir).await,
|
||||
commands::pczt::Command::Prove(command) => command.run(opts.wallet_dir).await,
|
||||
commands::pczt::Command::Sign(command) => command.run(opts.wallet_dir).await,
|
||||
commands::pczt::Command::Combine(command) => command.run().await,
|
||||
commands::pczt::Command::Send(command) => command.run(opts.wallet_dir).await,
|
||||
},
|
||||
None => Ok(()),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue