Skip to content

Commit

Permalink
Merge pull request #28 from dusk-network/poseidon_tree
Browse files Browse the repository at this point in the history
initial PoseidonTree draft
  • Loading branch information
krl authored Jun 15, 2020
2 parents a46c731 + 66ba4ef commit 8b8427a
Show file tree
Hide file tree
Showing 5 changed files with 183 additions and 112 deletions.
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
[package]
name = "poseidon252"
version = "0.4.0"
version = "0.5.0"
authors = [
"zer0 <[email protected]>", "vlopes11 <[email protected]>", "CPerezz <[email protected]>"
"zer0 <[email protected]>", "vlopes11 <[email protected]>", "CPerezz <carlos@dusk.network>", "Kristoffer Ström <kristoffer@dusk.network>"
]
edition = "2018"

Expand Down
46 changes: 17 additions & 29 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@
//! ### Zero Knowledge Merkle Opening Proof example:
//! ```no_run
//! use std::borrow::Borrow;
//! use poseidon252::{StorageScalar, PoseidonAnnotation};
//! use poseidon252::{StorageScalar, PoseidonTree};
//! use poseidon252::merkle_proof::merkle_opening_gadget;
//! use dusk_plonk::commitment_scheme::kzg10::PublicParameters;
//! use dusk_plonk::constraint_system::{Variable, StandardComposer};
Expand All @@ -83,9 +83,9 @@
//! 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 nstack: NStack<_, PoseidonAnnotation, Blake2b> = NStack::new();
//! let mut ptree: PoseidonTree<_, Blake2b> = PoseidonTree::new(17);
//! for i in 0..1024u64 {
//! nstack.push(StorageScalar(Scalar::from(i as u64)))
//! ptree.push(StorageScalar(Scalar::from(i as u64)))
//! .unwrap();
//! }
//!
Expand All @@ -98,24 +98,17 @@
//! // 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 = nstack.get(*i).unwrap().unwrap();
//! let branch = ptree.poseidon_branch(*i).unwrap().unwrap();
//!
//! // Get tree root.
//! let root = StorageScalar::from(branch
//! .levels()
//! .first()
//! .unwrap()
//! .annotation()
//! .unwrap()
//! .to_owned()
//! .borrow());
//! let root = ptree.root().unwrap();
//!
//! // Add the proven leaf value to the Constraint System
//! let proven_leaf = composer.add_input(Scalar::from(*i));
//!
//! // Print inside of the Composer Constraint System the Merkle Proof
//! // with all of the needed checks. Using branch length of 17
//! merkle_opening_gadget(&mut composer, branch, proven_leaf, root.0.into(), 17);
//! // with all of the needed checks.
//! merkle_opening_gadget(&mut composer, branch, proven_leaf, root);
//!
//! // Since we don't use all of the wires, we set some dummy constraints to avoid Committing
//! // to zero polynomials.
Expand All @@ -137,16 +130,15 @@
//! ### Standard Merkle Opening Proof example:
//! ```no_run
//! use std::borrow::Borrow;
//! use poseidon252::{StorageScalar, PoseidonAnnotation};
//! use poseidon252::{StorageScalar, PoseidonTree};
//! use poseidon252::merkle_proof::merkle_opening_scalar_verification;
//! use dusk_bls12_381::Scalar;
//! use kelvin::{Blake2b, Compound};
//! use nstack::NStack;
//!
//! // Generate a tree with random scalars inside.
//! let mut nstack: NStack<_, PoseidonAnnotation, Blake2b> = NStack::new();
//! let mut ptree: PoseidonTree<_, Blake2b> = PoseidonTree::new(17);
//! for i in 0..1024u64 {
//! nstack.push(StorageScalar(Scalar::from(i as u64)))
//! ptree.push(StorageScalar(Scalar::from(i as u64)))
//! .unwrap();
//! }
//!
Expand All @@ -157,24 +149,16 @@
//! // 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 = nstack.get(i).unwrap().unwrap();
//! let branch = ptree.poseidon_branch(i).unwrap().unwrap();
//!
//! // Get tree root.
//! let root = StorageScalar::from(branch
//! .levels()
//! .first()
//! .unwrap()
//! .annotation()
//! .unwrap()
//! .to_owned()
//! .borrow());
//! let root = ptree.root().unwrap();
//!
//! // Verify the `Branch`. Use a branch length of 17.
//! assert!(merkle_opening_scalar_verification(
//! branch,
//! root.0.into(),
//! root,
//! Scalar::from(i),
//! 17,
//! ));
//! }
//! ```
Expand Down Expand Up @@ -207,6 +191,10 @@ pub mod merkle_proof;
/// Reference implementation for the Poseidon Sponge hash function
pub mod sponge;

