Skip to content
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

[API] Refactor Merkle tree and its gadget #88

Closed
alxiong opened this issue Jul 29, 2022 · 2 comments · Fixed by #120 or #135
Closed

[API] Refactor Merkle tree and its gadget #88

alxiong opened this issue Jul 29, 2022 · 2 comments · Fixed by #120 or #135
Assignees
Milestone

Comments

@alxiong
Copy link
Contributor

alxiong commented Jul 29, 2022

Current API for MT and its gadgets need some refactoring, e.g. here's the code we use in ZPrice to generate a circuit of lots of Merkle Proof verification:

    // construct circuit constraining membership proof check
    let mut circuit = PlonkCircuit::new();
    // add root as a public input
    let root_var = circuit.create_public_variable(root)?;
    for (uid, proof) in merkle_proofs.iter().enumerate() {
        let leaf_var = circuit.create_variable(leaves[uid])?;
        let proof_var = AccMemberWitnessVar::new(&mut circuit, proof)?;
        let acc_elem_var = AccElemVars {
            uid: proof_var.uid,
            elem: leaf_var,
        };

        let claimed_root_var = circuit.compute_merkle_root(acc_elem_var, &proof_var.merkle_path)?;

        // enforce matching merkle root
        circuit.equal_gate(root_var, claimed_root_var)?;
    }

    // sanity check: the circuit must be satisfied.
    assert!(circuit.check_circuit_satisfiability(&[root]).is_ok());
  • mixed style of Struct::new() and field filling to instantiate structs
  • numerous MerklePath, MerkleNode etc are slightly confusing
  • gadget APIs are not intuitive at all
@alxiong
Copy link
Contributor Author

alxiong commented Aug 10, 2022

we should define something like trait AppendOnlyMerkleTree (or ForgettableMerkleTree or whatever, name subject to change), so that the interface of our MT is clear from the outset.

@mrain mrain linked a pull request Sep 15, 2022 that will close this issue
13 tasks
@mrain mrain mentioned this issue Nov 14, 2022
6 tasks
@alxiong
Copy link
Contributor Author

alxiong commented Nov 25, 2022

I feel that the following is more ergonomic:

use ark_ff::PrimeField;
use jf_relation::{errors::CircuitError, BoolVar, PlonkCircuit};

use crate::{
    merkle_tree::{
        prelude::{RescueMerkleTree, RescueSparseMerkleTree},
        MerkleTreeScheme, UniversalMerkleTreeScheme,
    },
    rescue::RescueParameter,
};

/// Gadgets for rescue-based merkle tree
pub trait MerkleTreeGadget<F: PrimeField + RescueParameter> {
    /// given an element and its merkle proof in a `RescueMerkleTree`,
    /// return `BoolVar` indicating the correctness of its membership proof
    fn is_member(
        &mut self,
        elem: &<RescueMerkleTree<F> as MerkleTreeScheme>::Element,
        merkle_proof: &<RescueMerkleTree<F> as MerkleTreeScheme>::MembershipProof,
        merkle_root: &<RescueMerkleTree<F> as MerkleTreeScheme>::NodeValue,
    ) -> Result<BoolVar, CircuitError>;

    /// Enforce correct `merkle_proof` for the `elem` against
    /// `expected_merkle_root`.
    fn enforce_merkle_proof(
        &mut self,
        elem: &<RescueMerkleTree<F> as MerkleTreeScheme>::Element,
        merkle_proof: &<RescueMerkleTree<F> as MerkleTreeScheme>::MembershipProof,
        expected_merkle_root: &<RescueMerkleTree<F> as MerkleTreeScheme>::NodeValue,
    ) -> Result<(), CircuitError>;
}

/// Gadget for sparse merkle tree and key-value map tree
pub trait SparseMerkleTreeGadget<F: PrimeField + RescueParameter> {
    /// checking non-membership proof
    fn is_non_member(
        &mut self,
        elem: &<RescueSparseMerkleTree<F, F> as MerkleTreeScheme>::Element,
        nonmerkle_proof: &<RescueSparseMerkleTree<F, F> as UniversalMerkleTreeScheme>::NonMembershipProof,
        merkle_root: &<RescueSparseMerkleTree<F, F> as MerkleTreeScheme>::NodeValue,
    ) -> Result<BoolVar, CircuitError>;
}

impl<F> MerkleTreeGadget<F> for PlonkCircuit<F>
where
    F: PrimeField + RescueParameter,
{
    fn is_member(
        &mut self,
        _elem: &<RescueMerkleTree<F> as MerkleTreeScheme>::Element,
        _merkle_proof: &<RescueMerkleTree<F> as MerkleTreeScheme>::MembershipProof,
        _merkle_root: &<RescueMerkleTree<F> as MerkleTreeScheme>::NodeValue,
    ) -> Result<BoolVar, CircuitError> {
        todo!();
    }

    fn enforce_merkle_proof(
        &mut self,
        elem: &<RescueMerkleTree<F> as MerkleTreeScheme>::Element,
        merkle_proof: &<RescueMerkleTree<F> as MerkleTreeScheme>::MembershipProof,
        expected_merkle_root: &<RescueMerkleTree<F> as MerkleTreeScheme>::NodeValue,
    ) -> Result<(), CircuitError> {
        let is_member = self.is_member(elem, merkle_proof, expected_merkle_root)?;
        self.enforce_true(is_member.into())
    }
}

@mrain @tessico

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants