Skip to content

Update solutions branch version to 0.5 #16

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 12 commits into
base: solutions
Choose a base branch
from
2 changes: 1 addition & 1 deletion .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Before we can merge this PR, please make sure that all the following items have
checked off. If any of the checklist items are not applicable, please leave them but
write a little note why.

- [ ] Targeted PR against correct branch (master)
- [ ] Targeted PR against correct branch (main)
- [ ] Linked to Github issue with discussion and accepted design OR have an explanation in the PR that describes this work.
- [ ] Wrote unit tests
- [ ] Updated relevant documentation in the code
Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ All other branches should be assumed to be miscellaneous feature development bra
All downstream users of the library should be using tagged versions of the library pulled from cargo.

## How to work on a fork
Please skip this section if you're familiar with contributing to opensource github projects.
Please skip this section if you're familiar with contributing to open source github projects.

First fork the repo from the github UI, and clone it locally.
Then in the repo, you want to add the repo you forked from as a new remote. You do this as:
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ First, checkout the `main` branch in the repository.
### Exercise 1: Merkle Tree Example

We'll design a simple circuit for checking a Merkle tree membership path for a given leaf.
Open [`merkle-tree-example/README.md`](./merkle-tree-example/src/README.md).
Open [`merkle-tree-example/README.md`](./merkle-tree-example/README.md).

### Exercise 2: Validating a single transaction

Expand Down
23 changes: 11 additions & 12 deletions merkle-tree-example/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
[package]
name = "merkle-tree-example"
version = "0.3.0"
version = "0.5.0"
authors = ["arkworks contributors"]
edition = "2018"

[dependencies]
ark-ff = { version = "^0.3.0", default-features = false }
ark-ec = { version = "^0.3.0", default-features = false }
ark-ed-on-bls12-381 = { version = "^0.3.0", features = ["r1cs"] }
ark-bls12-381 = { version = "^0.3.0", default-features = false }
ark-std = { version = "^0.3.0", default-features = false }
ark-relations = { version = "^0.3.0", default-features = false }
ark-ff = { version = "^0.5.0", default-features = false }
ark-ec = { version = "^0.5.0", default-features = false }
ark-ed-on-bls12-381 = { version = "^0.5.0", features = ["r1cs"] }
ark-bls12-381 = { version = "^0.5.0", default-features = false }
ark-std = { version = "^0.5.0", default-features = false }
ark-relations = { version = "^0.5.0", default-features = false }

ark-r1cs-std = { version = "^0.3.0", default-features = false }
ark-snark = { version = "^0.3.0", default-features = false }
ark-r1cs-std = { version = "^0.5.0", default-features = false }
ark-snark = { version = "^0.5.0", default-features = false }

ark-serialize = { version = "^0.3.0", default-features = false }

ark-crypto-primitives = { version = "^0.3.0", default-features = true, features = [ "r1cs" ] }
ark-serialize = { version = "^0.5.0", default-features = false }
ark-crypto-primitives = { version = "^0.5.0", default-features = true, features = [ "r1cs" , "crh", "merkle_tree"] }
tracing = { version = "0.1", default-features = false, features = [ "attributes" ] }
tracing-subscriber = { version = "0.2" }
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,10 @@ Let's go over this incantation part-by-part.

We similarly allocate the leaf as a public input variable, and allocate the parameters of the hash as "constants" in the constraint system. This means that these parameters are "baked" into the constraint system when it is created, and changing these parameters would result in a different constraint system. Finally, we allocate the membership path as a private witness variable.

Now, we must fill in the blanks by addng constraints to check the membership path. Go ahead and follow the hint in `constraints.rs` to complete this task.
Now, we must fill in the blanks by adding constraints to check the membership path. Go ahead and follow the hint in `constraints.rs` to complete this task.

## Testing our constraints