/// The module handling posedion-trees
pub mod tree;
pub use tree::PoseidonTree;

/// Maximum arity supported for trees.
///
/// This is due to the fact that actually we rely in Hades252 crate
Expand Down
15 changes: 15 additions & 0 deletions src/merkle_proof/poseidon_branch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,21 @@ impl PoseidonBranch {
}
}

/// Applies the extension padding n times to a scalar
pub(crate) fn extend_scalar(mut scalar: Scalar, n: usize) -> Scalar {
for _ in 0..n {
let flag = Scalar::from(0b1000);
let mut leaves = [Scalar::zero(); ARITY + 1];

leaves[0] = flag;
leaves[1] = scalar;

let level = PoseidonLevel { leaves, offset: 1 };
scalar = hash::merkle_level_hash_without_bitflags(&level);
}
scalar
}

#[derive(Debug, Clone, PartialEq)]
/// Represents a Merkle-Tree Level inside of a `PoseidonBranch`.
/// It stores the leaves as `Scalar` and the offset which represents
Expand Down
102 changes: 21 additions & 81 deletions src/merkle_proof/proof.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
//! Merkle-tree hashing functions using Poseidon252
//!
use super::poseidon_branch::{PoseidonBranch, PoseidonLevel};
use super::poseidon_branch::PoseidonBranch;
use crate::merkle_lvl_hash::hash::*;
use crate::ARITY;
use crate::{PoseidonAnnotation, StorageScalar};

use dusk_bls12_381::Scalar;
use dusk_plonk::constraint_system::{StandardComposer, Variable};
use hades252::WIDTH;
use nstack::NStack;

