Merge remote-tracking branch 'origin/master' into nv3

# Conflicts:
#	Cargo.lock
#	verification/src/accept_transaction.rs
#	verification/src/error.rs
This commit is contained in:
NikVolf 2018-12-04 13:37:32 +03:00
commit 94cd62aba4
18 changed files with 681 additions and 61 deletions

99
Cargo.lock generated
View File

@ -65,6 +65,21 @@ dependencies = [
"safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "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]] [[package]]
name = "bencher" name = "bencher"
version = "0.1.0" version = "0.1.0"
@ -132,6 +147,16 @@ dependencies = [
"constant_time_eq 0.1.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 = "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]] [[package]]
name = "bn" name = "bn"
version = "0.4.3" version = "0.4.3"
@ -203,6 +228,11 @@ name = "constant_time_eq"
version = "0.1.3" version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index" 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]] [[package]]
name = "crossbeam-deque" name = "crossbeam-deque"
version = "0.2.0" version = "0.2.0"
@ -220,7 +250,7 @@ dependencies = [
"arrayvec 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "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)", "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)", "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)", "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)", "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
@ -269,6 +299,14 @@ dependencies = [
"test-data 0.1.0", "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]] [[package]]
name = "display_derive" name = "display_derive"
version = "0.0.0" version = "0.0.0"
@ -389,6 +427,14 @@ dependencies = [
"rayon 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", "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]] [[package]]
name = "getopts" name = "getopts"
version = "0.2.15" version = "0.2.15"
@ -556,7 +602,7 @@ dependencies = [
"base58 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "base58 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"bitcrypto 0.1.0", "bitcrypto 0.1.0",
"eth-secp256k1 0.5.7 (git+https://github.com/ethcore/rust-secp256k1)", "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", "primitives 0.1.0",
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "rustc-hex 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -569,7 +615,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "lazy_static" name = "lazy_static"
version = "1.0.0" version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
@ -749,7 +795,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"bitcrypto 0.1.0", "bitcrypto 0.1.0",
"chain 0.1.0", "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", "primitives 0.1.0",
"rustc-hex 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serialization 0.1.0", "serialization 0.1.0",
@ -823,6 +869,15 @@ dependencies = [
"tokio-io 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "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]] [[package]]
name = "parking_lot" name = "parking_lot"
version = "0.4.8" version = "0.4.8"
@ -946,7 +1001,7 @@ version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "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)", "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)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1092,6 +1147,19 @@ name = "safemem"
version = "0.2.0" version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" 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]] [[package]]
name = "scoped-tls" name = "scoped-tls"
version = "0.1.0" version = "0.1.0"
@ -1357,7 +1425,7 @@ name = "thread_local"
version = "0.3.5" version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ 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)", "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -1422,6 +1490,11 @@ dependencies = [
"futures 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "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]] [[package]]
name = "ucd-util" name = "ucd-util"
version = "0.1.2" version = "0.1.2"
@ -1467,18 +1540,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
name = "verification" name = "verification"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"bellman 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"bitcrypto 0.1.0", "bitcrypto 0.1.0",
"blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc.git?branch=persona)", "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)", "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"chain 0.1.0", "chain 0.1.0",
"db 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)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"network 0.1.0", "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)", "parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"primitives 0.1.0", "primitives 0.1.0",
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "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)", "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", "script 0.1.0",
"serialization 0.1.0", "serialization 0.1.0",
"storage 0.1.0", "storage 0.1.0",
@ -1570,12 +1647,14 @@ 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 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 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 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 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 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.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 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 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.git?branch=persona)" = "<none>"
"checksum blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9)" = "<none>"
"checksum bn 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "110f279b7f5e161fa755841785d5c4181510b31287dc0b47d09ed6d158975906" "checksum bn 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "110f279b7f5e161fa755841785d5c4181510b31287dc0b47d09ed6d158975906"
"checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855" "checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855"
"checksum byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "74c0b906e9446b0a2e4f760cdb3fa4b2c48cdc6db8766a845c54b6ff063fd2e9" "checksum byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "74c0b906e9446b0a2e4f760cdb3fa4b2c48cdc6db8766a845c54b6ff063fd2e9"
@ -1584,11 +1663,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" "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 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 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-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-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 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 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 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 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 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" "checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"
@ -1604,6 +1685,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 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 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 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 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 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" "checksum heapsize 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "556cd479866cf85c3f671209c85e8a6990211c916d1002c2fcb2e9b7cf60bc36"
@ -1620,7 +1702,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 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 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 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 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 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" "checksum linked-hash-map 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6d262045c5b87c0861b3f004610afd0e2c851e2908d08b6c870cbb9d5f494ecd"
@ -1643,6 +1725,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 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 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 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 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 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" "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831"
@ -1668,6 +1751,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-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 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 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 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 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" "checksum semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a3186ec9e65071a2095434b1f5bb24838d4e8e130f584c790f6033c79943537"
@ -1699,6 +1783,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-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-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 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 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 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" "checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f"

View File