Once we've written our path-checking constraints, we have to check that the resulting constraint system satisfies two properties: that it accepts a valid membership path, and that it rejects an invalid path. We perform these checks via two tests: `merkle_tree_constraints_correctness` and `merkle_tree_constraints_soundness`. Go ahead and look at those for an example of how to test constraint systems in practice.

This wraps up this part of the tutorial. Go to the `simple_payments` folder for the next step!
This wraps up this part of the tutorial. Go to the `simple_payments` folder for the next step!
16 changes: 9 additions & 7 deletions merkle-tree-example/src/common.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
use ark_crypto_primitives::crh::constraints::{CRHGadget, TwoToOneCRHGadget};
use ark_crypto_primitives::crh::injective_map::constraints::{
PedersenCRHCompressorGadget, TECompressorGadget,
PedersenCRHCompressorGadget, PedersenTwoToOneCRHCompressorGadget, TECompressorGadget,
};
use ark_crypto_primitives::crh::injective_map::PedersenTwoToOneCRHCompressor;
use ark_crypto_primitives::crh::{
injective_map::{PedersenCRHCompressor, TECompressor},
pedersen,
};
use ark_crypto_primitives::crh::{CRHSchemeGadget, TwoToOneCRHSchemeGadget};
use ark_ed_on_bls12_381::{constraints::EdwardsVar, EdwardsProjective};

pub type TwoToOneHash = PedersenCRHCompressor<EdwardsProjective, TECompressor, TwoToOneWindow>;
pub type TwoToOneHash =
PedersenTwoToOneCRHCompressor<EdwardsProjective, TECompressor, TwoToOneWindow>;
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct TwoToOneWindow;

Expand All @@ -19,7 +21,6 @@ impl pedersen::Window for TwoToOneWindow {
}

pub type LeafHash = PedersenCRHCompressor<EdwardsProjective, TECompressor, LeafWindow>;

#[derive(Clone, PartialEq, Eq, Hash)]
pub struct LeafWindow;

Expand All @@ -29,7 +30,7 @@ impl pedersen::Window for LeafWindow {
const NUM_WINDOWS: usize = 144;
}

pub type TwoToOneHashGadget = PedersenCRHCompressorGadget<
pub type TwoToOneHashGadget = PedersenTwoToOneCRHCompressorGadget<
EdwardsProjective,
TECompressor,
TwoToOneWindow,
Expand All @@ -45,8 +46,9 @@ pub type LeafHashGadget = PedersenCRHCompressorGadget<
TECompressorGadget,
>;

pub type LeafHashParamsVar = <LeafHashGadget as CRHGadget<LeafHash, ConstraintF>>::ParametersVar;
pub type LeafHashParamsVar =
<LeafHashGadget as CRHSchemeGadget<LeafHash, ConstraintF>>::ParametersVar;
pub type TwoToOneHashParamsVar =
<TwoToOneHashGadget as TwoToOneCRHGadget<TwoToOneHash, ConstraintF>>::ParametersVar;
<TwoToOneHashGadget as TwoToOneCRHSchemeGadget<TwoToOneHash, ConstraintF>>::ParametersVar;

pub type ConstraintF = ark_ed_on_bls12_381::Fq;
61 changes: 44 additions & 17 deletions merkle-tree-example/src/constraints.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::common::*;
use crate::{common::*, MerkleConfig, MerkleConfigVar};
use crate::{Root, SimplePath};
use ark_crypto_primitives::crh::{TwoToOneCRH, TwoToOneCRHGadget, CRH};
use ark_crypto_primitives::crh::{CRHScheme, TwoToOneCRHScheme, TwoToOneCRHSchemeGadget};
use ark_crypto_primitives::merkle_tree::constraints::PathVar;
use ark_r1cs_std::prelude::*;
use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystemRef, SynthesisError};
Expand All @@ -9,18 +9,18 @@ use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystemRef, SynthesisE
// just know that these are types that you can use.)

