Skip to content

Commit

Permalink
Merge pull request #86 from dusk-network/mocello/85_poseidon
Browse files Browse the repository at this point in the history
poseidon: Update to dusk-poseidon v0.39.0
  • Loading branch information
moCello authored May 22, 2024
2 parents a4f5ba6 + 8f376d2 commit 070e225
Show file tree
Hide file tree
Showing 6 changed files with 103 additions and 58 deletions.
6 changes: 6 additions & 0 deletions poseidon-merkle/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -49,6 +54,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Add poseidon-merkle crate [#58]

<!-- ISSUES -->
[#85]: https://github.com/dusk-network/merkle/issues/85
[#58]: https://github.com/dusk-network/merkle/issues/58

<!-- VERSIONS -->
Expand Down
4 changes: 2 additions & 2 deletions poseidon-merkle/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand All @@ -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"]
Expand Down
12 changes: 6 additions & 6 deletions poseidon-merkle/examples/zk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -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<()>,
}

Expand All @@ -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 }
Expand Down Expand Up @@ -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);
Expand Down
104 changes: 72 additions & 32 deletions poseidon-merkle/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<T>`.
pub type Tree<T, const H: usize, const A: usize> =
dusk_merkle::Tree<Item<T>, H, A>;
pub type Tree<T, const H: usize> = dusk_merkle::Tree<Item<T>, H, ARITY>;

/// An alias for an opening of a tree containing `Item<T>`.
pub type Opening<T, const H: usize, const A: usize> =
dusk_merkle::Opening<Item<T>, H, A>;
pub type Opening<T, const H: usize> = dusk_merkle::Opening<Item<T>, H, ARITY>;

/// A type that wraps a piece of data `T` together with a poseidon hash - i.e. a
/// [`BlsScalar`].
Expand All @@ -32,38 +32,78 @@ pub type Opening<T, const H: usize, const A: usize> =
///
/// # 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<Data> for Item<Data> {
/// 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<usize>,
/// max: Option<usize>,
/// }
///
/// impl<const A: usize> Aggregate<A> for Data {
/// const EMPTY_SUBTREE: Data = Data(BlsScalar::zero());
/// // Implement `Aggragate` only for the `BHRange`
/// impl Aggregate<ARITY> 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<Data, H, A>;
///
/// // Create a merkle tree using the poseidon-hash for each level
/// type Tree = PoseidonTree<BHRange, H>;
/// 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(
Expand All @@ -83,20 +123,20 @@ impl<T> Item<T> {
}
}

impl<T, const A: usize> Aggregate<A> for Item<T>
impl<T> Aggregate<ARITY> for Item<T>
where
T: Aggregate<A>,
T: Aggregate<ARITY>,
{
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)| {
Expand All @@ -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),
}
}
Expand Down
20 changes: 11 additions & 9 deletions poseidon-merkle/src/zk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<T, const H: usize, const A: usize>(
pub fn opening_gadget<T, const H: usize>(
composer: &mut Composer,
opening: &Opening<T, H, A>,
opening: &Opening<T, H>,
leaf: Witness,
) -> Witness
where
T: Clone + Aggregate<A>,
T: Clone + Aggregate<ARITY>,
{
// 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() {
Expand Down Expand Up @@ -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()
Expand All @@ -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
Expand Down
15 changes: 6 additions & 9 deletions poseidon-merkle/tests/zk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -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,
}

Expand All @@ -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 }
}
}
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 070e225

Please sign in to comment.