@ -1,38 +1,83 @@
use std::fmt; use std::fmt;
use hex::ToHex; use hex::ToHex;
///
#[derive(Clone)] #[derive(Clone)]
pub struct Sapling { 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>, 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>, 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], pub binding_sig: [u8; 64],
} }
/// Single Spend transfer description.
#[derive(Clone, Serializable, Deserializable)] #[derive(Clone, Serializable, Deserializable)]
pub struct SaplingSpendDescription { 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], pub anchor: [u8; 32],
/// The nullifier for the input note.
pub nullifier: [u8; 32], 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], 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], pub spend_auth_sig: [u8; 64],
} }
/// Single Output transfer description.
#[derive(Clone, Serializable, Deserializable)] #[derive(Clone, Serializable, Deserializable)]
pub struct SaplingOutputDescription { pub struct SaplingOutputDescription {
pub cv: [u8; 32], /// Value commitment to the value of the output note.
pub cm: [u8; 32], 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], pub ephemeral_key: [u8; 32],
/// Ciphertext component for the encrypted output note.
pub enc_cipher_text: [u8; 580], 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], 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], pub zkproof: [u8; 192],
} }
impl Default for Sapling { impl Default for Sapling {
fn default() -> Self { fn default() -> Self {
Sapling { Sapling {
amount: Default::default(), balancing_value: Default::default(),
spends: Default::default(), spends: Default::default(),
outputs: Default::default(), outputs: Default::default(),
binding_sig: [0; 64], binding_sig: [0; 64],
@ -43,7 +88,7 @@ impl Default for Sapling {
impl fmt::Debug for Sapling { impl fmt::Debug for Sapling {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Sapling") f.debug_struct("Sapling")
.field("amount", &self.amount) .field("balancing_value", &self.balancing_value)
.field("spends", &self.spends) .field("spends", &self.spends)
.field("outputs", &self.outputs) .field("outputs", &self.outputs)
.field("binding_sig", &self.binding_sig.to_hex::<String>()) .field("binding_sig", &self.binding_sig.to_hex::<String>())
@ -53,7 +98,7 @@ impl fmt::Debug for Sapling {
impl PartialEq<Sapling> for Sapling { impl PartialEq<Sapling> for Sapling {
fn eq(&self, other: &Sapling) -> bool { fn eq(&self, other: &Sapling) -> bool {
self.amount == other.amount self.balancing_value == other.balancing_value
&& self.spends == other.spends && self.spends == other.spends
&& self.outputs == other.outputs && self.outputs == other.outputs
&& self.binding_sig.as_ref() == other.binding_sig.as_ref() && self.binding_sig.as_ref() == other.binding_sig.as_ref()
@ -63,10 +108,10 @@ impl PartialEq<Sapling> for Sapling {
impl Default for SaplingSpendDescription { impl Default for SaplingSpendDescription {
fn default() -> Self { fn default() -> Self {
SaplingSpendDescription { SaplingSpendDescription {
cv: Default::default(), value_commitment: Default::default(),
anchor: Default::default(), anchor: Default::default(),
nullifier: Default::default(), nullifier: Default::default(),
rk: Default::default(), randomized_key: Default::default(),
zkproof: [0; 192], zkproof: [0; 192],
spend_auth_sig: [0; 64], spend_auth_sig: [0; 64],
} }
@ -76,10 +121,10 @@ impl Default for SaplingSpendDescription {
impl fmt::Debug for SaplingSpendDescription { impl fmt::Debug for SaplingSpendDescription {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("SaplingSpendDescription") 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("anchor", &self.anchor.to_hex::<String>())
.field("nullifier", &self.nullifier.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("zkproof", &self.zkproof.to_hex::<String>())
.field("spend_auth_sig", &self.spend_auth_sig.to_hex::<String>()) .field("spend_auth_sig", &self.spend_auth_sig.to_hex::<String>())
.finish() .finish()
@ -88,10 +133,10 @@ impl fmt::Debug for SaplingSpendDescription {
impl PartialEq<SaplingSpendDescription> for SaplingSpendDescription { impl PartialEq<SaplingSpendDescription> for SaplingSpendDescription {
fn eq(&self, other: &SaplingSpendDescription) -> bool { fn eq(&self, other: &SaplingSpendDescription) -> bool {
self.cv == other.cv self.value_commitment == other.value_commitment
&& self.anchor == other.anchor && self.anchor == other.anchor
&& self.nullifier == other.nullifier && self.nullifier == other.nullifier
&& self.rk == other.rk && self.randomized_key == other.randomized_key
&& self.zkproof.as_ref() == other.zkproof.as_ref() && self.zkproof.as_ref() == other.zkproof.as_ref()
&& self.spend_auth_sig.as_ref() == other.spend_auth_sig.as_ref() && self.spend_auth_sig.as_ref() == other.spend_auth_sig.as_ref()
} }
@ -100,8 +145,8 @@ impl PartialEq<SaplingSpendDescription> for SaplingSpendDescription {
impl Default for SaplingOutputDescription { impl Default for SaplingOutputDescription {
fn default() -> Self { fn default() -> Self {
SaplingOutputDescription { SaplingOutputDescription {
cv: Default::default(), value_commitment: Default::default(),
cm: Default::default(), note_commitment: Default::default(),
ephemeral_key: Default::default(), ephemeral_key: Default::default(),
enc_cipher_text: [0; 580], enc_cipher_text: [0; 580],
out_cipher_text: [0; 80], out_cipher_text: [0; 80],
@ -113,8 +158,8 @@ impl Default for SaplingOutputDescription {
impl fmt::Debug for SaplingOutputDescription { impl fmt::Debug for SaplingOutputDescription {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("SaplingSpendDescription") f.debug_struct("SaplingSpendDescription")
.field("cv", &self.cv.to_hex::<String>()) .field("value_commitment", &self.value_commitment.to_hex::<String>())
.field("cm", &self.cm.to_hex::<String>()) .field("note_commitment", &self.note_commitment.to_hex::<String>())
.field("ephemeral_key", &self.ephemeral_key.to_hex::<String>()) .field("ephemeral_key", &self.ephemeral_key.to_hex::<String>())
.field("enc_cipher_text", &self.enc_cipher_text.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>()) .field("out_cipher_text", &self.out_cipher_text.to_hex::<String>())
@ -125,8 +170,8 @@ impl fmt::Debug for SaplingOutputDescription {
impl PartialEq<SaplingOutputDescription> for SaplingOutputDescription { impl PartialEq<SaplingOutputDescription> for SaplingOutputDescription {
fn eq(&self, other: &SaplingOutputDescription) -> bool { fn eq(&self, other: &SaplingOutputDescription) -> bool {
self.cv == other.cv self.value_commitment == other.value_commitment
&& self.cm == other.cm && self.note_commitment == other.note_commitment
&& self.ephemeral_key == other.ephemeral_key && self.ephemeral_key == other.ephemeral_key
&& self.enc_cipher_text.as_ref() == other.enc_cipher_text.as_ref() && self.enc_cipher_text.as_ref() == other.enc_cipher_text.as_ref()
&& self.out_cipher_text.as_ref() == other.out_cipher_text.as_ref() && self.out_cipher_text.as_ref() == other.out_cipher_text.as_ref()

View File

@ -224,7 +224,7 @@ impl Serializable for Transaction {
} }
if let Some(sapling) = self.sapling.as_ref() { if let Some(sapling) = self.sapling.as_ref() {
stream.append(&sapling.amount) stream.append(&sapling.balancing_value)
.append_list(&sapling.spends) .append_list(&sapling.spends)
.append_list(&sapling.outputs); .append_list(&sapling.outputs);
} }
@ -282,11 +282,11 @@ impl Deserializable for Transaction {
}; };
let mut sapling = if is_sapling_tx { let mut sapling = if is_sapling_tx {
let amount = reader.read()?; let balancing_value = reader.read()?;
let spends = reader.read_list()?; let spends = reader.read_list()?;
let outputs = reader.read_list()?; let outputs = reader.read_list()?;
Some(Sapling { Some(Sapling {
amount, balancing_value,
spends, spends,
outputs, outputs,
..Default::default() ..Default::default()

View File

@ -7,14 +7,15 @@ use bytes::Bytes;
use primitives::compact::Compact; use primitives::compact::Compact;
use chain::{ use chain::{
IndexedBlock, IndexedBlockHeader, IndexedTransaction, BlockHeader, Block, Transaction, IndexedBlock, IndexedBlockHeader, IndexedTransaction, BlockHeader, Block, Transaction,
OutPoint, TransactionOutput OutPoint, TransactionOutput, SAPLING_TX_VERSION_GROUP_ID,
}; };
use ser::{ use ser::{
deserialize, serialize, List deserialize, serialize, List
}; };
use kv::{ use kv::{
KeyValueDatabase, OverlayDatabase, Transaction as DBTransaction, Value, DiskDatabase, KeyValueDatabase, OverlayDatabase, Transaction as DBTransaction, Value, DiskDatabase,
DatabaseConfig, MemoryDatabase, AutoFlushingOverlayDatabase, KeyValue, Key, KeyState, CacheDatabase DatabaseConfig, MemoryDatabase, AutoFlushingOverlayDatabase, KeyValue, Key, KeyState,
CacheDatabase,
}; };
use kv::{ use kv::{
COL_COUNT, COL_BLOCK_HASHES, COL_BLOCK_HEADERS, COL_BLOCK_TRANSACTIONS, COL_TRANSACTIONS, COL_COUNT, COL_BLOCK_HASHES, COL_BLOCK_HEADERS, COL_BLOCK_TRANSACTIONS, COL_TRANSACTIONS,
@ -23,7 +24,8 @@ use kv::{
use storage::{ use storage::{
BlockRef, Error, BlockHeaderProvider, BlockProvider, BlockOrigin, TransactionMeta, IndexedBlockProvider, BlockRef, Error, BlockHeaderProvider, BlockProvider, BlockOrigin, TransactionMeta, IndexedBlockProvider,
TransactionMetaProvider, TransactionProvider, TransactionOutputProvider, BlockChain, Store, TransactionMetaProvider, TransactionProvider, TransactionOutputProvider, BlockChain, Store,
SideChainOrigin, ForkChain, Forkable, CanonStore, ConfigStore, BestBlock SideChainOrigin, ForkChain, Forkable, CanonStore, ConfigStore, BestBlock, NullifierTracker, Nullifier,
NullifierTag,
}; };
const KEY_BEST_BLOCK_NUMBER: &'static str = "best_block_number"; const KEY_BEST_BLOCK_NUMBER: &'static str = "best_block_number";
@ -221,7 +223,7 @@ impl<T> BlockChainDatabase<T> where T: KeyValueDatabase {
self.db.write(update).map_err(Error::DatabaseError) self.db.write(update).map_err(Error::DatabaseError)
} }
/// Rollbacks single best block /// Rollbacks single best block.
fn rollback_best(&self) -> Result<H256, Error> { fn rollback_best(&self) -> Result<H256, Error> {
let decanonized = match self.block(self.best_block.read().hash.clone().into()) { let decanonized = match self.block(self.best_block.read().hash.clone().into()) {
Some(block) => block, Some(block) => block,
@ -246,6 +248,7 @@ impl<T> BlockChainDatabase<T> where T: KeyValueDatabase {
} }
/// Marks block as a new best block. /// Marks block as a new best block.
///
/// Block must be already inserted into db, and it's parent must be current best block. /// Block must be already inserted into db, and it's parent must be current best block.
/// Updates meta data. /// Updates meta data.
pub fn canonize(&self, hash: &H256) -> Result<(), Error> { pub fn canonize(&self, hash: &H256) -> Result<(), Error> {
@ -284,8 +287,26 @@ impl<T> BlockChainDatabase<T> where T: KeyValueDatabase {
} }
for tx in block.transactions.iter().skip(1) { for tx in block.transactions.iter().skip(1) {
let is_sapling_group = tx.raw.version_group_id == SAPLING_TX_VERSION_GROUP_ID;
modified_meta.insert(tx.hash.clone(), TransactionMeta::new(new_best_block.number, tx.raw.outputs.len())); modified_meta.insert(tx.hash.clone(), TransactionMeta::new(new_best_block.number, tx.raw.outputs.len()));
if let Some(ref js) = tx.raw.join_split {
for js_descriptor in js.descriptions.iter() {
for nullifier in &js_descriptor.nullifiers[..] {
let nullifier_key = Nullifier::new(
if is_sapling_group { NullifierTag::Sapling } else { NullifierTag::Sprout },
H256::from(&nullifier[..])
);
if self.contains_nullifier(nullifier_key) {
trace!(target: "db", "Duplicate nullifer during canonization: {:?}", nullifier_key);
return Err(Error::CannotCanonize);
}
update.insert(KeyValue::Nullifier(nullifier_key));
}
}
}
for input in &tx.raw.inputs { for input in &tx.raw.inputs {
use std::collections::hash_map::Entry; use std::collections::hash_map::Entry;
@ -342,6 +363,23 @@ impl<T> BlockChainDatabase<T> where T: KeyValueDatabase {
let mut modified_meta: HashMap<H256, TransactionMeta> = HashMap::new(); let mut modified_meta: HashMap<H256, TransactionMeta> = HashMap::new();
for tx in block.transactions.iter().skip(1) { for tx in block.transactions.iter().skip(1) {
let is_sapling_group = tx.raw.version_group_id == SAPLING_TX_VERSION_GROUP_ID;
if let Some(ref js) = tx.raw.join_split {
for js_descriptor in js.descriptions.iter() {
for nullifier in &js_descriptor.nullifiers[..] {
let nullifier_key = Nullifier::new(
if is_sapling_group { NullifierTag::Sapling } else { NullifierTag::Sprout },
H256::from(&nullifier[..])
);
if !self.contains_nullifier(nullifier_key) {
warn!(target: "db", "cannot decanonize, no nullifier: {:?}", nullifier_key);
return Err(Error::CannotDecanonize);
}
update.delete(Key::Nullifier(nullifier_key));
}
}
}
for input in &tx.raw.inputs { for input in &tx.raw.inputs {
use std::collections::hash_map::Entry; use std::collections::hash_map::Entry;
@ -508,6 +546,12 @@ impl<T> TransactionOutputProvider for BlockChainDatabase<T> where T: KeyValueDat
} }
} }
impl<T> NullifierTracker for BlockChainDatabase<T> where T: KeyValueDatabase {
fn contains_nullifier(&self, nullifier: Nullifier) -> bool {
self.get(Key::Nullifier(nullifier)).is_some()
}
}
impl<T> BlockChain for BlockChainDatabase<T> where T: KeyValueDatabase { impl<T> BlockChain for BlockChainDatabase<T> where T: KeyValueDatabase {
fn insert(&self, block: IndexedBlock) -> Result<(), Error> { fn insert(&self, block: IndexedBlock) -> Result<(), Error> {
BlockChainDatabase::insert(self, block) BlockChainDatabase::insert(self, block)

View File

@ -7,7 +7,7 @@ use bytes::Bytes;
use ser::List; use ser::List;
use chain::{Transaction as ChainTransaction, BlockHeader}; use chain::{Transaction as ChainTransaction, BlockHeader};
use kv::{Transaction, Key, KeyState, Operation, Value, KeyValueDatabase, KeyValue}; use kv::{Transaction, Key, KeyState, Operation, Value, KeyValueDatabase, KeyValue};
use storage::{TransactionMeta}; use storage::{TransactionMeta, NullifierTag};
#[derive(Default, Debug)] #[derive(Default, Debug)]
struct InnerDatabase { struct InnerDatabase {
@ -19,6 +19,8 @@ struct InnerDatabase {
transaction_meta: HashMap<H256, KeyState<TransactionMeta>>, transaction_meta: HashMap<H256, KeyState<TransactionMeta>>,
block_number: HashMap<H256, KeyState<u32>>, block_number: HashMap<H256, KeyState<u32>>,
configuration: HashMap<&'static str, KeyState<Bytes>>, configuration: HashMap<&'static str, KeyState<Bytes>>,
sprout_nullifiers: HashMap<H256, KeyState<()>>,
sapling_nullifiers: HashMap<H256, KeyState<()>>,
} }
#[derive(Default, Debug)] #[derive(Default, Debug)]
@ -81,6 +83,10 @@ impl KeyValueDatabase for MemoryDatabase {
KeyValue::TransactionMeta(key, value) => { db.transaction_meta.insert(key, KeyState::Insert(value)); }, KeyValue::TransactionMeta(key, value) => { db.transaction_meta.insert(key, KeyState::Insert(value)); },
KeyValue::BlockNumber(key, value) => { db.block_number.insert(key, KeyState::Insert(value)); }, KeyValue::BlockNumber(key, value) => { db.block_number.insert(key, KeyState::Insert(value)); },
KeyValue::Configuration(key, value) => { db.configuration.insert(key, KeyState::Insert(value)); }, KeyValue::Configuration(key, value) => { db.configuration.insert(key, KeyState::Insert(value)); },
KeyValue::Nullifier(key) => match key.tag() {
NullifierTag::Sprout => { db.sprout_nullifiers.insert(*key.hash(), KeyState::Insert(())); },
NullifierTag::Sapling => { db.sapling_nullifiers.insert(*key.hash(), KeyState::Insert(())); },
},
}, },
Operation::Delete(delete) => match delete { Operation::Delete(delete) => match delete {
Key::Meta(key) => { db.meta.insert(key, KeyState::Delete); } Key::Meta(key) => { db.meta.insert(key, KeyState::Delete); }
@ -91,7 +97,11 @@ impl KeyValueDatabase for MemoryDatabase {
Key::TransactionMeta(key) => { db.transaction_meta.insert(key, KeyState::Delete); } Key::TransactionMeta(key) => { db.transaction_meta.insert(key, KeyState::Delete); }
Key::BlockNumber(key) => { db.block_number.insert(key, KeyState::Delete); } Key::BlockNumber(key) => { db.block_number.insert(key, KeyState::Delete); }
Key::Configuration(key) => { db.configuration.insert(key, KeyState::Delete); } Key::Configuration(key) => { db.configuration.insert(key, KeyState::Delete); }
} Key::Nullifier(key) => match key.tag() {
NullifierTag::Sprout => { db.sprout_nullifiers.insert(*key.hash(), KeyState::Delete); },
NullifierTag::Sapling => { db.sapling_nullifiers.insert(*key.hash(), KeyState::Delete); },
},
},
} }
} }
Ok(()) Ok(())
@ -108,6 +118,10 @@ impl KeyValueDatabase for MemoryDatabase {
Key::TransactionMeta(ref key) => db.transaction_meta.get(key).cloned().unwrap_or_default().map(Value::TransactionMeta), Key::TransactionMeta(ref key) => db.transaction_meta.get(key).cloned().unwrap_or_default().map(Value::TransactionMeta),
Key::BlockNumber(ref key) => db.block_number.get(key).cloned().unwrap_or_default().map(Value::BlockNumber), Key::BlockNumber(ref key) => db.block_number.get(key).cloned().unwrap_or_default().map(Value::BlockNumber),
Key::Configuration(ref key) => db.configuration.get(key).cloned().unwrap_or_default().map(Value::Configuration), Key::Configuration(ref key) => db.configuration.get(key).cloned().unwrap_or_default().map(Value::Configuration),
Key::Nullifier(ref key) => match key.tag() {
NullifierTag::Sprout => db.sprout_nullifiers.get(key.hash()).cloned().unwrap_or_default().map(|_| Value::Empty),
NullifierTag::Sapling => db.sapling_nullifiers.get(key.hash()).cloned().unwrap_or_default().map(|_| Value::Empty),
}
}; };
Ok(result) Ok(result)

View File

@ -2,9 +2,9 @@ use bytes::Bytes;
use hash::H256; use hash::H256;
use ser::{serialize, List, deserialize}; use ser::{serialize, List, deserialize};
use chain::{Transaction as ChainTransaction, BlockHeader}; use chain::{Transaction as ChainTransaction, BlockHeader};
use storage::{TransactionMeta}; use storage::{TransactionMeta, Nullifier, NullifierTag};
pub const COL_COUNT: u32 = 10; pub const COL_COUNT: u32 = 16;
pub const COL_META: u32 = 0; pub const COL_META: u32 = 0;
pub const COL_BLOCK_HASHES: u32 = 1; pub const COL_BLOCK_HASHES: u32 = 1;
pub const COL_BLOCK_HEADERS: u32 = 2; pub const COL_BLOCK_HEADERS: u32 = 2;
@ -12,7 +12,9 @@ pub const COL_BLOCK_TRANSACTIONS: u32 = 3;
pub const COL_TRANSACTIONS: u32 = 4; pub const COL_TRANSACTIONS: u32 = 4;
pub const COL_TRANSACTIONS_META: u32 = 5; pub const COL_TRANSACTIONS_META: u32 = 5;
pub const COL_BLOCK_NUMBERS: u32 = 6; pub const COL_BLOCK_NUMBERS: u32 = 6;
pub const COL_CONFIGURATION: u32 = 7; pub const COL_SPROUT_NULLIFIERS: u32 = 7;
pub const COL_SAPLING_NULLIFIERS: u32 = 8;
pub const COL_CONFIGURATION: u32 = 9;
#[derive(Debug)] #[derive(Debug)]
pub enum Operation { pub enum Operation {
@ -30,6 +32,7 @@ pub enum KeyValue {
TransactionMeta(H256, TransactionMeta), TransactionMeta(H256, TransactionMeta),
BlockNumber(H256, u32), BlockNumber(H256, u32),
Configuration(&'static str, Bytes), Configuration(&'static str, Bytes),
Nullifier(Nullifier),
} }
#[derive(Debug)] #[derive(Debug)]
@ -42,6 +45,7 @@ pub enum Key {
TransactionMeta(H256), TransactionMeta(H256),
BlockNumber(H256), BlockNumber(H256),
Configuration(&'static str), Configuration(&'static str),
Nullifier(Nullifier),
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -54,6 +58,7 @@ pub enum Value {
TransactionMeta(TransactionMeta), TransactionMeta(TransactionMeta),
BlockNumber(u32), BlockNumber(u32),
Configuration(Bytes), Configuration(Bytes),
Empty,
} }
impl Value { impl Value {
@ -67,6 +72,7 @@ impl Value {
Key::TransactionMeta(_) => deserialize(bytes).map(Value::TransactionMeta), Key::TransactionMeta(_) => deserialize(bytes).map(Value::TransactionMeta),
Key::BlockNumber(_) => deserialize(bytes).map(Value::BlockNumber), Key::BlockNumber(_) => deserialize(bytes).map(Value::BlockNumber),
Key::Configuration(_) => deserialize(bytes).map(Value::Configuration), Key::Configuration(_) => deserialize(bytes).map(Value::Configuration),
Key::Nullifier(_) => Ok(Value::Empty),
}.map_err(|e| format!("{:?}", e)) }.map_err(|e| format!("{:?}", e))
} }
@ -226,6 +232,10 @@ impl<'a> From<&'a KeyValue> for RawKeyValue {
KeyValue::BlockTransactions(ref key, ref value) => (COL_BLOCK_TRANSACTIONS, serialize(key), serialize(value)), KeyValue::BlockTransactions(ref key, ref value) => (COL_BLOCK_TRANSACTIONS, serialize(key), serialize(value)),
KeyValue::Transaction(ref key, ref value) => (COL_TRANSACTIONS, serialize(key), serialize(value)), KeyValue::Transaction(ref key, ref value) => (COL_TRANSACTIONS, serialize(key), serialize(value)),
KeyValue::TransactionMeta(ref key, ref value) => (COL_TRANSACTIONS_META, serialize(key), serialize(value)), KeyValue::TransactionMeta(ref key, ref value) => (COL_TRANSACTIONS_META, serialize(key), serialize(value)),
KeyValue::Nullifier(ref key) => match key.tag() {
NullifierTag::Sprout => (COL_SPROUT_NULLIFIERS, serialize(key.hash()), Bytes::new()),
NullifierTag::Sapling => (COL_SAPLING_NULLIFIERS, serialize(key.hash()), Bytes::new()),
},
KeyValue::BlockNumber(ref key, ref value) => (COL_BLOCK_NUMBERS, serialize(key), serialize(value)), KeyValue::BlockNumber(ref key, ref value) => (COL_BLOCK_NUMBERS, serialize(key), serialize(value)),
KeyValue::Configuration(ref key, ref value) => (COL_CONFIGURATION, serialize(key), serialize(value)), KeyValue::Configuration(ref key, ref value) => (COL_CONFIGURATION, serialize(key), serialize(value)),
}; };
@ -261,6 +271,10 @@ impl<'a> From<&'a Key> for RawKey {
Key::BlockTransactions(ref key) => (COL_BLOCK_TRANSACTIONS, serialize(key)), Key::BlockTransactions(ref key) => (COL_BLOCK_TRANSACTIONS, serialize(key)),
Key::Transaction(ref key) => (COL_TRANSACTIONS, serialize(key)), Key::Transaction(ref key) => (COL_TRANSACTIONS, serialize(key)),
Key::TransactionMeta(ref key) => (COL_TRANSACTIONS_META, serialize(key)), Key::TransactionMeta(ref key) => (COL_TRANSACTIONS_META, serialize(key)),
Key::Nullifier(ref key) => match key.tag() {
NullifierTag::Sprout => (COL_SPROUT_NULLIFIERS, serialize(key.hash())),
NullifierTag::Sapling => (COL_SAPLING_NULLIFIERS, serialize(key.hash())),
},
Key::BlockNumber(ref key) => (COL_BLOCK_NUMBERS, serialize(key)), Key::BlockNumber(ref key) => (COL_BLOCK_NUMBERS, serialize(key)),
Key::Configuration(ref key) => (COL_CONFIGURATION, serialize(key)), Key::Configuration(ref key) => (COL_CONFIGURATION, serialize(key)),
}; };

View File

@ -7,6 +7,7 @@ use std::hash::{Hash, Hasher};
macro_rules! impl_hash { macro_rules! impl_hash {
($name: ident, $size: expr) => { ($name: ident, $size: expr) => {
#[repr(C)] #[repr(C)]
#[derive(Copy)]
pub struct $name([u8; $size]); pub struct $name([u8; $size]);
impl Default for $name { impl Default for $name {

View File

@ -10,7 +10,7 @@ fn transaction_output(transactions: &[IndexedTransaction], prevout: &OutPoint) -
} }
fn is_spent(transactions: &[IndexedTransaction], prevout: &OutPoint) -> bool { fn is_spent(transactions: &[IndexedTransaction], prevout: &OutPoint) -> bool {
// the code below is valid, but has rather poor performance // TODO: the code below is valid, but has rather poor performance!
// if previous transaction output appears more than once than we can safely // if previous transaction output appears more than once than we can safely
// tell that it's spent (double spent) // tell that it's spent (double spent)

View File

@ -12,6 +12,9 @@ pub enum Error {
/// Ancient fork /// Ancient fork
#[display(fmt = "Fork is too long to proceed")] #[display(fmt = "Fork is too long to proceed")]
AncientFork, AncientFork,
/// Invalid block
#[display(fmt = "Cannot decanonize block (invalid database state)")]
CannotDecanonize,
} }
impl From<Error> for String { impl From<Error> for String {

View File

@ -21,6 +21,7 @@ mod error;
mod store; mod store;
mod transaction_meta; mod transaction_meta;
mod transaction_provider; mod transaction_provider;
mod nullifier;
pub use primitives::{hash, bytes}; pub use primitives::{hash, bytes};
@ -35,4 +36,4 @@ pub use error::Error;
pub use store::{AsSubstore, Store, SharedStore, CanonStore, ConfigStore}; pub use store::{AsSubstore, Store, SharedStore, CanonStore, ConfigStore};
pub use transaction_meta::TransactionMeta; pub use transaction_meta::TransactionMeta;
pub use transaction_provider::{TransactionProvider, TransactionOutputProvider, TransactionMetaProvider}; pub use transaction_provider::{TransactionProvider, TransactionOutputProvider, TransactionMetaProvider};
pub use nullifier::{Nullifier, NullifierTracker, Tag as NullifierTag};

54
storage/src/nullifier.rs Normal file
View File

@ -0,0 +1,54 @@
use hash::H256;
/// Nullifier epoch (tag).
///
/// Sprout and Sapling nullifiers are considered disjoint,
/// even if they have the same bit pattern.
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Tag {
/// Sprout nullifier.
Sprout,
/// Sapling nullifier.
Sapling,
}
/// Nullifier.
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Nullifier {
tag: Tag,
hash: H256,
}
/// Trait to query existing nullifier.
pub trait NullifierTracker {
fn contains_nullifier(&self, nullifier: Nullifier) -> bool;
}
impl Nullifier {
/// New nullifer.
pub fn new(tag: Tag, hash: H256) -> Self {
Nullifier {
tag: tag,
hash: hash,
}
}
/// Nullifer tag
pub fn tag(&self) -> Tag {
self.tag
}
/// Nullifer hash
pub fn hash(&self) -> &H256 {
&self.hash
}
}
impl From<(Tag, H256)> for Nullifier {
fn from(tuple: (Tag, H256)) -> Self {
Nullifier {
tag: tuple.0,
hash: tuple.1,
}
}
}

View File

@ -3,7 +3,7 @@ use chain::BlockHeader;
use primitives::compact::Compact; use primitives::compact::Compact;
use { use {
BestBlock, BlockProvider, BlockHeaderProvider, TransactionProvider, TransactionMetaProvider, BestBlock, BlockProvider, BlockHeaderProvider, TransactionProvider, TransactionMetaProvider,
TransactionOutputProvider, BlockChain, IndexedBlockProvider, Forkable, Error TransactionOutputProvider, BlockChain, IndexedBlockProvider, Forkable, Error, NullifierTracker,
}; };
pub trait CanonStore: Store + Forkable + ConfigStore { pub trait CanonStore: Store + Forkable + ConfigStore {
@ -32,7 +32,14 @@ pub trait Store: AsSubstore {
} }
/// Allows casting Arc<Store> to reference to any substore type /// Allows casting Arc<Store> to reference to any substore type
pub trait AsSubstore: BlockChain + IndexedBlockProvider + TransactionProvider + TransactionMetaProvider + TransactionOutputProvider { pub trait AsSubstore:
BlockChain +
IndexedBlockProvider +
TransactionProvider +
TransactionMetaProvider +
TransactionOutputProvider +
NullifierTracker
{
fn as_block_provider(&self) -> &BlockProvider; fn as_block_provider(&self) -> &BlockProvider;
fn as_block_header_provider(&self) -> &BlockHeaderProvider; fn as_block_header_provider(&self) -> &BlockHeaderProvider;
@ -42,9 +49,18 @@ pub trait AsSubstore: BlockChain + IndexedBlockProvider + TransactionProvider +
fn as_transaction_output_provider(&self) -> &TransactionOutputProvider; fn as_transaction_output_provider(&self) -> &TransactionOutputProvider;
fn as_transaction_meta_provider(&self) -> &TransactionMetaProvider; fn as_transaction_meta_provider(&self) -> &TransactionMetaProvider;
fn as_nullifier_tracker(&self) -> &NullifierTracker;
} }
impl<T> AsSubstore for T where T: BlockChain + IndexedBlockProvider + TransactionProvider + TransactionMetaProvider + TransactionOutputProvider { impl<T> AsSubstore for T
where T: BlockChain +
IndexedBlockProvider +
TransactionProvider +
TransactionMetaProvider +
TransactionOutputProvider +
NullifierTracker
{
fn as_block_provider(&self) -> &BlockProvider { fn as_block_provider(&self) -> &BlockProvider {
&*self &*self
} }
@ -64,6 +80,10 @@ impl<T> AsSubstore for T where T: BlockChain + IndexedBlockProvider + Transactio
fn as_transaction_meta_provider(&self) -> &TransactionMetaProvider { fn as_transaction_meta_provider(&self) -> &TransactionMetaProvider {
&*self &*self
} }
fn as_nullifier_tracker(&self) -> &NullifierTracker {
&*self
}
} }
pub type SharedStore = Arc<CanonStore + Send + Sync>; pub type SharedStore = Arc<CanonStore + Send + Sync>;

View File

@ -8,8 +8,12 @@ time = "0.1"
log = "0.4" log = "0.4"
rayon = "1.0" rayon = "1.0"
parking_lot = "0.4" parking_lot = "0.4"
bellman = "0.1"
blake2-rfc = { git = "https://github.com/gtank/blake2-rfc.git", branch = "persona" } blake2-rfc = { git = "https://github.com/gtank/blake2-rfc.git", branch = "persona" }
byteorder = "1.2" 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" } primitives = { path = "../primitives" }
chain = { path = "../chain" } chain = { path = "../chain" }
serialization = { path = "../serialization" } serialization = { path = "../serialization" }

View File

@ -4,6 +4,7 @@ use network::{ConsensusParams};
use script::{Script, verify_script, VerificationFlags, TransactionSignatureChecker, TransactionInputSigner}; use script::{Script, verify_script, VerificationFlags, TransactionSignatureChecker, TransactionInputSigner};
use duplex_store::DuplexTransactionOutputProvider; use duplex_store::DuplexTransactionOutputProvider;
use deployments::BlockDeployments; use deployments::BlockDeployments;
use sapling::accept_sapling;
use sigops::transaction_sigops; use sigops::transaction_sigops;
use canon::CanonTransaction; use canon::CanonTransaction;
use constants::{COINBASE_MATURITY}; use constants::{COINBASE_MATURITY};
@ -15,6 +16,7 @@ pub struct TransactionAcceptor<'a> {
pub bip30: TransactionBip30<'a>, pub bip30: TransactionBip30<'a>,
pub missing_inputs: TransactionMissingInputs<'a>, pub missing_inputs: TransactionMissingInputs<'a>,
pub maturity: TransactionMaturity<'a>, pub maturity: TransactionMaturity<'a>,
pub sapling_valid: TransactionSaplingValid<'a>,
pub overspent: TransactionOverspent<'a>, pub overspent: TransactionOverspent<'a>,
pub double_spent: TransactionDoubleSpend<'a>, pub double_spent: TransactionDoubleSpend<'a>,
pub eval: TransactionEval<'a>, pub eval: TransactionEval<'a>,
@ -41,6 +43,7 @@ impl<'a> TransactionAcceptor<'a> {
bip30: TransactionBip30::new_for_sync(transaction, meta_store), bip30: TransactionBip30::new_for_sync(transaction, meta_store),
missing_inputs: TransactionMissingInputs::new(transaction, output_store, transaction_index), missing_inputs: TransactionMissingInputs::new(transaction, output_store, transaction_index),
maturity: TransactionMaturity::new(transaction, meta_store, height), maturity: TransactionMaturity::new(transaction, meta_store, height),
sapling_valid: TransactionSaplingValid::new(transaction),
overspent: TransactionOverspent::new(transaction, output_store), overspent: TransactionOverspent::new(transaction, output_store),
double_spent: TransactionDoubleSpend::new(transaction, output_store), double_spent: TransactionDoubleSpend::new(transaction, output_store),
eval: TransactionEval::new(transaction, output_store, consensus, verification_level, height, time, deployments), eval: TransactionEval::new(transaction, output_store, consensus, verification_level, height, time, deployments),
@ -52,6 +55,7 @@ impl<'a> TransactionAcceptor<'a> {
self.bip30.check()?; self.bip30.check()?;
self.missing_inputs.check()?; self.missing_inputs.check()?;
self.maturity.check()?; self.maturity.check()?;
self.sapling_valid.check()?;
self.overspent.check()?; self.overspent.check()?;
self.double_spent.check()?; self.double_spent.check()?;
self.eval.check()?; self.eval.check()?;
@ -471,6 +475,29 @@ impl<'a> Nullifiers<'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(())
}
}
/// Join split verification /// Join split verification
pub struct JoinSplitVerification<'a> { pub struct JoinSplitVerification<'a> {
proof: JoinSplitProof<'a>, proof: JoinSplitProof<'a>,

View File

@ -132,5 +132,7 @@ pub enum TransactionError {
DuplicateSaplingSpendNullifier(usize, usize), DuplicateSaplingSpendNullifier(usize, usize),
/// Join split already declared earlier in the chain. /// Join split already declared earlier in the chain.
JoinSplitDeclared(H256), JoinSplitDeclared(H256),
/// Transaction sapling verification has failed.
InvalidSapling,
} }

View File

@ -56,11 +56,16 @@ extern crate time;
extern crate log; extern crate log;
extern crate parking_lot; extern crate parking_lot;
extern crate rayon; extern crate rayon;
extern crate bellman;
extern crate blake2_rfc; extern crate blake2_rfc;
extern crate byteorder; extern crate byteorder;
#[macro_use]
extern crate lazy_static;
#[cfg(test)] #[cfg(test)]
extern crate rand; extern crate rand;
extern crate rustc_hex as hex; extern crate rustc_hex as hex;
extern crate pairing;
extern crate sapling_crypto;
extern crate storage; extern crate storage;
extern crate chain; extern crate chain;
@ -78,6 +83,7 @@ mod deployments;
mod duplex_store; mod duplex_store;
mod equihash; mod equihash;
mod error; mod error;
mod sapling;
mod sigops; mod sigops;
mod timestamp; mod timestamp;
mod work; mod work;

300
verification/src/sapling.rs Normal file
View File

@ -0,0 +1,300 @@
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.
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
}

View File

@ -356,7 +356,7 @@ impl<'a> TransactionSapling<'a> {
fn check(&self) -> Result<(), TransactionError> { fn check(&self) -> Result<(), TransactionError> {
if let Some(ref sapling) = self.transaction.raw.sapling { if let Some(ref sapling) = self.transaction.raw.sapling {
// sapling balance should be zero if spends and outputs are empty // 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); return Err(TransactionError::EmptySaplingHasBalance);
} }
} }
@ -423,13 +423,13 @@ impl<'a> TransactionOutputValueOverflow<'a> {
if let Some(ref sapling) = self.transaction.raw.sapling { if let Some(ref sapling) = self.transaction.raw.sapling {
// check that sapling amount is within limits // 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); return Err(TransactionError::OutputValueOverflow);
} }
// negative sapling amount takes value from transparent pool // negative sapling amount takes value from transparent pool
if sapling.amount < 0 { if sapling.balancing_value < 0 {
total_output = match total_output.checked_add(-sapling.amount) { total_output = match total_output.checked_add(-sapling.balancing_value) {
Some(total_output) if total_output <= self.max_value => total_output, Some(total_output) if total_output <= self.max_value => total_output,
_ => return Err(TransactionError::OutputValueOverflow), _ => return Err(TransactionError::OutputValueOverflow),
}; };
@ -493,8 +493,8 @@ impl<'a> TransactionInputValueOverflow<'a> {
if let Some(ref sapling) = self.transaction.raw.sapling { if let Some(ref sapling) = self.transaction.raw.sapling {
// positive sapling amount adds value to the transparent pool // positive sapling amount adds value to the transparent pool
if sapling.amount > 0 { if sapling.balancing_value > 0 {
match total_input.checked_add(sapling.amount as u64) { match total_input.checked_add(sapling.balancing_value as u64) {
Some(total_input) if total_input <= self.max_value => (), Some(total_input) if total_input <= self.max_value => (),
_ => return Err(TransactionError::InputValueOverflow), _ => return Err(TransactionError::InputValueOverflow),
}; };
@ -721,18 +721,18 @@ mod tests {
.into(), &consensus).check(), Ok(())); .into(), &consensus).check(), Ok(()));
assert_eq!(TransactionOutputValueOverflow::new(&test_data::TransactionBuilder::with_sapling(Sapling { assert_eq!(TransactionOutputValueOverflow::new(&test_data::TransactionBuilder::with_sapling(Sapling {
amount: max_value, balancing_value: max_value,
..Default::default() ..Default::default()
}).into(), &consensus).check(), Ok(())); }).into(), &consensus).check(), Ok(()));
assert_eq!(TransactionOutputValueOverflow::new(&test_data::TransactionBuilder::with_sapling(Sapling { assert_eq!(TransactionOutputValueOverflow::new(&test_data::TransactionBuilder::with_sapling(Sapling {
amount: max_value + 1, balancing_value: max_value + 1,
..Default::default() ..Default::default()
}).into(), &consensus).check(), Err(TransactionError::OutputValueOverflow)); }).into(), &consensus).check(), Err(TransactionError::OutputValueOverflow));
assert_eq!(TransactionOutputValueOverflow::new(&test_data::TransactionBuilder::with_output(max_value as u64 / 2 + 1) assert_eq!(TransactionOutputValueOverflow::new(&test_data::TransactionBuilder::with_output(max_value as u64 / 2 + 1)
.set_sapling(Sapling { .set_sapling(Sapling {
amount: -max_value / 2, balancing_value: -max_value / 2,
..Default::default() ..Default::default()
}).into(), &consensus).check(), Err(TransactionError::OutputValueOverflow)); }).into(), &consensus).check(), Err(TransactionError::OutputValueOverflow));
@ -805,12 +805,12 @@ mod tests {
}).into(), &consensus).check(), Err(TransactionError::InputValueOverflow)); }).into(), &consensus).check(), Err(TransactionError::InputValueOverflow));
assert_eq!(TransactionInputValueOverflow::new(&test_data::TransactionBuilder::with_sapling(Sapling { assert_eq!(TransactionInputValueOverflow::new(&test_data::TransactionBuilder::with_sapling(Sapling {
amount: max_value, balancing_value: max_value,
..Default::default() ..Default::default()
}).into(), &consensus).check(), Ok(())); }).into(), &consensus).check(), Ok(()));
assert_eq!(TransactionInputValueOverflow::new(&test_data::TransactionBuilder::with_sapling(Sapling { assert_eq!(TransactionInputValueOverflow::new(&test_data::TransactionBuilder::with_sapling(Sapling {
amount: max_value + 1, balancing_value: max_value + 1,
..Default::default() ..Default::default()
}).into(), &consensus).check(), Err(TransactionError::InputValueOverflow)); }).into(), &consensus).check(), Err(TransactionError::InputValueOverflow));
@ -821,7 +821,7 @@ mod tests {
}], }],
..Default::default() ..Default::default()
}).set_sapling(Sapling { }).set_sapling(Sapling {
amount: max_value / 2, balancing_value: max_value / 2,
..Default::default() ..Default::default()
}).into(), &consensus).check(), Err(TransactionError::InputValueOverflow)); }).into(), &consensus).check(), Err(TransactionError::InputValueOverflow));
} }
@ -842,26 +842,26 @@ mod tests {
#[test] #[test]
fn transaction_sapling_works() { fn transaction_sapling_works() {
assert_eq!(TransactionSapling::new(&test_data::TransactionBuilder::with_sapling(Sapling { assert_eq!(TransactionSapling::new(&test_data::TransactionBuilder::with_sapling(Sapling {
amount: 100, balancing_value: 100,
spends: vec![Default::default()], spends: vec![Default::default()],
..Default::default() ..Default::default()
}).into()).check(), Ok(())); }).into()).check(), Ok(()));
assert_eq!(TransactionSapling::new(&test_data::TransactionBuilder::with_sapling(Sapling { assert_eq!(TransactionSapling::new(&test_data::TransactionBuilder::with_sapling(Sapling {
amount: 100, balancing_value: 100,
outputs: vec![Default::default()], outputs: vec![Default::default()],
..Default::default() ..Default::default()
}).into()).check(), Ok(())); }).into()).check(), Ok(()));
assert_eq!(TransactionSapling::new(&test_data::TransactionBuilder::with_sapling(Sapling { assert_eq!(TransactionSapling::new(&test_data::TransactionBuilder::with_sapling(Sapling {
amount: 100, balancing_value: 100,
outputs: vec![Default::default()], outputs: vec![Default::default()],
spends: vec![Default::default()], spends: vec![Default::default()],
..Default::default() ..Default::default()
}).into()).check(), Ok(())); }).into()).check(), Ok(()));
assert_eq!(TransactionSapling::new(&test_data::TransactionBuilder::with_sapling(Sapling { assert_eq!(TransactionSapling::new(&test_data::TransactionBuilder::with_sapling(Sapling {
amount: 100, balancing_value: 100,
..Default::default() ..Default::default()
}).into()).check(), Err(TransactionError::EmptySaplingHasBalance)); }).into()).check(), Err(TransactionError::EmptySaplingHasBalance));
} }