diff --git a/src/circuit/gadget/merkle.rs b/src/circuit/gadget/merkle.rs index 5af5de3a2..a8031002c 100644 --- a/src/circuit/gadget/merkle.rs +++ b/src/circuit/gadget/merkle.rs @@ -1,6 +1,6 @@ use halo2::{ - circuit::{Chip, Layouter}, - plonk::{Advice, Column, ConstraintSystem, Error, Expression, Fixed, Permutation, Selector}, + circuit::{Cell, Chip, Layouter}, + plonk::{Advice, Column, ConstraintSystem, Error, Expression, Fixed, Permutation}, poly::Rotation, }; use pasta_curves::arithmetic::{CurveAffine, FieldExt}; @@ -37,7 +37,7 @@ pub trait MerkleInstructions< layouter: impl Layouter, domain: &>::HashDomains, start_height: usize, - root: Option, + root: Cell, node: (>::Var, Option), merkle_path: Vec>, ) -> Result<>::Var, Error>; @@ -57,7 +57,6 @@ pub trait MerkleInstructions< #[derive(Clone, Debug)] pub struct MerkleConfig { - q_merkle: Selector, a: Column, b: Column, c: Column, @@ -103,7 +102,6 @@ impl, domain: &>::HashDomains, start_height: usize, - root: Option, + root: Cell, node: (>::Var, Option), merkle_path: Vec>, ) -> Result<>::Var, Error> { @@ -300,29 +288,10 @@ impl { - root: Option, + root: C::Base, leaf: (Option, Option), merkle_path: Vec>, _marker: PhantomData, @@ -784,7 +753,7 @@ pub mod tests { config.0.clone(), ); let merkle_chip_2 = - MerkleChip::::construct(config.1); + MerkleChip::::construct(config.1.clone()); // Process lo half of the Merkle path from leaf to intermediate root. let leaf = merkle_chip_1.load_private( @@ -800,6 +769,7 @@ pub mod tests { .into_iter() .collect(); + // Compute the intermediate root let intermediate_root = self .leaf .0 @@ -807,15 +777,30 @@ pub mod tests { .zip(path_lo) .map(|((leaf, pos), path)| hash_path(&merkle_crh, 0, leaf, &pos, &path)); + // Witness the intermediate root + let intermediate_root = merkle_chip_1.load_private( + layouter.namespace(|| "intermediate root"), + config.0.a, + intermediate_root, + )?; + let intermediate_root = merkle_chip_1.merkle_path_check( layouter.namespace(|| ""), &SinsemillaHashDomains::MerkleCrh, 0, - intermediate_root, + intermediate_root.cell(), (leaf, pos_lo), self.merkle_path[0..PATH_LENGTH].to_vec(), )?; + // Witness the final root. In the Orchard circuit, this is a public + // input that will be constrained to equal some cell in an advice column. + let final_root = merkle_chip_2.load_private( + layouter.namespace(|| "final root"), + config.1.a, + Some(self.root), + )?; + // Process hi half of the Merkle path from intermediate root to root. let pos_hi = self.leaf.1.map(|pos| pos >> (PATH_LENGTH)); @@ -823,7 +808,7 @@ pub mod tests { layouter.namespace(|| ""), &SinsemillaHashDomains::MerkleCrh, PATH_LENGTH, - self.root, + final_root.cell(), (intermediate_root, pos_hi), self.merkle_path[PATH_LENGTH..].to_vec(), )?; @@ -891,7 +876,7 @@ pub mod tests { let root = hash_path(&merkle_crh, 0, leaf, &pos_bool, &path); let circuit = MyCircuit:: { - root: Some(root), + root, leaf: (Some(leaf), Some(pos)), merkle_path: path.into_iter().map(Some).collect(), _marker: PhantomData,