Merge pull request #212 from ebfull/depends-updates-2

Dependency updates
This commit is contained in:
str4d 2020-03-04 15:11:42 +13:00 committed by GitHub
commit fc247fc898
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 1971 additions and 55 deletions

248
Cargo.lock generated
View File

@ -29,6 +29,14 @@ dependencies = [
"opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "aho-corasick"
version = "0.7.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "arrayref"
version = "0.3.5"
@ -42,6 +50,11 @@ dependencies = [
"nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "assert_matches"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "autocfg"
version = "0.1.6"
@ -60,13 +73,13 @@ dependencies = [
"blake2s_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
"ff 0.5.0",
"ff 0.5.2",
"futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"group 0.2.0",
"hex-literal 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
"pairing 0.15.0",
"pairing 0.15.1",
"rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -87,6 +100,11 @@ name = "bit-vec"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bitflags"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "blake2b_simd"
version = "0.5.8"
@ -163,6 +181,14 @@ name = "cfg-if"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "cloudabi"
version = "0.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "constant_time_eq"
version = "0.1.4"
@ -263,6 +289,15 @@ dependencies = [
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "env_logger"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "fake-simd"
version = "0.1.2"
@ -270,16 +305,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "ff"
version = "0.5.0"
version = "0.5.2"
dependencies = [
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"ff_derive 0.4.0",
"ff_derive 0.4.1",
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ff_derive"
version = "0.4.0"
version = "0.4.1"
dependencies = [
"num-bigint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
@ -301,6 +336,11 @@ dependencies = [
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "fuchsia-cprng"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "futures"
version = "0.1.29"
@ -337,7 +377,7 @@ dependencies = [
name = "group"
version = "0.2.0"
dependencies = [
"ff 0.5.0",
"ff 0.5.2",
"rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -381,12 +421,12 @@ dependencies = [
"bellman 0.2.0",
"blake2b_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
"blake2s_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
"ff 0.5.0",
"ff 0.5.2",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"pairing 0.15.0",
"pairing 0.15.1",
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"zcash_mmr 0.1.0 (git+https://github.com/nikvolf/zcash-mmr)",
"zcash_history 0.0.1",
"zcash_primitives 0.1.0",
"zcash_proofs 0.1.0",
]
@ -399,6 +439,11 @@ dependencies = [
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "memchr"
version = "2.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "memoffset"
version = "0.5.1"
@ -454,10 +499,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "pairing"
version = "0.15.0"
version = "0.15.1"
dependencies = [
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"ff 0.5.0",
"ff 0.5.2",
"group 0.2.0",
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -508,6 +553,17 @@ dependencies = [
"protobuf-codegen 2.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "quickcheck"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "quote"
version = "1.0.2"
@ -516,6 +572,24 @@ dependencies = [
"proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand"
version = "0.7.0"
@ -528,6 +602,15 @@ dependencies = [
"rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_chacha"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_chacha"
version = "0.2.1"
@ -537,6 +620,19 @@ dependencies = [
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_core"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_core"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rand_core"
version = "0.5.1"
@ -545,6 +641,14 @@ dependencies = [
"getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_hc"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_hc"
version = "0.2.0"
@ -553,6 +657,54 @@ dependencies = [
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_isaac"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_jitter"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_os"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_pcg"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_xorshift"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_xorshift"
version = "0.2.0"
@ -561,6 +713,30 @@ dependencies = [
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rdrand"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex"
version = "1.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"aho-corasick 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-syntax 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex-syntax"
version = "0.6.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "ripemd160"
version = "0.8.0"
@ -631,6 +807,14 @@ dependencies = [
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "thread_local"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "typenum"
version = "1.11.2"
@ -670,9 +854,9 @@ name = "zcash_client_backend"
version = "0.1.0"
dependencies = [
"bech32 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"ff 0.5.0",
"ff 0.5.2",
"hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"pairing 0.15.0",
"pairing 0.15.1",
"protobuf 2.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"protobuf-codegen-pure 2.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -682,13 +866,14 @@ dependencies = [
]
[[package]]
name = "zcash_mmr"
version = "0.1.0"
source = "git+https://github.com/nikvolf/zcash-mmr#26be46573ee7e0094f19d861fd29793adda6298e"
name = "zcash_history"
version = "0.0.1"
dependencies = [
"assert_matches 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"bigint 4.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"blake2b_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"quickcheck 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -700,13 +885,13 @@ dependencies = [
"blake2s_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"crypto_api_chachapoly 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"ff 0.5.0",
"ff 0.5.2",
"fpe 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"hex-literal 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"pairing 0.15.0",
"pairing 0.15.1",
"rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -723,8 +908,8 @@ dependencies = [
"blake2b_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"directories 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"ff 0.5.0",
"pairing 0.15.0",
"ff 0.5.2",
"pairing 0.15.1",
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"zcash_primitives 0.1.0",
@ -734,12 +919,15 @@ dependencies = [
"checksum aes 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "54eb1d8fe354e5fc611daf4f2ea97dd45a765f4f1e4512306ec183ae2e8f20c9"
"checksum aes-soft 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cfd7e7ae3f9a1fb5c03b389fc6bb9a51400d0c13053f0dca698c832bfd893a0d"
"checksum aesni 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f70a6b5f971e473091ab7cfb5ffac6cde81666c4556751d8d5620ead8abf100"
"checksum aho-corasick 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)" = "d5e63fd144e18ba274ae7095c0197a870a7b9468abc801dd62f190d80817d2ec"
"checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee"
"checksum arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b8d73f9beda665eaa98ab9e4f7442bd4e7de6652587de55b2525e52e29c1b0ba"
"checksum assert_matches 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7deb0a829ca7bcfaf5da70b073a8d128619259a7be8216a355e23f00763059e5"
"checksum autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b671c8fb71b457dd4ae18c4ba1e59aa81793daacc361d82fcd410cef0d491875"
"checksum bech32 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9e0089c35ab7c6f2bc55ab23f769913f0ac65b1023e7e74638a1f43128dd5df2"
"checksum bigint 4.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ebecac13b3c745150d7b6c3ea7572d372f09d627c2077e893bf26c5c7f70d282"
"checksum bit-vec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "02b4ff8b16e6076c3e14220b39fbc1fabb6737522281a388998046859400895f"
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
"checksum blake2b_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)" = "5850aeee1552f495dd0250014cf64b82b7c8879a89d83b33bbdace2cc4f63182"
"checksum blake2s_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)" = "979da0ce13c897d6be19e005ea77ac12b0fea0157aeeee7feb8c49f91386f0ea"
"checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b"
@ -750,6 +938,7 @@ dependencies = [
"checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101"
"checksum cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)" = "4fc9a35e1f4290eb9e5fc54ba6cf40671ed2a2514c3eeb2b2a908dda2ea5a1be"
"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33"
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
"checksum constant_time_eq 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "995a44c877f9212528ccc74b21a232f66ad69001e40ede5bcee2ac9ef2657120"
"checksum crossbeam 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2d818a4990769aac0c7ff1360e233ef3a41adcb009ebb2036bf6915eb0f6b23c"
"checksum crossbeam-channel 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c8ec7fcd21571dc78f96cc96243cab8d8f035247c3efd16c687be154c3fa9efa"
@ -762,8 +951,10 @@ dependencies = [
"checksum crypto_api_chachapoly 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "95b2ad7cab08fd71addba81df5077c49df208effdfb3118a1519f9cdeac5aaf2"
"checksum digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5"
"checksum directories 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "72d337a64190607d4fcca2cb78982c5dd57f4916e19696b48a575fa746b6cb0f"
"checksum env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3"
"checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
"checksum fpe 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "21988a326139165b75e3196bc6962ca638e5fb0c95102fbf152a3743174b01e4"
"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
"checksum futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)" = "1b980f2816d6ee8673b6517b52cb0e808a180efc92e5c19d02cdda79066703ef"
"checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4"
"checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec"
@ -774,6 +965,7 @@ dependencies = [
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
"checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba"
"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
"checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
"checksum memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce6075db033bbbb7ee5a0bbd3a3186bbae616f57fb001c485c7ff77955f8177f"
"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
"checksum num-bigint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f9c3f34cdd24f334cb265d9bf8bfa8a241920d026916785747a92f0e55541a1a"
@ -787,12 +979,26 @@ dependencies = [
"checksum protobuf 2.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40361836defdd5871ff7e84096c6f6444af7fc157f8ef1789f54f147687caa20"
"checksum protobuf-codegen 2.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "12c6abd78435445fc86898ebbd0521a68438063d4a73e23527b7134e6bf58b4a"
"checksum protobuf-codegen-pure 2.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c1646acda5319f5b28b0bff4a484324df43ddae2c0f5a3f3e63c0b26095cd600"
"checksum quickcheck 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)" = "9c35d9c36a562f37eca96e79f66d5fd56eefbc22560dacc4a864cabd2d277456"
"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
"checksum rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d47eab0e83d9693d40f825f86948aa16eff6750ead4bdffc4ab95b8b3a7f052c"
"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
"checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853"
"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
"checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
"checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4"
"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08"
"checksum rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b"
"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
"checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44"
"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c"
"checksum rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "77d416b86801d23dde1aa643023b775c3a462efc0ed96443add11546cdf1dca8"
"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
"checksum regex 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "322cf97724bea3ee221b78fe25ac9c46114ebb51747ad5babd51a2fc6a8235a8"
"checksum regex-syntax 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)" = "1132f845907680735a84409c3bebc64d1364a5683ffbce899550cd09d5eaefc1"
"checksum ripemd160 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ad5112e0dbbb87577bfbc56c42450235e3012ce336e29c5befd7807bd626da4a"
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d"
@ -802,10 +1008,10 @@ dependencies = [
"checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d"
"checksum subtle 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab3af2eb31c42e8f0ccf43548232556c42737e01a96db6e1777b0be108e79799"
"checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf"
"checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"
"checksum typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9"
"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
"checksum wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b89c3ce4ce14bdc6fb6beaf9ec7928ca331de5df7e5ea278375642a2f478570d"
"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
"checksum zcash_mmr 0.1.0 (git+https://github.com/nikvolf/zcash-mmr)" = "<none>"

View File

@ -6,6 +6,7 @@ members = [
"librustzcash",
"pairing",
"zcash_client_backend",
"zcash_history",
"zcash_primitives",
"zcash_proofs",
]

View File

@ -2,7 +2,6 @@
authors = ["Sean Bowe <ewillbefull@gmail.com>"]
description = "zk-SNARK library"
readme = "README.md"
documentation = "https://github.com/ebfull/bellman"
homepage = "https://github.com/ebfull/bellman"
license = "MIT/Apache-2.0"
name = "bellman"

View File

@ -22,7 +22,7 @@ impl fmt::Display for Fr {
}
impl Field for Fr {
fn random<R: RngCore>(rng: &mut R) -> Self {
fn random<R: RngCore + ?std::marker::Sized>(rng: &mut R) -> Self {
Fr(Wrapping(rng.next_u32()) % MODULUS_R)
}

View File

@ -1,6 +1,6 @@
[package]
name = "ff"
version = "0.5.0"
version = "0.5.2"
authors = ["Sean Bowe <ewillbefull@gmail.com>"]
description = "Library for building and interfacing with finite fields"
readme = "README.md"
@ -12,7 +12,7 @@ edition = "2018"
[dependencies]
byteorder = "1"
ff_derive = { version = "0.4.0", path = "ff_derive", optional = true }
ff_derive = { version = "^0.4.1", path = "ff_derive", optional = true }
rand_core = "0.5"
[features]

View File

@ -12,7 +12,7 @@ Add the `ff` crate to your `Cargo.toml`:
```toml
[dependencies]
ff = "0.4"
ff = "0.5"
```
The `ff` crate contains `Field`, `PrimeField`, `PrimeFieldRepr` and `SqrtField` traits.

View File

@ -1,6 +1,6 @@
[package]
name = "ff_derive"
version = "0.4.0"
version = "0.4.1"
authors = ["Sean Bowe <ewillbefull@gmail.com>"]
description = "Procedural macro library used to build custom prime field implementations"
documentation = "https://docs.rs/ff/"

View File

@ -877,7 +877,7 @@ fn prime_field_impl(
impl ::ff::Field for #name {
/// Computes a uniformly random element using rejection sampling.
fn random<R: ::rand_core::RngCore>(rng: &mut R) -> Self {
fn random<R: ::rand_core::RngCore + ?std::marker::Sized>(rng: &mut R) -> Self {
loop {
let mut tmp = {
let mut repr = [0u64; #limbs];

View File

@ -17,7 +17,7 @@ pub trait Field:
Sized + Eq + Copy + Clone + Send + Sync + fmt::Debug + fmt::Display + 'static
{
/// Returns an element chosen uniformly at random using a user-provided RNG.
fn random<R: RngCore>(rng: &mut R) -> Self;
fn random<R: RngCore + ?std::marker::Sized>(rng: &mut R) -> Self;
/// Returns the zero element of the field, the additive identity.
fn zero() -> Self;

View File

@ -28,7 +28,7 @@ libc = "0.2"
pairing = { version = "0.15.0", path = "../pairing" }
lazy_static = "1"
rand_core = "0.5.1"
zcash_mmr = { git = "https://github.com/nikvolf/zcash-mmr" }
zcash_history = { version = "0.0.1", path = "../zcash_history" }
zcash_primitives = { version = "0.1.0", path = "../zcash_primitives" }
zcash_proofs = { version = "0.1.0", path = "../zcash_proofs" }

View File

@ -65,7 +65,7 @@ use zcash_proofs::{
sprout,
};
use zcash_mmr::{Entry as MMREntry, NodeData as MMRNodeData, Tree as MMRTree};
use zcash_history::{Entry as MMREntry, NodeData as MMRNodeData, Tree as MMRTree};
#[cfg(test)]
mod tests;
@ -1173,7 +1173,7 @@ fn construct_mmr_tree(
// Indices of provided tree nodes, length of p_len+e_len
ni_ptr: *const u32,
// Provided tree nodes data, length of p_len+e_len
n_ptr: *const [c_uchar; zcash_mmr::MAX_ENTRY_SIZE],
n_ptr: *const [c_uchar; zcash_history::MAX_ENTRY_SIZE],
// Peaks count
p_len: size_t,
@ -1211,17 +1211,17 @@ pub extern "system" fn librustzcash_mmr_append(
// Indices of provided tree nodes, length of p_len
ni_ptr: *const u32,
// Provided tree nodes data, length of p_len
n_ptr: *const [c_uchar; zcash_mmr::MAX_ENTRY_SIZE],
n_ptr: *const [c_uchar; zcash_history::MAX_ENTRY_SIZE],
// Peaks count
p_len: size_t,
// New node pointer
nn_ptr: *const [u8; zcash_mmr::MAX_NODE_DATA_SIZE],
nn_ptr: *const [u8; zcash_history::MAX_NODE_DATA_SIZE],
// Return of root commitment
rt_ret: *mut [u8; 32],
// Return buffer for appended leaves, should be pre-allocated of ceiling(log2(t_len)) length
buf_ret: *mut [c_uchar; zcash_mmr::MAX_NODE_DATA_SIZE],
buf_ret: *mut [c_uchar; zcash_history::MAX_NODE_DATA_SIZE],
) -> u32 {
let new_node_bytes: &[u8; zcash_mmr::MAX_NODE_DATA_SIZE] = unsafe {
let new_node_bytes: &[u8; zcash_history::MAX_NODE_DATA_SIZE] = unsafe {
match nn_ptr.as_ref() {
Some(r) => r,
None => {
@ -1283,7 +1283,7 @@ pub extern "system" fn librustzcash_mmr_delete(
// Indices of provided tree nodes, length of p_len+e_len
ni_ptr: *const u32,
// Provided tree nodes data, length of p_len+e_len
n_ptr: *const [c_uchar; zcash_mmr::MAX_ENTRY_SIZE],
n_ptr: *const [c_uchar; zcash_history::MAX_ENTRY_SIZE],
// Peaks count
p_len: size_t,
// Extra nodes loaded (for deletion) count
@ -1319,10 +1319,10 @@ pub extern "system" fn librustzcash_mmr_delete(
#[no_mangle]
pub extern "system" fn librustzcash_mmr_hash_node(
cbranch: u32,
n_ptr: *const [u8; zcash_mmr::MAX_NODE_DATA_SIZE],
n_ptr: *const [u8; zcash_history::MAX_NODE_DATA_SIZE],
h_ret: *mut [u8; 32],
) -> u32 {
let node_bytes: &[u8; zcash_mmr::MAX_NODE_DATA_SIZE] = unsafe {
let node_bytes: &[u8; zcash_history::MAX_NODE_DATA_SIZE] = unsafe {
match n_ptr.as_ref() {
Some(r) => r,
None => return 1,

View File

@ -1,4 +1,4 @@
use zcash_mmr::{Entry, EntryLink, NodeData};
use zcash_history::{Entry, EntryLink, NodeData};
use crate::{librustzcash_mmr_append, librustzcash_mmr_delete};
@ -82,7 +82,7 @@ fn prepare_tree(nodes: &[NodeData]) -> TreeView {
TreeView { peaks, extra }
}
fn preload_tree_append(nodes: &[NodeData]) -> (Vec<u32>, Vec<[u8; zcash_mmr::MAX_ENTRY_SIZE]>) {
fn preload_tree_append(nodes: &[NodeData]) -> (Vec<u32>, Vec<[u8; zcash_history::MAX_ENTRY_SIZE]>) {
assert!(!nodes.is_empty());
let tree_view = prepare_tree(nodes);
@ -91,7 +91,7 @@ fn preload_tree_append(nodes: &[NodeData]) -> (Vec<u32>, Vec<[u8; zcash_mmr::MAX
let mut bytes = Vec::new();
for (idx, entry) in tree_view.peaks.into_iter() {
let mut buf = [0u8; zcash_mmr::MAX_ENTRY_SIZE];
let mut buf = [0u8; zcash_history::MAX_ENTRY_SIZE];
entry
.write(&mut &mut buf[..])
.expect("Cannot fail if enough buffer length");
@ -105,7 +105,7 @@ fn preload_tree_append(nodes: &[NodeData]) -> (Vec<u32>, Vec<[u8; zcash_mmr::MAX
// also returns number of peaks
fn preload_tree_delete(
nodes: &[NodeData],
) -> (Vec<u32>, Vec<[u8; zcash_mmr::MAX_ENTRY_SIZE]>, usize) {
) -> (Vec<u32>, Vec<[u8; zcash_history::MAX_ENTRY_SIZE]>, usize) {
assert!(!nodes.is_empty());
let tree_view = prepare_tree(nodes);
@ -120,7 +120,7 @@ fn preload_tree_delete(
.into_iter()
.chain(tree_view.extra.into_iter())
{
let mut buf = [0u8; zcash_mmr::MAX_ENTRY_SIZE];
let mut buf = [0u8; zcash_history::MAX_ENTRY_SIZE];
entry
.write(&mut &mut buf[..])
.expect("Cannot fail if enough buffer length");
@ -135,8 +135,8 @@ fn load_nodes(bytes: &'static [u8]) -> Vec<NodeData> {
let mut res = Vec::new();
let mut cursor = std::io::Cursor::new(bytes);
while (cursor.position() as usize) < bytes.len() {
let node_data =
zcash_mmr::NodeData::read(0, &mut cursor).expect("Statically checked to be correct");
let node_data = zcash_history::NodeData::read(0, &mut cursor)
.expect("Statically checked to be correct");
res.push(node_data);
}
@ -150,9 +150,9 @@ fn append() {
let mut rt_ret = [0u8; 32];
let mut buf_ret = Vec::<[u8; zcash_mmr::MAX_NODE_DATA_SIZE]>::with_capacity(32);
let mut buf_ret = Vec::<[u8; zcash_history::MAX_NODE_DATA_SIZE]>::with_capacity(32);
let mut new_node_data = [0u8; zcash_mmr::MAX_NODE_DATA_SIZE];
let mut new_node_data = [0u8; zcash_history::MAX_NODE_DATA_SIZE];
let new_node = NodeData {
consensus_branch_id: 0,
subtree_commitment: [0u8; 32],

View File

@ -2,7 +2,7 @@
name = "pairing"
# Remember to change version string in README.md.
version = "0.15.0"
version = "0.15.1"
authors = [
"Sean Bowe <ewillbefull@gmail.com>",
"Jack Grigg <jack@z.cash>",
@ -18,7 +18,7 @@ edition ="2018"
[dependencies]
byteorder = "1"
ff = { version = "0.5.0", path = "../ff", features = ["derive"] }
ff = { version = "^0.5.2", path = "../ff", features = ["derive"] }
group = { version = "0.2.0", path = "../group" }
rand_core = "0.5"

View File

@ -200,7 +200,7 @@ macro_rules! curve_impl {
type Base = $basefield;
type Affine = $affine;
fn random<R: RngCore>(rng: &mut R) -> Self {
fn random<R: RngCore + ?std::marker::Sized>(rng: &mut R) -> Self {
loop {
let x = $basefield::random(rng);
let greatest = rng.next_u32() % 2 != 0;

View File

@ -40,7 +40,7 @@ impl Fq12 {
}
impl Field for Fq12 {
fn random<R: RngCore>(rng: &mut R) -> Self {
fn random<R: RngCore + ?std::marker::Sized>(rng: &mut R) -> Self {
Fq12 {
c0: Fq6::random(rng),
c1: Fq6::random(rng),

View File

@ -57,7 +57,7 @@ impl Fq2 {
}
impl Field for Fq2 {
fn random<R: RngCore>(rng: &mut R) -> Self {
fn random<R: RngCore + ?std::marker::Sized>(rng: &mut R) -> Self {
Fq2 {
c0: Fq::random(rng),
c1: Fq::random(rng),

View File

@ -100,7 +100,7 @@ impl Fq6 {
}
impl Field for Fq6 {
fn random<R: RngCore>(rng: &mut R) -> Self {
fn random<R: RngCore + ?std::marker::Sized>(rng: &mut R) -> Self {
Fq6 {
c0: Fq2::random(rng),
c1: Fq2::random(rng),

4
zcash_history/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
/target
**/*.rs.bk
Cargo.lock
.idea

14
zcash_history/COPYRIGHT Normal file
View File

@ -0,0 +1,14 @@
Copyrights in the "zcash_history" library are retained by their contributors. No
copyright assignment is required to contribute to the "zcash_history" library.
The "zcash_history" library is licensed under either of
* Apache License, Version 2.0, (see ./LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
* MIT license (see ./LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
Unless you explicitly state otherwise, any contribution intentionally
submitted for inclusion in the work by you, as defined in the Apache-2.0
license, shall be dual licensed as above, without any additional terms or
conditions.

14
zcash_history/Cargo.toml Normal file
View File

@ -0,0 +1,14 @@
[package]
name = "zcash_history"
version = "0.0.1"
authors = ["NikVolf <nikvolf@gmail.com>"]
edition = "2018"
[dev-dependencies]
assert_matches = "1.3.0"
quickcheck = "0.8"
[dependencies]
bigint = "4"
byteorder = "1"
blake2 = { package = "blake2b_simd", version = "0.5" }

View File

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

25
zcash_history/LICENSE-MIT Normal file
View File

@ -0,0 +1,25 @@
Copyright (c) 2019 Nikolay Volf
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

26
zcash_history/README.md Normal file
View File

@ -0,0 +1,26 @@
# zcash_history
Special implementation of Merkle mountain ranges (MMR) for Zcash!
[![Build Status](https://travis-ci.org/NikVolf/zcash-mmr.svg?branch=master)](https://travis-ci.org/NikVolf/zcash-mmr)
The main design goals of this MMR implementation are
- Allow zero-cache and avoid db callbacks. As it is implemented, calling side must just smartly pre-load MMR nodes from the database (about log2(tree length) for append, twice as much for deletion).
- Reuse as much logic between rust and c++ clients and place it here and librustzcash.
- Close to zero memory consumption.
# License
`zcash_history` is distributed under the terms of both the MIT
license and the Apache License (Version 2.0), at your choice.
See LICENSE-APACHE, and LICENSE-MIT for details.
### Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in `zcash_history` by you, as defined in the Apache-2.0 license, shall be
dual licensed as above, without any additional terms or conditions.

View File

@ -0,0 +1,2 @@
// dummy example
pub fn main() {}

View File

@ -0,0 +1,86 @@
use zcash_history::{Entry, EntryLink, NodeData, Tree};
pub struct NodeDataIterator {
return_stack: Vec<NodeData>,
tree: Tree,
cursor: usize,
leaf_cursor: usize,
}
impl Iterator for NodeDataIterator {
type Item = NodeData;
fn next(&mut self) -> Option<NodeData> {
let result = if self.cursor == 1 {
self.leaf_cursor = 2;
Some(leaf(1))
} else if self.cursor == 2 {
self.leaf_cursor = 3;
Some(leaf(2))
} else if self.cursor == 3 {
Some(self.tree.root_node().expect("always exists").data().clone())
} else if self.return_stack.len() > 0 {
self.return_stack.pop()
} else {
for n_append in self
.tree
.append_leaf(leaf(self.leaf_cursor as u32))
.expect("full tree cannot fail")
.into_iter()
.rev()
{
self.return_stack.push(
self.tree
.resolve_link(n_append)
.expect("just pushed")
.data()
.clone(),
)
}
self.leaf_cursor += 1;
self.return_stack.pop()
};
self.cursor += 1;
result
}
}
impl NodeDataIterator {
pub fn new() -> Self {
let root = Entry::new(
NodeData::combine(&leaf(1), &leaf(2)),
EntryLink::Stored(0),
EntryLink::Stored(1),
);
let tree = Tree::new(
3,
vec![(2, root)],
vec![(0, leaf(1).into()), (1, leaf(2).into())],
);
NodeDataIterator {
return_stack: Vec::new(),
tree,
cursor: 1,
leaf_cursor: 1,
}
}
}
fn leaf(height: u32) -> NodeData {
NodeData {
consensus_branch_id: 0,
subtree_commitment: [0u8; 32],
start_time: height * 10 + 1,
end_time: (height + 1) * 10,
start_target: 100 + height * 10,
end_target: 100 + (height + 1) * 10,
start_sapling_root: [0u8; 32],
end_sapling_root: [0u8; 32],
subtree_total_work: 0.into(),
start_height: height as u64,
end_height: height as u64,
shielded_tx: 5 + height as u64,
}
}

View File

@ -0,0 +1,113 @@
use zcash_history::{Entry, EntryLink, NodeData, Tree};
#[path = "lib/shared.rs"]
mod share;
fn draft(into: &mut Vec<(u32, Entry)>, vec: &Vec<NodeData>, peak_pos: usize, h: u32) {
let node_data = vec[peak_pos - 1].clone();
let peak: Entry = match h {
0 => node_data.into(),
_ => Entry::new(
node_data,
EntryLink::Stored((peak_pos - (1 << h) - 1) as u32),
EntryLink::Stored((peak_pos - 2) as u32),
),
};
println!("Entry #{}: {}", into.len(), peak);
into.push(((peak_pos - 1) as u32, peak));
}
fn prepare_tree(vec: &Vec<NodeData>) -> Tree {
assert!(vec.len() > 0);
// integer log2 of (vec.len()+1), -1
let mut h = (32 - ((vec.len() + 1) as u32).leading_zeros() - 1) - 1;
let mut peak_pos = (1 << (h + 1)) - 1;
let mut nodes = Vec::new();
// used later
let mut last_peak_pos = 0;
let mut last_peak_h = 0;
loop {
if peak_pos > vec.len() {
// left child, -2^h
peak_pos = peak_pos - (1 << h);
h = h - 1;
}
if peak_pos <= vec.len() {
draft(&mut nodes, vec, peak_pos, h);
// save to be used in next loop
last_peak_pos = peak_pos;
last_peak_h = h;
// right sibling
peak_pos = peak_pos + (1 << (h + 1)) - 1;
}
if h == 0 {
break;
}
}
// for deletion, everything on the right slope of the last peak should be pre-loaded
let mut extra = Vec::new();
let mut h = last_peak_h;
let mut peak_pos = last_peak_pos;
while h > 0 {
let left_pos = peak_pos - (1 << h);
let right_pos = peak_pos - 1;
h = h - 1;
// drafting left child
draft(&mut extra, vec, left_pos, h);
// drafting right child
draft(&mut extra, vec, right_pos, h);
// continuing on right slope
peak_pos = right_pos;
}
println!("Total extra of {} required for deletion!", extra.len());
Tree::new(vec.len() as u32, nodes, extra)
}
fn main() {
let number = match std::env::args().skip(1).next() {
None => {
eprintln!("writer <number of nodes> [<out_file>]");
std::process::exit(1);
}
Some(number) => number.parse::<usize>().expect("invalid number"),
};
let long_vec = share::NodeDataIterator::new()
.take(number)
.collect::<Vec<NodeData>>();
let now = std::time::Instant::now();
let tree = prepare_tree(&long_vec);
let elapsed = now.elapsed();
println!(
"Tree final root: {}-{}",
tree.root_node().expect("root").data().start_height,
tree.root_node().expect("root").data().end_height,
);
println!(
"Prepare tree of {} length: {} ns / {} mcs / {} ms",
number,
elapsed.as_nanos(),
elapsed.as_micros(),
elapsed.as_millis()
);
}

View File

@ -0,0 +1,44 @@
#[path = "lib/shared.rs"]
mod share;
// Test data generator
// $ cargo run --example writer -- 16 nodes.dat
// or
// $ cargo run --example writer -- 16
// to preview
fn main() {
let mut args = std::env::args().skip(1);
let (number, out_file) = match args.next() {
None => {
eprintln!("writer <number of nodes> [<out_file>]");
std::process::exit(1);
}
Some(number) => (
number.parse::<usize>().expect("invalid number"),
args.next(),
),
};
let iterator = share::NodeDataIterator::new().take(number);
if let Some(out_file_path) = out_file {
use std::io::Write;
let mut buf = Vec::new();
for node in iterator {
node.write(&mut buf).expect("Failed to write data");
}
let mut file = std::fs::File::create(&out_file_path).expect("Failed to create output file");
file.write_all(&buf[..])
.expect("Failed to write data to file");
} else {
for n in iterator {
println!("{:?}", n);
}
}
}

123
zcash_history/src/entry.rs Normal file
View File

@ -0,0 +1,123 @@
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use crate::{EntryKind, EntryLink, Error, NodeData, MAX_NODE_DATA_SIZE};
/// Max serialized length of entry data.
pub const MAX_ENTRY_SIZE: usize = MAX_NODE_DATA_SIZE + 9;
/// MMR Entry.
#[derive(Debug)]
pub struct Entry {
pub(crate) kind: EntryKind,
pub(crate) data: NodeData,
}
impl Entry {
/// New entry of type node.
pub fn new(data: NodeData, left: EntryLink, right: EntryLink) -> Self {
Entry {
kind: EntryKind::Node(left, right),
data,
}
}
/// Returns if is this node complete (has total of 2^N leaves)
pub fn complete(&self) -> bool {
let leaves = self.leaf_count();
leaves & (leaves - 1) == 0
}
/// Number of leaves under this node.
pub fn leaf_count(&self) -> u64 {
self.data.end_height - (self.data.start_height - 1)
}
/// Is this node a leaf.
pub fn leaf(&self) -> bool {
if let EntryKind::Leaf = self.kind {
true
} else {
false
}
}
/// Left child
pub fn left(&self) -> Result<EntryLink, Error> {
match self.kind {
EntryKind::Leaf => Err(Error::node_expected()),
EntryKind::Node(left, _) => Ok(left),
}
}
/// Right child.
pub fn right(&self) -> Result<EntryLink, Error> {
match self.kind {
EntryKind::Leaf => Err(Error::node_expected()),
EntryKind::Node(_, right) => Ok(right),
}
}
/// Read from byte representation.
pub fn read<R: std::io::Read>(consensus_branch_id: u32, r: &mut R) -> std::io::Result<Self> {
let kind = {
match r.read_u8()? {
0 => {
let left = r.read_u32::<LittleEndian>()?;
let right = r.read_u32::<LittleEndian>()?;
EntryKind::Node(EntryLink::Stored(left), EntryLink::Stored(right))
}
1 => EntryKind::Leaf,
_ => return Err(std::io::Error::from(std::io::ErrorKind::InvalidData)),
}
};
let data = NodeData::read(consensus_branch_id, r)?;
Ok(Entry { kind, data })
}
/// Write to byte representation.
pub fn write<W: std::io::Write>(&self, w: &mut W) -> std::io::Result<()> {
match self.kind {
EntryKind::Node(EntryLink::Stored(left), EntryLink::Stored(right)) => {
w.write_u8(0)?;
w.write_u32::<LittleEndian>(left)?;
w.write_u32::<LittleEndian>(right)?;
}
EntryKind::Leaf => {
w.write_u8(1)?;
}
_ => {
return Err(std::io::Error::from(std::io::ErrorKind::InvalidData));
}
}
self.data.write(w)?;
Ok(())
}
/// Convert from byte representation.
pub fn from_bytes<T: AsRef<[u8]>>(consensus_branch_id: u32, buf: T) -> std::io::Result<Self> {
let mut cursor = std::io::Cursor::new(buf);
Self::read(consensus_branch_id, &mut cursor)
}
}
impl From<NodeData> for Entry {
fn from(s: NodeData) -> Self {
Entry {
kind: EntryKind::Leaf,
data: s,
}
}
}
impl std::fmt::Display for Entry {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self.kind {
EntryKind::Node(l, r) => write!(f, "node({}, {}, ..)", l, r),
EntryKind::Leaf => write!(f, "leaf(..)"),
}
}
}

79
zcash_history/src/lib.rs Normal file
View File

@ -0,0 +1,79 @@
//! Chain history library for Zcash
//!
//! To be used in zebra and via FFI bindings in zcashd
#![warn(missing_docs)]
mod entry;
mod node_data;
mod tree;
pub use entry::{Entry, MAX_ENTRY_SIZE};
pub use node_data::{NodeData, MAX_NODE_DATA_SIZE};
pub use tree::Tree;
/// Crate-level error type
#[derive(Debug)]
pub enum Error {
/// Entry expected to be presented in the tree view while it was not.
ExpectedInMemory(EntryLink),
/// Entry expected to be a node (specifying for which link this is not true).
ExpectedNode(Option<EntryLink>),
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match *self {
Self::ExpectedInMemory(l) => write!(f, "Node/leaf expected to be in memory: {}", l),
Self::ExpectedNode(None) => write!(f, "Node expected"),
Self::ExpectedNode(Some(l)) => write!(f, "Node expected, not leaf: {}", l),
}
}
}
/// Reference to to the tree node.
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub enum EntryLink {
/// Reference to the stored (in the array representation) leaf/node.
Stored(u32),
/// Reference to the generated leaf/node.
Generated(u32),
}
impl std::fmt::Display for EntryLink {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match *self {
Self::Stored(v) => write!(f, "stored({})", v),
Self::Generated(v) => write!(f, "generated({})", v),
}
}
}
/// MMR Node. It is leaf when `left`, `right` are `None` and node when they are not.
#[repr(C)]
#[derive(Debug)]
pub enum EntryKind {
/// Leaf entry.
Leaf,
/// Node entry with children links.
Node(EntryLink, EntryLink),
}
impl Error {
/// Entry expected to be a node (specifying for which link this is not true).
pub fn link_node_expected(link: EntryLink) -> Self {
Self::ExpectedNode(Some(link))
}
/// Some entry is expected to be node
pub fn node_expected() -> Self {
Self::ExpectedNode(None)
}
pub(crate) fn augment(self, link: EntryLink) -> Self {
match self {
Error::ExpectedNode(_) => Error::ExpectedNode(Some(link)),
val => val,
}
}
}

View File

@ -0,0 +1,238 @@
use bigint::U256;
use blake2::Params as Blake2Params;
use byteorder::{ByteOrder, LittleEndian, ReadBytesExt, WriteBytesExt};
/// Maximum serialized size of the node metadata.
pub const MAX_NODE_DATA_SIZE: usize = 32 + // subtree commitment
4 + // start time
4 + // end time
4 + // start target
4 + // end target
32 + // start sapling tree root
32 + // end sapling tree root
32 + // subtree total work
9 + // start height (compact uint)
9 + // end height (compact uint)
9; // shielded tx count (compact uint)
// = total of 171
/// Node metadata.
#[repr(C)]
#[derive(Debug, Clone, Default)]
#[cfg_attr(test, derive(PartialEq))]
pub struct NodeData {
/// Consensus branch id, should be provided by deserializing node.
pub consensus_branch_id: u32,
/// Subtree commitment - either block hash for leaves or hashsum of children for nodes.
pub subtree_commitment: [u8; 32],
/// Start time.
pub start_time: u32,
/// End time.
pub end_time: u32,
/// Start target.
pub start_target: u32,
/// End target.
pub end_target: u32,
/// Start sapling tree root.
pub start_sapling_root: [u8; 32],
/// End sapling tree root.
pub end_sapling_root: [u8; 32],
/// Part of tree total work.
pub subtree_total_work: U256,
/// Start height.
pub start_height: u64,
/// End height
pub end_height: u64,
/// Number of shielded transactions.
pub shielded_tx: u64,
}
fn blake2b_personal(personalization: &[u8], input: &[u8]) -> [u8; 32] {
let hash_result = Blake2Params::new()
.hash_length(32)
.personal(personalization)
.to_state()
.update(input)
.finalize();
let mut result = [0u8; 32];
result.copy_from_slice(hash_result.as_bytes());
result
}
fn personalization(branch_id: u32) -> [u8; 16] {
let mut result = [0u8; 16];
result[..12].copy_from_slice(b"ZcashHistory");
LittleEndian::write_u32(&mut result[12..], branch_id);
result
}
impl NodeData {
/// Combine two nodes metadata.
pub fn combine(left: &NodeData, right: &NodeData) -> NodeData {
assert_eq!(left.consensus_branch_id, right.consensus_branch_id);
let mut hash_buf = [0u8; MAX_NODE_DATA_SIZE * 2];
let size = {
let mut cursor = ::std::io::Cursor::new(&mut hash_buf[..]);
left.write(&mut cursor)
.expect("Writing to memory buf with enough length cannot fail; qed");
right
.write(&mut cursor)
.expect("Writing to memory buf with enough length cannot fail; qed");
cursor.position() as usize
};
let hash = blake2b_personal(
&personalization(left.consensus_branch_id),
&hash_buf[..size],
);
NodeData {
consensus_branch_id: left.consensus_branch_id,
subtree_commitment: hash,
start_time: left.start_time,
end_time: right.end_time,
start_target: left.start_target,
end_target: right.end_target,
start_sapling_root: left.start_sapling_root,
end_sapling_root: right.end_sapling_root,
subtree_total_work: left.subtree_total_work + right.subtree_total_work,
start_height: left.start_height,
end_height: right.end_height,
shielded_tx: left.shielded_tx + right.shielded_tx,
}
}
fn write_compact<W: std::io::Write>(w: &mut W, compact: u64) -> std::io::Result<()> {
match compact {
0..=0xfc => w.write_all(&[compact as u8])?,
0xfd..=0xffff => {
w.write_all(&[0xfd])?;
w.write_u16::<LittleEndian>(compact as u16)?;
}
0x10000..=0xffff_ffff => {
w.write_all(&[0xfe])?;
w.write_u32::<LittleEndian>(compact as u32)?;
}
_ => {
w.write_all(&[0xff])?;
w.write_u64::<LittleEndian>(compact)?;
}
}
Ok(())
}
fn read_compact<R: std::io::Read>(reader: &mut R) -> std::io::Result<u64> {
let result = match reader.read_u8()? {
i @ 0..=0xfc => i.into(),
0xfd => reader.read_u16::<LittleEndian>()?.into(),
0xfe => reader.read_u32::<LittleEndian>()?.into(),
_ => reader.read_u64::<LittleEndian>()?,
};
Ok(result)
}
/// Write to the byte representation.
pub fn write<W: std::io::Write>(&self, w: &mut W) -> std::io::Result<()> {
w.write_all(&self.subtree_commitment)?;
w.write_u32::<LittleEndian>(self.start_time)?;
w.write_u32::<LittleEndian>(self.end_time)?;
w.write_u32::<LittleEndian>(self.start_target)?;
w.write_u32::<LittleEndian>(self.end_target)?;
w.write_all(&self.start_sapling_root)?;
w.write_all(&self.end_sapling_root)?;
let mut work_buf = [0u8; 32];
self.subtree_total_work.to_little_endian(&mut work_buf[..]);
w.write_all(&work_buf)?;
Self::write_compact(w, self.start_height)?;
Self::write_compact(w, self.end_height)?;
Self::write_compact(w, self.shielded_tx)?;
Ok(())
}
/// Read from the byte representation.
pub fn read<R: std::io::Read>(consensus_branch_id: u32, r: &mut R) -> std::io::Result<Self> {
let mut data = Self::default();
data.consensus_branch_id = consensus_branch_id;
r.read_exact(&mut data.subtree_commitment)?;
data.start_time = r.read_u32::<LittleEndian>()?;
data.end_time = r.read_u32::<LittleEndian>()?;
data.start_target = r.read_u32::<LittleEndian>()?;
data.end_target = r.read_u32::<LittleEndian>()?;
r.read_exact(&mut data.start_sapling_root)?;
r.read_exact(&mut data.end_sapling_root)?;
let mut work_buf = [0u8; 32];
r.read_exact(&mut work_buf)?;
data.subtree_total_work = U256::from_little_endian(&work_buf);
data.start_height = Self::read_compact(r)?;
data.end_height = Self::read_compact(r)?;
data.shielded_tx = Self::read_compact(r)?;
Ok(data)
}
/// Convert to byte representation.
pub fn to_bytes(&self) -> Vec<u8> {
let mut buf = [0u8; MAX_NODE_DATA_SIZE];
let pos = {
let mut cursor = std::io::Cursor::new(&mut buf[..]);
self.write(&mut cursor).expect("Cursor cannot fail");
cursor.position() as usize
};
buf[0..pos].to_vec()
}
/// Convert from byte representation.
pub fn from_bytes<T: AsRef<[u8]>>(consensus_branch_id: u32, buf: T) -> std::io::Result<Self> {
let mut cursor = std::io::Cursor::new(buf);
Self::read(consensus_branch_id, &mut cursor)
}
/// Hash node metadata
pub fn hash(&self) -> [u8; 32] {
let bytes = self.to_bytes();
blake2b_personal(&personalization(self.consensus_branch_id), &bytes)
}
}
#[cfg(test)]
impl quickcheck::Arbitrary for NodeData {
fn arbitrary<G: quickcheck::Gen>(gen: &mut G) -> Self {
let mut node_data = NodeData::default();
node_data.consensus_branch_id = 0;
gen.fill_bytes(&mut node_data.subtree_commitment[..]);
node_data.start_time = gen.next_u32();
node_data.end_time = gen.next_u32();
node_data.start_target = gen.next_u32();
node_data.end_target = gen.next_u32();
gen.fill_bytes(&mut node_data.start_sapling_root[..]);
gen.fill_bytes(&mut node_data.end_sapling_root[..]);
let mut number = [0u8; 32];
gen.fill_bytes(&mut number[..]);
node_data.subtree_total_work = U256::from_little_endian(&number[..]);
node_data.start_height = gen.next_u64();
node_data.end_height = gen.next_u64();
node_data.shielded_tx = gen.next_u64();
node_data
}
}
#[cfg(test)]
mod tests {
use super::NodeData;
use quickcheck::{quickcheck, TestResult};
quickcheck! {
fn serialization_round_trip(node_data: NodeData) -> TestResult {
TestResult::from_bool(NodeData::from_bytes(0, &node_data.to_bytes()).unwrap() == node_data)
}
}
}

741
zcash_history/src/tree.rs Normal file
View File

@ -0,0 +1,741 @@
use std::collections::HashMap;
use crate::{Entry, EntryKind, EntryLink, Error, NodeData};
/// Represents partially loaded tree.
///
/// Some kind of "view" into the array representation of the MMR tree.
/// With only some of the leaves/nodes pre-loaded / pre-generated.
/// Exact amount of the loaded data can be calculated by the constructing party,
/// depending on the length of the tree and maximum amount of operations that are going
/// to happen after construction. `Tree` should not be used as self-contained data structure,
/// since it's internal state can grow indefinitely after serial operations.
/// Intended use of this `Tree` is to instantiate it based on partially loaded data (see example
/// how to pick right nodes from the array representation of MMR Tree), perform several operations
/// (append-s/delete-s) and then drop it.
pub struct Tree {
stored: HashMap<u32, Entry>,
// This can grow indefinitely if `Tree` is misused as a self-contained data structure
generated: Vec<Entry>,
// number of persistent(!) tree entries
stored_count: u32,
root: EntryLink,
}
impl Tree {
/// Resolve link originated from this tree
pub fn resolve_link(&self, link: EntryLink) -> Result<IndexedNode, Error> {
match link {
EntryLink::Generated(index) => self.generated.get(index as usize),
EntryLink::Stored(index) => self.stored.get(&index),
}
.map(|node| IndexedNode { node, link })
.ok_or(Error::ExpectedInMemory(link))
}
fn push(&mut self, data: Entry) -> EntryLink {
let idx = self.stored_count;
self.stored_count += 1;
self.stored.insert(idx, data);
EntryLink::Stored(idx)
}
fn push_generated(&mut self, data: Entry) -> EntryLink {
self.generated.push(data);
EntryLink::Generated(self.generated.len() as u32 - 1)
}
/// Populate tree with plain list of the leaves/nodes. For now, only for tests,
/// since this `Tree` structure is for partially loaded tree (but it might change)
#[cfg(test)]
pub fn populate(loaded: Vec<Entry>, root: EntryLink) -> Self {
let mut result = Tree::invalid();
result.stored_count = loaded.len() as u32;
for (idx, item) in loaded.into_iter().enumerate() {
result.stored.insert(idx as u32, item);
}
result.root = root;
result
}
// Empty tree with invalid root
fn invalid() -> Self {
Tree {
root: EntryLink::Generated(0),
generated: Default::default(),
stored: Default::default(),
stored_count: 0,
}
}
/// New view into the the tree array representation
///
/// `length` is total length of the array representation (is generally not a sum of
/// peaks.len + extra.len)
/// `peaks` is peaks of the mmr tree
/// `extra` is some extra nodes that calculated to be required during next one or more
/// operations on the tree.
///
/// # Panics
///
/// Will panic if `peaks` is empty.
pub fn new(length: u32, peaks: Vec<(u32, Entry)>, extra: Vec<(u32, Entry)>) -> Self {
assert!(peaks.len() > 0);
let mut result = Tree::invalid();
result.stored_count = length;
let mut gen = 0;
let mut root = EntryLink::Stored(peaks[0].0);
for (idx, node) in peaks.into_iter() {
result.stored.insert(idx, node);
if gen != 0 {
let next_generated = combine_nodes(
result
.resolve_link(root)
.expect("Inserted before, cannot fail; qed"),
result
.resolve_link(EntryLink::Stored(idx))
.expect("Inserted before, cannot fail; qed"),
);
root = result.push_generated(next_generated);
}
gen += 1;
}
for (idx, node) in extra {
result.stored.insert(idx, node);
}
result.root = root;
result
}
fn get_peaks(&self, root: EntryLink, target: &mut Vec<EntryLink>) -> Result<(), Error> {
let (left_child_link, right_child_link) = {
let root = self.resolve_link(root)?;
if root.node.complete() {
target.push(root.link);
return Ok(());
}
(root.left()?, root.right()?)
};
self.get_peaks(left_child_link, target)?;
self.get_peaks(right_child_link, target)?;
Ok(())
}
/// Append one leaf to the tree.
///
/// Returns links to actual nodes that has to be persisted as the result of the append.
/// If completed without error, at least one link to the appended
/// node (with metadata provided in `new_leaf`) will be returned.
pub fn append_leaf(&mut self, new_leaf: NodeData) -> Result<Vec<EntryLink>, Error> {
let root = self.root;
let new_leaf_link = self.push(new_leaf.into());
let mut appended = Vec::new();
appended.push(new_leaf_link);
let mut peaks = Vec::new();
self.get_peaks(root, &mut peaks)?;
let mut merge_stack = Vec::new();
merge_stack.push(new_leaf_link);
// Scan the peaks right-to-left, merging together equal-sized adjacent
// complete subtrees. After this, merge_stack only contains peaks of
// unequal-sized subtrees.
while let Some(next_peak) = peaks.pop() {
let next_merge = merge_stack
.pop()
.expect("there should be at least one, initial or re-pushed");
if let Some(stored) = {
let peak = self.resolve_link(next_peak)?;
let m = self.resolve_link(next_merge)?;
if peak.node.leaf_count() == m.node.leaf_count() {
Some(combine_nodes(peak, m))
} else {
None
}
} {
let link = self.push(stored);
merge_stack.push(link);
appended.push(link);
continue;
} else {
merge_stack.push(next_merge);
merge_stack.push(next_peak);
}
}
let mut new_root = merge_stack
.pop()
.expect("Loop above cannot reduce the merge_stack");
// Scan the peaks left-to-right, producing new generated nodes that
// connect the subtrees
while let Some(next_child) = merge_stack.pop() {
new_root = self.push_generated(combine_nodes(
self.resolve_link(new_root)?,
self.resolve_link(next_child)?,
))
}
self.root = new_root;
Ok(appended)
}
#[cfg(test)]
fn for_children<F: Fn(EntryLink, EntryLink)>(&self, node: EntryLink, f: F) {
let (left, right) = {
let link = self
.resolve_link(node)
.expect("Failed to resolve link in test");
(
link.left().expect("Failed to find node in test"),
link.right().expect("Failed to find node in test"),
)
};
f(left, right);
}
fn pop(&mut self) {
self.stored.remove(&(self.stored_count - 1));
self.stored_count = self.stored_count - 1;
}
/// Truncate one leaf from the end of the tree.
///
/// Returns actual number of nodes that should be removed by the caller
/// from the end of the array representation.
pub fn truncate_leaf(&mut self) -> Result<u32, Error> {
let root = {
let (leaves, root_left_child) = {
let n = self.resolve_link(self.root)?;
(n.node.leaf_count(), n.node.left()?)
};
if leaves & 1 != 0 {
self.pop();
self.root = root_left_child;
return Ok(1);
} else {
self.resolve_link(self.root)?
}
};
let mut peaks = vec![root.left()?];
let mut subtree_root_link = root.right()?;
let mut truncated = 1;
loop {
let left_link = self.resolve_link(subtree_root_link)?.node;
if let EntryKind::Node(left, right) = left_link.kind {
peaks.push(left);
subtree_root_link = right;
truncated += 1;
} else {
if root.node.complete() {
truncated += 1;
}
break;
}
}
let mut new_root = *peaks.get(0).expect("At lest 1 elements in peaks");
for next_peak in peaks.into_iter().skip(1) {
new_root = self.push_generated(combine_nodes(
self.resolve_link(new_root)?,
self.resolve_link(next_peak)?,
));
}
for _ in 0..truncated {
self.pop();
}
self.root = new_root;
Ok(truncated)
}
/// Length of array representation of the tree.
pub fn len(&self) -> u32 {
self.stored_count
}
/// Link to the root node
pub fn root(&self) -> EntryLink {
self.root
}
/// Reference to the root node.
pub fn root_node(&self) -> Result<IndexedNode, Error> {
self.resolve_link(self.root)
}
/// If this tree is empty.
pub fn is_empty(&self) -> bool {
self.stored_count == 0
}
}
/// Reference to the node with link attached.
#[derive(Debug)]
pub struct IndexedNode<'a> {
node: &'a Entry,
link: EntryLink,
}
impl<'a> IndexedNode<'a> {
fn left(&self) -> Result<EntryLink, Error> {
self.node.left().map_err(|e| e.augment(self.link))
}
fn right(&self) -> Result<EntryLink, Error> {
self.node.right().map_err(|e| e.augment(self.link))
}
/// Reference to the entry struct.
pub fn node(&self) -> &Entry {
self.node
}
/// Reference to the entry metadata.
pub fn data(&self) -> &NodeData {
&self.node.data
}
/// Actual link by what this node was resolved.
pub fn link(&self) -> EntryLink {
self.link
}
}
fn combine_nodes<'a>(left: IndexedNode<'a>, right: IndexedNode<'a>) -> Entry {
Entry {
kind: EntryKind::Node(left.link, right.link),
data: NodeData::combine(&left.node.data, &right.node.data),
}
}
#[cfg(test)]
mod tests {
use super::{Entry, EntryKind, EntryLink, NodeData, Tree};
use assert_matches::assert_matches;
use quickcheck::{quickcheck, TestResult};
fn leaf(height: u32) -> NodeData {
NodeData {
consensus_branch_id: 1,
subtree_commitment: [0u8; 32],
start_time: 0,
end_time: 0,
start_target: 0,
end_target: 0,
start_sapling_root: [0u8; 32],
end_sapling_root: [0u8; 32],
subtree_total_work: 0.into(),
start_height: height as u64,
end_height: height as u64,
shielded_tx: 7,
}
}
fn initial() -> Tree {
let node1: Entry = leaf(1).into();
let node2: Entry = leaf(2).into();
let node3 = Entry {
data: NodeData::combine(&node1.data, &node2.data),
kind: EntryKind::Leaf,
};
Tree::populate(vec![node1, node2, node3], EntryLink::Stored(2))
}
// returns tree with specified number of leafs and it's root
fn generated(length: u32) -> Tree {
assert!(length >= 3);
let mut tree = initial();
for i in 2..length {
tree.append_leaf(leaf(i + 1).into())
.expect("Failed to append");
}
tree
}
#[test]
fn discrete_append() {
let mut tree = initial();
// ** APPEND 3 **
let appended = tree.append_leaf(leaf(3)).expect("Failed to append");
let new_root = tree.root_node().expect("Failed to resolve root").node;
// initial tree: (2)
// / \
// (0) (1)
//
// new tree:
// (4g)
// / \
// (2) \
// / \ \
// (0) (1) (3)
//
// so only (3) is added as real leaf
// while new root, (4g) is generated one
assert_eq!(new_root.data.end_height, 3);
assert_eq!(appended.len(), 1);
// ** APPEND 4 **
let appended = tree.append_leaf(leaf(4)).expect("Failed to append");
let new_root = tree.root_node().expect("Failed to resolve root").node;
// intermediate tree:
// (4g)
// / \
// (2) \
// / \ \
// (0) (1) (3)
//
// new tree:
// ( 6 )
// / \
// (2) (5)
// / \ / \
// (0) (1) (3) (4)
//
// so (4), (5), (6) are added as real leaves
// and new root, (6) is stored one
assert_eq!(new_root.data.end_height, 4);
assert_eq!(appended.len(), 3);
assert_matches!(tree.root(), EntryLink::Stored(6));
// ** APPEND 5 **
let appended = tree.append_leaf(leaf(5)).expect("Failed to append");
let new_root = tree.root_node().expect("Failed to resolve root").node;
// intermediate tree:
// ( 6 )
// / \
// (2) (5)
// / \ / \
// (0) (1) (3) (4)
//
// new tree:
// ( 8g )
// / \
// ( 6 ) \
// / \ \
// (2) (5) \
// / \ / \ \
// (0) (1) (3) (4) (7)
//
// so (7) is added as real leaf
// and new root, (8g) is generated one
assert_eq!(new_root.data.end_height, 5);
assert_eq!(appended.len(), 1);
assert_matches!(tree.root(), EntryLink::Generated(_));
tree.for_children(tree.root(), |l, r| {
assert_matches!(l, EntryLink::Stored(6));
assert_matches!(r, EntryLink::Stored(7));
});
// *** APPEND #6 ***
let appended = tree.append_leaf(leaf(6)).expect("Failed to append");
let new_root = tree.root_node().expect("Failed to resolve root").node;
// intermediate tree:
// ( 8g )
// / \
// ( 6 ) \
// / \ \
// (2) (5) \
// / \ / \ \
// (0) (1) (3) (4) (7)
//
// new tree:
// (---10g--)
// / \
// ( 6 ) \
// / \ \
// (2) (5) (9)
// / \ / \ / \
// (0) (1) (3) (4) (7) (8)
//
// so (7) is added as real leaf
// and new root, (10g) is generated one
assert_eq!(new_root.data.end_height, 6);
assert_eq!(appended.len(), 2);
assert_matches!(tree.root(), EntryLink::Generated(_));
tree.for_children(tree.root(), |l, r| {
assert_matches!(l, EntryLink::Stored(6));
assert_matches!(r, EntryLink::Stored(9));
});
// *** APPEND #7 ***
let appended = tree.append_leaf(leaf(7)).expect("Failed to append");
let new_root = tree.root_node().expect("Failed to resolve root").node;
// intermediate tree:
// (---8g---)
// / \
// ( 6 ) \
// / \ \
// (2) (5) (9)
// / \ / \ / \
// (0) (1) (3) (4) (7) (8)
//
// new tree:
// (---12g--)
// / \
// (---11g---) \
// / \ \
// ( 6 ) \ \
// / \ \ \
// (2) (5) (9) \
// / \ / \ / \ \
// (0) (1) (3) (4) (7) (8) (10)
//
// so (10) is added as real leaf
// and new root, (12g) is generated one
assert_eq!(new_root.data.end_height, 7);
assert_eq!(appended.len(), 1);
assert_matches!(tree.root(), EntryLink::Generated(_));
tree.for_children(tree.root(), |l, r| {
assert_matches!(l, EntryLink::Generated(_));
tree.for_children(l, |l, r| {
assert_matches!((l, r), (EntryLink::Stored(6), EntryLink::Stored(9)))
});
assert_matches!(r, EntryLink::Stored(10));
});
}
#[test]
fn truncate_simple() {
let mut tree = generated(9);
let total_truncated = tree.truncate_leaf().expect("Failed to truncate");
// initial tree:
//
// (-------16g------)
// / \
// (--------14-------) \
// / \ \
// ( 6 ) ( 13 ) \
// / \ / \ \
// (2) (5) (9) (12) \
// / \ / \ / \ / \ \
// (0) (1) (3) (4) (7) (8) (10) (11) (15)
//
// new tree:
// (--------14-------)
// / \
// ( 6 ) ( 13 )
// / \ / \
// (2) (5) (9) (12)
// / \ / \ / \ / \
// (0) (1) (3) (4) (7) (8) (10) (11)
//
// so (15) is truncated
// and new root, (14) is a stored one now
assert_matches!(tree.root(), EntryLink::Stored(14));
assert_eq!(total_truncated, 1);
assert_eq!(tree.len(), 15);
}
#[test]
fn truncate_generated() {
let mut tree = generated(10);
let deleted = tree.truncate_leaf().expect("Failed to truncate");
// initial tree:
//
// (--------18g--------)
// / \
// (--------14-------) \
// / \ \
// ( 6 ) ( 13 ) \
// / \ / \ \
// (2) (5) (9) (12) (17)
// / \ / \ / \ / \ / \
// (0) (1) (3) (4) (7) (8) (10) (11) (15) (16)
//
// new tree:
// (-------16g------)
// / \
// (--------14-------) \
// / \ \
// ( 6 ) ( 13 ) \
// / \ / \ \
// (2) (5) (9) (12) \
// / \ / \ / \ / \ \
// (0) (1) (3) (4) (7) (8) (10) (11) (15)
// new root is generated
assert_matches!(tree.root(), EntryLink::Generated(_));
tree.for_children(tree.root(), |left, right| {
assert_matches!(
(left, right),
(EntryLink::Stored(14), EntryLink::Stored(15))
)
});
// two stored nodes should leave us (leaf 16 and no longer needed node 17)
assert_eq!(deleted, 2);
assert_eq!(tree.len(), 16);
}
#[test]
fn tree_len() {
let mut tree = initial();
assert_eq!(tree.len(), 3);
for i in 0..2 {
tree.append_leaf(leaf(i + 3)).expect("Failed to append");
}
assert_eq!(tree.len(), 7);
tree.truncate_leaf().expect("Failed to truncate");
assert_eq!(tree.len(), 4);
}
#[test]
fn tree_len_long() {
let mut tree = initial();
assert_eq!(tree.len(), 3);
for i in 0..4094 {
tree.append_leaf(leaf(i + 3)).expect("Failed to append");
}
assert_eq!(tree.len(), 8191); // 4096*2-1 (full tree)
for _ in 0..2049 {
tree.truncate_leaf().expect("Failed to truncate");
}
assert_eq!(tree.len(), 4083); // 4095 - log2(4096)
}
quickcheck! {
fn there_and_back(number: u32) -> TestResult {
if number > 1024*1024 {
TestResult::discard()
} else {
let mut tree = initial();
for i in 0..number {
tree.append_leaf(leaf(i+3)).expect("Failed to append");
}
for _ in 0..number {
tree.truncate_leaf().expect("Failed to truncate");
}
TestResult::from_bool(if let EntryLink::Stored(2) = tree.root() { true } else { false })
}
}
fn leaf_count(number: u32) -> TestResult {
if number > 1024 * 1024 || number < 3 {
TestResult::discard()
} else {
let mut tree = initial();
for i in 1..(number-1) {
tree.append_leaf(leaf(i+2)).expect("Failed to append");
}
TestResult::from_bool(
tree.root_node().expect("no root").node.leaf_count() == number as u64
)
}
}
fn parity(number: u32) -> TestResult {
if number > 2048 * 2048 || number < 3 {
TestResult::discard()
} else {
let mut tree = initial();
for i in 1..(number-1) {
tree.append_leaf(leaf(i+2)).expect("Failed to append");
}
TestResult::from_bool(
if number & (number - 1) == 0 {
if let EntryLink::Stored(_) = tree.root() { true }
else { false }
} else {
if let EntryLink::Generated(_) = tree.root() { true }
else { false }
}
)
}
}
fn parity_with_truncate(add: u32, delete: u32) -> TestResult {
// First we add `add` number of leaves, then delete `delete` number of leaves
// What is left should be consistent with generated-stored structure
if add > 2048 * 2048 || add < delete {
TestResult::discard()
} else {
let mut tree = initial();
for i in 0..add {
tree.append_leaf(leaf(i+3)).expect("Failed to append");
}
for _ in 0..delete {
tree.truncate_leaf().expect("Failed to truncate");
}
let total = add - delete + 2;
TestResult::from_bool(
if total & total - 1 == 0 {
if let EntryLink::Stored(_) = tree.root() { true }
else { false }
} else {
if let EntryLink::Generated(_) = tree.root() { true }
else { false }
}
)
}
}
// Length of tree is always less than number of leaves squared
fn stored_length(add: u32, delete: u32) -> TestResult {
if add > 2048 * 2048 || add < delete {
TestResult::discard()
} else {
let mut tree = initial();
for i in 0..add {
tree.append_leaf(leaf(i+3)).expect("Failed to append");
}
for _ in 0..delete {
tree.truncate_leaf().expect("Failed to truncate");
}
let total = add - delete + 2;
TestResult::from_bool(total * total > tree.len())
}
}
}
}

View File

@ -317,7 +317,7 @@ impl PrimeField for Fs {
}
impl Field for Fs {
fn random<R: RngCore>(rng: &mut R) -> Self {
fn random<R: RngCore + ?std::marker::Sized>(rng: &mut R) -> Self {
loop {
let mut tmp = {
let mut repr = [0u64; 4];