├── .gitignore ├── src ├── sparse_merkle_tree │ ├── hasher.rs │ ├── pedersen_hasher.rs │ └── mod.rs ├── lib.rs ├── circuit │ ├── mod.rs │ └── non_inclusion.rs ├── primitives.rs ├── transaction_tree │ └── mod.rs └── bin │ └── benchmark_proof_gen.rs ├── Cargo.toml ├── README.md └── Cargo.lock /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | .vscode 4 | *.key 5 | vk.sol 6 | VerificationKeys.sol 7 | start_demo.sh -------------------------------------------------------------------------------- /src/sparse_merkle_tree/hasher.rs: -------------------------------------------------------------------------------- 1 | // Hasher trait 2 | 3 | pub trait Hasher { 4 | fn hash_bits>(&self, value: I) -> Hash; 5 | fn compress(&self, lhs: &Hash, rhs: &Hash, i: usize) -> Hash; 6 | } 7 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_imports)] 2 | #![allow(unused_variables)] 3 | #![allow(dead_code)] 4 | #![allow(unused_must_use)] 5 | #![allow(unused_assignments)] 6 | 7 | extern crate bellman; 8 | extern crate rand; 9 | extern crate hex; 10 | extern crate sapling_crypto; 11 | extern crate crypto; 12 | 13 | pub mod sparse_merkle_tree; 14 | pub mod transaction_tree; 15 | pub mod circuit; 16 | pub mod primitives; -------------------------------------------------------------------------------- /src/circuit/mod.rs: -------------------------------------------------------------------------------- 1 | use bellman::pairing::ff::{ 2 | PrimeField, 3 | PrimeFieldRepr, 4 | Field, 5 | }; 6 | 7 | use bellman::{ 8 | SynthesisError, 9 | ConstraintSystem, 10 | Circuit 11 | }; 12 | 13 | use sapling_crypto; 14 | 15 | use sapling_crypto::circuit::{ 16 | Assignment, 17 | boolean, 18 | ecc, 19 | pedersen_hash, 20 | blake2s, 21 | sha256, 22 | num, 23 | multipack, 24 | baby_eddsa, 25 | float_point, 26 | }; 27 | 28 | use crate::transaction_tree; 29 | 30 | pub mod non_inclusion; 31 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Alex Vlasov "] 3 | description = "Use zkSNARK to compact the history in Plasma Cash or Cashflow" 4 | documentation = "https://github.com/matterinc/plasma_cash_history_snark" 5 | homepage = "https://github.com/matterinc/plasma_cash_history_snark" 6 | license = "MIT/Apache-2.0" 7 | name = "plasma_cash_history_snark" 8 | repository = "https://github.com/matterinc/plasma_cash_history_snark" 9 | version = "0.1.0" 10 | edition = "2018" 11 | 12 | [lib] 13 | name = "plasma_cash_history_snark" 14 | path = "src/lib.rs" 15 | 16 | [dependencies] 17 | rand = "0.4" 18 | hex = "0.3.2" 19 | time = "0.1" 20 | num-bigint = "0.2" 21 | rust-crypto = "0.2" 22 | 23 | sapling-crypto = { git = 'https://github.com/matterinc/sapling-crypto', tag = "0.0.4" } 24 | bellman = { git = 'https://github.com/matterinc/bellman', tag = "0.2.0"} 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/primitives.rs: -------------------------------------------------------------------------------- 1 | use bellman::pairing::ff::{Field, PrimeField, PrimeFieldRepr, BitIterator}; 2 | 3 | // TODO: replace Vec with Iterator? 4 | 5 | pub trait GetBits { 6 | fn get_bits_le(&self) -> Vec; 7 | } 8 | 9 | pub trait GetBitsFixed { 10 | 11 | /// Get exactly `n` bits from the value in little endian order 12 | /// If `n` is larger than value bit length, it is padded with `false` 13 | /// for the result to exactly match `n` 14 | fn get_bits_le_fixed(&self, n: usize) -> Vec; 15 | } 16 | 17 | impl GetBitsFixed for Fr { 18 | 19 | fn get_bits_le_fixed(&self, n: usize) -> Vec { 20 | let mut r: Vec = Vec::with_capacity(n); 21 | r.extend(BitIteratorLe::new(self.into_repr()).take(n)); 22 | let len = r.len(); 23 | r.extend((len..n).map(|_| false)); 24 | r 25 | } 26 | } 27 | 28 | // Resulting iterator is little endian: lowest bit first 29 | 30 | #[derive(Debug)] 31 | pub struct BitIteratorLe { 32 | t: E, 33 | n: usize, 34 | len: usize, 35 | } 36 | 37 | impl> BitIteratorLe { 38 | pub fn new(t: E) -> Self { 39 | let len = t.as_ref().len() * 64; 40 | 41 | BitIteratorLe { t, n: 0, len } 42 | } 43 | } 44 | 45 | impl> Iterator for BitIteratorLe { 46 | type Item = bool; 47 | 48 | fn next(&mut self) -> Option { 49 | if self.n == self.len { 50 | None 51 | } else { 52 | let part = self.n / 64; 53 | let bit = self.n - (64 * part); 54 | self.n += 1; 55 | 56 | Some(self.t.as_ref()[part] & (1 << bit) > 0) 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Plasma cash history SNARK 2 | 3 | Compacts history in Plasma Cashes by hiding Merkle proofs under the private witness. Currently contains only non-inclusion circuit, with inclusion being trivially extended. 4 | 5 | Without much optimization is requires 4270718 constraints for 128 block of non-inclusion for 24 tree depth. 6 | 7 | Public inputs to the zkSNARK: 8 | 9 | - Start of the interval index (if single coin - just index) 10 | - Interval length (is single coin - 1) 11 | - Set of roots for which this coin index is proved to be non-included 12 | 13 | ## Notice 14 | 15 | SNARK checks that start of the interval is divisible by the interval length, but in principle such check should be done outside of the snark as range start and length are public inputs. 16 | 17 | ## Run 18 | 19 | Requires Rust 1.31 or higher. 20 | 21 | Dummy tree and proof are generated for a large set of blocks 22 | ``` 23 | cargo run --release --bin benchmark_proof_gen 24 | ``` 25 | 26 | You can also sent an environment variable `BELLMAN_VERBOSE=1` to have some verbose setup and proof generation progress. 27 | 28 | ## Benchmark 29 | ``` 30 | Using test constraint system to check the satisfiability 31 | Synthsizing a snark for 128 block for 24 tree depth 32 | Looking for unconstrained variabled: 33 | Number of constraints = 4263710 34 | generating setup... 35 | Has generated 4263684 points 36 | setup generated in 358.876 s 37 | creating proof... 38 | proof created in 39.749 s 39 | Proof is valid 40 | ``` 41 | 42 | ## License 43 | 44 | Licensed under either of 45 | 46 | * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) 47 | * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) 48 | 49 | at your option. 50 | 51 | ### Contribution 52 | 53 | Unless you explicitly state otherwise, any contribution intentionally 54 | submitted for inclusion in the work by you, as defined in the Apache-2.0 55 | license, shall be dual licensed as above, without any additional terms or 56 | conditions. 57 | 58 | -------------------------------------------------------------------------------- /src/sparse_merkle_tree/pedersen_hasher.rs: -------------------------------------------------------------------------------- 1 | // Pedersen hash implementation of the Hasher trait 2 | 3 | use bellman::pairing::ff::{Field, PrimeField, PrimeFieldRepr}; 4 | use rand::{Rand, thread_rng}; 5 | use sapling_crypto::pedersen_hash::{baby_pedersen_hash, Personalization}; 6 | 7 | use bellman::pairing::bn256::Bn256; 8 | use sapling_crypto::alt_babyjubjub::{JubjubEngine, AltJubjubBn256, edwards::Point, PrimeOrder}; 9 | 10 | use super::super::primitives::BitIteratorLe; 11 | use super::hasher::Hasher; 12 | 13 | pub struct PedersenHasher { 14 | params: E::Params, 15 | } 16 | 17 | impl Hasher for PedersenHasher { 18 | 19 | fn hash_bits>(&self, input: I) -> E::Fr { 20 | let hash = baby_pedersen_hash::(Personalization::NoteCommitment, input, &self.params).into_xy().0; 21 | 22 | hash 23 | } 24 | 25 | fn compress(&self, lhs: &E::Fr, rhs: &E::Fr, i: usize) -> E::Fr { 26 | // println!("For level {} xl = {}", i, lhs.clone()); 27 | // println!("For level {} xr = {}", i, rhs.clone()); 28 | let lhs = BitIteratorLe::new(lhs.into_repr()).take(E::Fr::NUM_BITS as usize); 29 | let rhs = BitIteratorLe::new(rhs.into_repr()).take(E::Fr::NUM_BITS as usize); 30 | let input = lhs.chain(rhs); 31 | let hash = baby_pedersen_hash::(Personalization::MerkleTree(i), input, &self.params).into_xy().0; 32 | // println!("Current level hash = {}", hash); 33 | 34 | hash 35 | } 36 | 37 | } 38 | 39 | pub type BabyPedersenHasher = PedersenHasher; 40 | 41 | impl Default for PedersenHasher { 42 | fn default() -> Self { 43 | Self{ 44 | params: AltJubjubBn256::new(), 45 | } 46 | } 47 | } 48 | 49 | #[test] 50 | fn test_pedersen_hash() { 51 | let hasher = BabyPedersenHasher::default(); 52 | 53 | let hash = hasher.hash_bits(vec![false, false, false, true, true, true, true, true]); 54 | //println!("hash: {:?}", &hash); 55 | 56 | let hash2 = hasher.compress(&hash, &hash, 0); 57 | //println!("compr: {:?}", &hash2); 58 | 59 | let hash3 = hasher.compress(&hash, &hash, 1); 60 | //println!("compr: {:?}", &hash3); 61 | 62 | //assert_eq!(hasher.empty_hash(), 63 | } 64 | -------------------------------------------------------------------------------- /src/transaction_tree/mod.rs: -------------------------------------------------------------------------------- 1 | // Plasma account (Merkle tree leaf) 2 | 3 | use std::fmt::{self, Debug}; 4 | use bellman::pairing::ff::{Field, PrimeField, PrimeFieldRepr}; 5 | use rand::{Rand, thread_rng}; 6 | use bellman::pairing::bn256::{Bn256, Fr}; 7 | use sapling_crypto::alt_babyjubjub::{JubjubEngine, AltJubjubBn256, edwards::Point, PrimeOrder}; 8 | 9 | use super::primitives::{GetBits, GetBitsFixed}; 10 | use crate::sparse_merkle_tree; 11 | use crate::sparse_merkle_tree::pedersen_hasher::PedersenHasher; 12 | 13 | const HASH_LENGTH: usize = 256; 14 | 15 | #[derive(Debug, Clone)] 16 | pub struct Leaf{ 17 | pub hash: Vec, 18 | pub phantom: std::marker::PhantomData, 19 | } 20 | 21 | impl GetBits for Leaf { 22 | fn get_bits_le(&self) -> Vec { 23 | self.hash.clone() 24 | } 25 | } 26 | 27 | impl Default for Leaf { 28 | fn default() -> Self{ 29 | let mut v = Vec::with_capacity(HASH_LENGTH); 30 | v.resize(HASH_LENGTH, false); 31 | Self { 32 | hash: v, 33 | phantom: std::marker::PhantomData 34 | } 35 | } 36 | } 37 | 38 | // code below is for testing 39 | 40 | pub type BabyTransactionLeaf = Leaf; 41 | pub type BabyTransactionTree = sparse_merkle_tree::SparseMerkleTree>; 42 | 43 | impl BabyTransactionTree { 44 | pub fn verify_proof(&self, index: u32, item: BabyTransactionLeaf, proof: Vec<(Fr, bool)>) -> bool { 45 | use crate::sparse_merkle_tree::hasher::Hasher; 46 | assert!(index < self.capacity()); 47 | let item_bits = item.get_bits_le(); 48 | let mut hash = self.hasher.hash_bits(item_bits); 49 | let mut proof_index: u32 = 0; 50 | 51 | for (i, e) in proof.clone().into_iter().enumerate() { 52 | if e.1 { 53 | // current is right 54 | proof_index |= 1 << i; 55 | hash = self.hasher.compress(&e.0, &hash, i); 56 | } else { 57 | // current is left 58 | hash = self.hasher.compress(&hash, &e.0, i); 59 | } 60 | } 61 | 62 | if proof_index != index { 63 | return false; 64 | } 65 | 66 | hash == self.root_hash() 67 | } 68 | } 69 | 70 | #[cfg(test)] 71 | mod tests { 72 | 73 | use super::*; 74 | use rand::{Rand, thread_rng}; 75 | 76 | #[test] 77 | fn test_balance_tree() { 78 | let mut tree = BabyTransactionTree::new(3); 79 | let leaf = BabyTransactionLeaf::default(); 80 | tree.insert(3, leaf); 81 | let root = tree.root_hash(); 82 | let path = tree.merkle_path(0); 83 | } 84 | 85 | 86 | } 87 | -------------------------------------------------------------------------------- /src/bin/benchmark_proof_gen.rs: -------------------------------------------------------------------------------- 1 | extern crate rand; 2 | extern crate sapling_crypto; 3 | extern crate bellman; 4 | extern crate plasma_cash_history_snark; 5 | extern crate time; 6 | 7 | use time::PreciseTime; 8 | use bellman::pairing::ff::{PrimeField}; 9 | use bellman::pairing::bn256::*; 10 | use bellman::{Circuit}; 11 | use rand::{SeedableRng, Rng, XorShiftRng}; 12 | use sapling_crypto::circuit::test::*; 13 | use sapling_crypto::alt_babyjubjub::{AltJubjubBn256}; 14 | use plasma_cash_history_snark::transaction_tree::{BabyTransactionTree, BabyTransactionLeaf}; 15 | use plasma_cash_history_snark::circuit::non_inclusion::{NonInclusion, BlockWitness}; 16 | 17 | use bellman::groth16::{ 18 | create_random_proof, 19 | generate_random_parameters, 20 | prepare_verifying_key, 21 | verify_proof, 22 | }; 23 | 24 | const TREE_DEPTH: u32 = 24; 25 | const NUMBER_OF_BLOCKS_TO_PROVE: u32 = 128; 26 | 27 | fn main() { 28 | let params = &AltJubjubBn256::new(); 29 | 30 | let rng = &mut XorShiftRng::from_seed([0x3dbe6258, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 31 | 32 | let non_inclusion_level = 2; 33 | // println!("Proving for intersection level = {}", non_inclusion_level); 34 | 35 | let interval_length = Fr::from_str(&(1 << non_inclusion_level).to_string()).unwrap(); 36 | // println!("Interval length = {}", interval_length); 37 | 38 | let mut witnesses = vec![]; 39 | 40 | let start_of_slice = 0u32; 41 | let index_as_field_element = Fr::from_str(&start_of_slice.to_string()).unwrap(); 42 | 43 | for _ in 0..NUMBER_OF_BLOCKS_TO_PROVE { 44 | // create an empty tree 45 | 46 | let mut tree = BabyTransactionTree::new(TREE_DEPTH); 47 | 48 | // test will prove the large [0, 3] (length 4), 49 | // so we need to enter non-zero element at the leaf number 4 50 | 51 | let mut random_bools = vec![]; 52 | for _ in 0..256 { 53 | let bit: bool = rng.gen::(); 54 | random_bools.push(bit); 55 | } 56 | 57 | let empty_leaf = BabyTransactionLeaf::default(); 58 | 59 | let non_empty_leaf = BabyTransactionLeaf { 60 | hash: random_bools, 61 | phantom: std::marker::PhantomData 62 | }; 63 | 64 | // println!("Inserting a non-empty leaf"); 65 | 66 | let slice_len = 1 << non_inclusion_level; 67 | 68 | tree.insert(slice_len, non_empty_leaf.clone()); 69 | 70 | let root = tree.root_hash(); 71 | // println!("Root = {}", root); 72 | 73 | // println!("Checking reference proofs"); 74 | 75 | assert!(tree.verify_proof(slice_len, non_empty_leaf.clone(), tree.merkle_path(slice_len))); 76 | assert!(tree.verify_proof(start_of_slice, empty_leaf.clone(), tree.merkle_path(start_of_slice))); 77 | 78 | { 79 | let proof = tree.merkle_path(start_of_slice); 80 | let proof_as_some: Vec> = proof.into_iter().map(|e| Some(e.0)).collect(); 81 | 82 | let block_witness: BlockWitness = BlockWitness { 83 | root: Some(root), 84 | proof: proof_as_some 85 | }; 86 | 87 | witnesses.push(block_witness); 88 | } 89 | } 90 | 91 | println!("Using test constraint system to check the satisfiability"); 92 | 93 | { 94 | let mut cs = TestConstraintSystem::::new(); 95 | 96 | let instance = NonInclusion { 97 | params: params, 98 | number_of_blocks: NUMBER_OF_BLOCKS_TO_PROVE as usize, 99 | leaf_hash_length: 256, 100 | tree_depth: TREE_DEPTH as usize, 101 | interval_length: Some(interval_length), 102 | index: Some(index_as_field_element), 103 | witness: witnesses.clone(), 104 | }; 105 | 106 | println!("Synthsizing a snark for {} block for {} tree depth", NUMBER_OF_BLOCKS_TO_PROVE, TREE_DEPTH); 107 | 108 | instance.synthesize(&mut cs).unwrap(); 109 | 110 | println!("Looking for unconstrained variabled: {}", cs.find_unconstrained()); 111 | 112 | println!("Number of constraints = {}", cs.num_constraints()); 113 | // inputs are ONE, starting index, slice length + root * number of blocks 114 | // assert_eq!(cs.num_inputs(), (1 + 1 + 1 + NUMBER_OF_BLOCKS_TO_PROVE) as usize); 115 | 116 | let err = cs.which_is_unsatisfied(); 117 | if err.is_some() { 118 | panic!("ERROR satisfying in {}\n", err.unwrap()); 119 | } 120 | } 121 | let empty_witness: BlockWitness = BlockWitness { 122 | root: None, 123 | proof: vec![None; TREE_DEPTH as usize] 124 | }; 125 | 126 | let instance_for_generation = NonInclusion { 127 | params: params, 128 | number_of_blocks: NUMBER_OF_BLOCKS_TO_PROVE as usize, 129 | leaf_hash_length: 256, 130 | tree_depth: TREE_DEPTH as usize, 131 | interval_length: None, 132 | index: None, 133 | witness: vec![empty_witness; NUMBER_OF_BLOCKS_TO_PROVE as usize], 134 | }; 135 | 136 | println!("generating setup..."); 137 | let start = PreciseTime::now(); 138 | let circuit_params = generate_random_parameters(instance_for_generation, rng).unwrap(); 139 | println!("setup generated in {} s", start.to(PreciseTime::now()).num_milliseconds() as f64 / 1000.0); 140 | 141 | let instance_for_proof = NonInclusion { 142 | params: params, 143 | number_of_blocks: NUMBER_OF_BLOCKS_TO_PROVE as usize, 144 | leaf_hash_length: 256, 145 | tree_depth: TREE_DEPTH as usize, 146 | interval_length: Some(interval_length), 147 | index: Some(index_as_field_element), 148 | witness: witnesses.clone(), 149 | }; 150 | 151 | let pvk = prepare_verifying_key(&circuit_params.vk); 152 | 153 | println!("creating proof..."); 154 | let start = PreciseTime::now(); 155 | let proof = create_random_proof(instance_for_proof, &circuit_params, rng).unwrap(); 156 | println!("proof created in {} s", start.to(PreciseTime::now()).num_milliseconds() as f64 / 1000.0); 157 | 158 | let mut public_inputs = vec![]; 159 | public_inputs.push(index_as_field_element); 160 | public_inputs.push(interval_length); 161 | public_inputs.extend(witnesses.into_iter().map(|e| e.root.clone().unwrap())); 162 | 163 | let success = verify_proof(&pvk, &proof, &public_inputs).unwrap(); 164 | assert!(success); 165 | println!("Proof is valid"); 166 | } -------------------------------------------------------------------------------- /src/sparse_merkle_tree/mod.rs: -------------------------------------------------------------------------------- 1 | // Sparse Merkle tree with flexible hashing strategy 2 | 3 | pub mod hasher; 4 | pub mod pedersen_hasher; 5 | 6 | use std::fmt::Debug; 7 | use std::collections::HashMap; 8 | use self::hasher::Hasher; 9 | use super::primitives::GetBits; 10 | use bellman::pairing::ff::{PrimeField}; 11 | 12 | // Tree of depth 0 should contain ONE element that is also a root 13 | // Tree of depth 1 should contain TWO elements 14 | // Tree of depth 20 should contain 2^20 elements 15 | 16 | // [0, (2^TREE_DEPTH - 1)] 17 | type ItemIndex = u32; 18 | 19 | // [0, TREE_DEPTH] 20 | type Depth = u32; 21 | 22 | // Hash index determines on what level of the tree the hash is 23 | // and kept as level (where zero is a root) and item in a level indexed from 0 24 | type HashIndex = (u32, u32); 25 | 26 | type ItemIndexPacked = u64; 27 | 28 | trait PackToIndex { 29 | fn pack(&self) -> ItemIndexPacked; 30 | } 31 | 32 | impl PackToIndex for HashIndex { 33 | fn pack(&self) -> ItemIndexPacked { 34 | let mut packed = 0u64; 35 | packed += u64::from(self.0); 36 | packed <<= 32u64; 37 | packed += u64::from(self.1); 38 | 39 | packed 40 | } 41 | } 42 | 43 | #[derive(Debug, Clone)] 44 | pub struct SparseMerkleTree> 45 | { 46 | tree_depth: Depth, 47 | pub prehashed: Vec, 48 | pub items: HashMap, 49 | pub hashes: HashMap, 50 | pub hasher: H, 51 | } 52 | 53 | impl SparseMerkleTree 54 | where T: GetBits + Default, 55 | Hash: Clone + Eq + Debug, 56 | H: Hasher + Default, 57 | { 58 | 59 | pub fn new(tree_depth: Depth) -> Self { 60 | let hasher = H::default(); 61 | let items = HashMap::new(); 62 | let hashes = HashMap::new(); 63 | // we need to make sparse hashes for tree depth levels 64 | let mut prehashed = Vec::with_capacity((tree_depth + 1) as usize); 65 | let mut cur = hasher.hash_bits(T::default().get_bits_le()); 66 | prehashed.push(cur.clone()); 67 | 68 | for i in 0..tree_depth { 69 | cur = hasher.compress(&cur, &cur, i as usize); 70 | prehashed.push(cur.clone()); 71 | } 72 | prehashed.reverse(); 73 | 74 | // print!("Made default hashes in quantity {}\n", prehashed.len()); 75 | 76 | assert_eq!(prehashed.len() - 1, tree_depth as usize); 77 | Self{tree_depth, prehashed, items, hashes, hasher} 78 | } 79 | 80 | // How many items can the tree hold 81 | pub fn capacity(&self) -> u32 { 82 | 1 << self.tree_depth 83 | } 84 | 85 | pub fn insert(&mut self, index: ItemIndex, item: T) { 86 | assert!(index < self.capacity()); 87 | let hash_index = (self.tree_depth, index); 88 | 89 | let item_bits = item.get_bits_le(); 90 | // for b in item_bits.clone() { 91 | // if b { 92 | // print!("1"); 93 | // } else { 94 | // print!("0"); 95 | // } 96 | // } 97 | // print!("\n"); 98 | let hash = self.hasher.hash_bits(item_bits); 99 | // print!("Inserting at index {}\n", index); 100 | // print!("Packed into index {}, {}\n", hash_index.0, hash_index.1); 101 | 102 | //println!("hash [{}] = {:?}", (1 << hash_index.0) + hash_index.1, &hash); 103 | 104 | self.hashes.insert(hash_index.pack(), hash); 105 | 106 | self.items.insert(index, item); 107 | 108 | let mut next_level = (hash_index.0, hash_index.1); 109 | 110 | // print!("Have updated index {}, {}, will cascade\n", next_level.0, next_level.1); 111 | for _ in 0..next_level.0 { 112 | next_level = (next_level.0 - 1, next_level.1 >> 1); 113 | self.update_hash(next_level); 114 | 115 | } 116 | // print!("Have updated up to {}, {}\n", next_level.0, next_level.1); 117 | assert_eq!(next_level.0, 0); 118 | } 119 | 120 | // pub fn calculate_hash_index(& self, index: ItemIndex) -> HashIndex { 121 | // let hash_index = (1 << self.tree_depth-1) + index; 122 | // hash_index 123 | // } 124 | 125 | fn update_hash(&mut self, index: HashIndex) -> Hash { 126 | // should NEVER be used to update the leaf hash 127 | 128 | // print!("Updating index {}, {}\n", index.0, index.1); 129 | 130 | assert!(index.0 < self.tree_depth); 131 | assert!(index.1 < self.capacity()); 132 | 133 | // indices for child nodes in the tree 134 | let lhs_index = (index.0 + 1, (index.1 << 1)); 135 | let rhs_index = (index.0 + 1, (index.1 << 1) + 1); 136 | 137 | let lhs_hash = self.get_hash(lhs_index); 138 | let rhs_hash = self.get_hash(rhs_index); 139 | 140 | //let idx = (1 << index.0) + index.1; 141 | //println!("({:?}, {:?}, {})", &lhs_hash, &rhs_hash, (self.tree_depth - 1 - index.0)); 142 | 143 | let hash = self.hasher.compress(&lhs_hash, &rhs_hash, (self.tree_depth - 1 - index.0) as usize); 144 | 145 | //println!("hash [{}] = {:?}", (1 << index.0) + index.1, hash); 146 | 147 | self.hashes.insert(index.pack(), hash.clone()); 148 | hash 149 | 150 | } 151 | 152 | pub fn get_hash(&self, index: HashIndex) -> Hash { 153 | // print!("Reading hash for index {}, {}\n", index.0, index.1); 154 | 155 | assert!(index.0 <= self.tree_depth); 156 | assert!(index.1 < self.capacity()); 157 | 158 | if let Some(hash) = self.hashes.get(&index.pack()) { 159 | // if hash for this index exists, return it 160 | // print!("Found non-default hash for index {}, {}\n", index.0, index.1); 161 | hash.clone() 162 | } else { 163 | // otherwise return pre-computed 164 | // print!("Found default hash for index {}, {}\n", index.0, index.1); 165 | self.prehashed.get((index.0) as usize).unwrap().clone() 166 | } 167 | } 168 | 169 | pub fn merkle_path(&self, index: ItemIndex) -> Vec<(Hash, bool)> { 170 | // print!("Making a proof for index {}\n", index); 171 | assert!(index < self.capacity()); 172 | let mut hash_index = (self.tree_depth, index); 173 | 174 | (0..self.tree_depth).rev().map(|level| { 175 | let dir = (hash_index.1 & 1) > 0; 176 | let proof_index = (hash_index.0, hash_index.1 ^ 1); 177 | let hash = self.get_hash(proof_index); 178 | hash_index = (hash_index.0 - 1, hash_index.1 >> 1); 179 | (hash, dir) 180 | }).collect() 181 | } 182 | 183 | // pub fn verify_proof(&self, index: ItemIndex, item: T, proof: Vec<(Hash, bool)>) -> bool { 184 | // assert!(index < self.capacity()); 185 | // let item_bits = item.get_bits_le(); 186 | // let mut hash = self.hasher.hash_bits(item_bits); 187 | // let mut proof_index: ItemIndex = 0; 188 | 189 | // for (i, e) in proof.clone().into_iter().enumerate() { 190 | // if e.1 { 191 | // // current is right 192 | // proof_index |= 1 << i; 193 | // hash = self.hasher.compress(&e.0, &hash, i); 194 | // } else { 195 | // // current is left 196 | // hash = self.hasher.compress(&hash, &e.0, i); 197 | // } 198 | // } 199 | 200 | // if proof_index != index { 201 | // return false; 202 | // } 203 | 204 | // hash == self.root_hash() 205 | // } 206 | 207 | pub fn root_hash(&self) -> Hash { 208 | self.get_hash((0, 0)) 209 | } 210 | } 211 | 212 | #[cfg(test)] 213 | mod tests { 214 | use super::*; 215 | 216 | #[derive(Debug)] 217 | struct TestHasher {} 218 | 219 | impl GetBits for u64 { 220 | fn get_bits_le(&self) -> Vec { 221 | let mut acc = Vec::new(); 222 | let mut i = *self + 1; 223 | for _ in 0..16 { 224 | acc.push(i & 1 == 1); 225 | i >>= 1; 226 | } 227 | acc 228 | } 229 | } 230 | 231 | impl Default for TestHasher { 232 | fn default() -> Self { Self {} } 233 | } 234 | 235 | impl Hasher for TestHasher { 236 | 237 | fn hash_bits>(&self, value: I) -> u64 { 238 | let mut acc = 0; 239 | let v: Vec = value.into_iter().collect(); 240 | for i in v.iter() { 241 | acc <<= 1; 242 | if *i {acc |= 1}; 243 | } 244 | acc 245 | } 246 | 247 | fn compress(&self, lhs: &u64, rhs: &u64, i: usize) -> u64 { 248 | let r = 11 * lhs + 17 * rhs + 1 + i as u64; 249 | //println!("compress {} {}, {} => {}", lhs, rhs, i, r); 250 | r 251 | } 252 | 253 | } 254 | 255 | type TestSMT = SparseMerkleTree; 256 | 257 | // #[test] 258 | // fn test_merkle_tree_props() { 259 | // let mut tree = TestSMT::new(3); 260 | // assert_eq!(TestSMT::depth(1), 0); 261 | // assert_eq!(TestSMT::depth(2), 1); 262 | // assert_eq!(TestSMT::depth(3), 1); 263 | // assert_eq!(TestSMT::depth(4), 2); 264 | // } 265 | 266 | #[test] 267 | fn test_merkle_tree_insert() { 268 | let mut tree = TestSMT::new(3); 269 | 270 | assert_eq!(tree.capacity(), 8); 271 | 272 | tree.insert(0, 1); 273 | println!("{:?}", tree); 274 | assert_eq!(tree.root_hash(), 697516875); 275 | 276 | tree.insert(0, 2); 277 | println!("{:?}", tree); 278 | assert_eq!(tree.root_hash(), 741131083); 279 | 280 | tree.insert(3, 2); 281 | //println!("{:?}", tree); 282 | assert_eq!(tree.root_hash(), 793215819); 283 | } 284 | 285 | #[test] 286 | fn test_merkle_path() { 287 | let mut tree = TestSMT::new(3); 288 | tree.insert(2, 1); 289 | let path = tree.merkle_path(2); 290 | //println!("{:?}", tree); 291 | assert_eq!(path, [(32768, false), (917505, true), (25690142, false)]); 292 | } 293 | } 294 | -------------------------------------------------------------------------------- /src/circuit/non_inclusion.rs: -------------------------------------------------------------------------------- 1 | use bellman::pairing::ff::{ 2 | PrimeField, 3 | Field, 4 | BitIterator, 5 | PrimeFieldRepr 6 | }; 7 | 8 | use bellman::{ 9 | SynthesisError, 10 | ConstraintSystem, 11 | Circuit 12 | }; 13 | 14 | use sapling_crypto::jubjub::{ 15 | JubjubEngine, 16 | FixedGenerators, 17 | Unknown, 18 | edwards, 19 | JubjubParams 20 | }; 21 | 22 | use super::Assignment; 23 | use super::boolean; 24 | use super::ecc; 25 | use super::pedersen_hash; 26 | use super::sha256; 27 | use super::num; 28 | use super::multipack; 29 | use super::num::{AllocatedNum, Num}; 30 | use super::float_point::{parse_with_exponent_le, convert_to_float}; 31 | 32 | use sapling_crypto::eddsa::{ 33 | Signature, 34 | PrivateKey, 35 | PublicKey 36 | }; 37 | 38 | use super::baby_eddsa::EddsaSignature; 39 | 40 | #[derive(Clone)] 41 | pub struct BlockWitness { 42 | pub root: Option, 43 | pub proof: Vec>, 44 | } 45 | 46 | #[derive(Clone)] 47 | pub struct NonInclusion<'a, E: JubjubEngine> { 48 | pub params: &'a E::Params, 49 | 50 | // Number of blocks that this snark proves non-inclusion for 51 | pub number_of_blocks: usize, 52 | 53 | // Leaf hash length 54 | pub leaf_hash_length: usize, 55 | 56 | // Tree depth 57 | pub tree_depth: usize, 58 | 59 | // Non-inclusion level 60 | pub interval_length: Option, 61 | 62 | // Index we prove non-inclusion for 63 | pub index: Option, 64 | 65 | // Witnesses 66 | pub witness: Vec>, 67 | } 68 | 69 | // returns a bit vector with only one for the tree 70 | fn count_number_of_ones( 71 | mut cs: CS, 72 | a: &[boolean::Boolean] 73 | ) -> Result, SynthesisError> 74 | where E: JubjubEngine, 75 | CS: ConstraintSystem 76 | { 77 | let mut counter = Num::zero(); 78 | for bit in a.iter() { 79 | counter = counter.add_bool_with_coeff(CS::one(), &bit, E::Fr::one()); 80 | } 81 | 82 | let result = AllocatedNum::alloc( 83 | cs.namespace(|| "number of zeroes number"), 84 | || Ok(*counter.get_value().get()?) 85 | )?; 86 | 87 | cs.enforce( 88 | || "pack number of ones", 89 | |lc| lc + result.get_variable(), 90 | |lc| lc + CS::one(), 91 | |_| counter.lc(E::Fr::one()) 92 | ); 93 | 94 | Ok(result) 95 | } 96 | 97 | impl<'a, E: JubjubEngine> Circuit for NonInclusion<'a, E> { 98 | fn synthesize>(self, cs: &mut CS) -> Result<(), SynthesisError> 99 | { 100 | // Check that transactions are in a right quantity 101 | assert!(self.number_of_blocks == self.witness.len()); 102 | 103 | let mut zero_leaf = Vec::::with_capacity(self.leaf_hash_length); 104 | zero_leaf.resize(self.leaf_hash_length, boolean::Boolean::Constant(false)); 105 | 106 | // Expose index 107 | let index = AllocatedNum::alloc( 108 | cs.namespace(|| "index"), 109 | || { 110 | let index_value = self.index; 111 | Ok(*index_value.get()?) 112 | } 113 | )?; 114 | index.inputize(cs.namespace(|| "index input"))?; 115 | 116 | // Index is expected to be just a coin number 117 | let mut index_input_bits = index.into_bits_le( 118 | cs.namespace(|| "index bits") 119 | )?; 120 | index_input_bits.truncate(self.tree_depth); 121 | 122 | // Expose level 123 | let interval = AllocatedNum::alloc( 124 | cs.namespace(|| "slice interval"), 125 | || { 126 | let interval_length_value = self.interval_length; 127 | Ok(*interval_length_value.get()?) 128 | } 129 | )?; 130 | interval.inputize(cs.namespace(|| "slice interval input"))?; 131 | 132 | // prove that coin index is divisible by coin ID 133 | // In principle as index and length are public inputs, it's much easier to do 134 | // externally 135 | let division_result = AllocatedNum::alloc( 136 | cs.namespace(|| "division_result"), 137 | || { 138 | let interval_length = *interval.get_value().get()?; 139 | let interval_length_inverse = *interval_length.inverse().get()?; 140 | let mut division_result = *index.get_value().get()?; 141 | division_result.mul_assign(&interval_length_inverse); 142 | Ok(division_result) 143 | } 144 | )?; 145 | 146 | cs.enforce( 147 | || "enforce index by length division", 148 | |lc| lc + interval.get_variable(), 149 | |lc| lc + division_result.get_variable(), 150 | |lc| lc + index.get_variable() 151 | ); 152 | 153 | // if there was some fancy overflowing division, then top bits will be non-zero 154 | division_result.limit_number_of_bits( 155 | cs.namespace(|| "limit number of bits for new balance from"), 156 | self.tree_depth 157 | )?; 158 | 159 | // interval is expected to be power of two 160 | let mut interval_bits = interval.into_bits_le( 161 | cs.namespace(|| "level bits") 162 | )?; 163 | interval_bits.truncate(self.tree_depth); 164 | 165 | let num_of_ones_in_level = count_number_of_ones( 166 | cs.namespace(|| "count number of ones in internal length"), 167 | &interval_bits 168 | )?; 169 | 170 | cs.enforce( 171 | || "enforce number of ones", 172 | |lc| lc + num_of_ones_in_level.get_variable(), 173 | |lc| lc + CS::one(), 174 | |lc| lc + CS::one() 175 | ); 176 | 177 | // now create a bitmask for higher levels 178 | let mut level_mask_lc = Num::zero(); 179 | let mut coeff = E::Fr::one(); 180 | for bit in interval_bits.clone().into_iter() { 181 | level_mask_lc = level_mask_lc.add_bool_with_coeff(CS::one(), &bit, coeff); 182 | coeff.double(); 183 | } 184 | // subtract one 185 | let mut minus_one = E::Fr::one(); 186 | minus_one.negate(); 187 | level_mask_lc = level_mask_lc.add_bool_with_coeff(CS::one(), &boolean::Boolean::Constant(true), minus_one); 188 | // make number 189 | 190 | let level_mask_allocated = AllocatedNum::alloc( 191 | cs.namespace(|| "allocate level bitmask"), 192 | || Ok(*level_mask_lc.get_value().get()?) 193 | )?; 194 | 195 | cs.enforce( 196 | || "enforce bitmask for levels", 197 | |lc| lc + level_mask_allocated.get_variable(), 198 | |lc| lc + CS::one(), 199 | |_| level_mask_lc.lc(E::Fr::one()) 200 | ); 201 | 202 | // decompose again 203 | 204 | let mut level_bitmask = level_mask_allocated.into_bits_le( 205 | cs.namespace(|| "decompose bitmask again") 206 | )?; 207 | 208 | level_bitmask.truncate(self.tree_depth); 209 | 210 | // precompute empty nodes for a price of one tree depth of hashes 211 | 212 | let mut empty_levels = vec![]; 213 | 214 | // Compute the hash of the from leaf 215 | let empty_leaf_hash = pedersen_hash::pedersen_hash( 216 | cs.namespace(|| "empty leaf hash"), 217 | pedersen_hash::Personalization::NoteCommitment, 218 | &zero_leaf, 219 | self.params 220 | )?; 221 | 222 | let mut current_empty = empty_leaf_hash.get_x().clone(); 223 | 224 | empty_levels.push(current_empty.clone()); 225 | 226 | for i in 0..self.tree_depth-1 { 227 | let cs = &mut cs.namespace(|| format!("compute empty leafs merkle tree hash {}", i)); 228 | 229 | let mut preimage = vec![]; 230 | let cur_bits = current_empty.into_bits_le(cs.namespace(|| "current into bits"))?; 231 | preimage.extend(cur_bits.clone()); 232 | preimage.extend(cur_bits); 233 | 234 | // Compute the new subtree value 235 | current_empty = pedersen_hash::pedersen_hash( 236 | cs.namespace(|| "computation of pedersen hash"), 237 | pedersen_hash::Personalization::MerkleTree(i), 238 | &preimage, 239 | self.params 240 | )?.get_x().clone(); // Injective encoding 241 | 242 | empty_levels.push(current_empty.clone()); 243 | } 244 | 245 | let mut root_hash_inputs = vec![]; 246 | 247 | // allocate the inputs 248 | for (i, w) in self.witness.clone().into_iter().enumerate() { 249 | let cs = &mut cs.namespace(|| format!("block proof number {}", i)); 250 | // allocate public input 251 | let proof_input = AllocatedNum::alloc( 252 | cs.namespace(|| "root"), 253 | || Ok(*w.root.get()?) 254 | )?; 255 | 256 | proof_input.inputize( 257 | cs.namespace(|| "input for root") 258 | )?; 259 | 260 | root_hash_inputs.push(proof_input); 261 | } 262 | 263 | for (j, (root_hash, witness)) in root_hash_inputs.into_iter() 264 | .zip(self.witness.into_iter()) 265 | .enumerate() { 266 | 267 | let audit_path = witness.proof; 268 | assert_eq!(self.tree_depth, audit_path.len()); 269 | assert_eq!(self.tree_depth, level_bitmask.len()); 270 | assert_eq!(self.tree_depth, index_input_bits.len()); 271 | 272 | // at least at the bottom level there should be zero 273 | let mut cur = empty_leaf_hash.get_x().clone(); 274 | 275 | // Ascend the merkle tree authentication path 276 | for (i, ( (e, level_bit), direction_bit) ) in audit_path.clone().into_iter() 277 | .zip(level_bitmask.clone().into_iter()) 278 | .zip(index_input_bits.clone().into_iter()) 279 | // .zip(self.empty_hashes.clone().into_iter()) 280 | .enumerate() { 281 | let cs = &mut cs.namespace(|| format!("proof procedue for block {}, level {}", j, i)); 282 | // Direction bit determines if the current subtree is the "right" leaf at this 283 | // depth of the tree. 284 | 285 | let empty_leaf = num::AllocatedNum::alloc( 286 | cs.namespace(|| "reallocate empty leaf"), 287 | || { 288 | Ok(*empty_levels[i].get_value().get()?) 289 | } 290 | )?; 291 | 292 | let current_chosen = num::AllocatedNum::conditionally_select( 293 | cs.namespace(|| "conditional select of empty or not leaf hash"), 294 | &empty_leaf, 295 | &cur, 296 | &level_bit 297 | )?; 298 | 299 | // Witness the authentication path element adjacent 300 | // at this depth. 301 | let path_element = num::AllocatedNum::alloc( 302 | cs.namespace(|| "path element"), 303 | || { 304 | Ok(*e.get()?) 305 | } 306 | )?; 307 | 308 | // Swap the two if the current subtree is on the right 309 | let (xl, xr) = num::AllocatedNum::conditionally_reverse( 310 | cs.namespace(|| "conditional reversal of preimage"), 311 | ¤t_chosen, 312 | &path_element, 313 | &direction_bit 314 | )?; 315 | 316 | // We don't need to be strict, because the function is 317 | // collision-resistant. If the prover witnesses a congruency, 318 | // they will be unable to find an authentication path in the 319 | // tree with high probability. 320 | let mut preimage = vec![]; 321 | preimage.extend(xl.into_bits_le(cs.namespace(|| "xl into bits"))?); 322 | preimage.extend(xr.into_bits_le(cs.namespace(|| "xr into bits"))?); 323 | 324 | // Compute the new subtree value 325 | cur = pedersen_hash::pedersen_hash( 326 | cs.namespace(|| "computation of pedersen hash"), 327 | pedersen_hash::Personalization::MerkleTree(i), 328 | &preimage, 329 | self.params 330 | )?.get_x().clone(); // Injective encoding 331 | 332 | } 333 | 334 | // enforce that root is equal to the expected one 335 | cs.enforce( 336 | || format!("enforce correct root hash for block {}", j), 337 | |lc| lc + cur.get_variable(), 338 | |lc| lc + CS::one(), 339 | |lc| lc + root_hash.get_variable() 340 | ); 341 | } 342 | 343 | Ok(()) 344 | } 345 | } 346 | 347 | const TREE_DEPTH: u32 = 24; 348 | const NUMBER_OF_BLOCKS_TO_PROVE: u32 = 1; 349 | 350 | #[test] 351 | fn test_non_inclusion_proof() { 352 | use bellman::pairing::ff::{Field}; 353 | use bellman::pairing::bn256::*; 354 | use rand::{SeedableRng, Rng, XorShiftRng, Rand}; 355 | use sapling_crypto::circuit::test::*; 356 | use sapling_crypto::alt_babyjubjub::{AltJubjubBn256, fs, edwards, PrimeOrder}; 357 | use crate::transaction_tree::{BabyTransactionTree, BabyTransactionLeaf, Leaf}; 358 | 359 | extern crate hex; 360 | 361 | let p_g = FixedGenerators::SpendingKeyGenerator; 362 | let params = &AltJubjubBn256::new(); 363 | 364 | let rng = &mut XorShiftRng::from_seed([0x3dbe6258, 0x8d313d76, 0x3237db17, 0xe5bc0654]); 365 | 366 | let non_inclusion_level = 2; 367 | println!("Proving for intersection level = {}", non_inclusion_level); 368 | 369 | let interval_length = Fr::from_str(&(1 << non_inclusion_level).to_string()).unwrap(); 370 | println!("Interval length = {}", interval_length); 371 | 372 | let mut witnesses = vec![]; 373 | 374 | let start_of_slice = 0u32; 375 | let index_as_field_element = Fr::from_str(&start_of_slice.to_string()).unwrap(); 376 | 377 | for _ in 0..NUMBER_OF_BLOCKS_TO_PROVE { 378 | // create an empty tree 379 | 380 | let mut tree = BabyTransactionTree::new(TREE_DEPTH); 381 | 382 | let empty_tree_root = tree.root_hash(); 383 | println!("Empty root hash = {}", empty_tree_root); 384 | 385 | // test will prove the large [0, 3] (length 4), 386 | // so we need to enter non-zero element at the leaf number 4 387 | 388 | let mut random_bools = vec![]; 389 | for _ in 0..256 { 390 | let bit: bool = rng.gen::(); 391 | random_bools.push(bit); 392 | } 393 | 394 | let empty_leaf = BabyTransactionLeaf::default(); 395 | 396 | let non_empty_leaf = BabyTransactionLeaf { 397 | hash: random_bools, 398 | phantom: std::marker::PhantomData 399 | }; 400 | 401 | println!("Inserting a non-empty leaf"); 402 | 403 | let slice_len = 1 << non_inclusion_level; 404 | 405 | tree.insert(slice_len, non_empty_leaf.clone()); 406 | 407 | let root = tree.root_hash(); 408 | println!("Root = {}", root); 409 | 410 | println!("Checking reference proofs"); 411 | 412 | // assert!(tree.verify_proof(slice_len, non_empty_leaf.clone(), tree.merkle_path(slice_len))); 413 | assert!(tree.verify_proof(start_of_slice, empty_leaf.clone(), tree.merkle_path(start_of_slice))); 414 | 415 | let proof = tree.merkle_path(start_of_slice); 416 | let proof_as_some: Vec> = proof.into_iter().map(|e| Some(e.0)).collect(); 417 | 418 | let block_witness: BlockWitness = BlockWitness { 419 | root: Some(root), 420 | proof: proof_as_some 421 | }; 422 | 423 | witnesses.push(block_witness); 424 | } 425 | 426 | { 427 | assert_eq!(witnesses.len(), NUMBER_OF_BLOCKS_TO_PROVE as usize); 428 | 429 | let mut cs = TestConstraintSystem::::new(); 430 | 431 | let instance = NonInclusion { 432 | params: params, 433 | number_of_blocks: NUMBER_OF_BLOCKS_TO_PROVE as usize, 434 | leaf_hash_length: 256, 435 | tree_depth: TREE_DEPTH as usize, 436 | interval_length: Some(interval_length), 437 | index: Some(index_as_field_element), 438 | witness: witnesses, 439 | }; 440 | 441 | println!("Synthsizing a snark for {} block for {} tree depth", NUMBER_OF_BLOCKS_TO_PROVE, TREE_DEPTH); 442 | 443 | instance.synthesize(&mut cs).unwrap(); 444 | 445 | println!("{}", cs.find_unconstrained()); 446 | 447 | println!("Number of constraints = {}", cs.num_constraints()); 448 | // inputs are ONE, starting index, slice length + root * number of blocks 449 | assert_eq!(cs.num_inputs(), (1 + 1 + 1 + NUMBER_OF_BLOCKS_TO_PROVE) as usize); 450 | 451 | let err = cs.which_is_unsatisfied(); 452 | if err.is_some() { 453 | panic!("ERROR satisfying in {}\n", err.unwrap()); 454 | } 455 | } 456 | } -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "arrayvec" 5 | version = "0.4.8" 6 | source = "registry+https://github.com/rust-lang/crates.io-index" 7 | dependencies = [ 8 | "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", 9 | ] 10 | 11 | [[package]] 12 | name = "bellman" 13 | version = "0.2.0" 14 | source = "git+https://github.com/matterinc/bellman?tag=0.2.0#6e45a4b233e97a71f4a8a0565c8f8d753c04c08f" 15 | dependencies = [ 16 | "bit-vec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", 17 | "blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9)", 18 | "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", 19 | "crossbeam 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", 20 | "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", 21 | "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", 22 | "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", 23 | "pairing 0.16.2 (git+https://github.com/matterinc/pairing?tag=0.16.2)", 24 | "rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", 25 | ] 26 | 27 | [[package]] 28 | name = "bit-vec" 29 | version = "0.4.4" 30 | source = "registry+https://github.com/rust-lang/crates.io-index" 31 | 32 | [[package]] 33 | name = "bitflags" 34 | version = "1.0.4" 35 | source = "registry+https://github.com/rust-lang/crates.io-index" 36 | 37 | [[package]] 38 | name = "blake2-rfc" 39 | version = "0.2.18" 40 | source = "git+https://github.com/gtank/blake2-rfc?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9#7a5b5fc99ae483a0043db7547fb79a6fa44b88a9" 41 | dependencies = [ 42 | "arrayvec 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 43 | "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", 44 | "constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", 45 | ] 46 | 47 | [[package]] 48 | name = "byteorder" 49 | version = "1.2.7" 50 | source = "registry+https://github.com/rust-lang/crates.io-index" 51 | 52 | [[package]] 53 | name = "cfg-if" 54 | version = "0.1.7" 55 | source = "registry+https://github.com/rust-lang/crates.io-index" 56 | 57 | [[package]] 58 | name = "constant_time_eq" 59 | version = "0.1.3" 60 | source = "registry+https://github.com/rust-lang/crates.io-index" 61 | 62 | [[package]] 63 | name = "crossbeam" 64 | version = "0.7.1" 65 | source = "registry+https://github.com/rust-lang/crates.io-index" 66 | dependencies = [ 67 | "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", 68 | "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 69 | "crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", 70 | "crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", 71 | "crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 72 | "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", 73 | ] 74 | 75 | [[package]] 76 | name = "crossbeam-channel" 77 | version = "0.3.8" 78 | source = "registry+https://github.com/rust-lang/crates.io-index" 79 | dependencies = [ 80 | "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", 81 | "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", 82 | ] 83 | 84 | [[package]] 85 | name = "crossbeam-deque" 86 | version = "0.7.1" 87 | source = "registry+https://github.com/rust-lang/crates.io-index" 88 | dependencies = [ 89 | "crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", 90 | "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", 91 | ] 92 | 93 | [[package]] 94 | name = "crossbeam-epoch" 95 | version = "0.7.1" 96 | source = "registry+https://github.com/rust-lang/crates.io-index" 97 | dependencies = [ 98 | "arrayvec 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 99 | "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", 100 | "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", 101 | "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", 102 | "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 103 | "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 104 | ] 105 | 106 | [[package]] 107 | name = "crossbeam-queue" 108 | version = "0.1.2" 109 | source = "registry+https://github.com/rust-lang/crates.io-index" 110 | dependencies = [ 111 | "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", 112 | ] 113 | 114 | [[package]] 115 | name = "crossbeam-utils" 116 | version = "0.6.5" 117 | source = "registry+https://github.com/rust-lang/crates.io-index" 118 | dependencies = [ 119 | "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", 120 | "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", 121 | ] 122 | 123 | [[package]] 124 | name = "crunchy" 125 | version = "0.1.6" 126 | source = "registry+https://github.com/rust-lang/crates.io-index" 127 | 128 | [[package]] 129 | name = "digest" 130 | version = "0.7.6" 131 | source = "registry+https://github.com/rust-lang/crates.io-index" 132 | dependencies = [ 133 | "generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", 134 | ] 135 | 136 | [[package]] 137 | name = "ff" 138 | version = "0.5.0" 139 | source = "git+https://github.com/matterinc/ff?tag=0.5#056a13b95f4b971a9ae2c6fbb5fbc9f1e4f4828e" 140 | dependencies = [ 141 | "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", 142 | "ff_derive 0.4.0 (git+https://github.com/matterinc/ff?tag=0.5)", 143 | "rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", 144 | ] 145 | 146 | [[package]] 147 | name = "ff_derive" 148 | version = "0.4.0" 149 | source = "git+https://github.com/matterinc/ff?tag=0.5#056a13b95f4b971a9ae2c6fbb5fbc9f1e4f4828e" 150 | dependencies = [ 151 | "num-bigint 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 152 | "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", 153 | "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", 154 | "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", 155 | "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", 156 | "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", 157 | "syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)", 158 | ] 159 | 160 | [[package]] 161 | name = "fuchsia-zircon" 162 | version = "0.3.3" 163 | source = "registry+https://github.com/rust-lang/crates.io-index" 164 | dependencies = [ 165 | "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", 166 | "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 167 | ] 168 | 169 | [[package]] 170 | name = "fuchsia-zircon-sys" 171 | version = "0.3.3" 172 | source = "registry+https://github.com/rust-lang/crates.io-index" 173 | 174 | [[package]] 175 | name = "futures" 176 | version = "0.1.25" 177 | source = "registry+https://github.com/rust-lang/crates.io-index" 178 | 179 | [[package]] 180 | name = "futures-cpupool" 181 | version = "0.1.8" 182 | source = "registry+https://github.com/rust-lang/crates.io-index" 183 | dependencies = [ 184 | "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", 185 | "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", 186 | ] 187 | 188 | [[package]] 189 | name = "gcc" 190 | version = "0.3.55" 191 | source = "registry+https://github.com/rust-lang/crates.io-index" 192 | 193 | [[package]] 194 | name = "generic-array" 195 | version = "0.9.0" 196 | source = "registry+https://github.com/rust-lang/crates.io-index" 197 | dependencies = [ 198 | "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", 199 | ] 200 | 201 | [[package]] 202 | name = "hex" 203 | version = "0.3.2" 204 | source = "registry+https://github.com/rust-lang/crates.io-index" 205 | 206 | [[package]] 207 | name = "itoa" 208 | version = "0.4.3" 209 | source = "registry+https://github.com/rust-lang/crates.io-index" 210 | 211 | [[package]] 212 | name = "lazy_static" 213 | version = "1.3.0" 214 | source = "registry+https://github.com/rust-lang/crates.io-index" 215 | 216 | [[package]] 217 | name = "libc" 218 | version = "0.2.44" 219 | source = "registry+https://github.com/rust-lang/crates.io-index" 220 | 221 | [[package]] 222 | name = "memoffset" 223 | version = "0.2.1" 224 | source = "registry+https://github.com/rust-lang/crates.io-index" 225 | 226 | [[package]] 227 | name = "nodrop" 228 | version = "0.1.13" 229 | source = "registry+https://github.com/rust-lang/crates.io-index" 230 | 231 | [[package]] 232 | name = "num-bigint" 233 | version = "0.2.1" 234 | source = "registry+https://github.com/rust-lang/crates.io-index" 235 | dependencies = [ 236 | "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", 237 | "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", 238 | ] 239 | 240 | [[package]] 241 | name = "num-integer" 242 | version = "0.1.39" 243 | source = "registry+https://github.com/rust-lang/crates.io-index" 244 | dependencies = [ 245 | "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", 246 | ] 247 | 248 | [[package]] 249 | name = "num-traits" 250 | version = "0.2.6" 251 | source = "registry+https://github.com/rust-lang/crates.io-index" 252 | 253 | [[package]] 254 | name = "num_cpus" 255 | version = "1.8.0" 256 | source = "registry+https://github.com/rust-lang/crates.io-index" 257 | dependencies = [ 258 | "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", 259 | ] 260 | 261 | [[package]] 262 | name = "pairing" 263 | version = "0.16.2" 264 | source = "git+https://github.com/matterinc/pairing?tag=0.16.2#c2af46cac3e6ebc8e1e1f37bb993e5e6c7f689d1" 265 | dependencies = [ 266 | "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", 267 | "ff 0.5.0 (git+https://github.com/matterinc/ff?tag=0.5)", 268 | "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", 269 | "rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", 270 | "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", 271 | "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", 272 | "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", 273 | ] 274 | 275 | [[package]] 276 | name = "plasma_cash_history_snark" 277 | version = "0.1.0" 278 | dependencies = [ 279 | "bellman 0.2.0 (git+https://github.com/matterinc/bellman?tag=0.2.0)", 280 | "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", 281 | "num-bigint 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 282 | "rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", 283 | "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", 284 | "sapling-crypto 0.0.4 (git+https://github.com/matterinc/sapling-crypto?tag=0.0.4)", 285 | "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", 286 | ] 287 | 288 | [[package]] 289 | name = "proc-macro2" 290 | version = "0.4.24" 291 | source = "registry+https://github.com/rust-lang/crates.io-index" 292 | dependencies = [ 293 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 294 | ] 295 | 296 | [[package]] 297 | name = "quote" 298 | version = "0.6.10" 299 | source = "registry+https://github.com/rust-lang/crates.io-index" 300 | dependencies = [ 301 | "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", 302 | ] 303 | 304 | [[package]] 305 | name = "rand" 306 | version = "0.3.22" 307 | source = "registry+https://github.com/rust-lang/crates.io-index" 308 | dependencies = [ 309 | "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 310 | "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", 311 | "rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", 312 | ] 313 | 314 | [[package]] 315 | name = "rand" 316 | version = "0.4.3" 317 | source = "registry+https://github.com/rust-lang/crates.io-index" 318 | dependencies = [ 319 | "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 320 | "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", 321 | "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", 322 | ] 323 | 324 | [[package]] 325 | name = "redox_syscall" 326 | version = "0.1.43" 327 | source = "registry+https://github.com/rust-lang/crates.io-index" 328 | 329 | [[package]] 330 | name = "rust-crypto" 331 | version = "0.2.36" 332 | source = "registry+https://github.com/rust-lang/crates.io-index" 333 | dependencies = [ 334 | "gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)", 335 | "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", 336 | "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", 337 | "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", 338 | "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", 339 | ] 340 | 341 | [[package]] 342 | name = "rustc-serialize" 343 | version = "0.3.24" 344 | source = "registry+https://github.com/rust-lang/crates.io-index" 345 | 346 | [[package]] 347 | name = "ryu" 348 | version = "0.2.7" 349 | source = "registry+https://github.com/rust-lang/crates.io-index" 350 | 351 | [[package]] 352 | name = "sapling-crypto" 353 | version = "0.0.4" 354 | source = "git+https://github.com/matterinc/sapling-crypto?tag=0.0.4#6ac48e2f920bd54358b7a4cca0a96f87753009e4" 355 | dependencies = [ 356 | "bellman 0.2.0 (git+https://github.com/matterinc/bellman?tag=0.2.0)", 357 | "blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9)", 358 | "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", 359 | "digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", 360 | "rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", 361 | "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", 362 | "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", 363 | "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", 364 | ] 365 | 366 | [[package]] 367 | name = "scopeguard" 368 | version = "0.3.3" 369 | source = "registry+https://github.com/rust-lang/crates.io-index" 370 | 371 | [[package]] 372 | name = "serde" 373 | version = "1.0.89" 374 | source = "registry+https://github.com/rust-lang/crates.io-index" 375 | 376 | [[package]] 377 | name = "serde_derive" 378 | version = "1.0.89" 379 | source = "registry+https://github.com/rust-lang/crates.io-index" 380 | dependencies = [ 381 | "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", 382 | "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", 383 | "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", 384 | ] 385 | 386 | [[package]] 387 | name = "serde_json" 388 | version = "1.0.39" 389 | source = "registry+https://github.com/rust-lang/crates.io-index" 390 | dependencies = [ 391 | "itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", 392 | "ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", 393 | "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", 394 | ] 395 | 396 | [[package]] 397 | name = "smallvec" 398 | version = "0.6.9" 399 | source = "registry+https://github.com/rust-lang/crates.io-index" 400 | 401 | [[package]] 402 | name = "syn" 403 | version = "0.14.9" 404 | source = "registry+https://github.com/rust-lang/crates.io-index" 405 | dependencies = [ 406 | "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", 407 | "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", 408 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 409 | ] 410 | 411 | [[package]] 412 | name = "syn" 413 | version = "0.15.29" 414 | source = "registry+https://github.com/rust-lang/crates.io-index" 415 | dependencies = [ 416 | "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", 417 | "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", 418 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 419 | ] 420 | 421 | [[package]] 422 | name = "time" 423 | version = "0.1.40" 424 | source = "registry+https://github.com/rust-lang/crates.io-index" 425 | dependencies = [ 426 | "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", 427 | "redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", 428 | "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", 429 | ] 430 | 431 | [[package]] 432 | name = "tiny-keccak" 433 | version = "1.4.2" 434 | source = "registry+https://github.com/rust-lang/crates.io-index" 435 | dependencies = [ 436 | "crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 437 | ] 438 | 439 | [[package]] 440 | name = "typenum" 441 | version = "1.10.0" 442 | source = "registry+https://github.com/rust-lang/crates.io-index" 443 | 444 | [[package]] 445 | name = "unicode-xid" 446 | version = "0.1.0" 447 | source = "registry+https://github.com/rust-lang/crates.io-index" 448 | 449 | [[package]] 450 | name = "winapi" 451 | version = "0.3.6" 452 | source = "registry+https://github.com/rust-lang/crates.io-index" 453 | dependencies = [ 454 | "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 455 | "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 456 | ] 457 | 458 | [[package]] 459 | name = "winapi-i686-pc-windows-gnu" 460 | version = "0.4.0" 461 | source = "registry+https://github.com/rust-lang/crates.io-index" 462 | 463 | [[package]] 464 | name = "winapi-x86_64-pc-windows-gnu" 465 | version = "0.4.0" 466 | source = "registry+https://github.com/rust-lang/crates.io-index" 467 | 468 | [metadata] 469 | "checksum arrayvec 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "f405cc4c21cd8b784f6c8fc2adf9bc00f59558f0049b5ec21517f875963040cc" 470 | "checksum bellman 0.2.0 (git+https://github.com/matterinc/bellman?tag=0.2.0)" = "" 471 | "checksum bit-vec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "02b4ff8b16e6076c3e14220b39fbc1fabb6737522281a388998046859400895f" 472 | "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" 473 | "checksum blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9)" = "" 474 | "checksum byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94f88df23a25417badc922ab0f5716cc1330e87f71ddd9203b3a3ccd9cedf75d" 475 | "checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4" 476 | "checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e" 477 | "checksum crossbeam 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b14492071ca110999a20bf90e3833406d5d66bfd93b4e52ec9539025ff43fe0d" 478 | "checksum crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "0f0ed1a4de2235cabda8558ff5840bffb97fcb64c97827f354a451307df5f72b" 479 | "checksum crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b18cd2e169ad86297e6bc0ad9aa679aee9daa4f19e8163860faf7c164e4f5a71" 480 | "checksum crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "04c9e3102cc2d69cd681412141b390abd55a362afc1540965dad0ad4d34280b4" 481 | "checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b" 482 | "checksum crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f8306fcef4a7b563b76b7dd949ca48f52bc1141aa067d2ea09565f3e2652aa5c" 483 | "checksum crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a2f4a431c5c9f662e1200b7c7f02c34e91361150e382089a8f2dec3ba680cbda" 484 | "checksum digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "03b072242a8cbaf9c145665af9d250c59af3b958f83ed6824e13533cf76d5b90" 485 | "checksum ff 0.5.0 (git+https://github.com/matterinc/ff?tag=0.5)" = "" 486 | "checksum ff_derive 0.4.0 (git+https://github.com/matterinc/ff?tag=0.5)" = "" 487 | "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" 488 | "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" 489 | "checksum futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)" = "49e7653e374fe0d0c12de4250f0bdb60680b8c80eed558c5c7538eec9c89e21b" 490 | "checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" 491 | "checksum gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" 492 | "checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d" 493 | "checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" 494 | "checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b" 495 | "checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" 496 | "checksum libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)" = "10923947f84a519a45c8fefb7dd1b3e8c08747993381adee176d7a82b4195311" 497 | "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" 498 | "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" 499 | "checksum num-bigint 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "10b8423ea72ec64751198856a853e07b37087cfc9b53a87ecb19bff67b6d1320" 500 | "checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea" 501 | "checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1" 502 | "checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" 503 | "checksum pairing 0.16.2 (git+https://github.com/matterinc/pairing?tag=0.16.2)" = "" 504 | "checksum proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)" = "77619697826f31a02ae974457af0b29b723e5619e113e9397b8b82c6bd253f09" 505 | "checksum quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "53fa22a1994bd0f9372d7a816207d8a2677ad0325b073f5c5332760f0fb62b5c" 506 | "checksum rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "15a732abf9d20f0ad8eeb6f909bf6868722d9a06e1e50802b6a70351f40b4eb1" 507 | "checksum rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8356f47b32624fef5b3301c1be97e5944ecdd595409cc5da11d05f211db6cfbd" 508 | "checksum redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "679da7508e9a6390aeaf7fbd02a800fdc64b73fe2204dd2c8ae66d22d9d5ad5d" 509 | "checksum rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a" 510 | "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" 511 | "checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7" 512 | "checksum sapling-crypto 0.0.4 (git+https://github.com/matterinc/sapling-crypto?tag=0.0.4)" = "" 513 | "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" 514 | "checksum serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)" = "92514fb95f900c9b5126e32d020f5c6d40564c27a5ea6d1d7d9f157a96623560" 515 | "checksum serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)" = "bb6eabf4b5914e88e24eea240bb7c9f9a2cbc1bbbe8d961d381975ec3c6b806c" 516 | "checksum serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)" = "5a23aa71d4a4d43fdbfaac00eff68ba8a06a51759a89ac3304323e800c4dd40d" 517 | "checksum smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c4488ae950c49d403731982257768f48fada354a5203fe81f9bb6f43ca9002be" 518 | "checksum syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)" = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741" 519 | "checksum syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)" = "1825685f977249735d510a242a6727b46efe914bb67e38d30c071b1b72b1d5c2" 520 | "checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b" 521 | "checksum tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e9175261fbdb60781fcd388a4d6cc7e14764a2b629a7ad94abb439aed223a44f" 522 | "checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" 523 | "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" 524 | "checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" 525 | "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 526 | "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 527 | --------------------------------------------------------------------------------