From 23e501863e356ad0c82fea5d7833987cb2d80a33 Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Fri, 4 Jun 2021 20:05:55 +0800 Subject: [PATCH] Do not take in root in merkle_path_check(). In the Orchard circuit, the root (i.e. anchor) is a public input. We will not have direct access to its value in the circuit, but will instead constrain the output of the Merkle hash to be equal to the corresponding cell in the public input column. --- src/circuit/gadget/merkle.rs | 86 ++++++++++-------------------------- 1 file changed, 23 insertions(+), 63 deletions(-) diff --git a/src/circuit/gadget/merkle.rs b/src/circuit/gadget/merkle.rs index 5af5de3a2..38bb2a99c 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}, + plonk::{Advice, Column, ConstraintSystem, Error, Expression, Fixed, Permutation}, poly::Rotation, }; use pasta_curves::arithmetic::{CurveAffine, FieldExt}; @@ -37,7 +37,6 @@ pub trait MerkleInstructions< layouter: impl Layouter, domain: &>::HashDomains, start_height: usize, - root: Option, node: (>::Var, Option), merkle_path: Vec>, ) -> Result<>::Var, Error>; @@ -57,7 +56,6 @@ pub trait MerkleInstructions< #[derive(Clone, Debug)] pub struct MerkleConfig { - q_merkle: Selector, a: Column, b: Column, c: Column, @@ -103,7 +101,6 @@ impl( impl MerkleInstructions for MerkleChip { - /// Check the validity of a Merkle path from a given leaf to a claimed root. + /// Hash a Merkle path from a given leaf and output the root. #[allow(non_snake_case)] fn merkle_path_check( &self, mut layouter: impl Layouter, domain: &>::HashDomains, start_height: usize, - root: Option, node: (>::Var, Option), merkle_path: Vec>, ) -> Result<>::Var, Error> { @@ -300,31 +286,6 @@ impl { - root: Option, leaf: (Option, Option), merkle_path: Vec>, _marker: PhantomData, @@ -783,8 +743,9 @@ pub mod tests { let merkle_chip_1 = MerkleChip::::construct( config.0.clone(), ); - let merkle_chip_2 = - MerkleChip::::construct(config.1); + let merkle_chip_2 = MerkleChip::::construct( + config.1.clone(), + ); // Process lo half of the Merkle path from leaf to intermediate root. let leaf = merkle_chip_1.load_private( @@ -793,25 +754,11 @@ pub mod tests { self.leaf.0, )?; let pos_lo = self.leaf.1.map(|pos| pos & ((1 << PATH_LENGTH) - 1)); - let pos_lo_bool = pos_lo.map(i2lebsp::<16>); - - let path_lo: Option> = self.merkle_path[0..PATH_LENGTH] - .to_vec() - .into_iter() - .collect(); - - let intermediate_root = self - .leaf - .0 - .zip(pos_lo_bool) - .zip(path_lo) - .map(|((leaf, pos), path)| hash_path(&merkle_crh, 0, leaf, &pos, &path)); let intermediate_root = merkle_chip_1.merkle_path_check( layouter.namespace(|| ""), &SinsemillaHashDomains::MerkleCrh, 0, - intermediate_root, (leaf, pos_lo), self.merkle_path[0..PATH_LENGTH].to_vec(), )?; @@ -819,15 +766,28 @@ pub mod tests { // Process hi half of the Merkle path from intermediate root to root. let pos_hi = self.leaf.1.map(|pos| pos >> (PATH_LENGTH)); - merkle_chip_2.merkle_path_check( + let computed_final_root = merkle_chip_2.merkle_path_check( layouter.namespace(|| ""), &SinsemillaHashDomains::MerkleCrh, PATH_LENGTH, - self.root, (intermediate_root, pos_hi), self.merkle_path[PATH_LENGTH..].to_vec(), )?; + // The expected final root + let pos_bool = i2lebsp::<32>(self.leaf.1.unwrap()); + let path: Option> = self.merkle_path.to_vec().into_iter().collect(); + let final_root = hash_path( + &merkle_crh, + 0, + self.leaf.0.unwrap(), + &pos_bool, + &path.unwrap(), + ); + + // Check the computed final root against the expected final root. + assert_eq!(computed_final_root.value().unwrap(), final_root); + Ok(()) } } @@ -888,10 +848,10 @@ pub mod tests { .map(|_| pallas::Base::rand()) .collect(); - let root = hash_path(&merkle_crh, 0, leaf, &pos_bool, &path); + // This root is provided as a public input in the Orchard circuit. + let _root = hash_path(&merkle_crh, 0, leaf, &pos_bool, &path); let circuit = MyCircuit:: { - root: Some(root), leaf: (Some(leaf), Some(pos)), merkle_path: path.into_iter().map(Some).collect(), _marker: PhantomData,