From 8f376d2de75a7715c8d64311b1790352c0c36a38 Mon Sep 17 00:00:00 2001 From: moana Date: Fri, 10 May 2024 15:37:39 +0100 Subject: [PATCH] poseidon: Update to dusk-poseidon v0.39.0 --- poseidon-merkle/CHANGELOG.md | 6 ++ poseidon-merkle/Cargo.toml | 4 +- poseidon-merkle/examples/zk.rs | 12 ++-- poseidon-merkle/src/lib.rs | 104 +++++++++++++++++++++++---------- poseidon-merkle/src/zk.rs | 20 ++++--- poseidon-merkle/tests/zk.rs | 15 ++--- 6 files changed, 103 insertions(+), 58 deletions(-) diff --git a/poseidon-merkle/CHANGELOG.md b/poseidon-merkle/CHANGELOG.md index 0cdaafb..a358944 100644 --- a/poseidon-merkle/CHANGELOG.md +++ b/poseidon-merkle/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Changed + +- Update `dusk-poseidon` to 0.39 [#85] +- Fix `ARITY` in the poseidon-tree to `4` [#85] + ## [0.5.0] - 2024-01-03 ### Changed @@ -49,6 +54,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add poseidon-merkle crate [#58] +[#85]: https://github.com/dusk-network/merkle/issues/85 [#58]: https://github.com/dusk-network/merkle/issues/58 diff --git a/poseidon-merkle/Cargo.toml b/poseidon-merkle/Cargo.toml index f0ed0a1..23a7de4 100644 --- a/poseidon-merkle/Cargo.toml +++ b/poseidon-merkle/Cargo.toml @@ -16,7 +16,7 @@ license = "MPL-2.0" [dependencies] dusk-merkle = "0.5" -dusk-poseidon = { version = "0.33", default-features = false, features = ["merkle"] } +dusk-poseidon = "0.39" dusk-bls12_381 = { version = "0.13", default-features = false } dusk-plonk = { version = "0.19", optional = true, default-features = false } rkyv = { version = "0.7", optional = true, default-features = false } @@ -28,7 +28,7 @@ criterion = "0.3" ff = { version = "0.13", default-features = false } [features] -zk = ["dusk-plonk/alloc", "dusk-poseidon/alloc"] +zk = ["dusk-plonk/alloc", "dusk-poseidon/zk"] size_16 = ["rkyv/size_16"] size_32 = ["rkyv/size_32"] size_64 = ["rkyv/size_64"] diff --git a/poseidon-merkle/examples/zk.rs b/poseidon-merkle/examples/zk.rs index ddb482f..0d5e7eb 100644 --- a/poseidon-merkle/examples/zk.rs +++ b/poseidon-merkle/examples/zk.rs @@ -5,7 +5,7 @@ // Copyright (c) DUSK NETWORK. All rights reserved. use dusk_plonk::prelude::*; -use dusk_poseidon::sponge::hash as poseidon_hash; +use dusk_poseidon::{Domain, Hash}; use ff::Field; use rand::rngs::StdRng; use rand::{RngCore, SeedableRng}; @@ -18,14 +18,13 @@ use poseidon_merkle::{ // set max circuit size to 2^16 gates const CAPACITY: usize = 16; -// set height and arity of the poseidon merkle tree +// set height of the poseidon merkle tree const HEIGHT: usize = 17; -const ARITY: usize = 4; // Create a circuit for the opening #[derive(Debug, Clone, Hash, Eq, PartialEq)] struct OpeningCircuit { - opening: PoseidonOpening<(), HEIGHT, ARITY>, + opening: PoseidonOpening<(), HEIGHT>, leaf: PoseidonItem<()>, } @@ -48,7 +47,7 @@ impl Default for OpeningCircuit { impl OpeningCircuit { /// Create a new OpeningCircuit pub fn new( - opening: PoseidonOpening<(), HEIGHT, ARITY>, + opening: PoseidonOpening<(), HEIGHT>, leaf: PoseidonItem<()>, ) -> Self { Self { opening, leaf } @@ -85,7 +84,8 @@ fn main() { let mut leaf = PoseidonItem::<()>::new(BlsScalar::zero(), ()); let mut position = 0; for _ in 0..100 { - let hash = poseidon_hash(&[BlsScalar::random(&mut rng)]); + let hash = + Hash::digest(Domain::Other, &[BlsScalar::random(&mut rng)])[0]; position = rng.next_u64() % u8::MAX as u64; leaf = PoseidonItem::<()>::new(hash, ()); tree.insert(position as u64, leaf); diff --git a/poseidon-merkle/src/lib.rs b/poseidon-merkle/src/lib.rs index 796ea52..f1d9a00 100644 --- a/poseidon-merkle/src/lib.rs +++ b/poseidon-merkle/src/lib.rs @@ -13,15 +13,15 @@ pub mod zk; use dusk_bls12_381::BlsScalar; use dusk_merkle::Aggregate; -use dusk_poseidon::sponge::merkle::hash as poseidon_merkle_hash; +use dusk_poseidon::{Domain, Hash}; + +pub const ARITY: usize = 4; /// An alias for a tree containing `Item`. -pub type Tree = - dusk_merkle::Tree, H, A>; +pub type Tree = dusk_merkle::Tree, H, ARITY>; /// An alias for an opening of a tree containing `Item`. -pub type Opening = - dusk_merkle::Opening, H, A>; +pub type Opening = dusk_merkle::Opening, H, ARITY>; /// A type that wraps a piece of data `T` together with a poseidon hash - i.e. a /// [`BlsScalar`]. @@ -32,38 +32,78 @@ pub type Opening = /// /// # Example /// ```rust +/// use std::cmp::{max, min}; +/// /// use dusk_bls12_381::BlsScalar; -/// use poseidon_merkle::{Item, Tree as PoseidonTree}; -/// use dusk_poseidon::sponge; /// use dusk_merkle::Aggregate; +/// use dusk_poseidon::{Domain, Hash}; +/// use poseidon_merkle::{ARITY, Item, Tree as PoseidonTree}; /// -/// struct Data(BlsScalar); +/// const H: usize = 17; /// -/// impl From for Item { -/// fn from(data: Data) -> Self { -/// Item { -/// hash: sponge::hash(&[data.0]), -/// data, -/// } -/// } +/// // Leaf struct that carries some data and the current block-height. +/// struct Leaf { +/// leaf_data: BlsScalar, +/// bh: usize, +/// } +/// +/// // A node of the merkle tree that keeps track of the min and max +/// // block-height of all of it's children nodes. +/// struct BHRange { +/// min: Option, +/// max: Option, /// } /// -/// impl Aggregate for Data { -/// const EMPTY_SUBTREE: Data = Data(BlsScalar::zero()); +/// // Implement `Aggragate` only for the `BHRange` +/// impl Aggregate for BHRange { +/// const EMPTY_SUBTREE: BHRange = BHRange { +/// min: None, +/// max: None, +/// }; /// -/// fn aggregate(items: [&Self; A]) -> Self { -/// Self(items.iter().map(|d| d.0).sum()) +/// fn aggregate(items: [&Self; ARITY]) -> Self { +/// let mut parent = Self::EMPTY_SUBTREE; +/// +/// for child in items { +/// parent.min = match (parent.min, child.min) { +/// (Some(parent_min), Some(child_min)) => { +/// Some(min(parent_min, child_min)) +/// } +/// (Some(parent_min), None) => Some(parent_min), +/// (None, Some(child_min)) => Some(child_min), +/// (None, None) => None, +/// }; +/// parent.max = match (parent.max, child.max) { +/// (Some(parent_max), Some(child_max)) => { +/// Some(max(parent_max, child_max)) +/// } +/// (Some(parent_max), None) => Some(parent_max), +/// (None, Some(child_max)) => Some(child_max), +/// (None, None) => None, +/// } +/// } +/// +/// parent /// } /// } /// -/// const H: usize = 17; -/// const A: usize = 4; -/// type Tree = PoseidonTree; -/// +/// // Create a merkle tree using the poseidon-hash for each level +/// type Tree = PoseidonTree; /// let mut tree = Tree::new(); -/// tree.insert(42, Data(BlsScalar::one())); -/// tree.insert(7, Data(BlsScalar::one())); -/// tree.insert(0xbeef, Data(BlsScalar::one())); +/// +/// let leaf = Leaf { +/// leaf_data: BlsScalar::from(42), +/// bh: 42, +/// }; +/// +/// let item = Item { +/// hash: Hash::digest(Domain::Other, &[leaf.leaf_data])[0], +/// data: BHRange { +/// min: Some(leaf.bh), +/// max: Some(leaf.bh), +/// }, +/// }; +/// tree.insert(42, item); /// ``` #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] #[cfg_attr( @@ -83,20 +123,20 @@ impl Item { } } -impl Aggregate for Item +impl Aggregate for Item where - T: Aggregate, + T: Aggregate, { const EMPTY_SUBTREE: Self = Item { hash: BlsScalar::zero(), data: T::EMPTY_SUBTREE, }; - fn aggregate(items: [&Self; A]) -> Self { + fn aggregate(items: [&Self; ARITY]) -> Self { let empty = &T::EMPTY_SUBTREE; - let mut level_hashes = [BlsScalar::zero(); A]; - let mut level_data = [empty; A]; + let mut level_hashes = [BlsScalar::zero(); ARITY]; + let mut level_data = [empty; ARITY]; // grab hashes and data items.into_iter().enumerate().for_each(|(i, item)| { @@ -107,7 +147,7 @@ where // create new aggregated item with the hash being the poseidon hash of // the previous level Item { - hash: poseidon_merkle_hash(&level_hashes), + hash: Hash::digest(Domain::Merkle4, &level_hashes)[0], data: T::aggregate(level_data), } } diff --git a/poseidon-merkle/src/zk.rs b/poseidon-merkle/src/zk.rs index a18e60f..965dd83 100644 --- a/poseidon-merkle/src/zk.rs +++ b/poseidon-merkle/src/zk.rs @@ -4,26 +4,26 @@ // // Copyright (c) DUSK NETWORK. All rights reserved. -use crate::Opening; +use crate::{Opening, ARITY}; use dusk_merkle::Aggregate; use dusk_plonk::prelude::{BlsScalar, Composer, Constraint, Witness}; -use dusk_poseidon::sponge::merkle::gadget as poseidon_merkle_gadget; +use dusk_poseidon::{Domain, HashGadget}; /// Builds the gadget for the poseidon opening and returns the computed /// root. -pub fn opening_gadget( +pub fn opening_gadget( composer: &mut Composer, - opening: &Opening, + opening: &Opening, leaf: Witness, ) -> Witness where - T: Clone + Aggregate, + T: Clone + Aggregate, { // append the siblings and position to the circuit - let mut level_witnesses = [[Composer::ZERO; A]; H]; + let mut level_witnesses = [[Composer::ZERO; ARITY]; H]; // if i == position: pos_bits[i] = 1 else: pos_bits[i] = 0 - let mut pos_bits = [[Composer::ZERO; A]; H]; + let mut pos_bits = [[Composer::ZERO; ARITY]; H]; for h in (0..H).rev() { let level = &opening.branch()[h]; for (i, item) in level.iter().enumerate() { @@ -57,7 +57,7 @@ where // keep track of the computed hash along our path with needle let mut needle = leaf; for h in (0..H).rev() { - for i in 0..A { + for i in 0..ARITY { // assert that: // pos_bits[h][i] * level_hash[i] = pos_bits[h][i] * needle let constraint = Constraint::new() @@ -73,7 +73,9 @@ where } // hash the current level - needle = poseidon_merkle_gadget(composer, &level_witnesses[h]); + needle = + HashGadget::digest(composer, Domain::Merkle4, &level_witnesses[h]) + [0]; } // return the computed root as a witness in the circuit diff --git a/poseidon-merkle/tests/zk.rs b/poseidon-merkle/tests/zk.rs index 9088c5e..b36b0af 100644 --- a/poseidon-merkle/tests/zk.rs +++ b/poseidon-merkle/tests/zk.rs @@ -8,7 +8,7 @@ use poseidon_merkle::zk::opening_gadget; use poseidon_merkle::{Item, Opening, Tree}; use dusk_plonk::prelude::*; -use dusk_poseidon::sponge::hash as poseidon_hash; +use dusk_poseidon::{Domain, Hash}; use rand::rngs::StdRng; use rand::{RngCore, SeedableRng}; @@ -18,16 +18,15 @@ use ff::Field; // set max circuit size to 2^15 gates const CAPACITY: usize = 15; -// set height and arity of the poseidon merkle tree +// set height of the poseidon merkle tree const HEIGHT: usize = 17; -const ARITY: usize = 4; type PoseidonItem = Item<()>; // Create a circuit for the opening #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] struct OpeningCircuit { - opening: Opening<(), HEIGHT, ARITY>, + opening: Opening<(), HEIGHT>, leaf: PoseidonItem, } @@ -49,10 +48,7 @@ impl Default for OpeningCircuit { impl OpeningCircuit { /// Create a new OpeningCircuit - pub fn new( - opening: Opening<(), HEIGHT, ARITY>, - leaf: PoseidonItem, - ) -> Self { + pub fn new(opening: Opening<(), HEIGHT>, leaf: PoseidonItem) -> Self { Self { opening, leaf } } } @@ -88,7 +84,8 @@ fn opening() { let mut leaf = PoseidonItem::new(BlsScalar::zero(), ()); let mut position = 0; for _ in 0..100 { - let hash = poseidon_hash(&[BlsScalar::random(&mut rng)]); + let hash = + Hash::digest(Domain::Other, &[BlsScalar::random(&mut rng)])[0]; position = rng.next_u64() % tree.capacity(); leaf = PoseidonItem::new(hash, ()); tree.insert(position as u64, leaf);