/// Provided a `kelvin::Branch`, a `&mut StandardComposer`, a leaf value and a root, print inside of the
/// constraint system a Merkle Tree Proof that hashes up from the searched leaf in kelvin until
Expand All @@ -17,21 +15,12 @@ use nstack::NStack;
///
/// NOTE: The root of the `Branch` (root of the Merkle tree) will be set as Public Input so we
/// can re-use the circuits that rely on this gadget.
pub fn merkle_opening_gadget<H>(
pub fn merkle_opening_gadget(
composer: &mut StandardComposer,
branch: kelvin::Branch<NStack<StorageScalar, PoseidonAnnotation, H>, H>,
branch: PoseidonBranch,
proven_leaf: Variable,
proven_root: Scalar,
branch_length: usize,
) where
H: kelvin::ByteHash,
{
// Generate a `PoseidonBranch` from the kelvin Branch.
let mut branch = PoseidonBranch::from(&branch);

let n_extensions = branch.extend(branch_length);
let proven_root = extend_scalar(proven_root, n_extensions);

) {
// Allocate space for each level Variables that will be generated.
let mut lvl_vars = [composer.zero_var; WIDTH];
// Allocate space for the last level computed hash as a variable to compare
Expand Down Expand Up @@ -102,44 +91,20 @@ pub fn merkle_opening_gadget<H>(
assert_eq!(branch.root, proven_root);
}

/// Applies the extension padding n times to the scalar
fn extend_scalar(mut scalar: Scalar, n: usize) -> Scalar {
for _ in 0..n {
let flag = Scalar::from(0b1000);
let mut leaves = [Scalar::zero(); ARITY + 1];

leaves[0] = flag;
leaves[1] = scalar;

let level = PoseidonLevel { leaves, offset: 1 };
scalar = merkle_level_hash_without_bitflags(&level);
}
scalar
}

/// Provided a `PoseidonBranch` and a Merkle Tree root, verify that
/// the path to the root is correct.
///
/// `branch_length` controls how much padding should be added to the branch to make it the correct length.
///
/// This hashing-chain is performed using Poseidon hashing algorithm
/// and relies on the `Hades252` permutation.
pub fn merkle_opening_scalar_verification<H>(
branch: kelvin::Branch<NStack<StorageScalar, PoseidonAnnotation, H>, H>,
pub fn merkle_opening_scalar_verification(
branch: PoseidonBranch,
root: Scalar,
leaf: Scalar,
branch_length: usize,
) -> bool
where
H: kelvin::ByteHash,
{
let mut branch = PoseidonBranch::from(&branch);
let n_extensions = branch.extend(branch_length);

let extended_root = extend_scalar(root, n_extensions);

) -> bool {
// Check that the root is indeed the one that we think
if branch.root != extended_root {
if branch.root != root {
return false;
};
// Allocate space for the last level computed hash as a variable to compare
Expand Down Expand Up @@ -187,20 +152,18 @@ where
mod tests {
use super::*;
use crate::hashing_utils::scalar_storage::StorageScalar;
use crate::PoseidonAnnotation;
use crate::PoseidonTree;
use dusk_plonk::commitment_scheme::kzg10::PublicParameters;
use dusk_plonk::fft::EvaluationDomain;
use kelvin::{Blake2b, Compound};
use kelvin::Blake2b;
use merlin::Transcript;
use nstack::NStack;
use std::borrow::Borrow;

#[test]
fn scalar_merkle_proof() {
// Generate a tree with random scalars inside.
let mut nstack: NStack<_, PoseidonAnnotation, Blake2b> = NStack::new();
let mut ptree: PoseidonTree<_, Blake2b> = PoseidonTree::new(17);
for i in 0..1024u64 {
nstack.push(StorageScalar(Scalar::from(i as u64))).unwrap();
ptree.push(StorageScalar(Scalar::from(i as u64))).unwrap();
}

for i in 0..1024u64 {
Expand All @@ -210,24 +173,15 @@ mod tests {
// 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 = nstack.get(i).unwrap().unwrap();
let branch = ptree.poseidon_branch(i).unwrap().unwrap();

// Get tree root.
let root = StorageScalar::from(
branch
.levels()
.first()
.unwrap()
.annotation()
.unwrap()
.borrow(),
);
let root = ptree.root().unwrap();

assert!(merkle_opening_scalar_verification(
branch,
root.0.into(),
root,
Scalar::from(i),
17,
));
}
}
Expand All @@ -239,9 +193,9 @@ mod tests {
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 nstack: NStack<_, PoseidonAnnotation, Blake2b> = NStack::new();
let mut ptree: PoseidonTree<_, Blake2b> = PoseidonTree::new(17);
for i in 0..1024u64 {
nstack.push(StorageScalar(Scalar::from(i as u64))).unwrap();
ptree.push(StorageScalar(Scalar::from(i as u64))).unwrap();
}

let mut composer_sizes = vec![];
Expand All @@ -255,29 +209,15 @@ mod tests {
// 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 = nstack.get(*i).unwrap().unwrap();
let branch = ptree.poseidon_branch(*i).unwrap().unwrap();

// Get tree root.
let root = StorageScalar::from(
branch
.levels()
.first()
.unwrap()
.annotation()
.unwrap()
.borrow(),
);
let root = ptree.root().unwrap();

// Add the proven leaf value to the Constraint System
let proven_leaf = composer.add_input(Scalar::from(*i));

merkle_opening_gadget(
&mut composer,
branch,
proven_leaf,
root.0.into(),
17,
);
merkle_opening_gadget(&mut composer, branch, proven_leaf, root);

// Since we don't use all of the wires, we set some dummy constraints to avoid Committing
// to zero polynomials.
Expand Down
Loading

0 comments on commit 8b8427a

Please sign in to comment.