Skip to content

Commit

Permalink
Merge pull request #121 from dusk-network/release-0.20
Browse files Browse the repository at this point in the history
Update `plonk` from `0.6` to `0.7` (#120)
  • Loading branch information
vlopes11 authored Apr 6, 2021
2 parents 4a27474 + bfa13ea commit 91bab8c
Show file tree
Hide file tree
Showing 7 changed files with 175 additions and 75 deletions.
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [0.20.0] - 2021-04-06

### Changed

- Update `dusk-plonk` from `0.6` to `0.7` #119
- Update `dusk-hades` from `0.14` to `0.15` #119

### Fixed

- Merkle Opening constant circuit description [#122]

## [0.19.0] - 2021-03-11

### Changed
Expand Down
6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "dusk-poseidon"
version = "0.19.0"
version = "0.20.0"
authors = [
"zer0 <matteo@dusk.network>", "vlopes11 <victor@dusk.network>", "CPerezz <carlos@dusk.network>", "Kristoffer Ström <kristoffer@dusk.network>"
]
Expand All @@ -15,13 +15,13 @@ repository = "https://github.com/dusk-network/poseidon252"
dusk-bls12_381 = {version = "0.6", default-features = false}
dusk-jubjub = {version = "0.8", default-features = false}
dusk-bytes = "0.1"
dusk-hades = { version = "0.14", default-features = false }
dusk-hades = { version = "0.15", default-features = false }
canonical = {version = "0.5", optional = true}
canonical_derive = {version = "0.5", optional = true}
microkelvin = {version = "0.6", optional = true}
nstack = {version = "0.7", optional = true}

dusk-plonk = {version="0.6", default-features = false, optional = true}
dusk-plonk = {version="0.7", default-features = false, optional = true}
anyhow = { version = "1.0", optional = true }
thiserror = { version = "1.0", optional = true }

Expand Down
5 changes: 1 addition & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,10 +140,7 @@ fn main() -> Result<()> {
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::<DEPTH>(composer, &branch, leaf);
let root_p = merkle_opening::<DEPTH>(composer, &branch);
composer.constrain_to_constant(root_p, BlsScalar::zero(), Some(-root));
};
Expand Down
13 changes: 12 additions & 1 deletion src/tree/branch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,20 @@ pub struct PoseidonLevel {
impl PoseidonLevel {
/// Represents the offset of a node for a given path produced by a branch
/// in a merkle opening
pub fn offset(&self) -> u64 {
///
/// The first position in a level set is represented as offset `1` because internally the hades
/// permutation preprend the bitflags for merkle opening consistency
pub const fn offset(&self) -> u64 {
self.offset
}

/// Represents the current level offset as a bitflag
///
/// The LSB (least significant bit) represents the offset `1`. Any increment on the offset will
/// left shift this flag by `1`.
pub const fn offset_flag(&self) -> u64 {
1 << (self.offset - 1)
}
}

impl Deref for PoseidonLevel {
Expand Down
5 changes: 1 addition & 4 deletions src/tree/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,7 @@
//! 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::<DEPTH>(composer, &branch, leaf);
//! let root_p = merkle_opening::<DEPTH>(composer, &branch);
//! composer.constrain_to_constant(root_p, BlsScalar::zero(), Some(-root));
//! };
//!
Expand Down
11 changes: 11 additions & 0 deletions src/tree/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use canonical_host::MemStore;
use core::borrow::Borrow;
use dusk_bls12_381::BlsScalar;
use dusk_hades::{ScalarStrategy, Strategy};
use rand::{CryptoRng, RngCore};

#[derive(Debug, Default, Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Canon)]
pub struct MockLeaf {
Expand All @@ -21,6 +22,16 @@ pub struct MockLeaf {
pub expiration: u64,
}

impl MockLeaf {
pub fn random<R: RngCore + CryptoRng>(rng: &mut R) -> Self {
let s = BlsScalar::random(rng);
let pos = 0;
let expiration = rng.next_u64();

Self { s, pos, expiration }
}
}

impl From<u64> for MockLeaf {
fn from(n: u64) -> MockLeaf {
MockLeaf {
Expand Down
199 changes: 136 additions & 63 deletions src/tree/zk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ use dusk_plonk::prelude::*;
pub fn merkle_opening<const DEPTH: usize>(
composer: &mut StandardComposer,
branch: &PoseidonBranch<DEPTH>,
leaf: Variable,
) -> Variable {
// Generate and constraint zero.
let zero = composer.add_witness_to_circuit_description(BlsScalar::zero());
Expand All @@ -24,21 +23,61 @@ pub fn merkle_opening<const DEPTH: usize>(
// For every level, replace the level offset with needle,
// permutate the level and set the needle to the next level
// to the poseidon result of the permutation
branch.as_ref().iter().fold(leaf, |needle, level| {
let offset = level.offset() as usize;

level.as_ref().iter().enumerate().for_each(|(i, l)| {
if i != offset {
perm[i] = composer.add_input(*l);
}
branch.as_ref().iter().for_each(|level| {
// Create the bits representation of the offset as witness
let offset_flag = level.offset_flag();
let mut sum = zero;
let mut offset_bits = [zero; dusk_hades::WIDTH - 1];
offset_bits.iter_mut().fold(1, |mask, bit| {
*bit = composer
.add_input(BlsScalar::from((offset_flag & mask).min(1)));

sum = composer.add(
(BlsScalar::one(), sum),
(BlsScalar::one(), *bit),
BlsScalar::zero(),
None,
);

mask << 1
});
composer.constrain_to_constant(sum, BlsScalar::one(), None);

let leaf = composer.add_input(**level);
level
.as_ref()
.iter()
.zip(perm.iter_mut())
.enumerate()
.for_each(|(i, (l, p))| {
*p = composer.add_input(*l);

if i > 0 {
let b = offset_bits[i - 1];

let a = composer.mul(
BlsScalar::one(),
b,
*p,
BlsScalar::zero(),
None,
);

let b = composer.mul(
BlsScalar::one(),
b,
leaf,
BlsScalar::zero(),
None,
);

composer.assert_equal(a, b);
}
});

root = perm[1];
perm[offset] = needle;

let mut h = GadgetStrategy::new(composer);
h.perm(&mut perm);
perm[1]
});

root
Expand All @@ -47,64 +86,98 @@ pub fn merkle_opening<const DEPTH: usize>(
#[cfg(test)]
mod tests {
use crate::tree::tests::MockLeaf;
use crate::tree::{merkle_opening, PoseidonAnnotation, PoseidonTree};
use anyhow::Result;
use crate::tree::{self, PoseidonAnnotation, PoseidonBranch, PoseidonTree};
use canonical_host::MemStore;
use dusk_plonk::circuit;
use dusk_plonk::error::Error as PlonkError;
use dusk_plonk::prelude::*;
use rand::rngs::StdRng;
use rand::SeedableRng;
use rand::{CryptoRng, RngCore};

#[test]
fn tree_merkle_opening() -> Result<()> {
const DEPTH: usize = 17;

let pub_params =
PublicParameters::setup(1 << 15, &mut rand::thread_rng())?;
let (ck, ok) = pub_params.trim(1 << 15)?;

let mut tree: PoseidonTree<
MockLeaf,
PoseidonAnnotation,
MemStore,
DEPTH,
> = PoseidonTree::new();

for i in 0..1024 {
let l = MockLeaf::from(i as u64);
tree.push(l).unwrap();
const DEPTH: usize = 17;
const CAPACITY: usize = 1 << 15;
type Tree = PoseidonTree<MockLeaf, PoseidonAnnotation, MemStore, DEPTH>;

struct MerkleOpeningCircuit {
branch: PoseidonBranch<DEPTH>,
}

impl MerkleOpeningCircuit {
pub fn random<R: RngCore + CryptoRng>(
rng: &mut R,
tree: &mut Tree,
) -> Self {
let leaf = MockLeaf::random(rng);
let pos = tree
.push(leaf.clone())
.expect("Failed to append to the tree");

let branch = tree
.branch(pos)
.expect("Failed to read the tree for the branch")
.expect("Failed to fetch the branch of the created leaf from the tree");

Self { branch }
}

let gadget_tester = |composer: &mut StandardComposer,
tree: &PoseidonTree<
MockLeaf,
PoseidonAnnotation,
MemStore,
DEPTH,
>,
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::<DEPTH>(composer, &branch, leaf);
composer.constrain_to_constant(root_p, BlsScalar::zero(), Some(-root));
};

let label = b"opening_gadget";

for i in [0, 567, 1023].iter() {
let mut prover = Prover::new(label);
gadget_tester(prover.mut_cs(), &tree, *i);
prover.preprocess(&ck)?;
let proof = prover.prove(&ck)?;

let mut verifier = Verifier::new(label);
gadget_tester(verifier.mut_cs(), &tree, *i);
verifier.preprocess(&ck)?;
let pi = verifier.mut_cs().construct_dense_pi_vec();
verifier.verify(&proof, &ok, &pi).unwrap();
pub fn public_inputs(&self) -> Vec<PublicInputValue> {
vec![(*self.branch.root()).into()]
}
}

impl Circuit for MerkleOpeningCircuit {
const CIRCUIT_ID: [u8; 32] = [0xff; 32];

fn gadget(
&mut self,
composer: &mut StandardComposer,
) -> Result<(), PlonkError> {
let root = self.branch.root();
let root_p = tree::merkle_opening::<DEPTH>(composer, &self.branch);

Ok(())
composer.constrain_to_constant(
root_p,
BlsScalar::zero(),
Some(-root),
);

Ok(())
}

fn padded_circuit_size(&self) -> usize {
CAPACITY
}
}

#[test]
fn tree_merkle_opening() {
let mut rng = StdRng::seed_from_u64(0xbeef);
let pp = PublicParameters::setup(CAPACITY, &mut rng).unwrap();
let label = b"dusk-network";

let mut tree = Tree::default();
let mut circuit = MerkleOpeningCircuit::random(&mut rng, &mut tree);
let (pk, vd) = circuit.compile(&pp).expect("Failed to compile circuit");

let mut tree = Tree::default();
for _ in 0..13 {
let mut circuit = MerkleOpeningCircuit::random(&mut rng, &mut tree);

let proof = circuit
.gen_proof(&pp, &pk, label)
.expect("Failed to generate proof");
let pi = circuit.public_inputs();

circuit::verify_proof(
&pp,
vd.key(),
&proof,
pi.as_slice(),
vd.pi_pos(),
label,
)
.expect("Proof verification failed");
}
}
}

0 comments on commit 91bab8c

Please sign in to comment.