/// The R1CS equivalent of the the Merkle tree root.
pub type RootVar = <TwoToOneHashGadget as TwoToOneCRHGadget<TwoToOneHash, ConstraintF>>::OutputVar;
pub type RootVar =
<TwoToOneHashGadget as TwoToOneCRHSchemeGadget<TwoToOneHash, ConstraintF>>::OutputVar;

/// The R1CS equivalent of the the Merkle tree path.
pub type SimplePathVar =
PathVar<crate::MerkleConfig, LeafHashGadget, TwoToOneHashGadget, ConstraintF>;
pub type SimplePathVar = PathVar<MerkleConfig, ConstraintF, MerkleConfigVar>;

////////////////////////////////////////////////////////////////////////////////

pub struct MerkleTreeVerification {
// These are constants that will be embedded into the circuit
pub leaf_crh_params: <LeafHash as CRH>::Parameters,
pub two_to_one_crh_params: <TwoToOneHash as TwoToOneCRH>::Parameters,
pub leaf_crh_params: <LeafHash as CRHScheme>::Parameters,
pub two_to_one_crh_params: <TwoToOneHash as TwoToOneCRHScheme>::Parameters,

// These are the public inputs to the circuit.
pub root: Root,
Expand Down Expand Up @@ -55,8 +55,8 @@ impl ConstraintSynthesizer<ConstraintF> for MerkleTreeVerification {
// Now, we have to check membership. How do we do that?
// Hint: look at https://github.com/arkworks-rs/crypto-primitives/blob/6be606259eab0aec010015e2cfd45e4f134cd9bf/src/merkle_tree/constraints.rs#L135

let is_member = // TODO: FILL IN THE BLANK!
path.verify_membership(
// TODO: FILL IN THE BLANK!
let is_member = path.verify_membership(
&leaf_crh_params,
&two_to_one_crh_params,
&root,
Expand All @@ -80,15 +80,24 @@ fn merkle_tree_constraints_correctness() {
let mut rng = ark_std::test_rng();

// First, let's sample the public parameters for the hash functions:
let leaf_crh_params = <LeafHash as CRH>::setup(&mut rng).unwrap();
let two_to_one_crh_params = <TwoToOneHash as TwoToOneCRH>::setup(&mut rng).unwrap();
let leaf_crh_params = <LeafHash as CRHScheme>::setup(&mut rng).unwrap();
let two_to_one_crh_params = <TwoToOneHash as TwoToOneCRHScheme>::setup(&mut rng).unwrap();

// Next, let's construct our tree.
// This follows the API in https://github.com/arkworks-rs/crypto-primitives/blob/6be606259eab0aec010015e2cfd45e4f134cd9bf/src/merkle_tree/mod.rs#L156
let tree = crate::SimpleMerkleTree::new(
&leaf_crh_params,
&two_to_one_crh_params,
&[1u8, 2u8, 3u8, 10u8, 9u8, 17u8, 70u8, 45u8], // the i-th entry is the i-th leaf.
&[
&[1u8][..],
&[2u8][..],
&[3u8][..],
&[10u8][..],
&[9u8][..],
&[17u8][..],
&[70u8][..],
&[45u8][..],
], // the i-th entry is the i-th leaf.
)
.unwrap();

Expand Down Expand Up @@ -141,23 +150,41 @@ fn merkle_tree_constraints_soundness() {
let mut rng = ark_std::test_rng();

// First, let's sample the public parameters for the hash functions:
let leaf_crh_params = <LeafHash as CRH>::setup(&mut rng).unwrap();
let two_to_one_crh_params = <TwoToOneHash as TwoToOneCRH>::setup(&mut rng).unwrap();
let leaf_crh_params = <LeafHash as CRHScheme>::setup(&mut rng).unwrap();
let two_to_one_crh_params = <TwoToOneHash as TwoToOneCRHScheme>::setup(&mut rng).unwrap();

// Next, let's construct our tree.
// This follows the API in https://github.com/arkworks-rs/crypto-primitives/blob/6be606259eab0aec010015e2cfd45e4f134cd9bf/src/merkle_tree/mod.rs#L156
let tree = crate::SimpleMerkleTree::new(
&leaf_crh_params,
&two_to_one_crh_params,
&[1u8, 2u8, 3u8, 10u8, 9u8, 17u8, 70u8, 45u8], // the i-th entry is the i-th leaf.
&[
&[1u8][..],
&[2u8][..],
&[3u8][..],
&[10u8][..],
&[9u8][..],
&[17u8][..],
&[70u8][..],
&[45u8][..],
], // the i-th entry is the i-th leaf.
)
.unwrap();

// We just mutate the first leaf
let second_tree = crate::SimpleMerkleTree::new(
&leaf_crh_params,
&two_to_one_crh_params,
&[4u8, 2u8, 3u8, 10u8, 9u8, 17u8, 70u8, 45u8], // the i-th entry is the i-th leaf.
&[
&[4u8][..],
&[2u8][..],
&[3u8][..],
&[10u8][..],
&[9u8][..],
&[17u8][..],
&[70u8][..],
&[45u8][..],
], // the i-th entry is the i-th leaf.
)
.unwrap();

Expand Down Expand Up @@ -192,4 +219,4 @@ fn merkle_tree_constraints_soundness() {
let is_satisfied = cs.is_satisfied().unwrap();
// We expect this to fail!
assert!(!is_satisfied);
}
}
46 changes: 38 additions & 8 deletions merkle-tree-example/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
use ark_crypto_primitives::crh::TwoToOneCRH;
use ark_crypto_primitives::merkle_tree::{Config, MerkleTree, Path};
use ark_crypto_primitives::crh::{
CRHScheme, CRHSchemeGadget, TwoToOneCRHScheme, TwoToOneCRHSchemeGadget,
};
use ark_crypto_primitives::merkle_tree::constraints::{BytesVarDigestConverter, ConfigGadget};
use ark_crypto_primitives::merkle_tree::{ByteDigestConverter, Config, MerkleTree, Path};

pub mod common;
use ark_r1cs_std::uint8::UInt8;
use common::*;

mod constraints;
Expand All @@ -12,35 +16,61 @@ pub struct MerkleConfig;
impl Config for MerkleConfig {
// Our Merkle tree relies on two hashes: one to hash leaves, and one to hash pairs
// of internal nodes.
type Leaf = [u8];
type LeafHash = LeafHash;
type TwoToOneHash = TwoToOneHash;
type LeafDigest = <LeafHash as CRHScheme>::Output;
type LeafInnerDigestConverter = ByteDigestConverter<Self::LeafDigest>;
type InnerDigest = <TwoToOneHash as TwoToOneCRHScheme>::Output;
}

struct MerkleConfigVar;
impl ConfigGadget<MerkleConfig, ConstraintF> for MerkleConfigVar {
type Leaf = LeafVar<ConstraintF>;
type LeafDigest = <LeafHashGadget as CRHSchemeGadget<LeafHash, ConstraintF>>::OutputVar;
type LeafInnerConverter = BytesVarDigestConverter<Self::LeafDigest, ConstraintF>;
type InnerDigest =
<TwoToOneHashGadget as TwoToOneCRHSchemeGadget<TwoToOneHash, ConstraintF>>::OutputVar;
type LeafHash = LeafHashGadget;
type TwoToOneHash = TwoToOneHashGadget;
}

type LeafVar<ConstraintF> = [UInt8<ConstraintF>];

/// A Merkle tree containing account information.
pub type SimpleMerkleTree = MerkleTree<MerkleConfig>;
/// The root of the account Merkle tree.
pub type Root = <TwoToOneHash as TwoToOneCRH>::Output;
pub type Root = <TwoToOneHash as TwoToOneCRHScheme>::Output;
/// A membership proof for a given account.
pub type SimplePath = Path<MerkleConfig>;

// Run this test via `cargo test --release test_merkle_tree`.
#[test]
fn test_merkle_tree() {
use ark_crypto_primitives::crh::CRH;
use ark_crypto_primitives::crh::CRHScheme;
// Let's set up an RNG for use within tests. Note that this is *not* safe
// for any production use.
let mut rng = ark_std::test_rng();

// First, let's sample the public parameters for the hash functions:
let leaf_crh_params = <LeafHash as CRH>::setup(&mut rng).unwrap();
let two_to_one_crh_params = <TwoToOneHash as TwoToOneCRH>::setup(&mut rng).unwrap();
let leaf_crh_params = <LeafHash as CRHScheme>::setup(&mut rng).unwrap();
let two_to_one_crh_params = <TwoToOneHash as TwoToOneCRHScheme>::setup(&mut rng).unwrap();

// Next, let's construct our tree.
// This follows the API in https://github.com/arkworks-rs/crypto-primitives/blob/6be606259eab0aec010015e2cfd45e4f134cd9bf/src/merkle_tree/mod.rs#L156
let tree = SimpleMerkleTree::new(
&leaf_crh_params,
&two_to_one_crh_params,
&[1u8, 2u8, 3u8, 10u8, 9u8, 17u8, 70u8, 45u8], // the i-th entry is the i-th leaf.
&[
&[1u8][..],
&[2u8][..],
&[3u8][..],
&[10u8][..],
&[9u8][..],
&[17u8][..],
&[70u8][..],
&[45u8][..],
], // the i-th entry is the i-th leaf.
)
.unwrap();

Expand All @@ -56,7 +86,7 @@ fn test_merkle_tree() {
&leaf_crh_params,
&two_to_one_crh_params,
&root,
&[9u8], // The claimed leaf
&[9u8][..], // The claimed leaf
)
.unwrap();
assert!(result);
Expand Down
27 changes: 14 additions & 13 deletions rollup/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "ark-rollup"
version = "0.3.0"
version = "0.5.0"
authors = [ "arkworks contributors" ]
description = "A SNARK-based rollup for a simple payments system"
repository = "https://github.com/arkworks-rs/r1cs-tutorial"
Expand All @@ -11,21 +11,22 @@ license = "MIT/Apache-2.0"
edition = "2018"

[dependencies]
ark-ff = { version = "^0.3.0", default-features = false }
ark-ec = { version = "^0.3.0", default-features = false }
ark-ed-on-bls12-381 = { version = "^0.3.0", features = ["r1cs"] }
ark-bls12-381 = { version = "^0.3.0" }
ark-std = { version = "^0.3.0", default-features = false }
ark-relations = { version = "^0.3.0", default-features = false, optional = true }
ark-ff = { version = "^0.5.0", default-features = false }
ark-ec = { version = "^0.5.0", default-features = false }
ark-ed-on-bls12-381 = { version = "^0.5.0", features = ["r1cs"] }
ark-bls12-381 = { version = "^0.5.0" }

ark-r1cs-std = { version = "^0.3.0", optional = true, default-features = false }
ark-snark = { version = "^0.3.0", default-features = false }
ark-groth16 = { version = "^0.3.0" }
ark-gm17 = { version = "^0.3.0" }
ark-std = { version = "^0.5.0", default-features = false }
ark-relations = { version = "^0.5.0", default-features = false, optional = true }

ark-serialize = { version = "^0.3.0", default-features = false }
ark-r1cs-std = { version = "^0.5.0", optional = true, default-features = false }
ark-snark = { version = "^0.5.0", default-features = false }
ark-groth16 = { version = "^0.5.0" }

ark-crypto-primitives = { version = "^0.3.0", default-features = true }

ark-serialize = { version = "^0.5.0", default-features = false }

ark-crypto-primitives = { version = "^0.5.0", default-features = true }
ark-simple-payments = { path = "../simple-payments", default-features = true }
blake2 = { version = "0.9" }
digest = "0.9"
Expand Down
Loading