From 26918fa506e7bff507c66b1c5a47eca34d673110 Mon Sep 17 00:00:00 2001 From: Victor Lopez Date: Mon, 2 Nov 2020 20:06:16 +0100 Subject: [PATCH 1/5] WiP - Walkable annotation --- Cargo.toml | 3 +- src/lib.rs | 2 +- src/main.rs | 69 +++++++++ src/tree/annotation/max.rs | 97 +++++++++++++ src/tree/annotation/mod.rs | 45 ++++++ .../{annotation.rs => annotation/poseidon.rs} | 104 ++++++++------ src/tree/branch.rs | 16 +-- src/tree/mod.rs | 134 ++++++++++++++---- 8 files changed, 382 insertions(+), 88 deletions(-) create mode 100644 src/main.rs create mode 100644 src/tree/annotation/max.rs create mode 100644 src/tree/annotation/mod.rs rename src/tree/{annotation.rs => annotation/poseidon.rs} (81%) diff --git a/Cargo.toml b/Cargo.toml index 926427a..88bdd1b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,8 @@ canonical_derive = "0.4" microkelvin = "0.5" nstack = "0.6" -[dev-dependencies] +##### REMOVE +#[dev-dependencies] canonical_host = "0.4" rand = "0.7" rand_core = "0.5" diff --git a/src/lib.rs b/src/lib.rs index 40f8644..2b2de10 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -160,7 +160,7 @@ //! - If you want to contribute to this repository/project please, check [CONTRIBUTING.md](https://github.com/dusk-network/Poseidon252/blob/master/CONTRIBUTING.md) //! - If you want to report a bug or request a new feature addition, please open an issue on this repository. -#![deny(missing_docs)] +//#![deny(missing_docs)] #![feature(min_const_generics)] /// Encryption and decryption implementation over a Poseidon cipher diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..308dd5d --- /dev/null +++ b/src/main.rs @@ -0,0 +1,69 @@ +use anyhow::Result; +use canonical::Canon; +use canonical_derive::Canon; +use canonical_host::MemStore; +use core::borrow::Borrow; +use dusk_plonk::prelude::*; +use poseidon252::tree::{PoseidonLeaf, PoseidonMaxAnnotation, PoseidonTree}; + +#[derive(Debug, Default, Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Canon)] +struct MockLeaf { + s: BlsScalar, + expiration: u64, +} + +impl From for MockLeaf { + fn from(n: u64) -> MockLeaf { + MockLeaf { + s: BlsScalar::from(n), + expiration: n / 3, + } + } +} + +impl PoseidonLeaf for MockLeaf { + fn poseidon_hash(&self) -> BlsScalar { + self.s + } +} + +impl Borrow for MockLeaf { + fn borrow(&self) -> &u64 { + &self.expiration + } +} + +fn main() { + let mut tree: PoseidonTree = + PoseidonTree::new(); + let mut v = vec![]; + let max = 4097; + + for i in 0..max { + let s = MockLeaf::from(i as u64); + let pos = tree.push(s).unwrap(); + assert_eq!(i, pos); + v.push(s); + } + + let tree_p = tree.clone(); + let mut walk = tree_p.iter_walk(1).unwrap(); + println!("SomeIteration: {:?}", walk.next().unwrap().unwrap()); + println!("SomeIteration: {:?}", walk.next().unwrap().unwrap()); + println!("SomeIteration: {:?}", walk.next().unwrap().unwrap()); + println!("SomeIteration: {:?}", walk.next().unwrap().unwrap()); + println!("SomeIteration: {:?}", walk.next().unwrap().unwrap()); + + println!("{:?}", tree.get(2).unwrap().unwrap()); + println!("{:?}", tree.get(3).unwrap().unwrap()); + + v.iter().enumerate().for_each(|(i, s)| { + let l = tree.get(i).unwrap().unwrap(); + assert_eq!(s, &l); + }); + + v.into_iter().rev().for_each(|s| { + let t = tree.pop().unwrap().unwrap(); + assert_eq!(s, t); + }); +} diff --git a/src/tree/annotation/max.rs b/src/tree/annotation/max.rs new file mode 100644 index 0000000..e127b1b --- /dev/null +++ b/src/tree/annotation/max.rs @@ -0,0 +1,97 @@ +use super::{ + PoseidonAnnotation, PoseidonTreeAnnotation, PoseidonWalkableAnnotation, +}; +use crate::tree::PoseidonLeaf; +use canonical::{Canon, Store}; +use canonical_derive::Canon; +use core::borrow::Borrow; +use dusk_plonk::prelude::*; +use microkelvin::{Annotation, Cardinality, Compound, Max, Step, Walk}; +use nstack::NStack; + +#[derive(Debug, Clone, Canon)] +pub struct PoseidonMaxAnnotation { + poseidon: PoseidonAnnotation, + max: Max, +} + +impl Borrow for PoseidonMaxAnnotation { + fn borrow(&self) -> &Cardinality { + self.poseidon.borrow() + } +} + +impl Borrow for PoseidonMaxAnnotation { + fn borrow(&self) -> &BlsScalar { + self.poseidon.borrow() + } +} + +impl Borrow for PoseidonMaxAnnotation { + fn borrow(&self) -> &u64 { + match &self.max { + Max::Maximum(m) => m, + Max::NegativeInfinity => &u64::min_value(), + } + } +} + +impl PoseidonTreeAnnotation for PoseidonMaxAnnotation +where + L: PoseidonLeaf, + L: Borrow, + S: Store, +{ +} + +impl Annotation, S> + for PoseidonMaxAnnotation +where + L: PoseidonLeaf, + L: Borrow, + S: Store, +{ + fn identity() -> Self { + let poseidon = , + S, + >>::identity(); + let max = as Annotation, S>>::identity(); + + Self { poseidon, max } + } + + fn from_leaf(leaf: &L) -> Self { + let poseidon = PoseidonAnnotation::from_leaf(leaf); + let max = + as Annotation, S>>::from_leaf(leaf); + + Self { poseidon, max } + } + + fn from_node(node: &NStack) -> Self { + let poseidon = PoseidonAnnotation::from_generic_node(node); + let max = + as Annotation, S>>::from_node(node); + + Self { poseidon, max } + } +} + +impl PoseidonWalkableAnnotation for PoseidonMaxAnnotation +where + L: PoseidonLeaf, + L: Borrow, + C: Clone, + C::Annotation: Annotation, + C: Compound, + S: Store, +{ + fn poseidon_walk(walk: Walk<'_, C, S>, data: u64) -> Step<'_, C, S> { + match walk { + Walk::Leaf(l) if data <= *l.borrow() => Step::Found(l), + Walk::Node(n) if data <= *n.annotation().borrow() => Step::Into(n), + _ => Step::Next, + } + } +} diff --git a/src/tree/annotation/mod.rs b/src/tree/annotation/mod.rs new file mode 100644 index 0000000..4bfc099 --- /dev/null +++ b/src/tree/annotation/mod.rs @@ -0,0 +1,45 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// +// Copyright (c) DUSK NETWORK. All rights reserved. + +use super::PoseidonLeaf; +use canonical::{Canon, Store}; +use core::borrow::Borrow; +use dusk_plonk::prelude::*; +use microkelvin::{Annotation, Cardinality, Compound, Step, Walk}; +use nstack::NStack; + +mod max; +mod poseidon; + +pub use max::PoseidonMaxAnnotation; +pub use poseidon::PoseidonAnnotation; + +/// Any structure that implements this trait is guaranteed to be compatible +/// as a poseidon tree annotation +pub trait PoseidonTreeAnnotation: + Canon + + Annotation, S> + + Borrow + + Borrow +where + L: PoseidonLeaf, + S: Store, +{ +} + +/// This trait will grant the ability of tree traversal using the `Branch::walk` +/// for a provided annotation +pub trait PoseidonWalkableAnnotation: + PoseidonTreeAnnotation +where + C: Compound, + C: Clone, + D: Clone, + L: PoseidonLeaf, + S: Store, +{ + fn poseidon_walk(walk: Walk<'_, C, S>, data: D) -> Step<'_, C, S>; +} diff --git a/src/tree/annotation.rs b/src/tree/annotation/poseidon.rs similarity index 81% rename from src/tree/annotation.rs rename to src/tree/annotation/poseidon.rs index 10d4629..7dbf47b 100644 --- a/src/tree/annotation.rs +++ b/src/tree/annotation/poseidon.rs @@ -4,6 +4,8 @@ // // Copyright (c) DUSK NETWORK. All rights reserved. +use super::PoseidonTreeAnnotation; +use crate::tree::PoseidonLeaf; use canonical::{Canon, Store}; use canonical_derive::Canon; use core::borrow::Borrow; @@ -24,6 +26,53 @@ pub struct PoseidonAnnotation { } impl PoseidonAnnotation { + pub fn from_generic_node(node: &NStack) -> Self + where + L: PoseidonLeaf, + A: PoseidonTreeAnnotation, + S: Store, + { + let cardinality = + , S>>::from_node(node); + + let mut perm = [BlsScalar::zero(); hades252::WIDTH]; + let mut flag = 1; + let mut mask = 0; + + match node { + NStack::Leaf(l) => { + l.iter().zip(perm.iter_mut().skip(1)).for_each(|(l, p)| { + if let Some(l) = l { + mask |= flag; + *p = l.poseidon_hash(); + } + + flag <<= 1; + }); + } + + NStack::Node(n) => { + n.iter().zip(perm.iter_mut().skip(1)).for_each(|(n, p)| { + if let Some(n) = n { + mask |= flag; + *p = *n.annotation().borrow(); + } + + flag <<= 1; + }); + } + } + + perm[0] = BlsScalar::from(mask); + ScalarStrategy::new().perm(&mut perm); + let poseidon_root = perm[1]; + + Self { + cardinality, + poseidon_root, + } + } + /// Return the scalar representation of the root of the annotated subtree pub fn poseidon_root(&self) -> &BlsScalar { &self.poseidon_root @@ -42,12 +91,17 @@ impl Borrow for PoseidonAnnotation { } } +impl PoseidonTreeAnnotation for PoseidonAnnotation +where + L: PoseidonLeaf, + S: Store, +{ +} + impl Annotation, S> for PoseidonAnnotation where - L: Canon, - L: Clone, - for<'a> &'a L: Into, + L: PoseidonLeaf, S: Store, { fn identity() -> Self { @@ -68,7 +122,7 @@ where NStack, S, >>::from_leaf(leaf); - let poseidon_root = leaf.into(); + let poseidon_root = leaf.poseidon_hash(); Self { cardinality, @@ -77,46 +131,6 @@ where } fn from_node(node: &NStack) -> Self { - let cardinality = , - S, - >>::from_node(node); - - let mut perm = [BlsScalar::zero(); hades252::WIDTH]; - let mut flag = 1; - let mut mask = 0; - - match node { - NStack::Leaf(l) => { - l.iter().zip(perm.iter_mut().skip(1)).for_each(|(l, p)| { - if let Some(l) = l { - mask |= flag; - *p = l.into(); - } - - flag <<= 1; - }); - } - - NStack::Node(n) => { - n.iter().zip(perm.iter_mut().skip(1)).for_each(|(n, p)| { - if let Some(n) = n { - mask |= flag; - *p = n.annotation().poseidon_root; - } - - flag <<= 1; - }); - } - } - - perm[0] = BlsScalar::from(mask); - ScalarStrategy::new().perm(&mut perm); - let poseidon_root = perm[1]; - - Self { - cardinality, - poseidon_root, - } + Self::from_generic_node(node) } } diff --git a/src/tree/branch.rs b/src/tree/branch.rs index d604920..e91b01c 100644 --- a/src/tree/branch.rs +++ b/src/tree/branch.rs @@ -4,12 +4,12 @@ // // Copyright (c) DUSK NETWORK. All rights reserved. -use canonical::{Canon, Store}; -use core::borrow::Borrow; +use super::{PoseidonLeaf, PoseidonTreeAnnotation}; +use canonical::Store; use core::ops::Deref; use dusk_plonk::prelude::BlsScalar; use hades252::{ScalarStrategy, Strategy}; -use microkelvin::{Annotation, Branch}; +use microkelvin::Branch; use nstack::NStack; /// Represents a level of a branch on a given depth @@ -75,12 +75,8 @@ impl AsRef<[PoseidonLevel]> for PoseidonBranch { impl From<&Branch<'_, NStack, S, DEPTH>> for PoseidonBranch where - L: Canon, - L: Clone, - for<'a> &'a L: Into, - A: Canon, - A: Annotation, S>, - A: Borrow, + L: PoseidonLeaf, + A: PoseidonTreeAnnotation, S: Store, { fn from(b: &Branch<'_, NStack, S, DEPTH>) -> Self { @@ -105,7 +101,7 @@ where .for_each(|(leaf, l)| { if let Some(leaf) = leaf { mask |= flag; - *l = leaf.into(); + *l = leaf.poseidon_hash(); } flag <<= 1; diff --git a/src/tree/mod.rs b/src/tree/mod.rs index b56190f..2109de9 100644 --- a/src/tree/mod.rs +++ b/src/tree/mod.rs @@ -6,12 +6,15 @@ use anyhow::{anyhow, Result}; use canonical::{Canon, Store}; -use core::borrow::Borrow; +use core::marker::PhantomData; use dusk_plonk::prelude::BlsScalar; -use microkelvin::{Annotation, Cardinality, Nth}; +use microkelvin::{Branch, Cardinality, Nth}; use nstack::NStack; -pub use annotation::PoseidonAnnotation; +pub use annotation::{ + PoseidonAnnotation, PoseidonMaxAnnotation, PoseidonTreeAnnotation, + PoseidonWalkableAnnotation, +}; pub use branch::{PoseidonBranch, PoseidonLevel}; mod annotation; @@ -23,6 +26,14 @@ pub mod zk; #[cfg(test)] mod tests; +/// A struct that will be used as a poseidon tree leaf must implement this trait +pub trait PoseidonLeaf: Canon + Clone +where + S: Store, +{ + fn poseidon_hash(&self) -> BlsScalar; +} + /// Represents a Merkle Tree with a given depth that will be calculated using poseidon hash /// /// The `BlsScalar` borrow of the annotation must represent the root poseidon merkle opening @@ -30,13 +41,8 @@ mod tests; #[derive(Debug, Clone)] pub struct PoseidonTree where - L: Canon, - L: Clone, - for<'a> &'a L: Into, - A: Canon, - A: Annotation, S>, - A: Borrow, - A: Borrow, + L: PoseidonLeaf, + A: PoseidonTreeAnnotation, S: Store, { inner: NStack, @@ -45,13 +51,8 @@ where impl AsRef> for PoseidonTree where - L: Canon, - L: Clone, - for<'a> &'a L: Into, - A: Canon, - A: Annotation, S>, - A: Borrow, - A: Borrow, + L: PoseidonLeaf, + A: PoseidonTreeAnnotation, S: Store, { fn as_ref(&self) -> &NStack { @@ -62,13 +63,8 @@ where impl AsMut> for PoseidonTree where - L: Canon, - L: Clone, - for<'a> &'a L: Into, - A: Canon, - A: Annotation, S>, - A: Borrow, - A: Borrow, + L: PoseidonLeaf, + A: PoseidonTreeAnnotation, S: Store, { fn as_mut(&mut self) -> &mut NStack { @@ -78,13 +74,8 @@ where impl PoseidonTree where - L: Canon, - L: Clone, - for<'a> &'a L: Into, - A: Canon, - A: Annotation, S>, - A: Borrow, - A: Borrow, + L: PoseidonLeaf, + A: PoseidonTreeAnnotation, S: Store, { /// Creates a new poseidon tree @@ -147,4 +138,85 @@ where pub fn root(&self) -> Result { self.branch(0).map(|b| b.unwrap_or_default().root()) } + + pub fn iter_walk( + &self, + data: D, + ) -> Result> + where + A: PoseidonWalkableAnnotation, D, L, S>, + { + PoseidonTreeIterator::new(&self.inner, data) + } +} + +pub struct PoseidonTreeIterator<'a, L, A, S, W, D, const DEPTH: usize> +where + L: PoseidonLeaf, + A: PoseidonTreeAnnotation, + S: Store, + W: PoseidonWalkableAnnotation, D, L, S>, + D: Clone, +{ + tree: &'a NStack, + data: D, + walk: PhantomData, + branch: Option, S, DEPTH>>, +} + +impl<'a, L, A, S, W, D, const DEPTH: usize> + PoseidonTreeIterator<'a, L, A, S, W, D, DEPTH> +where + L: PoseidonLeaf, + A: PoseidonTreeAnnotation, + S: Store, + W: PoseidonWalkableAnnotation, D, L, S>, + D: Clone, +{ + pub fn new(tree: &'a NStack, data: D) -> Result { + let branch = , S, DEPTH>>::walk(tree, |w| { + W::poseidon_walk(w, data.clone()) + }) + .map_err(|e| anyhow!("Error fetching the branch: {:?}", e))?; + + Ok(Self { + tree, + data, + walk: PhantomData, + branch, + }) + } +} + +impl<'a, L, A, S, W, D, const DEPTH: usize> Iterator + for PoseidonTreeIterator<'a, L, A, S, W, D, DEPTH> +where + L: PoseidonLeaf, + A: PoseidonTreeAnnotation, + S: Store, + W: PoseidonWalkableAnnotation, D, L, S>, + D: Clone, +{ + type Item = Result; + + fn next(&mut self) -> Option { + let next = match &self.branch { + Some(b) => (*b).clone(), + None => return None, + }; + + // We are only iterating over the same base compound, so we have an infinite loop here + // Check issue #86 + // https://github.com/dusk-network/dusk-blindbid/issues/86#issuecomment-720664968 + self.branch = match Branch::walk(self.tree, |w| { + W::poseidon_walk(w, self.data.clone()) + }) + .map_err(|e| anyhow!("Error fetching the branch: {:?}", e)) + { + Ok(b) => b, + Err(e) => return Some(Err(e)), + }; + + Some(Ok(next)) + } } From 84dd80a809307ef0ee5c5ac39b0a0d19077660e6 Mon Sep 17 00:00:00 2001 From: Victor Lopez Date: Mon, 2 Nov 2020 22:39:52 +0100 Subject: [PATCH 2/5] `PoseidonAnnotation` generic for walkable trees --- CHANGELOG.md | 2 + README.md | 182 ++++++++++++++++---------------- src/lib.rs | 160 +--------------------------- src/main.rs | 69 ------------ src/tree/annotation/max.rs | 10 ++ src/tree/annotation/mod.rs | 17 ++- src/tree/annotation/poseidon.rs | 1 + src/tree/mod.rs | 113 ++++++++++++-------- src/tree/tests.rs | 104 ++++++++++++++++-- 9 files changed, 291 insertions(+), 367 deletions(-) delete mode 100644 src/main.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 597b7d7..711cd85 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +- `PoseidonAnnotation` as generic to support walkable implementations + ## [0.11.0] - 30-10-20 ### Changed - Bump `hades252` to `v0.10.0` diff --git a/README.md b/README.md index d418659..3fbc464 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,19 @@ [![Build Status](https://travis-ci.com/dusk-network/Poseidon252.svg?branch=master)](https://travis-ci.com/dusk-network/Poseidon252) -[![Repository](https://dusk-network.github.io/Poseidon252/repo-badge.svg)](https://github.com/dusk-network/Poseidon252) -[![Documentation](https://dusk-network.github.io/Poseidon252/badge.svg)](https://dusk-network.github.io/Poseidon252/index.html) +[![Repository](https://img.shields.io/badge/github-poseidon252-blueviolet)](https://github.com/dusk-network/Poseidon252) +[![Documentation](https://img.shields.io/badge/docs-poseidon252-blue)](https://dusk-network.github.io/Poseidon252/index.html) -# Poseidon252 +# Poseidon252 Reference implementation for the Poseidon Hashing algorithm. #### Reference [Starkad and Poseidon: New Hash Functions for Zero Knowledge Proof Systems](https://eprint.iacr.org/2019/458.pdf) - - This repository has been created so there's a unique library that holds the tools & functions required to perform Poseidon Hashes. -This hashes heavily rely on the Hades permutation, which is one of the key parts that Poseidon needs in order -to work. +This hashes heavily rely on the Hades permutation, which is one of the key parts that Poseidon needs in order +to work. This library uses the reference implementation of [Hades252](https://github.com/dusk-network/hades252) which has been designed & build by the [Dusk-Network team](https://dusk.network/). @@ -68,103 +66,107 @@ computed and placed in the first Level position. ### Zero Knowledge Merkle Opening Proof example: -```rust -use poseidon252::{StorageScalar, PoseidonAnnotation}; -use poseidon252::merkle_proof::merkle_opening_gadget; -use dusk_plonk::prelude::*; -use kelvin::{Blake2b, Compound}; -use kelvin_hamt::{HAMTSearch, NarrowHAMT}; - -// Generate Composer & Public Parameters -let pub_params = - PublicParameters::setup(1 << 17, &mut rand::thread_rng()).unwrap(); -let (ck, vk) = pub_params.trim(1 << 16).unwrap(); -// Generate a tree with random scalars inside. -let mut ptree: PoseidonTree<_, Blake2b> = PoseidonTree::new(17); -for i in 0..1024u64 { - ptree - .push(StorageScalar(BlsScalar::from(i as u64))) - .unwrap(); -} - -for i in [0u64, 567, 1023].iter() { - let mut gadget_tester = |composer: &mut StandardComposer| { - // We want to proof that we know the Scalar tied to the key Xusize - // and that indeed, it is inside the merkle tree. - // In this case, the key X corresponds to the Scalar(X). - // We're supposing that we're provided with a Kelvin::Branch to perform - // the proof. - let branch = ptree.poseidon_branch(*i).unwrap().unwrap(); +```no_run +use anyhow::Result; +use canonical::Canon; +use canonical_derive::Canon; +use canonical_host::MemStore; +use dusk_plonk::prelude::*; +use poseidon252::tree::zk::merkle_opening; +use poseidon252::tree::{PoseidonAnnotation, PoseidonLeaf, PoseidonTree}; - // Get tree root. - let root = ptree.root().unwrap(); +// Constant depth of the merkle tree +const DEPTH: usize = 17; - // Add the proven leaf value to the Constraint System - let proven_leaf = composer.add_input(BlsScalar::from(*i)); +// Leaf representation +#[derive(Debug, Default, Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Canon)] +struct DataLeaf { + data: BlsScalar, + idx: u64, +} - merkle_opening_gadget(composer, branch, proven_leaf, root); +// Example helper +impl From for DataLeaf { + fn from(n: u64) -> DataLeaf { + DataLeaf { + data: BlsScalar::from(n), + idx: n, + } + } +} - // Since we don't use all of the wires, we set some dummy constraints to avoid Committing - // to zero polynomials. - composer.add_dummy_constraints(); - }; +// Any leaf of the poseidon tree must implement `PoseidonLeaf` +impl PoseidonLeaf for DataLeaf { + // Cryptographic hash of the data leaf + fn poseidon_hash(&self) -> BlsScalar { + self.data + } + + // Position on the tree + fn tree_idx(&self) -> u64 { + self.idx + } + + // Method used to set the position on the tree after the `PoseidonTree::push` call + fn tree_idx_mut(&mut self) -> &mut u64 { + &mut self.idx + } +} - // Proving - let mut prover = Prover::new(b"merkle_opening_tester"); - gadget_tester(prover.mut_cs()); +fn main() -> Result<()> { + // Create the ZK keys + let pub_params = PublicParameters::setup(1 << 15, &mut rand::thread_rng())?; + let (ck, ok) = pub_params.trim(1 << 15)?; + + // Instantiate a new tree with the MemStore implementation + let mut tree: PoseidonTree = + PoseidonTree::new(); + + // Append 1024 elements to the tree + for i in 0..1024 { + let l = DataLeaf::from(i as u64); + tree.push(l)?; + } + + // Create a merkle opening tester gadget + let gadget_tester = + |composer: &mut StandardComposer, + tree: &PoseidonTree, + n: usize| { + let branch = tree.branch(n).unwrap().unwrap(); + let root = tree.root().unwrap(); + + let leaf = BlsScalar::from(n as u64); + let leaf = composer.add_input(leaf); + + let root_p = merkle_opening::(composer, &branch, leaf); + composer.constrain_to_constant(root_p, BlsScalar::zero(), -root); + }; + + // Define the transcript initializer for the ZK backend + let label = b"opening_gadget"; + let idx = 0; + + // Create a merkle opening ZK proof + let mut prover = Prover::new(label); + gadget_tester(prover.mut_cs(), &tree, idx); prover.preprocess(&ck)?; let proof = prover.prove(&ck)?; - // Verify - let mut verifier = Verifier::new(b"merkle_opening_tester"); - gadget_tester(verifier.mut_cs()); + // Verify the merkle opening proof + let mut verifier = Verifier::new(label); + gadget_tester(verifier.mut_cs(), &tree, idx); verifier.preprocess(&ck)?; - assert!(verifier - .verify(&proof, &vk, &vec![BlsScalar::zero()]) - .is_ok()); -} -``` - - -### Standard Merkle Opening Proof example: -```rust -use poseidon252::{StorageScalar, PoseidonAnnotation}; -use poseidon252::merkle_proof::merkle_opening_scalar_verification; -use dusk_plonk::bls12_381::Scalar as BlsScalar; -use kelvin::{Blake2b, Compound}; -use poseidon252::PoseidonTree; - - // Generate a tree with random scalars inside. -let mut ptree: PoseidonTree<_, Blake2b> = PoseidonTree::new(17); -for i in 0..1024u64 { - ptree - .push(StorageScalar(BlsScalar::from(i as u64))) - .unwrap(); -} - -for i in 0..1024u64 { - // We want to proof that we know the Scalar tied to the key Xusize - // and that indeed, it is inside the merkle tree. - - // In this case, the key X corresponds to the Scalar(X). - // We're supposing that we're provided with a Kelvin::Branch to perform - // the proof. - let branch = ptree.poseidon_branch(i).unwrap().unwrap(); - - // Get tree root. - let root = ptree.root().unwrap(); + let pi = verifier.mut_cs().public_inputs.clone(); + verifier.verify(&proof, &ok, &pi).unwrap(); - assert!(merkle_opening_scalar_verification( - branch, - root, - BlsScalar::from(i), - )); + Ok(()) } ``` ## Documentation -This crate contains info about all of the functions that the library provides as well as the +This crate contains info about all of the functions that the library provides as well as the documentation regarding the data structures that it exports. To check it, please feel free to go to the [documentation page](https://dusk-network.github.io/Poseidon252/poseidon252/index.html) @@ -178,4 +180,4 @@ Implementation designed by the [dusk](https://dusk.network) team. ## Contributing - If you want to contribute to this repository/project please, check [CONTRIBUTING.md](https://github.com/dusk-network/Poseidon252/blob/master/CONTRIBUTING.md) -- If you want to report a bug or request a new feature addition, please open an issue on this repository. \ No newline at end of file +- If you want to report a bug or request a new feature addition, please open an issue on this repository. diff --git a/src/lib.rs b/src/lib.rs index 2b2de10..4a34ad4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,164 +4,10 @@ // // Copyright (c) DUSK NETWORK. All rights reserved. -//! ![Build Status](https://travis-ci.com/dusk-network/Poseidon252.svg?branch=master)](https://travis-ci.com/dusk-network/Poseidon252) -//! ![Repository](https://dusk-network.github.io/Poseidon252/repo-badge.svg)](https://github.com/dusk-network/Poseidon252) -//! ![Documentation](https://dusk-network.github.io/Poseidon252/badge.svg)](https://dusk-network.github.io/Poseidon252/index.html) -//! -//! # Poseidon252 -//! Reference implementation for the Poseidon Hashing algorithm. -//! -//! #### Reference -//! -//! [Starkad and Poseidon: New Hash Functions for Zero Knowledge Proof Systems](https://eprint.iacr.org/2019/458.pdf) -//! -//! This repository has been created so there's a unique library that holds the tools & functions -//! required to perform Poseidon Hashes. -//! -//! This hashes heavily rely on the Hades permutation, which is one of the key parts that Poseidon needs in order -//! to work. -//! This library uses the reference implementation of [Hades252](https://github.com/dusk-network/hades252) which has been -//! designed & build by the [Dusk-Network team](https://dusk.network/). -//! -//! **The library provides the two hashing techniques of Poseidon:** -//! -//! ## Sponge Hash -//! The `Sponge` techniqe in Poseidon allows to hash an unlimited ammount of data -//! into a single `Scalar`. -//! The sponge hash techniqe requires a padding to be applied before the data can -//! be hashed. -//! -//! This is done to avoid hash collitions as stated in the paper of the Poseidon Hash -//! algorithm. See: (https://eprint.iacr.org/2019/458.pdf)[https://eprint.iacr.org/2019/458.pdf]. -//! The inputs of the `sponge_hash` are always `Scalar` or need to be capable of being represented -//! as it. -//! -//! The module provides two sponge hash implementations: -//! - Sponge hash using `Scalar` as backend. Which hashes the inputed `Scalar`s and returns a single -//! `Scalar`. -//! -//! - Sponge hash gadget using `dusk_plonk::Variable` as a backend. This techniqe is used/required -//! when you want to proof pre-images of unconstrained data inside of Zero-Knowledge PLONK circuits. -//! -//! -//! ## Merkle Hash -//! The Merkle Level Hashing is a technique that Poseidon is optimized-by-design -//! to perform. -//! This technique allows us to perform hashes of an entire Merkle Tree using -//! `Hades252` as backend. -//! -//! The technique requires the computation of a `bitflags` element which is always -//! positioned as the first item of the level when we hash it, and it basically generated -//! in respect of the presence or absence of a leaf in the tree level. -//! This allows to prevent hashing collitions. -//! -//! At the moment, this library is designed and optimized to work only with trees of `ARITY` -//! up to 4. **That means that trees with a bigger ARITY SHOULD NEVER be used with this lib.** -//! The module contains the implementation of 4 variants of the same algorithm to support the -//! majority of the configurations that the user may need: -//! -//! - Scalar backend for hashing Merkle Tree levels outside of ZK-Circuits whith two variants: -//! One of them computes the bitflags item while the other assumes that it has already been -//! computed and placed in the first Level position. -//! -//! - `dusk_plonk::Variable` backend for hashing Merkle Tree levels inside of ZK-Circuits, -//! specifically, PLONK circuits. This implementation comes also whith two variants; -//! One of them computes the bitflags item while the other assumes that it has already been -//! computed and placed in the first Level position. -//! -//! -//! -//! ### Zero Knowledge Merkle Opening Proof example: -//! -//! ```no_run -//! use anyhow::Result; -//! use canonical::Canon; -//! use canonical_derive::Canon; -//! use canonical_host::MemStore; -//! use dusk_plonk::prelude::*; -//! use poseidon252::tree::zk::merkle_opening; -//! use poseidon252::tree::{PoseidonAnnotation, PoseidonTree}; -//! -//! const DEPTH: usize = 17; -//! -//! #[derive(Debug, Default, Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Canon)] -//! struct MockLeaf(pub BlsScalar); -//! -//! impl From for MockLeaf { -//! fn from(n: u64) -> MockLeaf { -//! MockLeaf(BlsScalar::from(n)) -//! } -//! } -//! -//! impl Into for &MockLeaf { -//! fn into(self) -> BlsScalar { -//! self.0 -//! } -//! } -//! -//! fn main() -> Result<()> { -//! let pub_params = PublicParameters::setup(1 << 15, &mut rand::thread_rng())?; -//! let (ck, ok) = pub_params.trim(1 << 15)?; -//! -//! let mut tree: PoseidonTree = -//! PoseidonTree::new(); -//! -//! for i in 0..1024 { -//! let l = MockLeaf::from(i as u64); -//! tree.push(l)?; -//! } -//! -//! let gadget_tester = -//! |composer: &mut StandardComposer, -//! tree: &PoseidonTree, -//! n: usize| { -//! let branch = tree.branch(n).unwrap().unwrap(); -//! let root = tree.root().unwrap(); -//! -//! let leaf = BlsScalar::from(n as u64); -//! let leaf = composer.add_input(leaf); -//! -//! let root_p = merkle_opening::(composer, &branch, leaf); -//! composer.constrain_to_constant(root_p, BlsScalar::zero(), -root); -//! }; -//! -//! let label = b"opening_gadget"; -//! let idx = 0; -//! -//! let mut prover = Prover::new(label); -//! gadget_tester(prover.mut_cs(), &tree, idx); -//! prover.preprocess(&ck)?; -//! let proof = prover.prove(&ck)?; -//! -//! let mut verifier = Verifier::new(label); -//! gadget_tester(verifier.mut_cs(), &tree, idx); -//! verifier.preprocess(&ck)?; -//! let pi = verifier.mut_cs().public_inputs.clone(); -//! verifier.verify(&proof, &ok, &pi).unwrap(); -//! -//! Ok(()) -//! } -//! ``` -//! -//! ## Documentation -//! This crate contains info about all of the functions that the library provides as well as the -//! documentation regarding the data structures that it exports. To check it, please feel free to go to -//! the [documentation page](https://dusk-network.github.io/Poseidon252/poseidon252/index.html) -//! -//! ## Licensing -//! -//! This code is licensed under Mozilla Public License Version 2.0 (MPL-2.0). Please see [LICENSE](https://github.com/dusk-network/plonk/blob/master/LICENSE) for further info. -//! -//! ## About -//! -//! Implementation designed by the [dusk](https://dusk.network) team. -//! -//! ## Contributing -//! - If you want to contribute to this repository/project please, check [CONTRIBUTING.md](https://github.com/dusk-network/Poseidon252/blob/master/CONTRIBUTING.md) -//! - If you want to report a bug or request a new feature addition, please open an issue on this repository. - -//#![deny(missing_docs)] +#![deny(missing_docs)] #![feature(min_const_generics)] +#![feature(external_doc)] +#![doc(include = "../README.md")] /// Encryption and decryption implementation over a Poseidon cipher pub mod cipher; diff --git a/src/main.rs b/src/main.rs deleted file mode 100644 index 308dd5d..0000000 --- a/src/main.rs +++ /dev/null @@ -1,69 +0,0 @@ -use anyhow::Result; -use canonical::Canon; -use canonical_derive::Canon; -use canonical_host::MemStore; -use core::borrow::Borrow; -use dusk_plonk::prelude::*; -use poseidon252::tree::{PoseidonLeaf, PoseidonMaxAnnotation, PoseidonTree}; - -#[derive(Debug, Default, Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Canon)] -struct MockLeaf { - s: BlsScalar, - expiration: u64, -} - -impl From for MockLeaf { - fn from(n: u64) -> MockLeaf { - MockLeaf { - s: BlsScalar::from(n), - expiration: n / 3, - } - } -} - -impl PoseidonLeaf for MockLeaf { - fn poseidon_hash(&self) -> BlsScalar { - self.s - } -} - -impl Borrow for MockLeaf { - fn borrow(&self) -> &u64 { - &self.expiration - } -} - -fn main() { - let mut tree: PoseidonTree = - PoseidonTree::new(); - let mut v = vec![]; - let max = 4097; - - for i in 0..max { - let s = MockLeaf::from(i as u64); - let pos = tree.push(s).unwrap(); - assert_eq!(i, pos); - v.push(s); - } - - let tree_p = tree.clone(); - let mut walk = tree_p.iter_walk(1).unwrap(); - println!("SomeIteration: {:?}", walk.next().unwrap().unwrap()); - println!("SomeIteration: {:?}", walk.next().unwrap().unwrap()); - println!("SomeIteration: {:?}", walk.next().unwrap().unwrap()); - println!("SomeIteration: {:?}", walk.next().unwrap().unwrap()); - println!("SomeIteration: {:?}", walk.next().unwrap().unwrap()); - - println!("{:?}", tree.get(2).unwrap().unwrap()); - println!("{:?}", tree.get(3).unwrap().unwrap()); - - v.iter().enumerate().for_each(|(i, s)| { - let l = tree.get(i).unwrap().unwrap(); - assert_eq!(s, &l); - }); - - v.into_iter().rev().for_each(|s| { - let t = tree.pop().unwrap().unwrap(); - assert_eq!(s, t); - }); -} diff --git a/src/tree/annotation/max.rs b/src/tree/annotation/max.rs index e127b1b..915f91a 100644 --- a/src/tree/annotation/max.rs +++ b/src/tree/annotation/max.rs @@ -1,3 +1,9 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// +// Copyright (c) DUSK NETWORK. All rights reserved. + use super::{ PoseidonAnnotation, PoseidonTreeAnnotation, PoseidonWalkableAnnotation, }; @@ -9,6 +15,10 @@ use dusk_plonk::prelude::*; use microkelvin::{Annotation, Cardinality, Compound, Max, Step, Walk}; use nstack::NStack; +/// Extends the standard [`PoseidonAnnotation`] with an annotation that holds an agnostic maximum +/// value +/// +/// This maximum value is representes as `u64`, and the tree is iterable over it #[derive(Debug, Clone, Canon)] pub struct PoseidonMaxAnnotation { poseidon: PoseidonAnnotation, diff --git a/src/tree/annotation/mod.rs b/src/tree/annotation/mod.rs index 4bfc099..07b25ea 100644 --- a/src/tree/annotation/mod.rs +++ b/src/tree/annotation/mod.rs @@ -35,11 +35,26 @@ where pub trait PoseidonWalkableAnnotation: PoseidonTreeAnnotation where - C: Compound, + C: Compound, C: Clone, D: Clone, L: PoseidonLeaf, S: Store, { + /// Traversal logic of the walkable annotation + /// + /// This will define the traversal path over the tree provided the generic data. + /// + /// The purpose of the data is to act as a filter over annotations, and this will be equally + /// passed to leaves and nodes. fn poseidon_walk(walk: Walk<'_, C, S>, data: D) -> Step<'_, C, S>; + + /// Uses the internal implementation of `poseidon_walk` to check if a leaf is compatible with + /// a provided data. + fn poseidon_leaf_found(leaf: &L, data: D) -> bool { + match Self::poseidon_walk(Walk::Leaf(leaf), data) { + Step::Found(_) => true, + _ => false, + } + } } diff --git a/src/tree/annotation/poseidon.rs b/src/tree/annotation/poseidon.rs index 7dbf47b..91e951d 100644 --- a/src/tree/annotation/poseidon.rs +++ b/src/tree/annotation/poseidon.rs @@ -26,6 +26,7 @@ pub struct PoseidonAnnotation { } impl PoseidonAnnotation { + /// Create a new poseidon annotation from a generic node implementation pub fn from_generic_node(node: &NStack) -> Self where L: PoseidonLeaf, diff --git a/src/tree/mod.rs b/src/tree/mod.rs index 2109de9..42d699d 100644 --- a/src/tree/mod.rs +++ b/src/tree/mod.rs @@ -6,7 +6,6 @@ use anyhow::{anyhow, Result}; use canonical::{Canon, Store}; -use core::marker::PhantomData; use dusk_plonk::prelude::BlsScalar; use microkelvin::{Branch, Cardinality, Nth}; use nstack::NStack; @@ -27,11 +26,26 @@ pub mod zk; mod tests; /// A struct that will be used as a poseidon tree leaf must implement this trait +/// +/// After [`PoseidonTree::push`], `tree_idx_mut` will be called to set the +/// index of the leaf on the tree pub trait PoseidonLeaf: Canon + Clone where S: Store, { + /// Poseidon hash implementation of the leaf structure. + /// + /// The result of this function will be used as opening for the merkle tree. fn poseidon_hash(&self) -> BlsScalar; + + /// Index of the leaf structure on the merkle tree. + fn tree_idx(&self) -> u64; + + /// Index of the leaf structure on the merkle tree. + /// + /// This method is internally used to set the index after the data has been inserted in the + /// merkle tree. + fn tree_idx_mut(&mut self) -> &mut u64; } /// Represents a Merkle Tree with a given depth that will be calculated using poseidon hash @@ -86,7 +100,10 @@ where } /// Append a leaf to the tree. Return the index of the appended leaf. - pub fn push(&mut self, leaf: L) -> Result { + /// + /// Will call the `tree_idx_mut` implementation of the leaf to + /// set its index + pub fn push(&mut self, mut leaf: L) -> Result { let size = match &self.inner { NStack::Leaf(l) => l.iter().filter(|l| l.is_some()).count(), NStack::Node(n) => n @@ -98,6 +115,7 @@ where .sum(), }; + *leaf.tree_idx_mut() = size as u64; self.inner .push(leaf) .map_err(|e| anyhow!("Error pushing to the tree: {:?}", e))?; @@ -139,84 +157,93 @@ where self.branch(0).map(|b| b.unwrap_or_default().root()) } + /// Iterates over the tree, provided its annotation implements [`PoseidonWalkableAnnotation`] pub fn iter_walk( &self, data: D, - ) -> Result> + ) -> Result> where A: PoseidonWalkableAnnotation, D, L, S>, { - PoseidonTreeIterator::new(&self.inner, data) + PoseidonTreeIterator::new(&self, data) } } -pub struct PoseidonTreeIterator<'a, L, A, S, W, D, const DEPTH: usize> +/// Main iterator of the poseidon tree. +/// +/// Depends on an implementation of `PoseidonWalkableAnnotation` for the tree annotation +/// +/// Every iteration will check for a valid `PoseidonWalkableAnnotation::poseidon_walk` call and +/// return a next leaf if the provided data holds true for the implemented logic +/// +/// The data can be any struct that implements `Clone`, and will be used to define the traversal +/// path over the tree. +pub struct PoseidonTreeIterator where L: PoseidonLeaf, A: PoseidonTreeAnnotation, S: Store, - W: PoseidonWalkableAnnotation, D, L, S>, D: Clone, { - tree: &'a NStack, + tree: PoseidonTree, + idx: usize, data: D, - walk: PhantomData, - branch: Option, S, DEPTH>>, } -impl<'a, L, A, S, W, D, const DEPTH: usize> - PoseidonTreeIterator<'a, L, A, S, W, D, DEPTH> +impl PoseidonTreeIterator where L: PoseidonLeaf, A: PoseidonTreeAnnotation, + A: PoseidonWalkableAnnotation, D, L, S>, S: Store, - W: PoseidonWalkableAnnotation, D, L, S>, D: Clone, { - pub fn new(tree: &'a NStack, data: D) -> Result { - let branch = , S, DEPTH>>::walk(tree, |w| { - W::poseidon_walk(w, data.clone()) + /// Iterator constructor + pub fn new(tree: &PoseidonTree, data: D) -> Result { + let tree = tree.clone(); + + // TODO - Naive implementation until iterable branch is implemented + // https://github.com/dusk-network/microkelvin/issues/23 + let idx = , S, DEPTH>>::walk(&tree.inner, |w| { + A::poseidon_walk(w, data.clone()) }) - .map_err(|e| anyhow!("Error fetching the branch: {:?}", e))?; + .map_err(|e| anyhow!("Error fetching the branch: {:?}", e))? + .map(|l| l.tree_idx()) + .unwrap_or(u64::max_value()) as usize; - Ok(Self { - tree, - data, - walk: PhantomData, - branch, - }) + Ok(Self { tree, idx, data }) } } -impl<'a, L, A, S, W, D, const DEPTH: usize> Iterator - for PoseidonTreeIterator<'a, L, A, S, W, D, DEPTH> +impl Iterator + for PoseidonTreeIterator where L: PoseidonLeaf, A: PoseidonTreeAnnotation, + A: PoseidonWalkableAnnotation, D, L, S>, S: Store, - W: PoseidonWalkableAnnotation, D, L, S>, D: Clone, { type Item = Result; fn next(&mut self) -> Option { - let next = match &self.branch { - Some(b) => (*b).clone(), - None => return None, - }; - - // We are only iterating over the same base compound, so we have an infinite loop here - // Check issue #86 - // https://github.com/dusk-network/dusk-blindbid/issues/86#issuecomment-720664968 - self.branch = match Branch::walk(self.tree, |w| { - W::poseidon_walk(w, self.data.clone()) - }) - .map_err(|e| anyhow!("Error fetching the branch: {:?}", e)) - { - Ok(b) => b, - Err(e) => return Some(Err(e)), - }; - - Some(Ok(next)) + let idx = self.idx; + let (idx_p, overflow) = self.idx.overflowing_add(1); + if overflow { + return None; + } + self.idx = idx_p; + + match self.tree.get(idx) { + // Hack until iterable branch is available + // This will prevent the iteration over non-filtered data + // https://github.com/dusk-network/microkelvin/issues/23 + Ok(Some(l)) if A::poseidon_leaf_found(&l, self.data.clone()) => { + Some(Ok(l)) + } + Ok(Some(_)) => self.next(), + Err(e) => Some(Err(e)), + _ => None, + } } } diff --git a/src/tree/tests.rs b/src/tree/tests.rs index a0c15a8..059c5d1 100644 --- a/src/tree/tests.rs +++ b/src/tree/tests.rs @@ -5,26 +5,51 @@ // Copyright (c) DUSK NETWORK. All rights reserved. use crate::tree::zk::merkle_opening; -use crate::tree::{PoseidonAnnotation, PoseidonTree}; +use crate::tree::{ + PoseidonAnnotation, PoseidonLeaf, PoseidonMaxAnnotation, PoseidonTree, +}; use anyhow::Result; use canonical::Canon; use canonical_derive::Canon; use canonical_host::MemStore; +use core::borrow::Borrow; use dusk_plonk::prelude::*; use hades252::{ScalarStrategy, Strategy}; #[derive(Debug, Default, Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Canon)] -struct MockLeaf(pub BlsScalar); +struct MockLeaf { + s: BlsScalar, + pub idx: u64, + pub expiration: u64, +} impl From for MockLeaf { fn from(n: u64) -> MockLeaf { - MockLeaf(BlsScalar::from(n)) + MockLeaf { + s: BlsScalar::from(n), + idx: 0, + expiration: n / 3, + } + } +} + +impl PoseidonLeaf for MockLeaf { + fn poseidon_hash(&self) -> BlsScalar { + self.s + } + + fn tree_idx(&self) -> u64 { + self.idx + } + + fn tree_idx_mut(&mut self) -> &mut u64 { + &mut self.idx } } -impl Into for &MockLeaf { - fn into(self) -> BlsScalar { - self.0 +impl Borrow for MockLeaf { + fn borrow(&self) -> &u64 { + &self.expiration } } @@ -36,9 +61,10 @@ fn tree_append_fetch() { let max = 4097; for i in 0..max { - let s = MockLeaf::from(i as u64); + let mut s = MockLeaf::from(i as u64); let pos = tree.push(s).unwrap(); assert_eq!(i, pos); + s.idx = i as u64; v.push(s); } @@ -53,6 +79,70 @@ fn tree_append_fetch() { }); } +#[test] +fn tree_max_walk() { + let mut tree: PoseidonTree = + PoseidonTree::new(); + let mut v = vec![]; + let max = 1025; + + for i in 0..max { + let mut s = MockLeaf::from(i as u64); + let pos = tree.push(s).unwrap(); + assert_eq!(i, pos); + s.idx = i as u64; + v.push(s); + } + + let w = 170; + let idx = w * 3; + tree.iter_walk(w) + .unwrap() + .map(|l| l.unwrap()) + .enumerate() + .for_each(|(i, leaf)| { + assert_eq!(idx + i as u64, leaf.tree_idx()); + }); + + assert!(tree.iter_walk((max + 1) as u64).unwrap().next().is_none()); +} + +#[test] +fn tree_max_walk_non_continuous() { + let mut tree: PoseidonTree = + PoseidonTree::new(); + let mut v = vec![]; + let max = 1025; + + for i in 0..max { + let mut s = MockLeaf::from(i as u64); + + if i % 4 == 0 { + s.expiration = 0; + } + + let pos = tree.push(s).unwrap(); + assert_eq!(i, pos); + s.idx = i as u64; + v.push(s); + } + + let w = 170; + let mut idx = w * 3; + tree.iter_walk(w) + .unwrap() + .map(|l| l.unwrap()) + .for_each(|leaf| { + if idx % 4 == 0 { + idx += 1; + } + assert_eq!(idx, leaf.tree_idx()); + idx += 1; + }); + + assert!(tree.iter_walk((max + 1) as u64).unwrap().next().is_none()); +} + #[test] fn tree_branch_leaf() { const DEPTH: usize = 17; From 6c76a2f2d38c76637e7539a62f7702e310ab9421 Mon Sep 17 00:00:00 2001 From: Victor Lopez Date: Mon, 2 Nov 2020 22:41:23 +0100 Subject: [PATCH 3/5] Correction of Cargo.toml to proper dev-deps --- Cargo.toml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 88bdd1b..926427a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,8 +17,7 @@ canonical_derive = "0.4" microkelvin = "0.5" nstack = "0.6" -##### REMOVE -#[dev-dependencies] +[dev-dependencies] canonical_host = "0.4" rand = "0.7" rand_core = "0.5" From f77bfe92a8ac5098f4cb7ac19dd39984092e3cbf Mon Sep 17 00:00:00 2001 From: Victor Lopez Date: Tue, 3 Nov 2020 20:30:48 +0100 Subject: [PATCH 4/5] Replacement of idx for pos --- README.md | 18 +++++++++--------- src/tree/mod.rs | 26 +++++++++++++------------- src/tree/tests.rs | 32 ++++++++++++++++---------------- 3 files changed, 38 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index 3fbc464..0773559 100644 --- a/README.md +++ b/README.md @@ -83,7 +83,7 @@ const DEPTH: usize = 17; #[derive(Debug, Default, Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Canon)] struct DataLeaf { data: BlsScalar, - idx: u64, + pos: u64, } // Example helper @@ -91,7 +91,7 @@ impl From for DataLeaf { fn from(n: u64) -> DataLeaf { DataLeaf { data: BlsScalar::from(n), - idx: n, + pos: n, } } } @@ -104,13 +104,13 @@ impl PoseidonLeaf for DataLeaf { } // Position on the tree - fn tree_idx(&self) -> u64 { - self.idx + fn tree_pos(&self) -> u64 { + self.pos } // Method used to set the position on the tree after the `PoseidonTree::push` call - fn tree_idx_mut(&mut self) -> &mut u64 { - &mut self.idx + fn tree_pos_mut(&mut self) -> &mut u64 { + &mut self.pos } } @@ -146,17 +146,17 @@ fn main() -> Result<()> { // Define the transcript initializer for the ZK backend let label = b"opening_gadget"; - let idx = 0; + let pos = 0; // Create a merkle opening ZK proof let mut prover = Prover::new(label); - gadget_tester(prover.mut_cs(), &tree, idx); + gadget_tester(prover.mut_cs(), &tree, pos); prover.preprocess(&ck)?; let proof = prover.prove(&ck)?; // Verify the merkle opening proof let mut verifier = Verifier::new(label); - gadget_tester(verifier.mut_cs(), &tree, idx); + gadget_tester(verifier.mut_cs(), &tree, pos); verifier.preprocess(&ck)?; let pi = verifier.mut_cs().public_inputs.clone(); verifier.verify(&proof, &ok, &pi).unwrap(); diff --git a/src/tree/mod.rs b/src/tree/mod.rs index 42d699d..a4683c0 100644 --- a/src/tree/mod.rs +++ b/src/tree/mod.rs @@ -27,7 +27,7 @@ mod tests; /// A struct that will be used as a poseidon tree leaf must implement this trait /// -/// After [`PoseidonTree::push`], `tree_idx_mut` will be called to set the +/// After [`PoseidonTree::push`], `tree_pos_mut` will be called to set the /// index of the leaf on the tree pub trait PoseidonLeaf: Canon + Clone where @@ -39,13 +39,13 @@ where fn poseidon_hash(&self) -> BlsScalar; /// Index of the leaf structure on the merkle tree. - fn tree_idx(&self) -> u64; + fn tree_pos(&self) -> u64; /// Index of the leaf structure on the merkle tree. /// /// This method is internally used to set the index after the data has been inserted in the /// merkle tree. - fn tree_idx_mut(&mut self) -> &mut u64; + fn tree_pos_mut(&mut self) -> &mut u64; } /// Represents a Merkle Tree with a given depth that will be calculated using poseidon hash @@ -101,7 +101,7 @@ where /// Append a leaf to the tree. Return the index of the appended leaf. /// - /// Will call the `tree_idx_mut` implementation of the leaf to + /// Will call the `tree_pos_mut` implementation of the leaf to /// set its index pub fn push(&mut self, mut leaf: L) -> Result { let size = match &self.inner { @@ -115,7 +115,7 @@ where .sum(), }; - *leaf.tree_idx_mut() = size as u64; + *leaf.tree_pos_mut() = size as u64; self.inner .push(leaf) .map_err(|e| anyhow!("Error pushing to the tree: {:?}", e))?; @@ -186,7 +186,7 @@ where D: Clone, { tree: PoseidonTree, - idx: usize, + pos: usize, data: D, } @@ -204,14 +204,14 @@ where // TODO - Naive implementation until iterable branch is implemented // https://github.com/dusk-network/microkelvin/issues/23 - let idx = , S, DEPTH>>::walk(&tree.inner, |w| { + let pos = , S, DEPTH>>::walk(&tree.inner, |w| { A::poseidon_walk(w, data.clone()) }) .map_err(|e| anyhow!("Error fetching the branch: {:?}", e))? - .map(|l| l.tree_idx()) + .map(|l| l.tree_pos()) .unwrap_or(u64::max_value()) as usize; - Ok(Self { tree, idx, data }) + Ok(Self { tree, pos, data }) } } @@ -227,14 +227,14 @@ where type Item = Result; fn next(&mut self) -> Option { - let idx = self.idx; - let (idx_p, overflow) = self.idx.overflowing_add(1); + let pos = self.pos; + let (pos_p, overflow) = self.pos.overflowing_add(1); if overflow { return None; } - self.idx = idx_p; + self.pos = pos_p; - match self.tree.get(idx) { + match self.tree.get(pos) { // Hack until iterable branch is available // This will prevent the iteration over non-filtered data // https://github.com/dusk-network/microkelvin/issues/23 diff --git a/src/tree/tests.rs b/src/tree/tests.rs index 059c5d1..143410c 100644 --- a/src/tree/tests.rs +++ b/src/tree/tests.rs @@ -19,7 +19,7 @@ use hades252::{ScalarStrategy, Strategy}; #[derive(Debug, Default, Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Canon)] struct MockLeaf { s: BlsScalar, - pub idx: u64, + pub pos: u64, pub expiration: u64, } @@ -27,7 +27,7 @@ impl From for MockLeaf { fn from(n: u64) -> MockLeaf { MockLeaf { s: BlsScalar::from(n), - idx: 0, + pos: 0, expiration: n / 3, } } @@ -38,12 +38,12 @@ impl PoseidonLeaf for MockLeaf { self.s } - fn tree_idx(&self) -> u64 { - self.idx + fn tree_pos(&self) -> u64 { + self.pos } - fn tree_idx_mut(&mut self) -> &mut u64 { - &mut self.idx + fn tree_pos_mut(&mut self) -> &mut u64 { + &mut self.pos } } @@ -64,7 +64,7 @@ fn tree_append_fetch() { let mut s = MockLeaf::from(i as u64); let pos = tree.push(s).unwrap(); assert_eq!(i, pos); - s.idx = i as u64; + s.pos = i as u64; v.push(s); } @@ -90,18 +90,18 @@ fn tree_max_walk() { let mut s = MockLeaf::from(i as u64); let pos = tree.push(s).unwrap(); assert_eq!(i, pos); - s.idx = i as u64; + s.pos = i as u64; v.push(s); } let w = 170; - let idx = w * 3; + let pos = w * 3; tree.iter_walk(w) .unwrap() .map(|l| l.unwrap()) .enumerate() .for_each(|(i, leaf)| { - assert_eq!(idx + i as u64, leaf.tree_idx()); + assert_eq!(pos + i as u64, leaf.tree_pos()); }); assert!(tree.iter_walk((max + 1) as u64).unwrap().next().is_none()); @@ -123,21 +123,21 @@ fn tree_max_walk_non_continuous() { let pos = tree.push(s).unwrap(); assert_eq!(i, pos); - s.idx = i as u64; + s.pos = i as u64; v.push(s); } let w = 170; - let mut idx = w * 3; + let mut pos = w * 3; tree.iter_walk(w) .unwrap() .map(|l| l.unwrap()) .for_each(|leaf| { - if idx % 4 == 0 { - idx += 1; + if pos % 4 == 0 { + pos += 1; } - assert_eq!(idx, leaf.tree_idx()); - idx += 1; + assert_eq!(pos, leaf.tree_pos()); + pos += 1; }); assert!(tree.iter_walk((max + 1) as u64).unwrap().next().is_none()); From 9404575e0765809f16c02d2a64578c9c6cb40747 Mon Sep 17 00:00:00 2001 From: Victor Lopez Date: Tue, 3 Nov 2020 21:05:54 +0100 Subject: [PATCH 5/5] Bump version to v0.12.0 --- CHANGELOG.md | 3 ++- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 79338b0..03a24dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,9 +6,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] + +## [0.12.0] - 03-11-20 ### Added - Gate-featured `canonical` impl. - - `PoseidonAnnotation` as generic to support walkable implementations ## [0.11.0] - 30-10-20 diff --git a/Cargo.toml b/Cargo.toml index c784067..23dc483 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "poseidon252" -version = "0.11.0" +version = "0.12.0" authors = [ "zer0 ", "vlopes11 ", "CPerezz ", "Kristoffer Ström " ]