Skip to content

Commit

Permalink
Configure Merkle chip (create gates)
Browse files Browse the repository at this point in the history
  • Loading branch information
therealyingtong committed Jun 3, 2021
1 parent 1e1185d commit 8075681
Showing 1 changed file with 103 additions and 0 deletions.
103 changes: 103 additions & 0 deletions src/circuit/gadget/orchard_action/merkle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,109 @@ pub struct MerkleChip<
_marker: PhantomData<C>,
}

impl<C: CurveAffine, const PATH_LENGTH: usize, const K: usize, const MAX_WORDS: usize>
MerkleChip<C, PATH_LENGTH, K, MAX_WORDS>
{
pub fn configure(
meta: &mut ConstraintSystem<C::Base>,
advices: [Column<Advice>; 5],
lookup: (Column<Fixed>, Column<Fixed>, Column<Fixed>),
perm: Permutation,
) -> MerkleConfig<PATH_LENGTH> {
let cond_swap_config =
CondSwapChip::configure(meta, advices[..5].try_into().unwrap(), perm.clone());
let sinsemilla_config = SinsemillaChip::<C, K, MAX_WORDS>::configure(
meta,
advices[..5].try_into().unwrap(),
lookup,
perm.clone(),
);

let a = advices[0];
let b = advices[1];
let c = advices[2];
let left = advices[3];
let right = advices[4];

let q_merkle = meta.selector();
let l_star = meta.fixed_column();

// Check that pieces have been decomposed correctly for Sinsemilla hash.
// <https://zips.z.cash/protocol/nu5.pdf#orchardmerklecrh>
//
// `a = a_0||a_1` = `l_star` || (bits 0..=239 of `left`)
// `b = b_0||b_1` = (bits 240..=254 of `left`) || (bits 0..=234 of `right`)
// `c = bits 235..=254 of `right`
meta.create_gate("Merkle path validity check", |meta| {
let a_whole = meta.query_advice(a, Rotation::cur());
let b_whole = meta.query_advice(b, Rotation::cur());
let c_whole = meta.query_advice(c, Rotation::cur());
let left_node = meta.query_advice(left, Rotation::cur());
let right_node = meta.query_advice(right, Rotation::cur());

let a_0 = meta.query_advice(a, Rotation::next());
let a_1 = meta.query_advice(b, Rotation::next());
let b_0 = meta.query_advice(c, Rotation::next());
let b_1 = meta.query_advice(left, Rotation::next());

let l_star_plus1 = meta.query_fixed(l_star, Rotation::cur());

// a = a_0||a_1` = `l_star` (10 bits) || (bits 0..=239 of `left`)
// Check that a = a_0 || a_1
let a_check = a_0.clone() + a_1.clone() * C::Base::from_u64(1 << 10) - a_whole;

// Check that a_0 = l_star
let l_star_check = a_0 - (l_star_plus1.clone() - Expression::Constant(C::Base::one()));

// `b = b_0||b_1` = (bits 240..=254 of `left`) || (bits 0..=234 of `right`)
// Check that b = b_0 (15 bits) || b_1 (235 bits)
let b_check = b_0.clone() + b_1.clone() * C::Base::from_u64(1 << 15) - b_whole;

// Check that left = a_1 (240 bits) || b_0 (15 bits)
let two_pow_240 = C::Base::from_u128(1 << 120).square();
let left_check = a_1 + b_0 * two_pow_240 - left_node;

// Check that right = b_1 (235 bits) || c (20 bits)
let two_pow_235 = C::Base::from_u64(1 << 47).pow(&[5, 0, 0, 0]);
let right_check = b_1 + c_whole * two_pow_235 - right_node;

[a_check, l_star_check, b_check, left_check, right_check]
.iter()
.map(|poly| l_star_plus1.clone() * poly.clone())
.collect()
});

// Check that root is recovered at the end of Merkle hash.
meta.create_gate("Root check", |meta| {
let q_merkle = meta.query_selector(q_merkle, Rotation::cur());
let root = meta.query_advice(a, Rotation::cur());
let computed_root = meta.query_advice(b, Rotation::cur());

vec![q_merkle * (root - computed_root)]
});

MerkleConfig {
q_merkle,
a,
b,
c,
left,
right,
l_star,
perm,
cond_swap_config,
sinsemilla_config,
}
}

pub fn construct(config: MerkleConfig<PATH_LENGTH>) -> Self {
MerkleChip {
config,
_marker: PhantomData,
}
}
}

impl<C: CurveAffine, const PATH_LENGTH: usize, const K: usize, const MAX_WORDS: usize> Chip<C::Base>
for MerkleChip<C, PATH_LENGTH, K, MAX_WORDS>
{
Expand Down

0 comments on commit 8075681

Please sign in to comment.