TransactionSaplingValid
This commit is contained in:
parent
964f027422
commit
3a1cf6dc15
|
@ -65,6 +65,21 @@ dependencies = [
|
|||
"safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bellman"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bit-vec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures-cpupool 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pairing 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bencher"
|
||||
version = "0.1.0"
|
||||
|
@ -131,6 +146,16 @@ dependencies = [
|
|||
"constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "blake2-rfc"
|
||||
version = "0.2.18"
|
||||
source = "git+https://github.com/gtank/blake2-rfc?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9#7a5b5fc99ae483a0043db7547fb79a6fa44b88a9"
|
||||
dependencies = [
|
||||
"arrayvec 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.2.3"
|
||||
|
@ -187,6 +212,11 @@ name = "constant_time_eq"
|
|||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.2.0"
|
||||
|
@ -204,7 +234,7 @@ dependencies = [
|
|||
"arrayvec 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -253,6 +283,14 @@ dependencies = [
|
|||
"test-data 0.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "display_derive"
|
||||
version = "0.0.0"
|
||||
|
@ -373,6 +411,14 @@ dependencies = [
|
|||
"rayon 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getopts"
|
||||
version = "0.2.15"
|
||||
|
@ -540,7 +586,7 @@ dependencies = [
|
|||
"base58 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitcrypto 0.1.0",
|
||||
"eth-secp256k1 0.5.7 (git+https://github.com/ethcore/rust-secp256k1)",
|
||||
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"primitives 0.1.0",
|
||||
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-hex 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -553,7 +599,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.0.0"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
|
@ -732,7 +778,7 @@ name = "network"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"chain 0.1.0",
|
||||
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"primitives 0.1.0",
|
||||
"rustc-hex 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serialization 0.1.0",
|
||||
|
@ -806,6 +852,15 @@ dependencies = [
|
|||
"tokio-io 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pairing"
|
||||
version = "0.14.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.4.8"
|
||||
|
@ -929,7 +984,7 @@ version = "1.4.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -1075,6 +1130,19 @@ name = "safemem"
|
|||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "sapling-crypto"
|
||||
version = "0.0.1"
|
||||
source = "git+https://github.com/zcash-hackworks/sapling-crypto.git?rev=21084bde2019c04bd34208e63c3560fe2c02fb0e#21084bde2019c04bd34208e63c3560fe2c02fb0e"
|
||||
dependencies = [
|
||||
"bellman 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9)",
|
||||
"byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pairing 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scoped-tls"
|
||||
version = "0.1.0"
|
||||
|
@ -1340,7 +1408,7 @@ name = "thread_local"
|
|||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
|
@ -1405,6 +1473,11 @@ dependencies = [
|
|||
"futures 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "ucd-util"
|
||||
version = "0.1.2"
|
||||
|
@ -1450,18 +1523,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
name = "verification"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bellman 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitcrypto 0.1.0",
|
||||
"blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc.git?branch=persona)",
|
||||
"byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"chain 0.1.0",
|
||||
"db 0.1.0",
|
||||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"network 0.1.0",
|
||||
"pairing 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"primitives 0.1.0",
|
||||
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-hex 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sapling-crypto 0.0.1 (git+https://github.com/zcash-hackworks/sapling-crypto.git?rev=21084bde2019c04bd34208e63c3560fe2c02fb0e)",
|
||||
"script 0.1.0",
|
||||
"serialization 0.1.0",
|
||||
"storage 0.1.0",
|
||||
|
@ -1553,23 +1630,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
"checksum atty 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "21e50800ec991574876040fff8ee46b136a53e985286fbe6a3bdfe6421b78860"
|
||||
"checksum base58 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5024ee8015f02155eee35c711107ddd9a9bf3cb689cf2a9089c97e79b6e1ae83"
|
||||
"checksum base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96434f987501f0ed4eb336a411e0631ecd1afa11574fe148587adc4ff96143c9"
|
||||
"checksum bellman 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "eae372472c7ea8f7c8fc6a62f7d5535db8302de7f1aafda2e13a97c4830d3bcf"
|
||||
"checksum bigint 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "5d1b3ef6756498df0e2c6bb67c065f4154d0ecd721eb5b3c3f865c8012b9fd74"
|
||||
"checksum bit-vec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "02b4ff8b16e6076c3e14220b39fbc1fabb6737522281a388998046859400895f"
|
||||
"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
|
||||
"checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"
|
||||
"checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf"
|
||||
"checksum blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc.git?branch=persona)" = "<none>"
|
||||
"checksum blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9)" = "<none>"
|
||||
"checksum byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "74c0b906e9446b0a2e4f760cdb3fa4b2c48cdc6db8766a845c54b6ff063fd2e9"
|
||||
"checksum bytes 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d828f97b58cc5de3e40c421d0cf2132d6b2da4ee0e11b8632fa838f0f9333ad6"
|
||||
"checksum cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a9b13a57efd6b30ecd6598ebdb302cca617930b5470647570468a65d12ef9719"
|
||||
"checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de"
|
||||
"checksum clap 2.27.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1b8c532887f1a292d17de05ae858a8fe50a301e196f9ef0ddb7ccd0d1d00f180"
|
||||
"checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e"
|
||||
"checksum crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "24ce9782d4d5c53674646a6a4c1863a21a8fc0cb649b3c94dfc16e45071dea19"
|
||||
"checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3"
|
||||
"checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150"
|
||||
"checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9"
|
||||
"checksum csv 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "71903184af9960c555e7f3b32ff17390d20ecaaf17d4f18c4a0993f2df8a49e3"
|
||||
"checksum csv-core 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4dd8e6d86f7ba48b4276ef1317edc8cc36167546d8972feb4a2b5fec0b374105"
|
||||
"checksum digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "03b072242a8cbaf9c145665af9d250c59af3b958f83ed6824e13533cf76d5b90"
|
||||
"checksum display_derive 0.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4bba5dcd6d2855639fcf65a9af7bbad0bfb6dbf6fe68fba70bab39a6eb973ef4"
|
||||
"checksum domain 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c1850bf2c3c3349e1dba2aa214d86cf9edaa057a09ce46b1a02d5c07d5da5e65"
|
||||
"checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"
|
||||
|
@ -1585,6 +1666,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
"checksum futures 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "118b49cac82e04121117cbd3121ede3147e885627d82c4546b87c702debb90c1"
|
||||
"checksum futures-cpupool 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "e86f49cc0d92fe1b97a5980ec32d56208272cbb00f15044ea9e2799dde766fdf"
|
||||
"checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb"
|
||||
"checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d"
|
||||
"checksum getopts 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "65922871abd2f101a2eb0eaebadc66668e54a87ad9c3dd82520b5f86ede5eff9"
|
||||
"checksum globset 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "90d069fe6beb9be359ef505650b3f73228c5591a3c4b1f32be2f4f44459ffa3a"
|
||||
"checksum heapsize 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "556cd479866cf85c3f671209c85e8a6990211c916d1002c2fcb2e9b7cf60bc36"
|
||||
|
@ -1601,7 +1683,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
"checksum jsonrpc-server-utils 8.0.0 (git+https://github.com/ethcore/jsonrpc.git)" = "<none>"
|
||||
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||
"checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a"
|
||||
"checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d"
|
||||
"checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1"
|
||||
"checksum lazycell 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3b585b7a6811fb03aa10e74b278a0f00f8dd9b45dc681f148bb29fa5cb61859b"
|
||||
"checksum libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "5ba3df4dcb460b9dfbd070d41c94c19209620c191b0340b929ce748a2bcd42d2"
|
||||
"checksum linked-hash-map 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6d262045c5b87c0861b3f004610afd0e2c851e2908d08b6c870cbb9d5f494ecd"
|
||||
|
@ -1624,6 +1706,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
"checksum num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "514f0d73e64be53ff320680ca671b64fe3fb91da01e1ae2ddc99eb51d453b20d"
|
||||
"checksum ole32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d2c49021782e5233cd243168edfa8037574afed4eba4bbaf538b3d8d1789d8c"
|
||||
"checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37"
|
||||
"checksum pairing 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ceda21136251c6d5a422d3d798d8ac22515a6e8d3521bb60c59a8349d36d0d57"
|
||||
"checksum parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "149d8f5b97f3c1133e3cfcd8886449959e856b557ff281e292b733d7c69e005e"
|
||||
"checksum parking_lot_core 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4f610cb9664da38e417ea3225f23051f589851999535290e077939838ab7a595"
|
||||
"checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831"
|
||||
|
@ -1649,6 +1732,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
|
||||
"checksum rustc_version 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b9743a7670d88d5d52950408ecdb7c71d8986251ab604d4689dd2ca25c9bca69"
|
||||
"checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f"
|
||||
"checksum sapling-crypto 0.0.1 (git+https://github.com/zcash-hackworks/sapling-crypto.git?rev=21084bde2019c04bd34208e63c3560fe2c02fb0e)" = "<none>"
|
||||
"checksum scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f417c22df063e9450888a7561788e9bd46d3bb3c1466435b4eccb903807f147d"
|
||||
"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27"
|
||||
"checksum semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a3186ec9e65071a2095434b1f5bb24838d4e8e130f584c790f6033c79943537"
|
||||
|
@ -1680,6 +1764,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
"checksum tokio-io 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "514aae203178929dbf03318ad7c683126672d4d96eccb77b29603d33c9e25743"
|
||||
"checksum tokio-proto 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8fbb47ae81353c63c487030659494b295f6cb6576242f907f203473b191b0389"
|
||||
"checksum tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "24da22d077e0f15f55162bdbdc661228c1581892f52074fb242678d015b45162"
|
||||
"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169"
|
||||
"checksum ucd-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d0f8bfa9ff0cadcd210129ad9d2c5f145c13e9ced3d3e5d948a6213487d52444"
|
||||
"checksum unicase 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "284b6d3db520d67fbe88fd778c21510d1b0ba4a551e5d0fbb023d33405f6de8a"
|
||||
"checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f"
|
||||
|
|
|
@ -1,38 +1,81 @@
|
|||
use std::fmt;
|
||||
use hex::ToHex;
|
||||
|
||||
///
|
||||
#[derive(Clone)]
|
||||
pub struct Sapling {
|
||||
pub amount: i64,
|
||||
/// The net value of Spend transfers minus Output transfers in a transaction is
|
||||
/// called the balancing_value.
|
||||
/// A positive balancing_value takes value from the Sapling value pool and adds
|
||||
/// it to the transparent value pool.
|
||||
/// A negative balancing value does the reverse.
|
||||
pub balancing_value: i64,
|
||||
/// A Spend transfer spends a note. Its Spend description includes a Pedersen value
|
||||
/// commitment to the value of the note. It is associated with an instance of a Spend
|
||||
/// statement for which it provides a zk-SNARK proof.
|
||||
pub spends: Vec<SaplingSpendDescription>,
|
||||
/// An Output transfer creates a note. Its Output description includes a Pedersen value
|
||||
/// commitment to the note value. It is associated with an instance of an Output statement
|
||||
/// for which it provides a zk-SNARK proof.
|
||||
pub outputs: Vec<SaplingOutputDescription>,
|
||||
/// Consistency of balancing_value with the value commitments in Spend descriptions
|
||||
/// and Output descriptions is enforced by the binding_sig.
|
||||
/// This signature has a dual role in Sapling:
|
||||
/// 1) to prove that the total value spent by Spend transfers, minus that produced by
|
||||
/// Output transfers, is consistent with the v balance field of the transaction;
|
||||
/// 2) To prove that the signer knew the randomness used for the spend and output value
|
||||
/// commitments, in order to prevent Output descriptions from being replayed by an
|
||||
/// adversary in a different transaction. (A Spend description already cannot be
|
||||
/// replayed due to its spend authorization signature.)
|
||||
pub binding_sig: [u8; 64],
|
||||
}
|
||||
|
||||
/// Single Spend transfer description.
|
||||
#[derive(Clone, Serializable, Deserializable)]
|
||||
pub struct SaplingSpendDescription {
|
||||
pub cv: [u8; 32],
|
||||
/// Value commitment to the value of the input note.
|
||||
pub value_commitment: [u8; 32],
|
||||
/// An anchor for the output treestate of a previous block.
|
||||
pub anchor: [u8; 32],
|
||||
/// The nullifier for the input note.
|
||||
pub nullifier: [u8; 32],
|
||||
pub rk: [u8; 32],
|
||||
/// Randomized public key that should be used to verify spend_auth_sig.
|
||||
pub randomized_key: [u8; 32],
|
||||
/// Zero-knowledge proof with primary input
|
||||
/// (value_commitment, anchor, nullifier, randomized_key)
|
||||
/// for the spend statement.
|
||||
pub zkproof: [u8; 192],
|
||||
/// Spend authorization signature. Is used to prove knowledge of the spending key
|
||||
/// authorizing spending of an input note.
|
||||
pub spend_auth_sig: [u8; 64],
|
||||
}
|
||||
|
||||
/// Single Output transfer description.
|
||||
#[derive(Clone, Serializable, Deserializable)]
|
||||
pub struct SaplingOutputDescription {
|
||||
pub cv: [u8; 32],
|
||||
pub cm: [u8; 32],
|
||||
/// Value commitment to the value of the output note.
|
||||
pub value_commitment: [u8; 32],
|
||||
/// The note commitment for the output note.
|
||||
pub note_commitment: [u8; 32],
|
||||
/// Key agreement public key, used to derive the key for encryption of the transmitted
|
||||
/// note ciphertext.
|
||||
pub ephemeral_key: [u8; 32],
|
||||
/// Ciphertext component for the encrypted output note.
|
||||
pub enc_cipher_text: [u8; 580],
|
||||
/// Ciphertext component that allows the holder of a full viewing key to recover the recipient
|
||||
/// diversified transmission key and teh ephemeral private key (and therefore the entire note
|
||||
/// plaintext).
|
||||
pub out_cipher_text: [u8; 80],
|
||||
/// Zero-knowledge proof with primary input
|
||||
/// (value_commitment, cm, ephemeral_key)
|
||||
/// for the output statement.
|
||||
pub zkproof: [u8; 192],
|
||||
}
|
||||
|
||||
impl Default for Sapling {
|
||||
fn default() -> Self {
|
||||
Sapling {
|
||||
amount: Default::default(),
|
||||
balancing_value: Default::default(),
|
||||
spends: Default::default(),
|
||||
outputs: Default::default(),
|
||||
binding_sig: [0; 64],
|
||||
|
@ -43,7 +86,7 @@ impl Default for Sapling {
|
|||
impl fmt::Debug for Sapling {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_struct("Sapling")
|
||||
.field("amount", &self.amount)
|
||||
.field("balancing_value", &self.balancing_value)
|
||||
.field("spends", &self.spends)
|
||||
.field("outputs", &self.outputs)
|
||||
.field("binding_sig", &self.binding_sig.to_hex::<String>())
|
||||
|
@ -53,7 +96,7 @@ impl fmt::Debug for Sapling {
|
|||
|
||||
impl PartialEq<Sapling> for Sapling {
|
||||
fn eq(&self, other: &Sapling) -> bool {
|
||||
self.amount == other.amount
|
||||
self.balancing_value == other.balancing_value
|
||||
&& self.spends == other.spends
|
||||
&& self.outputs == other.outputs
|
||||
&& self.binding_sig.as_ref() == other.binding_sig.as_ref()
|
||||
|
@ -63,10 +106,10 @@ impl PartialEq<Sapling> for Sapling {
|
|||
impl Default for SaplingSpendDescription {
|
||||
fn default() -> Self {
|
||||
SaplingSpendDescription {
|
||||
cv: Default::default(),
|
||||
value_commitment: Default::default(),
|
||||
anchor: Default::default(),
|
||||
nullifier: Default::default(),
|
||||
rk: Default::default(),
|
||||
randomized_key: Default::default(),
|
||||
zkproof: [0; 192],
|
||||
spend_auth_sig: [0; 64],
|
||||
}
|
||||
|
@ -76,10 +119,10 @@ impl Default for SaplingSpendDescription {
|
|||
impl fmt::Debug for SaplingSpendDescription {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_struct("SaplingSpendDescription")
|
||||
.field("cv", &self.cv.to_hex::<String>())
|
||||
.field("value_commitment", &self.value_commitment.to_hex::<String>())
|
||||
.field("anchor", &self.anchor.to_hex::<String>())
|
||||
.field("nullifier", &self.nullifier.to_hex::<String>())
|
||||
.field("rk", &self.rk.to_hex::<String>())
|
||||
.field("randomized_key", &self.randomized_key.to_hex::<String>())
|
||||
.field("zkproof", &self.zkproof.to_hex::<String>())
|
||||
.field("spend_auth_sig", &self.spend_auth_sig.to_hex::<String>())
|
||||
.finish()
|
||||
|
@ -88,10 +131,10 @@ impl fmt::Debug for SaplingSpendDescription {
|
|||
|
||||
impl PartialEq<SaplingSpendDescription> for SaplingSpendDescription {
|
||||
fn eq(&self, other: &SaplingSpendDescription) -> bool {
|
||||
self.cv == other.cv
|
||||
self.value_commitment == other.value_commitment
|
||||
&& self.anchor == other.anchor
|
||||
&& self.nullifier == other.nullifier
|
||||
&& self.rk == other.rk
|
||||
&& self.randomized_key == other.randomized_key
|
||||
&& self.zkproof.as_ref() == other.zkproof.as_ref()
|
||||
&& self.spend_auth_sig.as_ref() == other.spend_auth_sig.as_ref()
|
||||
}
|
||||
|
@ -100,8 +143,8 @@ impl PartialEq<SaplingSpendDescription> for SaplingSpendDescription {
|
|||
impl Default for SaplingOutputDescription {
|
||||
fn default() -> Self {
|
||||
SaplingOutputDescription {
|
||||
cv: Default::default(),
|
||||
cm: Default::default(),
|
||||
value_commitment: Default::default(),
|
||||
note_commitment: Default::default(),
|
||||
ephemeral_key: Default::default(),
|
||||
enc_cipher_text: [0; 580],
|
||||
out_cipher_text: [0; 80],
|
||||
|
@ -113,8 +156,8 @@ impl Default for SaplingOutputDescription {
|
|||
impl fmt::Debug for SaplingOutputDescription {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_struct("SaplingSpendDescription")
|
||||
.field("cv", &self.cv.to_hex::<String>())
|
||||
.field("cm", &self.cm.to_hex::<String>())
|
||||
.field("value_commitment", &self.value_commitment.to_hex::<String>())
|
||||
.field("note_commitment", &self.note_commitment.to_hex::<String>())
|
||||
.field("ephemeral_key", &self.ephemeral_key.to_hex::<String>())
|
||||
.field("enc_cipher_text", &self.enc_cipher_text.to_hex::<String>())
|
||||
.field("out_cipher_text", &self.out_cipher_text.to_hex::<String>())
|
||||
|
@ -125,8 +168,8 @@ impl fmt::Debug for SaplingOutputDescription {
|
|||
|
||||
impl PartialEq<SaplingOutputDescription> for SaplingOutputDescription {
|
||||
fn eq(&self, other: &SaplingOutputDescription) -> bool {
|
||||
self.cv == other.cv
|
||||
&& self.cm == other.cm
|
||||
self.value_commitment == other.value_commitment
|
||||
&& self.note_commitment == other.note_commitment
|
||||
&& self.ephemeral_key == other.ephemeral_key
|
||||
&& self.enc_cipher_text.as_ref() == other.enc_cipher_text.as_ref()
|
||||
&& self.out_cipher_text.as_ref() == other.out_cipher_text.as_ref()
|
||||
|
|
|
@ -224,7 +224,7 @@ impl Serializable for Transaction {
|
|||
}
|
||||
|
||||
if let Some(sapling) = self.sapling.as_ref() {
|
||||
stream.append(&sapling.amount)
|
||||
stream.append(&sapling.balancing_value)
|
||||
.append_list(&sapling.spends)
|
||||
.append_list(&sapling.outputs);
|
||||
}
|
||||
|
@ -282,11 +282,11 @@ impl Deserializable for Transaction {
|
|||
};
|
||||
|
||||
let mut sapling = if is_sapling_tx {
|
||||
let amount = reader.read()?;
|
||||
let balancing_value = reader.read()?;
|
||||
let spends = reader.read_list()?;
|
||||
let outputs = reader.read_list()?;
|
||||
Some(Sapling {
|
||||
amount,
|
||||
balancing_value,
|
||||
spends,
|
||||
outputs,
|
||||
..Default::default()
|
||||
|
|
|
@ -8,8 +8,12 @@ time = "0.1"
|
|||
log = "0.4"
|
||||
rayon = "1.0"
|
||||
parking_lot = "0.4"
|
||||
bellman = "0.1"
|
||||
blake2-rfc = { git = "https://github.com/gtank/blake2-rfc.git", branch = "persona" }
|
||||
byteorder = "1.2"
|
||||
lazy_static = "1.2.0"
|
||||
pairing = "0.14.2"
|
||||
sapling-crypto = { git = "https://github.com/zcash-hackworks/sapling-crypto.git", rev = "21084bde2019c04bd34208e63c3560fe2c02fb0e" }
|
||||
primitives = { path = "../primitives" }
|
||||
chain = { path = "../chain" }
|
||||
serialization = { path = "../serialization" }
|
||||
|
|
|
@ -4,6 +4,7 @@ use network::{ConsensusParams};
|
|||
use script::{Script, verify_script, VerificationFlags, TransactionSignatureChecker, TransactionInputSigner};
|
||||
use duplex_store::DuplexTransactionOutputProvider;
|
||||
use deployments::BlockDeployments;
|
||||
use sapling::accept_sapling;
|
||||
use sigops::transaction_sigops;
|
||||
use canon::CanonTransaction;
|
||||
use constants::{COINBASE_MATURITY};
|
||||
|
@ -15,6 +16,7 @@ pub struct TransactionAcceptor<'a> {
|
|||
pub bip30: TransactionBip30<'a>,
|
||||
pub missing_inputs: TransactionMissingInputs<'a>,
|
||||
pub maturity: TransactionMaturity<'a>,
|
||||
pub sapling_valid: TransactionSaplingValid<'a>,
|
||||
pub overspent: TransactionOverspent<'a>,
|
||||
pub double_spent: TransactionDoubleSpend<'a>,
|
||||
pub eval: TransactionEval<'a>,
|
||||
|
@ -41,6 +43,7 @@ impl<'a> TransactionAcceptor<'a> {
|
|||
bip30: TransactionBip30::new_for_sync(transaction, meta_store),
|
||||
missing_inputs: TransactionMissingInputs::new(transaction, output_store, transaction_index),
|
||||
maturity: TransactionMaturity::new(transaction, meta_store, height),
|
||||
sapling_valid: TransactionSaplingValid::new(transaction),
|
||||
overspent: TransactionOverspent::new(transaction, output_store),
|
||||
double_spent: TransactionDoubleSpend::new(transaction, output_store),
|
||||
eval: TransactionEval::new(transaction, output_store, consensus, verification_level, height, time, deployments),
|
||||
|
@ -52,6 +55,7 @@ impl<'a> TransactionAcceptor<'a> {
|
|||
self.bip30.check()?;
|
||||
self.missing_inputs.check()?;
|
||||
self.maturity.check()?;
|
||||
self.sapling_valid.check()?;
|
||||
self.overspent.check()?;
|
||||
self.double_spent.check()?;
|
||||
self.eval.check()?;
|
||||
|
@ -432,6 +436,29 @@ impl<'a> TransactionSize<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Checks that sapling signatures/proofs are valid.
|
||||
pub struct TransactionSaplingValid<'a> {
|
||||
transaction: CanonTransaction<'a>,
|
||||
}
|
||||
|
||||
impl<'a> TransactionSaplingValid<'a> {
|
||||
fn new(transaction: CanonTransaction<'a>) -> Self {
|
||||
TransactionSaplingValid {
|
||||
transaction: transaction,
|
||||
}
|
||||
}
|
||||
|
||||
fn check(&self) -> Result<(), TransactionError> {
|
||||
if let Some(sapling) = self.transaction.raw.sapling.as_ref() {
|
||||
let sighash = Default::default(); // TODO: pass real sighash when ready
|
||||
accept_sapling(&sighash, sapling)
|
||||
.map_err(|_| TransactionError::InvalidSapling)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
|
@ -465,4 +492,4 @@ mod tests {
|
|||
.verify_p2sh(true);
|
||||
assert_eq!(verify_script(&input_script, &output_script, &flags, &checker), Ok(()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -129,5 +129,7 @@ pub enum TransactionError {
|
|||
DuplicateJoinSplitNullifier(usize, usize),
|
||||
/// Transaction has sapling spends with duplicate nullifiers. Sapling spends indexes are provided.
|
||||
DuplicateSaplingSpendNullifier(usize, usize),
|
||||
/// Transaction sapling verification has failed.
|
||||
InvalidSapling,
|
||||
}
|
||||
|
||||
|
|
|
@ -56,11 +56,16 @@ extern crate time;
|
|||
extern crate log;
|
||||
extern crate parking_lot;
|
||||
extern crate rayon;
|
||||
extern crate bellman;
|
||||
extern crate blake2_rfc;
|
||||
extern crate byteorder;
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
#[cfg(test)]
|
||||
extern crate rand;
|
||||
extern crate rustc_hex as hex;
|
||||
extern crate pairing;
|
||||
extern crate sapling_crypto;
|
||||
|
||||
extern crate storage;
|
||||
extern crate chain;
|
||||
|
@ -78,6 +83,7 @@ mod deployments;
|
|||
mod duplex_store;
|
||||
mod equihash;
|
||||
mod error;
|
||||
mod sapling;
|
||||
mod sigops;
|
||||
mod timestamp;
|
||||
mod work;
|
||||
|
|
|
@ -0,0 +1,302 @@
|
|||
use std::io::Error as IoError;
|
||||
use chain::{Sapling, SaplingSpendDescription, SaplingOutputDescription};
|
||||
use pairing::{bls12_381::{Bls12, Fr, FrRepr}, PrimeField, PrimeFieldRepr, PrimeFieldDecodingError};
|
||||
use bellman::{SynthesisError, groth16::{verify_proof, PreparedVerifyingKey, Proof,}};
|
||||
|
||||
use sapling_crypto::{circuit::multipack, redjubjub::{self, Signature}};
|
||||
use sapling_crypto::jubjub::{edwards,fs::FsRepr, FixedGenerators, JubjubBls12, JubjubParams, Unknown};
|
||||
|
||||
type Point = edwards::Point<Bls12, Unknown>;
|
||||
|
||||
lazy_static! {
|
||||
static ref JUBJUB: JubjubBls12 = { JubjubBls12::new() };
|
||||
static ref SAPLING_SPEND_VK: Option<PreparedVerifyingKey<Bls12>> = None;
|
||||
static ref SAPLING_OUTPUT_VK: Option<PreparedVerifyingKey<Bls12>> = None;
|
||||
}
|
||||
|
||||
/// Errors that could occur during sapling verification.
|
||||
pub enum Error {
|
||||
/// Spend description verification error.
|
||||
Spend(usize, SpendError),
|
||||
/// Output description verification error.
|
||||
Output(usize, OutputError),
|
||||
/// Invalid balance value.
|
||||
InvalidBalanceValue,
|
||||
/// Error deserializing/verifying binding_sig.
|
||||
BindingSig(SignatureError),
|
||||
}
|
||||
|
||||
/// Errors that can occur during spend description verification.
|
||||
pub enum SpendError {
|
||||
/// Error deserializing value commitment.
|
||||
ValueCommitment(PointError),
|
||||
/// Error deserializing anchor.
|
||||
Anchor(PrimeFieldDecodingError),
|
||||
/// Error deserializing randomized key.
|
||||
RandomizedKey(PublicKeyError),
|
||||
/// Error deserializing/verifying spend_auth_sig.
|
||||
SpendAuthSig(SignatureError),
|
||||
/// Error deserializing/verifying zk-proof.
|
||||
Proof(ProofError),
|
||||
}
|
||||
|
||||
/// Errors that can occur during output description verification.
|
||||
pub enum OutputError {
|
||||
/// Error deserializing value commitment.
|
||||
ValueCommitment(PointError),
|
||||
/// Error deserializing note commitment.
|
||||
NoteCommitment(PrimeFieldDecodingError),
|
||||
/// Error deserializing ephemeral key.
|
||||
EphemeralKey(PointError),
|
||||
/// Error deserializing/verifying zk-proof.
|
||||
Proof(ProofError),
|
||||
}
|
||||
|
||||
/// Errors that can occur during point deserialization.
|
||||
pub enum PointError {
|
||||
/// The point is invalid.
|
||||
Invalid(IoError),
|
||||
/// The point MUST NOT be small order.
|
||||
SmallOrder,
|
||||
}
|
||||
|
||||
/// Errors that can occur during public key deserialization.
|
||||
pub enum PublicKeyError {
|
||||
/// The public key is invalid.
|
||||
Invalid(IoError),
|
||||
/// The point corresponding to the public key MUST NOT be small order.
|
||||
SmallOrder,
|
||||
}
|
||||
|
||||
/// Error that can occur during signature deserialization/verification.
|
||||
pub enum SignatureError {
|
||||
/// The signature is invalid.
|
||||
Invalid(IoError),
|
||||
/// The signature verifciation has failed.
|
||||
Failed,
|
||||
}
|
||||
|
||||
/// Proof verification error.
|
||||
pub enum ProofError {
|
||||
/// The proof is invalid.
|
||||
Invalid(IoError),
|
||||
/// The error that could occur during circuit synthesis context.
|
||||
Synthesis(SynthesisError),
|
||||
/// The proof verification has invalid.
|
||||
Failed,
|
||||
}
|
||||
|
||||
/// Verify sapling proofs/signatures validity.
|
||||
pub fn accept_sapling(sighash: &[u8; 32], sapling: &Sapling) -> Result<(), Error> {
|
||||
// binding verification key is not encoded explicitly in transaction and must be recalculated
|
||||
let mut total = edwards::Point::zero();
|
||||
|
||||
// verify each spend description
|
||||
for (idx, spend) in sapling.spends.iter().enumerate() {
|
||||
accept_spend(sighash, &mut total, spend)
|
||||
.map_err(|err| Error::Spend(idx, err))?;
|
||||
}
|
||||
|
||||
// verify each output description
|
||||
for (idx, output) in sapling.outputs.iter().enumerate() {
|
||||
accept_output(&mut total, output)
|
||||
.map_err(|err| Error::Output(idx, err))?;
|
||||
}
|
||||
|
||||
// check binding signature
|
||||
accept_sapling_final(sighash, total, sapling)
|
||||
}
|
||||
|
||||
/// Verify sapling spend description.
|
||||
fn accept_spend(sighash: &[u8; 32], total: &mut Point, spend: &SaplingSpendDescription) -> Result<(), SpendError> {
|
||||
// deserialize and check value commitment
|
||||
let value_commitment = require_non_small_order_point(&spend.value_commitment)
|
||||
.map_err(SpendError::ValueCommitment)?;
|
||||
|
||||
// accumulate the value commitment
|
||||
*total = total.add(&value_commitment, &JUBJUB);
|
||||
|
||||
// deserialize the anchor, which should be an element of Fr
|
||||
let anchor = Fr::from_repr(read_le(&spend.anchor))
|
||||
.map_err(SpendError::Anchor)?;
|
||||
|
||||
// compute the signature's message for randomized key && spend_auth_sig
|
||||
let mut data_to_be_signed = [0u8; 64];
|
||||
data_to_be_signed[..32].copy_from_slice(&spend.randomized_key);
|
||||
data_to_be_signed[32..].copy_from_slice(sighash);
|
||||
|
||||
// deserialize and check randomized key
|
||||
let randomized_key = redjubjub::PublicKey::<Bls12>::read(&spend.randomized_key[..], &JUBJUB)
|
||||
.map_err(|err| SpendError::RandomizedKey(PublicKeyError::Invalid(err)))?;
|
||||
if is_small_order(&randomized_key.0) {
|
||||
return Err(SpendError::RandomizedKey(PublicKeyError::SmallOrder));
|
||||
}
|
||||
|
||||
// deserialize the signature
|
||||
let spend_auth_sig = Signature::read(&spend.spend_auth_sig[..])
|
||||
.map_err(|err| SpendError::SpendAuthSig(SignatureError::Invalid(err)))?;
|
||||
|
||||
// verify the spend_auth_sig
|
||||
if !randomized_key.verify(&data_to_be_signed, &spend_auth_sig, FixedGenerators::SpendingKeyGenerator, &JUBJUB) {
|
||||
return Err(SpendError::SpendAuthSig(SignatureError::Failed));
|
||||
}
|
||||
|
||||
// Add the nullifier through multiscalar packing
|
||||
let nullifier = multipack::bytes_to_bits_le(&spend.nullifier);
|
||||
let nullifier = multipack::compute_multipacking::<Bls12>(&nullifier);
|
||||
assert_eq!(nullifier.len(), 2);
|
||||
|
||||
// construct public input for circuit
|
||||
let (randomized_key_x, randomized_key_y) = randomized_key.0.into_xy();
|
||||
let (value_commitment_x, value_commitment_y) = value_commitment.into_xy();
|
||||
let public_input = [
|
||||
randomized_key_x,
|
||||
randomized_key_y,
|
||||
value_commitment_x,
|
||||
value_commitment_y,
|
||||
anchor,
|
||||
nullifier[0],
|
||||
nullifier[1],
|
||||
];
|
||||
|
||||
// deserialize the proof
|
||||
let zkproof = Proof::<Bls12>::read(&spend.zkproof[..])
|
||||
.map_err(|err| SpendError::Proof(ProofError::Invalid(err)))?;
|
||||
|
||||
// check the proof
|
||||
let verification_key = SAPLING_SPEND_VK.as_ref().expect("TODO");
|
||||
let is_verification_ok = verify_proof(verification_key, &zkproof, &public_input[..])
|
||||
.map_err(|err| SpendError::Proof(ProofError::Synthesis(err)))?;
|
||||
if !is_verification_ok {
|
||||
return Err(SpendError::Proof(ProofError::Failed));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn accept_output(total: &mut Point, output: &SaplingOutputDescription) -> Result<(), OutputError> {
|
||||
// deserialize and check value commitment
|
||||
let value_commitment = require_non_small_order_point(&output.value_commitment)
|
||||
.map_err(OutputError::ValueCommitment)?;
|
||||
|
||||
// accumulate the value commitment
|
||||
*total = total.add(&value_commitment.clone().negate(), &JUBJUB);
|
||||
|
||||
// deserialize the commitment, which should be an element of Fr
|
||||
let note_commitment = Fr::from_repr(read_le(&output.note_commitment))
|
||||
.map_err(OutputError::NoteCommitment)?;
|
||||
|
||||
// deserialize the ephemeral key
|
||||
let ephemeral_key = require_non_small_order_point(&output.ephemeral_key)
|
||||
.map_err(OutputError::EphemeralKey)?;
|
||||
|
||||
// construct public input for circuit
|
||||
let (ephemeral_key_x, ephemeral_key_y) = ephemeral_key.into_xy();
|
||||
let (value_commitment_x, value_commitment_y) = value_commitment.into_xy();
|
||||
let public_input = [
|
||||
value_commitment_x,
|
||||
value_commitment_y,
|
||||
ephemeral_key_x,
|
||||
ephemeral_key_y,
|
||||
note_commitment,
|
||||
];
|
||||
|
||||
// deserialize the proof
|
||||
let zkproof = Proof::<Bls12>::read(&output.zkproof[..])
|
||||
.map_err(|err| OutputError::Proof(ProofError::Invalid(err)))?;
|
||||
|
||||
// check the proof
|
||||
let verification_key = SAPLING_OUTPUT_VK.as_ref().expect("TODO");
|
||||
let is_verification_ok = verify_proof(verification_key, &zkproof, &public_input[..])
|
||||
.map_err(|err| OutputError::Proof(ProofError::Synthesis(err)))?;
|
||||
if !is_verification_ok {
|
||||
return Err(OutputError::Proof(ProofError::Failed));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn accept_sapling_final(sighash: &[u8; 32], total: Point, sapling: &Sapling) -> Result<(), Error> {
|
||||
// obtain current bvk from the context
|
||||
let mut binding_verification_key = redjubjub::PublicKey(total);
|
||||
|
||||
// compute value balance
|
||||
let mut value_balance = compute_value_balance(sapling.balancing_value)?;
|
||||
|
||||
// subtract value_balance from current bvk to get final bvk
|
||||
value_balance = value_balance.negate();
|
||||
binding_verification_key.0 = binding_verification_key.0.add(&value_balance, &JUBJUB);
|
||||
|
||||
// compute the signature's message for binding_verification_key/binding_sig
|
||||
let mut data_to_be_signed = [0u8; 64];
|
||||
binding_verification_key.0.write(&mut data_to_be_signed[..32]).expect("bvk is 32 bytes");
|
||||
data_to_be_signed[32..].copy_from_slice(&sighash[..]);
|
||||
|
||||
// deserialize the binding signature
|
||||
let binding_sig = Signature::read(&sapling.binding_sig[..])
|
||||
.map_err(|err| Error::BindingSig(SignatureError::Invalid(err)))?;
|
||||
|
||||
// check the binding signature
|
||||
let is_verification_ok = binding_verification_key
|
||||
.verify(&data_to_be_signed, &binding_sig, FixedGenerators::ValueCommitmentRandomness, &JUBJUB);
|
||||
if !is_verification_ok {
|
||||
return Err(Error::BindingSig(SignatureError::Failed));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// This function computes `value` in the exponent of the value commitment base
|
||||
fn compute_value_balance(value: i64) -> Result<Point, Error> {
|
||||
// Compute the absolute value (failing if -i64::MAX is the value)
|
||||
let abs = match value.checked_abs() {
|
||||
Some(a) => a as u64,
|
||||
None => return Err(Error::InvalidBalanceValue),
|
||||
};
|
||||
|
||||
// Is it negative? We'll have to negate later if so.
|
||||
let is_negative = value.is_negative();
|
||||
|
||||
// Compute it in the exponent
|
||||
let mut value_balance = JUBJUB
|
||||
.generator(FixedGenerators::ValueCommitmentValue)
|
||||
.mul(FsRepr::from(abs), &JUBJUB);
|
||||
|
||||
// Negate if necessary
|
||||
if is_negative {
|
||||
value_balance = value_balance.negate();
|
||||
}
|
||||
|
||||
// Convert to unknown order point
|
||||
Ok(value_balance.into())
|
||||
}
|
||||
|
||||
/// Reads an FrRepr from a [u8] of length 32.
|
||||
/// This will panic (abort) if length provided is
|
||||
/// not correct.
|
||||
fn read_le(from: &[u8; 32]) -> FrRepr {
|
||||
let mut repr = FrRepr::default();
|
||||
repr.read_le(&from[..]).expect("length is 32 bytes");
|
||||
repr
|
||||
}
|
||||
|
||||
|
||||
/// Deserializes point from the serialized buffer, checking that it is on the curve
|
||||
/// AND it MUST NOT be of small order.
|
||||
fn require_non_small_order_point(point_buff: &[u8; 32]) -> Result<Point, PointError> {
|
||||
let point = Point::read(&point_buff[..], &JUBJUB).map_err(PointError::Invalid)?;
|
||||
if is_small_order(&point) {
|
||||
return Err(PointError::SmallOrder);
|
||||
}
|
||||
Ok(point)
|
||||
}
|
||||
|
||||
/// Is this a small order point?
|
||||
fn is_small_order(point: &Point) -> bool {
|
||||
point.double(&JUBJUB).double(&JUBJUB).double(&JUBJUB) == edwards::Point::zero()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
// TODO: detailed tests when sighash + verification keys are available
|
||||
}
|
|
@ -356,7 +356,7 @@ impl<'a> TransactionSapling<'a> {
|
|||
fn check(&self) -> Result<(), TransactionError> {
|
||||
if let Some(ref sapling) = self.transaction.raw.sapling {
|
||||
// sapling balance should be zero if spends and outputs are empty
|
||||
if sapling.amount != 0 && sapling.spends.is_empty() && sapling.outputs.is_empty() {
|
||||
if sapling.balancing_value != 0 && sapling.spends.is_empty() && sapling.outputs.is_empty() {
|
||||
return Err(TransactionError::EmptySaplingHasBalance);
|
||||
}
|
||||
}
|
||||
|
@ -423,13 +423,13 @@ impl<'a> TransactionOutputValueOverflow<'a> {
|
|||
|
||||
if let Some(ref sapling) = self.transaction.raw.sapling {
|
||||
// check that sapling amount is within limits
|
||||
if sapling.amount < -self.max_value || sapling.amount > self.max_value {
|
||||
if sapling.balancing_value < -self.max_value || sapling.balancing_value > self.max_value {
|
||||
return Err(TransactionError::OutputValueOverflow);
|
||||
}
|
||||
|
||||
// negative sapling amount takes value from transparent pool
|
||||
if sapling.amount < 0 {
|
||||
total_output = match total_output.checked_add(-sapling.amount) {
|
||||
if sapling.balancing_value < 0 {
|
||||
total_output = match total_output.checked_add(-sapling.balancing_value) {
|
||||
Some(total_output) if total_output <= self.max_value => total_output,
|
||||
_ => return Err(TransactionError::OutputValueOverflow),
|
||||
};
|
||||
|
@ -493,8 +493,8 @@ impl<'a> TransactionInputValueOverflow<'a> {
|
|||
|
||||
if let Some(ref sapling) = self.transaction.raw.sapling {
|
||||
// positive sapling amount adds value to the transparent pool
|
||||
if sapling.amount > 0 {
|
||||
match total_input.checked_add(sapling.amount as u64) {
|
||||
if sapling.balancing_value > 0 {
|
||||
match total_input.checked_add(sapling.balancing_value as u64) {
|
||||
Some(total_input) if total_input <= self.max_value => (),
|
||||
_ => return Err(TransactionError::InputValueOverflow),
|
||||
};
|
||||
|
@ -721,18 +721,18 @@ mod tests {
|
|||
.into(), &consensus).check(), Ok(()));
|
||||
|
||||
assert_eq!(TransactionOutputValueOverflow::new(&test_data::TransactionBuilder::with_sapling(Sapling {
|
||||
amount: max_value,
|
||||
balancing_value: max_value,
|
||||
..Default::default()
|
||||
}).into(), &consensus).check(), Ok(()));
|
||||
|
||||
assert_eq!(TransactionOutputValueOverflow::new(&test_data::TransactionBuilder::with_sapling(Sapling {
|
||||
amount: max_value + 1,
|
||||
balancing_value: max_value + 1,
|
||||
..Default::default()
|
||||
}).into(), &consensus).check(), Err(TransactionError::OutputValueOverflow));
|
||||
|
||||
assert_eq!(TransactionOutputValueOverflow::new(&test_data::TransactionBuilder::with_output(max_value as u64 / 2 + 1)
|
||||
.set_sapling(Sapling {
|
||||
amount: -max_value / 2,
|
||||
balancing_value: -max_value / 2,
|
||||
..Default::default()
|
||||
}).into(), &consensus).check(), Err(TransactionError::OutputValueOverflow));
|
||||
|
||||
|
@ -805,12 +805,12 @@ mod tests {
|
|||
}).into(), &consensus).check(), Err(TransactionError::InputValueOverflow));
|
||||
|
||||
assert_eq!(TransactionInputValueOverflow::new(&test_data::TransactionBuilder::with_sapling(Sapling {
|
||||
amount: max_value,
|
||||
balancing_value: max_value,
|
||||
..Default::default()
|
||||
}).into(), &consensus).check(), Ok(()));
|
||||
|
||||
assert_eq!(TransactionInputValueOverflow::new(&test_data::TransactionBuilder::with_sapling(Sapling {
|
||||
amount: max_value + 1,
|
||||
balancing_value: max_value + 1,
|
||||
..Default::default()
|
||||
}).into(), &consensus).check(), Err(TransactionError::InputValueOverflow));
|
||||
|
||||
|
@ -821,7 +821,7 @@ mod tests {
|
|||
}],
|
||||
..Default::default()
|
||||
}).set_sapling(Sapling {
|
||||
amount: max_value / 2,
|
||||
balancing_value: max_value / 2,
|
||||
..Default::default()
|
||||
}).into(), &consensus).check(), Err(TransactionError::InputValueOverflow));
|
||||
}
|
||||
|
@ -842,26 +842,26 @@ mod tests {
|
|||
#[test]
|
||||
fn transaction_sapling_works() {
|
||||
assert_eq!(TransactionSapling::new(&test_data::TransactionBuilder::with_sapling(Sapling {
|
||||
amount: 100,
|
||||
balancing_value: 100,
|
||||
spends: vec![Default::default()],
|
||||
..Default::default()
|
||||
}).into()).check(), Ok(()));
|
||||
|
||||
assert_eq!(TransactionSapling::new(&test_data::TransactionBuilder::with_sapling(Sapling {
|
||||
amount: 100,
|
||||
balancing_value: 100,
|
||||
outputs: vec![Default::default()],
|
||||
..Default::default()
|
||||
}).into()).check(), Ok(()));
|
||||
|
||||
assert_eq!(TransactionSapling::new(&test_data::TransactionBuilder::with_sapling(Sapling {
|
||||
amount: 100,
|
||||
balancing_value: 100,
|
||||
outputs: vec![Default::default()],
|
||||
spends: vec![Default::default()],
|
||||
..Default::default()
|
||||
}).into()).check(), Ok(()));
|
||||
|
||||
assert_eq!(TransactionSapling::new(&test_data::TransactionBuilder::with_sapling(Sapling {
|
||||
amount: 100,
|
||||
balancing_value: 100,
|
||||
..Default::default()
|
||||
}).into()).check(), Err(TransactionError::EmptySaplingHasBalance));
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue