From 8ea942ca732bc20d9478e4101fc667b1b7d7b03a Mon Sep 17 00:00:00 2001 From: Tom Shen Date: Thu, 7 Oct 2021 22:09:50 -0700 Subject: [PATCH 01/10] add poW interface --- src/lib.rs | 1 + src/pow/mod.rs | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 src/pow/mod.rs diff --git a/src/lib.rs b/src/lib.rs index f1de5d1c..4cfb9f72 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,6 +22,7 @@ pub mod crh; pub mod merkle_tree; pub mod encryption; +pub mod pow; pub mod prf; pub mod signature; pub mod snark; diff --git a/src/pow/mod.rs b/src/pow/mod.rs new file mode 100644 index 00000000..f5935fbd --- /dev/null +++ b/src/pow/mod.rs @@ -0,0 +1,91 @@ +use ark_std::rand::Rng; + +/// Any cryptographic hash implementation will satisfy those two properties: +/// - **Preimage Resistance**: For all adversary, given y = H(x) where x is +/// random, the probability to find z such that H(z) = y is negligible. +/// - **Collision Resistant**: It's computationally infeasible to find two +/// distinct inputs to lead to same output. This property is also satisfied by +/// CRH trait implementors. +pub trait CryptoHash { + /// Parameter for the crypto hash. + type Parameters; + /// Input of the hash. + type Input; + /// Output of the Hash. + type Output; + /// Generate the parameter for the crypto hash using `rng`. + fn setup(rng: &mut R) -> &Self::Parameters; + + /// Given the input and parameters, compute the output. + fn digest(param: &Self::Parameters, input: &Self::Input) -> Self::Output; +} + +/// An extension trait for `CryptoHash`. Any implementation can be used for +/// proof of work. +/// +/// A valid proof of work with difficulty `k` will have `H(M||Nonce)` that make +/// `verify(M, Nonce, k)` output true. In most cases, `verify` outputs true +/// when the bit composition of output has `k` trailing zeroes, but this trait +/// allows implementation to implement their own `verify` logic. +pub trait PoW: CryptoHash { + /// Nonce used with input, such that a valid proof of work for input `M` and + /// difficulty `k` will have `H(M||Nonce)` that make `verify(M, Nonce, + /// k)` output true. In most cases, `verify` outputs true when the bit + /// composition of output has `k` trailing zeroes, but this trait allows + /// implementation to implement their own `verify` logic. + type Nonce; + + /// Given input and nonce, check whether `H(input||nonce)` is a valid proof + /// of work under certain difficulty. + fn verify( + param: &Self::Parameters, + input: &Self::Input, + nonce: &Self::Nonce, + difficulty: usize, + ) -> bool; + + /// Given input and a list of nonces, batch verify the correctness of nonce + /// under given difficulty. + fn batch_verify( + param: &Self::Parameters, + input: &Self::Input, + nonces: &[Self::Nonce], + difficulty: usize, + ) -> Vec { + cfg_iter!(nonces) + .map(|nonce| Self::verify(param, input, nonce, difficulty)) + .collect() + } + + /// Return the initial nonce that can be used for PoW generation. + fn initial_nonce(param: &Self::Parameters) -> Self::Nonce; + + /// Return the next nonce for PoW Generation. + fn next_nonce(param: &Self::Parameters, nonce: Self::Nonce) -> Self::Nonce; + + /// Generate initial batch of nonces. + fn initial_nonce_batch(param: &Self::Parameters, batch_size: usize) -> Vec { + todo!() + } + + /// Given the last element of previous batch, return the next nonce batch. + fn next_nonce_batch( + param: &Self::Parameters, + prev_nonce: Self::Nonce, + batch_size: usize, + ) -> Vec { + todo!() + } + + /// Generate the nonce as proof of work such that H(input||nonce) is valid + /// under given difficulty. + /// This function will run `verify` on a batch of `nonces` for iteration. + fn generate_pow( + param: &Self::Parameters, + input: &Self::Input, + difficulty: usize, + batch_size: usize, + ) -> Self::Nonce { + todo!() + } +} From f2f55aa8887c5befa530c84ec7b8c9316b2d0060 Mon Sep 17 00:00:00 2001 From: Tom Shen Date: Thu, 7 Oct 2021 22:34:39 -0700 Subject: [PATCH 02/10] update api --- src/pow/mod.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/pow/mod.rs b/src/pow/mod.rs index f5935fbd..43211bf3 100644 --- a/src/pow/mod.rs +++ b/src/pow/mod.rs @@ -1,4 +1,7 @@ +#![allow(unused_variables)] // TODO: remove after finished this use ark_std::rand::Rng; +#[cfg(feature = "parallel")] +use rayon::prelude::*; /// Any cryptographic hash implementation will satisfy those two properties: /// - **Preimage Resistance**: For all adversary, given y = H(x) where x is @@ -8,9 +11,9 @@ use ark_std::rand::Rng; /// CRH trait implementors. pub trait CryptoHash { /// Parameter for the crypto hash. - type Parameters; + type Parameters: Sync; /// Input of the hash. - type Input; + type Input: Sync; /// Output of the Hash. type Output; /// Generate the parameter for the crypto hash using `rng`. @@ -33,7 +36,7 @@ pub trait PoW: CryptoHash { /// k)` output true. In most cases, `verify` outputs true when the bit /// composition of output has `k` trailing zeroes, but this trait allows /// implementation to implement their own `verify` logic. - type Nonce; + type Nonce: Clone + Sync; /// Given input and nonce, check whether `H(input||nonce)` is a valid proof /// of work under certain difficulty. From be56bac1bbd1315b688a903ebed067c6a4872857 Mon Sep 17 00:00:00 2001 From: Tom Shen Date: Sun, 10 Oct 2021 20:00:00 -0700 Subject: [PATCH 03/10] poW interface --- src/pow/mod.rs | 45 +++++++++++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/src/pow/mod.rs b/src/pow/mod.rs index 43211bf3..9be6a9ba 100644 --- a/src/pow/mod.rs +++ b/src/pow/mod.rs @@ -1,4 +1,6 @@ -#![allow(unused_variables)] // TODO: remove after finished this +pub mod poseidon; + +// TODO: remove after finished this use ark_std::rand::Rng; #[cfg(feature = "parallel")] use rayon::prelude::*; @@ -61,34 +63,49 @@ pub trait PoW: CryptoHash { } /// Return the initial nonce that can be used for PoW generation. - fn initial_nonce(param: &Self::Parameters) -> Self::Nonce; + fn initial_nonce(param: &Self::Parameters, rng: &mut R) -> Self::Nonce; /// Return the next nonce for PoW Generation. - fn next_nonce(param: &Self::Parameters, nonce: Self::Nonce) -> Self::Nonce; + fn next_nonce(param: &Self::Parameters, nonce: &Self::Nonce) -> Self::Nonce; /// Generate initial batch of nonces. - fn initial_nonce_batch(param: &Self::Parameters, batch_size: usize) -> Vec { - todo!() - } - - /// Given the last element of previous batch, return the next nonce batch. - fn next_nonce_batch( + fn batch_nonce( param: &Self::Parameters, - prev_nonce: Self::Nonce, + initial_nonce: Self::Nonce, batch_size: usize, ) -> Vec { - todo!() + let mut result = Vec::with_capacity(batch_size); + result.push(initial_nonce); + for _ in 0..batch_size - 1 { + result.push(Self::next_nonce(param, result.last().unwrap())); + } + + result } /// Generate the nonce as proof of work such that H(input||nonce) is valid /// under given difficulty. - /// This function will run `verify` on a batch of `nonces` for iteration. - fn generate_pow( + /// This function will repeatedly run `verify` on a batch of `nonces`, and + /// return the first nonce that successfully let `verify` return true. + fn generate_pow( param: &Self::Parameters, + rng: &mut R, input: &Self::Input, difficulty: usize, batch_size: usize, ) -> Self::Nonce { - todo!() + let mut nonces = Self::batch_nonce(param, Self::initial_nonce(param, rng), batch_size); + loop { + if let Some((i, _)) = Self::batch_verify(param, input, &nonces, difficulty) + .into_iter() + .enumerate() + .filter(|(_, v)| *v) + .next() + { + return nonces[i].clone(); + }; + let last_nonce = nonces.last().unwrap().clone(); + nonces = Self::batch_nonce(param, last_nonce, batch_size); + } } } From 5b3fc5d199e171c096158d3bbb4a5570e9152145 Mon Sep 17 00:00:00 2001 From: Tom Shen Date: Sun, 10 Oct 2021 21:55:47 -0700 Subject: [PATCH 04/10] proof of work native code --- src/merkle_tree/mod.rs | 99 ++++++++++++++++++++------------- src/merkle_tree/tests/mod.rs | 11 ++-- src/pow/mod.rs | 21 +++++-- src/pow/poseidon.rs | 104 +++++++++++++++++++++++++++++++++++ 4 files changed, 185 insertions(+), 50 deletions(-) create mode 100644 src/pow/poseidon.rs diff --git a/src/merkle_tree/mod.rs b/src/merkle_tree/mod.rs index 998dd125..ba38fb2a 100644 --- a/src/merkle_tree/mod.rs +++ b/src/merkle_tree/mod.rs @@ -5,24 +5,23 @@ use crate::crh::TwoToOneCRHScheme; use crate::{CRHScheme, Error}; use ark_ff::ToBytes; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, Read, SerializationError, Write}; -use ark_std::borrow::Borrow; -use ark_std::hash::Hash; -use ark_std::vec::Vec; +use ark_std::{borrow::Borrow, hash::Hash, vec::Vec}; #[cfg(test)] -mod tests; +pub(crate) mod tests; #[cfg(feature = "r1cs")] pub mod constraints; -/// Convert the hash digest in different layers by converting previous layer's output to -/// `TargetType`, which is a `Borrow` to next layer's input. +/// Convert the hash digest in different layers by converting previous layer's +/// output to `TargetType`, which is a `Borrow` to next layer's input. pub trait DigestConverter { type TargetType: Borrow; fn convert(item: From) -> Result; } -/// A trivial converter where digest of previous layer's hash is the same as next layer's input. +/// A trivial converter where digest of previous layer's hash is the same as +/// next layer's input. pub struct IdentityDigestConverter { _prev_layer_digest: T, } @@ -34,8 +33,8 @@ impl DigestConverter for IdentityDigestConverter { } } -/// Convert previous layer's digest to bytes and use bytes as input for next layer's digest. -/// TODO: `ToBytes` trait will be deprecated in future versions. +/// Convert previous layer's digest to bytes and use bytes as input for next +/// layer's digest. TODO: `ToBytes` trait will be deprecated in future versions. pub struct ByteDigestConverter { _prev_layer_digest: T, } @@ -44,15 +43,18 @@ impl DigestConverter for ByteDigestCon type TargetType = Vec; fn convert(item: T) -> Result { - // TODO: In some tests, `serialize` is not consistent with constraints. Try fix those. + // TODO: In some tests, `serialize` is not consistent with constraints. Try fix + // those. Ok(crate::to_unchecked_bytes!(item)?) } } /// Merkle tree have three types of hashes. /// * `LeafHash`: Convert leaf to leaf digest -/// * `TwoLeavesToOneHash`: Convert two leaf digests to one inner digest. This one can be a wrapped -/// version `TwoHashesToOneHash`, which first converts leaf digest to inner digest. +/// * `TwoLeavesToOneHash`: Convert two leaf digests to one inner digest. This +/// one can be a wrapped +/// version `TwoHashesToOneHash`, which first converts leaf digest to inner +/// digest. /// * `TwoHashesToOneHash`: Compress two inner digests to one inner digest pub trait Config { type Leaf: ?Sized; // merkle tree does not store the leaf @@ -80,12 +82,14 @@ pub trait Config { + CanonicalSerialize + CanonicalDeserialize; - // Tom's Note: in the future, if we want different hash function, we can simply add more - // types of digest here and specify a digest converter. Same for constraints. + // Tom's Note: in the future, if we want different hash function, we can simply + // add more types of digest here and specify a digest converter. Same for + // constraints. /// leaf -> leaf digest - /// If leaf hash digest and inner hash digest are different, we can create a new - /// leaf hash which wraps the original leaf hash and convert its output to `Digest`. + /// If leaf hash digest and inner hash digest are different, we can create a + /// new leaf hash which wraps the original leaf hash and convert its + /// output to `Digest`. type LeafHash: CRHScheme; /// 2 inner digest -> inner digest type TwoToOneHash: TwoToOneCRHScheme; @@ -105,7 +109,8 @@ pub type LeafParam

= <

::LeafHash as CRHScheme>::Parameters; /// .. / \ .... /// [I] J /// ``` -/// Suppose we want to prove I, then `leaf_sibling_hash` is J, `auth_path` is `[C,D]` +/// Suppose we want to prove I, then `leaf_sibling_hash` is J, `auth_path` is +/// `[C,D]` #[derive(Derivative, CanonicalSerialize, CanonicalDeserialize)] #[derivative( Clone(bound = "P: Config"), @@ -114,17 +119,20 @@ pub type LeafParam

= <

::LeafHash as CRHScheme>::Parameters; )] pub struct Path { pub leaf_sibling_hash: P::LeafDigest, - /// The sibling of path node ordered from higher layer to lower layer (does not include root node). + /// The sibling of path node ordered from higher layer to lower layer (does + /// not include root node). pub auth_path: Vec, /// stores the leaf index of the node pub leaf_index: usize, } impl Path

{ - /// The position of on_path node in `leaf_and_sibling_hash` and `non_leaf_and_sibling_hash_path`. - /// `position[i]` is 0 (false) iff `i`th on-path node from top to bottom is on the left. + /// The position of on_path node in `leaf_and_sibling_hash` and + /// `non_leaf_and_sibling_hash_path`. `position[i]` is 0 (false) iff + /// `i`th on-path node from top to bottom is on the left. /// - /// This function simply converts `self.leaf_index` to boolean array in big endian form. + /// This function simply converts `self.leaf_index` to boolean array in big + /// endian form. #[allow(unused)] // this function is actually used when r1cs feature is on fn position_list(&'_ self) -> impl '_ + Iterator { (0..self.auth_path.len() + 1) @@ -137,7 +145,8 @@ impl Path

{ /// Verify that a leaf is at `self.index` of the merkle tree. /// * `leaf_size`: leaf size in number of bytes /// - /// `verify` infers the tree height by setting `tree_height = self.auth_path.len() + 2` + /// `verify` infers the tree height by setting `tree_height = + /// self.auth_path.len() + 2` pub fn verify>( &self, leaf_hash_params: &LeafParam

, @@ -184,8 +193,9 @@ impl Path

{ /// `index` is the first `path.len()` bits of /// the position of tree. /// -/// If the least significant bit of `index` is 0, then `sibling` will be left and `computed` will be right. -/// Otherwise, `sibling` will be right and `computed` will be left. +/// If the least significant bit of `index` is 0, then `sibling` will be left +/// and `computed` will be right. Otherwise, `sibling` will be right and +/// `computed` will be left. /// /// Returns: (left, right) fn select_left_right_child( @@ -203,17 +213,21 @@ fn select_left_right_child( } /// Defines a merkle tree data structure. -/// This merkle tree has runtime fixed height, and assumes number of leaves is 2^height. +/// This merkle tree has runtime fixed height, and assumes number of leaves is +/// 2^height. /// /// TODO: add RFC-6962 compatible merkle tree in the future. -/// For this release, padding will not be supported because of security concerns: if the leaf hash and two to one hash uses same underlying -/// CRH, a malicious prover can prove a leaf while the actual node is an inner node. In the future, we can prefix leaf hashes in different layers to +/// For this release, padding will not be supported because of security +/// concerns: if the leaf hash and two to one hash uses same underlying +/// CRH, a malicious prover can prove a leaf while the actual node is an inner +/// node. In the future, we can prefix leaf hashes in different layers to /// solve the problem. #[derive(Derivative)] #[derivative(Clone(bound = "P: Config"))] pub struct MerkleTree { - /// stores the non-leaf nodes in level order. The first element is the root node. - /// The ith nodes (starting at 1st) children are at indices `2*i`, `2*i+1` + /// stores the non-leaf nodes in level order. The first element is the root + /// node. The ith nodes (starting at 1st) children are at indices `2*i`, + /// `2*i+1` non_leaf_nodes: Vec, /// store the hash of leaf nodes from left to right leaf_nodes: Vec, @@ -227,7 +241,8 @@ pub struct MerkleTree { impl MerkleTree

{ /// Create an empty merkle tree such that all leaves are zero-filled. - /// Consider using a sparse merkle tree if you need the tree to be low memory + /// Consider using a sparse merkle tree if you need the tree to be low + /// memory pub fn blank( leaf_hash_param: &LeafParam

, two_to_one_hash_param: &TwoToOneParam

, @@ -288,9 +303,10 @@ impl MerkleTree

{ let start_index = level_indices.pop().unwrap(); let upper_bound = left_child(start_index); for current_index in start_index..upper_bound { - // `left_child(current_index)` and `right_child(current_index) returns the position of - // leaf in the whole tree (represented as a list in level order). We need to shift it - // by `-upper_bound` to get the index in `leaf_nodes` list. + // `left_child(current_index)` and `right_child(current_index) returns the + // position of leaf in the whole tree (represented as a list in + // level order). We need to shift it by `-upper_bound` to get + // the index in `leaf_nodes` list. let left_leaf_index = left_child(current_index) - upper_bound; let right_leaf_index = right_child(current_index) - upper_bound; // compute hash @@ -352,9 +368,11 @@ impl MerkleTree

{ self.leaf_nodes[index - 1].clone() }; - // path.len() = `tree height - 2`, the two missing elements being the leaf sibling hash and the root + // path.len() = `tree height - 2`, the two missing elements being the leaf + // sibling hash and the root let mut path = Vec::with_capacity(tree_height - 2); - // Iterate from the bottom layer after the leaves, to the top, storing all sibling node's hash values. + // Iterate from the bottom layer after the leaves, to the top, storing all + // sibling node's hash values. let mut current_node = parent(leaf_index_in_tree).unwrap(); while !is_root(current_node) { let sibling_node = sibling(current_node).unwrap(); @@ -374,8 +392,9 @@ impl MerkleTree

{ }) } - /// Given the index and new leaf, return the hash of leaf and an updated path in order from root to bottom non-leaf level. - /// This does not mutate the underlying tree. + /// Given the index and new leaf, return the hash of leaf and an updated + /// path in order from root to bottom non-leaf level. This does not + /// mutate the underlying tree. fn updated_path>( &self, index: usize, @@ -438,7 +457,8 @@ impl MerkleTree

{ /// .. / \ .... /// [I] J /// ``` - /// update(3, {new leaf}) would swap the leaf value at `[I]` and cause a recomputation of `[A]`, `[B]`, and `[E]`. + /// update(3, {new leaf}) would swap the leaf value at `[I]` and cause a + /// recomputation of `[A]`, `[B]`, and `[E]`. pub fn update(&mut self, index: usize, new_leaf: &P::Leaf) -> Result<(), crate::Error> { assert!(index < self.leaf_nodes.len(), "index out of range"); let (updated_leaf_hash, mut updated_path) = self.updated_path(index, new_leaf)?; @@ -451,7 +471,8 @@ impl MerkleTree

{ Ok(()) } - /// Update the leaf and check if the updated root is equal to `asserted_new_root`. + /// Update the leaf and check if the updated root is equal to + /// `asserted_new_root`. /// /// Tree will not be modified if the check fails. pub fn check_update>( diff --git a/src/merkle_tree/tests/mod.rs b/src/merkle_tree/tests/mod.rs index 1d1296c0..6a66d7c7 100644 --- a/src/merkle_tree/tests/mod.rs +++ b/src/merkle_tree/tests/mod.rs @@ -1,6 +1,6 @@ #[cfg(feature = "r1cs")] mod constraints; -mod test_utils; +pub(crate) mod test_utils; mod bytes_mt_tests { @@ -119,10 +119,11 @@ mod bytes_mt_tests { } mod field_mt_tests { - use crate::crh::poseidon; - use crate::merkle_tree::tests::test_utils::poseidon_parameters; - use crate::merkle_tree::{Config, IdentityDigestConverter}; - use crate::MerkleTree; + use crate::{ + crh::poseidon, + merkle_tree::{tests::test_utils::poseidon_parameters, Config, IdentityDigestConverter}, + MerkleTree, + }; use ark_std::{test_rng, One, UniformRand}; type F = ark_ed_on_bls12_381::Fr; diff --git a/src/pow/mod.rs b/src/pow/mod.rs index 9be6a9ba..63923411 100644 --- a/src/pow/mod.rs +++ b/src/pow/mod.rs @@ -1,7 +1,11 @@ pub mod poseidon; -// TODO: remove after finished this +use ark_std::borrow::Borrow; + use ark_std::rand::Rng; + +use ark_std::vec::Vec; + #[cfg(feature = "parallel")] use rayon::prelude::*; @@ -15,14 +19,14 @@ pub trait CryptoHash { /// Parameter for the crypto hash. type Parameters: Sync; /// Input of the hash. - type Input: Sync; + type Input: Sync + ?Sized; /// Output of the Hash. type Output; /// Generate the parameter for the crypto hash using `rng`. fn setup(rng: &mut R) -> &Self::Parameters; /// Given the input and parameters, compute the output. - fn digest(param: &Self::Parameters, input: &Self::Input) -> Self::Output; + fn digest>(param: &Self::Parameters, input: T) -> Self::Output; } /// An extension trait for `CryptoHash`. Any implementation can be used for @@ -87,14 +91,18 @@ pub trait PoW: CryptoHash { /// under given difficulty. /// This function will repeatedly run `verify` on a batch of `nonces`, and /// return the first nonce that successfully let `verify` return true. + /// + /// This function return the first valid nonce and number of batches it has + /// iterated. fn generate_pow( param: &Self::Parameters, rng: &mut R, input: &Self::Input, difficulty: usize, batch_size: usize, - ) -> Self::Nonce { + ) -> (Self::Nonce, usize) { let mut nonces = Self::batch_nonce(param, Self::initial_nonce(param, rng), batch_size); + let mut counter = 0; loop { if let Some((i, _)) = Self::batch_verify(param, input, &nonces, difficulty) .into_iter() @@ -102,10 +110,11 @@ pub trait PoW: CryptoHash { .filter(|(_, v)| *v) .next() { - return nonces[i].clone(); + return (nonces[i].clone(), counter); }; let last_nonce = nonces.last().unwrap().clone(); - nonces = Self::batch_nonce(param, last_nonce, batch_size); + nonces = Self::batch_nonce(param, Self::next_nonce(param, &last_nonce), batch_size); + counter += 1; } } } diff --git a/src/pow/poseidon.rs b/src/pow/poseidon.rs new file mode 100644 index 00000000..c73db4c7 --- /dev/null +++ b/src/pow/poseidon.rs @@ -0,0 +1,104 @@ +use ark_std::borrow::Borrow; + +use ark_sponge::{ + poseidon::{PoseidonParameters, PoseidonSponge}, + Absorb, CryptographicSponge, +}; +use ark_std::marker::PhantomData; + +use ark_ff::{BitIteratorLE, PrimeField}; + +use ark_std::vec::Vec; + +use super::{CryptoHash, PoW}; + +/// A wrapper to poseidon cryptographic sponge. +pub struct PoseidonHash { + _field: PhantomData, + _input: PhantomData, +} + +impl CryptoHash for PoseidonHash { + type Parameters = PoseidonParameters; + + type Input = I; + + type Output = F; + + fn setup(_rng: &mut R) -> &Self::Parameters { + // automatic generation of parameters are not implemented yet + // therefore, the developers must specify the parameters themselves + unimplemented!() + } + + fn digest>(param: &Self::Parameters, input: T) -> Self::Output { + let input = input.borrow(); + + let mut sponge = PoseidonSponge::new(param); + sponge.absorb(input); + + let res = sponge.squeeze_field_elements::(1); + res[0] + } +} + +impl PoW for PoseidonHash { + type Nonce = F; + + fn verify( + param: &Self::Parameters, + input: &Self::Input, + nonce: &Self::Nonce, + difficulty: usize, + ) -> bool { + assert!(F::size_in_bits() >= 20, "difficulty is too large"); + let input = input.borrow(); + + let mut sponge = PoseidonSponge::new(param); + sponge.absorb(input); + sponge.absorb(nonce); + + let res = sponge.squeeze_field_elements::(1)[0]; + // we requires the least significant `difficulty` bits are zero + let res = BitIteratorLE::new(res.into_repr()) + .take(difficulty) + .collect::>(); + res.into_iter().all(|x| !x) + } + + fn initial_nonce(_param: &Self::Parameters, rng: &mut R) -> Self::Nonce { + // Start with a random position. + F::rand(rng) + } + + fn next_nonce(_param: &Self::Parameters, nonce: &Self::Nonce) -> Self::Nonce { + *nonce + F::one() + } +} + +#[cfg(test)] +mod tests { + use ark_std::test_rng; + + use crate::{merkle_tree::tests::test_utils::poseidon_parameters, pow::PoW}; + + use super::PoseidonHash; + #[test] + fn test_pow() { + const BATCH_SIZE: usize = 64; + const DIFFICULTY: usize = 15; + let param = poseidon_parameters(); + let message = vec![0x11, 0x12, 0x13, 0x14, 0x15]; + let mut rng = test_rng(); + let (proof, num_batches_iterated) = + PoseidonHash::generate_pow(¶m, &mut rng, &&message[..], DIFFICULTY, BATCH_SIZE); + println!( + "total number of iterations: {}x{} = {}", + num_batches_iterated, + BATCH_SIZE, + num_batches_iterated * BATCH_SIZE + ); + let result = PoseidonHash::verify(¶m, &&message[..], &proof, DIFFICULTY); + assert!(result); + } +} From 8e8049b83ec3e25a1631ba6f5475aff45659126d Mon Sep 17 00:00:00 2001 From: Tom Shen Date: Mon, 11 Oct 2021 00:00:06 -0700 Subject: [PATCH 05/10] fix CI bug --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6cc570d1..3e82826e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,7 +3,7 @@ on: pull_request: push: branches: - - master + - main env: RUST_BACKTRACE: 1 From e342f9dfa2642b1894b6797e85e6693e067afc98 Mon Sep 17 00:00:00 2001 From: Tom Shen Date: Mon, 11 Oct 2021 21:31:59 -0700 Subject: [PATCH 06/10] PoW constraints midway --- src/pow/constraints/mod.rs | 54 ++++++++++++++++++++++++++ src/pow/constraints/poseidon.rs | 67 +++++++++++++++++++++++++++++++++ src/pow/mod.rs | 4 ++ src/pow/poseidon.rs | 2 +- 4 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 src/pow/constraints/mod.rs create mode 100644 src/pow/constraints/poseidon.rs diff --git a/src/pow/constraints/mod.rs b/src/pow/constraints/mod.rs new file mode 100644 index 00000000..21229b93 --- /dev/null +++ b/src/pow/constraints/mod.rs @@ -0,0 +1,54 @@ +pub mod poseidon; + +use ark_ff::PrimeField; +use ark_r1cs_std::{alloc::AllocVar, boolean::Boolean}; +use ark_relations::r1cs::{ConstraintSystemRef, SynthesisError}; +use ark_std::borrow::Borrow; + +use super::{CryptoHash, PoW}; + +/// R1CS Gadget for Crypto Hash. +pub trait CryptoHashGadget { + type Parameters; + /// Input of the hash + type InputVar: ?Sized; + /// Outout of the Hash + type OutputVar; + + /// Given the input var and parameters, compute the output var. + fn digest>( + cs: ConstraintSystemRef, + param: &Self::Parameters, + input: T, + ) -> Result; +} + +/// R1CS Gadget for Proof of Work +pub trait PoWGadget: CryptoHashGadget { + type NonceVar; + /// Given input var and nonce var, check whether `H(input||nonce)` is a + /// valid proof of work under certain difficulty. + fn verify( + cs: ConstraintSystemRef, + param: &Self::Parameters, + input: &Self::InputVar, + nonce: &Self::NonceVar, + difficulty: usize, + ) -> Result, SynthesisError>; +} + +/// Extension trait for crypto hash to get the gadget. +pub trait CryptoHashWithGadget: CryptoHash +where + >::OutputVar: AllocVar, +{ + type Gadget: CryptoHashGadget; +} + +/// Extension trait for PoW to get the gadget. +pub trait PoWWithGadget: PoW +where + >::OutputVar: AllocVar, +{ + type Gadget: PoWGadget; +} diff --git a/src/pow/constraints/poseidon.rs b/src/pow/constraints/poseidon.rs new file mode 100644 index 00000000..a0ee6eca --- /dev/null +++ b/src/pow/constraints/poseidon.rs @@ -0,0 +1,67 @@ +use ark_relations::r1cs::{ConstraintSystemRef, SynthesisError}; +use ark_sponge::{ + constraints::{AbsorbGadget, CryptographicSpongeVar}, + poseidon::{constraints::PoseidonSpongeVar, PoseidonParameters}, +}; +use ark_std::marker::PhantomData; + +use ark_ff::PrimeField; +use ark_r1cs_std::{boolean::Boolean, fields::fp::FpVar, ToBitsGadget}; + +use super::{CryptoHashGadget, PoWGadget}; + +pub struct PoseidonHashGadget> { + _field: PhantomData, + _input: PhantomData, +} + +impl> CryptoHashGadget for PoseidonHashGadget { + type Parameters = PoseidonParameters; + + type InputVar = I; + + type OutputVar = FpVar; + + fn digest>( + cs: ConstraintSystemRef, + params: &Self::Parameters, + input: T, + ) -> Result { + let input = input.borrow(); + let mut sponge = PoseidonSpongeVar::new(cs, params); + sponge.absorb(input)?; + + let res = sponge.squeeze_field_elements(1)?; + Ok(res[0].clone()) + } +} + +impl> PoWGadget for PoseidonHashGadget { + type NonceVar = FpVar; + + fn verify( + cs: ConstraintSystemRef, + params: &Self::Parameters, + input: &Self::InputVar, + nonce: &Self::NonceVar, + difficulty: usize, + ) -> Result, SynthesisError> { + assert!(F::size_in_bits() >= difficulty, "difficulty is too large"); + + let mut sponge = PoseidonSpongeVar::new(cs, params); + sponge.absorb(input)?; + sponge.absorb(nonce)?; + + let res = sponge.squeeze_field_elements(1)?[0].clone(); + // we require the least significant `difficulty` bits are zero. + let mut result = Boolean::TRUE; + + res.to_bits_le()? + .into_iter() + .try_for_each(|b| -> Result<(), SynthesisError> { + result = result.and(&b.not())?; + Ok(()) + })?; + Ok(result) + } +} diff --git a/src/pow/mod.rs b/src/pow/mod.rs index 63923411..370bb73b 100644 --- a/src/pow/mod.rs +++ b/src/pow/mod.rs @@ -1,3 +1,4 @@ +pub mod constraints; pub mod poseidon; use ark_std::borrow::Borrow; @@ -94,6 +95,9 @@ pub trait PoW: CryptoHash { /// /// This function return the first valid nonce and number of batches it has /// iterated. + /// + /// When `parallel` feature is on, for each batch, all nonces will be + /// checked in parallel. fn generate_pow( param: &Self::Parameters, rng: &mut R, diff --git a/src/pow/poseidon.rs b/src/pow/poseidon.rs index c73db4c7..05fe5920 100644 --- a/src/pow/poseidon.rs +++ b/src/pow/poseidon.rs @@ -51,7 +51,7 @@ impl PoW for PoseidonHash { nonce: &Self::Nonce, difficulty: usize, ) -> bool { - assert!(F::size_in_bits() >= 20, "difficulty is too large"); + assert!(F::size_in_bits() >= difficulty, "difficulty is too large"); let input = input.borrow(); let mut sponge = PoseidonSponge::new(param); From 1e596df9aa12a18ba63d7a0a84f89828a652dce2 Mon Sep 17 00:00:00 2001 From: Tom Shen Date: Wed, 13 Oct 2021 22:39:54 -0700 Subject: [PATCH 07/10] update constraints and tests --- src/cryptographic_hash/constraints/mod.rs | 22 +++++ .../constraints/poseidon.rs | 73 +++++++++++++++ src/cryptographic_hash/mod.rs | 29 ++++++ src/cryptographic_hash/poseidon.rs | 41 +++++++++ src/lib.rs | 1 + src/pow/constraints/mod.rs | 25 ++---- src/pow/constraints/poseidon.rs | 89 ++++++++++++------- src/pow/mod.rs | 39 +++----- src/pow/poseidon.rs | 57 ++++-------- 9 files changed, 258 insertions(+), 118 deletions(-) create mode 100644 src/cryptographic_hash/constraints/mod.rs create mode 100644 src/cryptographic_hash/constraints/poseidon.rs create mode 100644 src/cryptographic_hash/mod.rs create mode 100644 src/cryptographic_hash/poseidon.rs diff --git a/src/cryptographic_hash/constraints/mod.rs b/src/cryptographic_hash/constraints/mod.rs new file mode 100644 index 00000000..eb59af13 --- /dev/null +++ b/src/cryptographic_hash/constraints/mod.rs @@ -0,0 +1,22 @@ +use ark_std::borrow::Borrow; + +use ark_ff::PrimeField; +use ark_relations::r1cs::{ConstraintSystemRef, SynthesisError}; + +pub mod poseidon; + +/// R1CS Gadget for Crypto Hash. +pub trait CryptoHashGadget { + type Parameters; + /// Input of the hash + type InputVar: ?Sized; + /// Outout of the Hash + type OutputVar; + + /// Given the input var and parameters, compute the output var. + fn digest>( + cs: ConstraintSystemRef, + param: &Self::Parameters, + input: T, + ) -> Result; +} diff --git a/src/cryptographic_hash/constraints/poseidon.rs b/src/cryptographic_hash/constraints/poseidon.rs new file mode 100644 index 00000000..7289633f --- /dev/null +++ b/src/cryptographic_hash/constraints/poseidon.rs @@ -0,0 +1,73 @@ +use std::{borrow::Borrow, marker::PhantomData}; + +use ark_ff::PrimeField; +use ark_r1cs_std::fields::fp::FpVar; +use ark_relations::r1cs::{ConstraintSystemRef, SynthesisError}; +use ark_sponge::{ + constraints::{AbsorbGadget, CryptographicSpongeVar}, + poseidon::{constraints::PoseidonSpongeVar, PoseidonParameters}, +}; + +use super::CryptoHashGadget; + +pub struct PoseidonHashGadget> { + _field: PhantomData, + _input: PhantomData, +} + +impl> CryptoHashGadget for PoseidonHashGadget { + type Parameters = PoseidonParameters; + + type InputVar = I; + + type OutputVar = FpVar; + + fn digest>( + cs: ConstraintSystemRef, + params: &Self::Parameters, + input: T, + ) -> Result { + let input = input.borrow(); + let mut sponge = PoseidonSpongeVar::new(cs, params); + sponge.absorb(input)?; + + let res = sponge.squeeze_field_elements(1)?; + Ok(res[0].clone()) + } +} + +#[cfg(test)] +mod tests { + use crate::{ + ark_std::UniformRand, + cryptographic_hash::{constraints::CryptoHashGadget, poseidon::PoseidonHash, CryptoHash}, + merkle_tree::tests::test_utils::poseidon_parameters, + }; + use ark_ed_on_bls12_381::Fr; + use ark_r1cs_std::{alloc::AllocVar, fields::fp::FpVar, R1CSVar}; + use ark_relations::r1cs::ConstraintSystem; + use ark_std::test_rng; + + use super::PoseidonHashGadget; + + #[test] + fn test_digest() { + let cs = ConstraintSystem::new_ref(); + let mut rng = test_rng(); + let input = (0..14).map(|_| Fr::rand(&mut rng)).collect::>(); + let input_var = input + .iter() + .map(|x| FpVar::new_witness(cs.clone(), || Ok(*x)).unwrap()) + .collect::>(); + + let param = poseidon_parameters(); + + let native_result = PoseidonHash::<_, &[Fr]>::digest(¶m, input.as_slice()); + let var_result = + PoseidonHashGadget::<_, &[FpVar<_>]>::digest(cs.clone(), ¶m, input_var.as_slice()) + .unwrap(); + + assert_eq!(native_result, var_result.value().unwrap()); + assert!(cs.is_satisfied().unwrap()); + } +} diff --git a/src/cryptographic_hash/mod.rs b/src/cryptographic_hash/mod.rs new file mode 100644 index 00000000..931e9dda --- /dev/null +++ b/src/cryptographic_hash/mod.rs @@ -0,0 +1,29 @@ +pub mod poseidon; + +#[cfg(feature = "r1cs")] +pub mod constraints; + +use ark_std::borrow::Borrow; + +use ark_std::rand::Rng; + +/// Any cryptographic hash implementation will satisfy those two properties: +/// - **Preimage Resistance**: For all adversary, given y = H(x) where x is +/// random, the probability to find z such that H(z) = y is negligible. +/// - **Collision Resistant**: It's computationally infeasible to find two +/// distinct inputs to lead to same output. This property is also satisfied by +/// CRH trait implementors. +/// - **One-way**: +pub trait CryptoHash { + /// Parameter for the crypto hash. + type Parameters: Sync; + /// Input of the hash. + type Input: Sync + ?Sized; + /// Output of the Hash. + type Output; + /// Generate the parameter for the crypto hash using `rng`. + fn setup(rng: &mut R) -> &Self::Parameters; + + /// Given the input and parameters, compute the output. + fn digest>(param: &Self::Parameters, input: T) -> Self::Output; +} diff --git a/src/cryptographic_hash/poseidon.rs b/src/cryptographic_hash/poseidon.rs new file mode 100644 index 00000000..8273496f --- /dev/null +++ b/src/cryptographic_hash/poseidon.rs @@ -0,0 +1,41 @@ +use ark_std::borrow::Borrow; + +use ark_std::marker::PhantomData; + +use ark_ff::PrimeField; +use ark_sponge::{ + poseidon::{PoseidonParameters, PoseidonSponge}, + Absorb, CryptographicSponge, +}; + +use super::CryptoHash; + +/// A wrapper to poseidon cryptographic sponge. +pub struct PoseidonHash { + _field: PhantomData, + _input: PhantomData, +} + +impl CryptoHash for PoseidonHash { + type Parameters = PoseidonParameters; + + type Input = I; + + type Output = F; + + fn setup(_rng: &mut R) -> &Self::Parameters { + // automatic generation of parameters are not implemented yet + // therefore, the developers must specify the parameters themselves + unimplemented!() + } + + fn digest>(param: &Self::Parameters, input: T) -> Self::Output { + let input = input.borrow(); + + let mut sponge = PoseidonSponge::new(param); + sponge.absorb(input); + + let res = sponge.squeeze_field_elements::(1); + res[0] + } +} diff --git a/src/lib.rs b/src/lib.rs index 4cfb9f72..c2a7d45e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,6 +21,7 @@ pub mod commitment; pub mod crh; pub mod merkle_tree; +pub mod cryptographic_hash; pub mod encryption; pub mod pow; pub mod prf; diff --git a/src/pow/constraints/mod.rs b/src/pow/constraints/mod.rs index 21229b93..ef22a65a 100644 --- a/src/pow/constraints/mod.rs +++ b/src/pow/constraints/mod.rs @@ -1,37 +1,24 @@ pub mod poseidon; +use ark_std::borrow::Borrow; + use ark_ff::PrimeField; use ark_r1cs_std::{alloc::AllocVar, boolean::Boolean}; use ark_relations::r1cs::{ConstraintSystemRef, SynthesisError}; -use ark_std::borrow::Borrow; -use super::{CryptoHash, PoW}; +use crate::cryptographic_hash::{constraints::CryptoHashGadget, CryptoHash}; -/// R1CS Gadget for Crypto Hash. -pub trait CryptoHashGadget { - type Parameters; - /// Input of the hash - type InputVar: ?Sized; - /// Outout of the Hash - type OutputVar; - - /// Given the input var and parameters, compute the output var. - fn digest>( - cs: ConstraintSystemRef, - param: &Self::Parameters, - input: T, - ) -> Result; -} +use super::PoW; /// R1CS Gadget for Proof of Work pub trait PoWGadget: CryptoHashGadget { type NonceVar; /// Given input var and nonce var, check whether `H(input||nonce)` is a /// valid proof of work under certain difficulty. - fn verify( + fn verify_pow>( cs: ConstraintSystemRef, param: &Self::Parameters, - input: &Self::InputVar, + input: T, nonce: &Self::NonceVar, difficulty: usize, ) -> Result, SynthesisError>; diff --git a/src/pow/constraints/poseidon.rs b/src/pow/constraints/poseidon.rs index a0ee6eca..52060c24 100644 --- a/src/pow/constraints/poseidon.rs +++ b/src/pow/constraints/poseidon.rs @@ -1,55 +1,32 @@ +use ark_std::borrow::Borrow; + use ark_relations::r1cs::{ConstraintSystemRef, SynthesisError}; use ark_sponge::{ constraints::{AbsorbGadget, CryptographicSpongeVar}, - poseidon::{constraints::PoseidonSpongeVar, PoseidonParameters}, + poseidon::constraints::PoseidonSpongeVar, }; -use ark_std::marker::PhantomData; use ark_ff::PrimeField; use ark_r1cs_std::{boolean::Boolean, fields::fp::FpVar, ToBitsGadget}; -use super::{CryptoHashGadget, PoWGadget}; - -pub struct PoseidonHashGadget> { - _field: PhantomData, - _input: PhantomData, -} - -impl> CryptoHashGadget for PoseidonHashGadget { - type Parameters = PoseidonParameters; - - type InputVar = I; +use crate::cryptographic_hash::constraints::poseidon::PoseidonHashGadget; - type OutputVar = FpVar; - - fn digest>( - cs: ConstraintSystemRef, - params: &Self::Parameters, - input: T, - ) -> Result { - let input = input.borrow(); - let mut sponge = PoseidonSpongeVar::new(cs, params); - sponge.absorb(input)?; - - let res = sponge.squeeze_field_elements(1)?; - Ok(res[0].clone()) - } -} +use super::PoWGadget; impl> PoWGadget for PoseidonHashGadget { type NonceVar = FpVar; - fn verify( + fn verify_pow>( cs: ConstraintSystemRef, params: &Self::Parameters, - input: &Self::InputVar, + input: T, nonce: &Self::NonceVar, difficulty: usize, ) -> Result, SynthesisError> { assert!(F::size_in_bits() >= difficulty, "difficulty is too large"); let mut sponge = PoseidonSpongeVar::new(cs, params); - sponge.absorb(input)?; + sponge.absorb(input.borrow())?; sponge.absorb(nonce)?; let res = sponge.squeeze_field_elements(1)?[0].clone(); @@ -58,6 +35,7 @@ impl> PoWGadget for PoseidonHashGadget Result<(), SynthesisError> { result = result.and(&b.not())?; Ok(()) @@ -65,3 +43,52 @@ impl> PoWGadget for PoseidonHashGadget>(); + let message_var = message + .iter() + .map(|x| FpVar::new_witness(cs.clone(), || Ok(x.clone())).unwrap()) + .collect::>(); + let (proof, _) = PoseidonHash::<_, &[_]>::generate_pow( + ¶m, + &mut rng, + message.as_slice(), + DIFFICULTY, + BATCH_SIZE, + ); + + let proof_var = FpVar::new_witness(cs.clone(), || Ok(proof)).unwrap(); + let result = PoseidonHashGadget::<_, &[_]>::verify_pow( + cs.clone(), + ¶m, + message_var.as_slice(), + &proof_var, + DIFFICULTY, + ) + .unwrap(); + assert!(result.value().unwrap()); + assert!(cs.is_satisfied().unwrap()); + } +} diff --git a/src/pow/mod.rs b/src/pow/mod.rs index 370bb73b..83e0a6fa 100644 --- a/src/pow/mod.rs +++ b/src/pow/mod.rs @@ -1,7 +1,8 @@ +#[cfg(feature = "r1cs")] pub mod constraints; pub mod poseidon; -use ark_std::borrow::Borrow; +use std::borrow::Borrow; use ark_std::rand::Rng; @@ -10,25 +11,7 @@ use ark_std::vec::Vec; #[cfg(feature = "parallel")] use rayon::prelude::*; -/// Any cryptographic hash implementation will satisfy those two properties: -/// - **Preimage Resistance**: For all adversary, given y = H(x) where x is -/// random, the probability to find z such that H(z) = y is negligible. -/// - **Collision Resistant**: It's computationally infeasible to find two -/// distinct inputs to lead to same output. This property is also satisfied by -/// CRH trait implementors. -pub trait CryptoHash { - /// Parameter for the crypto hash. - type Parameters: Sync; - /// Input of the hash. - type Input: Sync + ?Sized; - /// Output of the Hash. - type Output; - /// Generate the parameter for the crypto hash using `rng`. - fn setup(rng: &mut R) -> &Self::Parameters; - - /// Given the input and parameters, compute the output. - fn digest>(param: &Self::Parameters, input: T) -> Self::Output; -} +use crate::cryptographic_hash::CryptoHash; /// An extension trait for `CryptoHash`. Any implementation can be used for /// proof of work. @@ -47,23 +30,24 @@ pub trait PoW: CryptoHash { /// Given input and nonce, check whether `H(input||nonce)` is a valid proof /// of work under certain difficulty. - fn verify( + fn verify_pow>( param: &Self::Parameters, - input: &Self::Input, + input: T, nonce: &Self::Nonce, difficulty: usize, ) -> bool; /// Given input and a list of nonces, batch verify the correctness of nonce /// under given difficulty. - fn batch_verify( + fn batch_verify>( param: &Self::Parameters, - input: &Self::Input, + input: T, nonces: &[Self::Nonce], difficulty: usize, ) -> Vec { + let input = input.borrow(); cfg_iter!(nonces) - .map(|nonce| Self::verify(param, input, nonce, difficulty)) + .map(|nonce| Self::verify_pow(param, input, nonce, difficulty)) .collect() } @@ -98,13 +82,14 @@ pub trait PoW: CryptoHash { /// /// When `parallel` feature is on, for each batch, all nonces will be /// checked in parallel. - fn generate_pow( + fn generate_pow>( param: &Self::Parameters, rng: &mut R, - input: &Self::Input, + input: T, difficulty: usize, batch_size: usize, ) -> (Self::Nonce, usize) { + let input = input.borrow(); let mut nonces = Self::batch_nonce(param, Self::initial_nonce(param, rng), batch_size); let mut counter = 0; loop { diff --git a/src/pow/poseidon.rs b/src/pow/poseidon.rs index 05fe5920..d42961e2 100644 --- a/src/pow/poseidon.rs +++ b/src/pow/poseidon.rs @@ -1,57 +1,26 @@ -use ark_std::borrow::Borrow; +use std::borrow::Borrow; -use ark_sponge::{ - poseidon::{PoseidonParameters, PoseidonSponge}, - Absorb, CryptographicSponge, -}; -use ark_std::marker::PhantomData; +use ark_sponge::{poseidon::PoseidonSponge, Absorb, CryptographicSponge}; use ark_ff::{BitIteratorLE, PrimeField}; use ark_std::vec::Vec; -use super::{CryptoHash, PoW}; +use crate::cryptographic_hash::poseidon::PoseidonHash; -/// A wrapper to poseidon cryptographic sponge. -pub struct PoseidonHash { - _field: PhantomData, - _input: PhantomData, -} - -impl CryptoHash for PoseidonHash { - type Parameters = PoseidonParameters; - - type Input = I; - - type Output = F; - - fn setup(_rng: &mut R) -> &Self::Parameters { - // automatic generation of parameters are not implemented yet - // therefore, the developers must specify the parameters themselves - unimplemented!() - } - - fn digest>(param: &Self::Parameters, input: T) -> Self::Output { - let input = input.borrow(); - - let mut sponge = PoseidonSponge::new(param); - sponge.absorb(input); - - let res = sponge.squeeze_field_elements::(1); - res[0] - } -} +use super::PoW; impl PoW for PoseidonHash { type Nonce = F; - fn verify( + fn verify_pow>( param: &Self::Parameters, - input: &Self::Input, + input: T, nonce: &Self::Nonce, difficulty: usize, ) -> bool { assert!(F::size_in_bits() >= difficulty, "difficulty is too large"); + let input = input.borrow(); let mut sponge = PoseidonSponge::new(param); @@ -90,15 +59,21 @@ mod tests { let param = poseidon_parameters(); let message = vec![0x11, 0x12, 0x13, 0x14, 0x15]; let mut rng = test_rng(); - let (proof, num_batches_iterated) = - PoseidonHash::generate_pow(¶m, &mut rng, &&message[..], DIFFICULTY, BATCH_SIZE); + let (proof, num_batches_iterated) = PoseidonHash::<_, &[u32]>::generate_pow( + ¶m, + &mut rng, + message.as_slice(), + DIFFICULTY, + BATCH_SIZE, + ); println!( "total number of iterations: {}x{} = {}", num_batches_iterated, BATCH_SIZE, num_batches_iterated * BATCH_SIZE ); - let result = PoseidonHash::verify(¶m, &&message[..], &proof, DIFFICULTY); + let result = + PoseidonHash::<_, &[u32]>::verify_pow(¶m, message.as_slice(), &proof, DIFFICULTY); assert!(result); } } From 6e80af22121d2273f8d5a9d82648ccc4ae05dba2 Mon Sep 17 00:00:00 2001 From: Tom Shen Date: Wed, 13 Oct 2021 22:45:26 -0700 Subject: [PATCH 08/10] add CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cea38a85..cca5d45d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ ### Features +- [\#75](https://github.com/arkworks-rs/crypto-primitives/pull/75) Add Cryptographic Hash and Proof of Work. - [\#59](https://github.com/arkworks-rs/crypto-primitives/pull/59) Implement `TwoToOneCRHScheme` for Bowe-Hopwood CRH. - [\#60](https://github.com/arkworks-rs/crypto-primitives/pull/60) Merkle tree no longer requires CRH to input and output bytes. Leaf can be any raw input of CRH, such as field elements. - [\#67](https://github.com/arkworks-rs/crypto-primitives/pull/67) User can access or replace leaf index variable in `PathVar`. From 291a9b64804d3aaae3bda075104604e6472a0300 Mon Sep 17 00:00:00 2001 From: Tom Shen Date: Wed, 13 Oct 2021 22:50:54 -0700 Subject: [PATCH 09/10] fix no-std, reduce pow difficulty in test a little bit --- src/cryptographic_hash/constraints/poseidon.rs | 2 +- src/merkle_tree/tests/mod.rs | 2 +- src/pow/mod.rs | 2 +- src/pow/poseidon.rs | 6 ++++-- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/cryptographic_hash/constraints/poseidon.rs b/src/cryptographic_hash/constraints/poseidon.rs index 7289633f..c5add9a1 100644 --- a/src/cryptographic_hash/constraints/poseidon.rs +++ b/src/cryptographic_hash/constraints/poseidon.rs @@ -1,4 +1,4 @@ -use std::{borrow::Borrow, marker::PhantomData}; +use ark_std::{borrow::Borrow, marker::PhantomData}; use ark_ff::PrimeField; use ark_r1cs_std::fields::fp::FpVar; diff --git a/src/merkle_tree/tests/mod.rs b/src/merkle_tree/tests/mod.rs index 6a66d7c7..b925eb11 100644 --- a/src/merkle_tree/tests/mod.rs +++ b/src/merkle_tree/tests/mod.rs @@ -124,8 +124,8 @@ mod field_mt_tests { merkle_tree::{tests::test_utils::poseidon_parameters, Config, IdentityDigestConverter}, MerkleTree, }; + use ark_std::vec::Vec; use ark_std::{test_rng, One, UniformRand}; - type F = ark_ed_on_bls12_381::Fr; type H = poseidon::CRH; type TwoToOneH = poseidon::TwoToOneCRH; diff --git a/src/pow/mod.rs b/src/pow/mod.rs index 83e0a6fa..48b01dc4 100644 --- a/src/pow/mod.rs +++ b/src/pow/mod.rs @@ -2,7 +2,7 @@ pub mod constraints; pub mod poseidon; -use std::borrow::Borrow; +use ark_std::borrow::Borrow; use ark_std::rand::Rng; diff --git a/src/pow/poseidon.rs b/src/pow/poseidon.rs index d42961e2..16b02599 100644 --- a/src/pow/poseidon.rs +++ b/src/pow/poseidon.rs @@ -1,4 +1,4 @@ -use std::borrow::Borrow; +use ark_std::borrow::Borrow; use ark_sponge::{poseidon::PoseidonSponge, Absorb, CryptographicSponge}; @@ -55,10 +55,11 @@ mod tests { #[test] fn test_pow() { const BATCH_SIZE: usize = 64; - const DIFFICULTY: usize = 15; + const DIFFICULTY: usize = 14; let param = poseidon_parameters(); let message = vec![0x11, 0x12, 0x13, 0x14, 0x15]; let mut rng = test_rng(); + #[allow(unused)] let (proof, num_batches_iterated) = PoseidonHash::<_, &[u32]>::generate_pow( ¶m, &mut rng, @@ -66,6 +67,7 @@ mod tests { DIFFICULTY, BATCH_SIZE, ); + #[cfg(feature = "std")] println!( "total number of iterations: {}x{} = {}", num_batches_iterated, From f98fac5e0102d4dda37ea604c498f6e8da5c2e56 Mon Sep 17 00:00:00 2001 From: Tom Shen Date: Wed, 13 Oct 2021 22:53:44 -0700 Subject: [PATCH 10/10] fmt --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cca5d45d..d3e89afd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,7 @@ ### Features -- [\#75](https://github.com/arkworks-rs/crypto-primitives/pull/75) Add Cryptographic Hash and Proof of Work. +- [\#75](https://github.com/arkworks-rs/crypto-primitives/pull/75) Add Cryptographic Hash and Proof of Work. - [\#59](https://github.com/arkworks-rs/crypto-primitives/pull/59) Implement `TwoToOneCRHScheme` for Bowe-Hopwood CRH. - [\#60](https://github.com/arkworks-rs/crypto-primitives/pull/60) Merkle tree no longer requires CRH to input and output bytes. Leaf can be any raw input of CRH, such as field elements. - [\#67](https://github.com/arkworks-rs/crypto-primitives/pull/67) User can access or replace leaf index variable in `PathVar`.