diff --git a/src/circuit.rs b/src/circuit.rs index f8e97b20..2fa22192 100644 --- a/src/circuit.rs +++ b/src/circuit.rs @@ -256,6 +256,7 @@ impl plonk::Circuit for Circuit { meta, advices[..5].try_into().unwrap(), advices[6], + lagrange_coeffs[0], lookup, range_check.clone(), ); @@ -273,6 +274,7 @@ impl plonk::Circuit for Circuit { meta, advices[5..].try_into().unwrap(), advices[7], + lagrange_coeffs[1], lookup, range_check, ); diff --git a/src/circuit/gadget/sinsemilla.rs b/src/circuit/gadget/sinsemilla.rs index ddff43fe..7c1d7073 100644 --- a/src/circuit/gadget/sinsemilla.rs +++ b/src/circuit/gadget/sinsemilla.rs @@ -484,6 +484,7 @@ mod tests { meta, advices[..5].try_into().unwrap(), advices[2], + lagrange_coeffs[0], lookup, range_check.clone(), ); @@ -491,6 +492,7 @@ mod tests { meta, advices[5..].try_into().unwrap(), advices[7], + lagrange_coeffs[1], lookup, range_check, ); diff --git a/src/circuit/gadget/sinsemilla/chip.rs b/src/circuit/gadget/sinsemilla/chip.rs index fed40eb5..8858c87e 100644 --- a/src/circuit/gadget/sinsemilla/chip.rs +++ b/src/circuit/gadget/sinsemilla/chip.rs @@ -30,13 +30,16 @@ mod hash_to_point; /// Configuration for the Sinsemilla hash chip #[derive(Eq, PartialEq, Clone, Debug)] pub struct SinsemillaConfig { - /// Selector used in the lookup argument as well as Sinsemilla custom gates. + /// Binary selector used in lookup argument and in the body of the Sinsemilla hash. q_sinsemilla1: Selector, - /// Fixed column used in Sinsemilla custom gates, to toggle behaviour at the ends of - /// message pieces. + /// Non-binary selector used in lookup argument and in the body of the Sinsemilla hash. q_sinsemilla2: Column, - /// Fixed column used to constrain hash initialization to be consistent with + /// q_sinsemilla2 is used to define a synthetic selector, + /// q_sinsemilla3 = (q_sinsemilla2) ⋅ (q_sinsemilla2 - 1) + /// Simple selector used to constrain hash initialization to be consistent with /// the y-coordinate of the domain $Q$. + q_sinsemilla4: Selector, + /// Fixed column used to load the y-coordinate of the domain $Q$. fixed_y_q: Column, /// Advice column used to store the x-coordinate of the accumulator at each /// iteration of the hash. @@ -110,6 +113,7 @@ impl SinsemillaChip { meta: &mut ConstraintSystem, advices: [Column; 5], witness_pieces: Column, + fixed_y_q: Column, lookup: (Column, Column, Column), range_check: LookupRangeCheckConfig, ) -> >::Config { @@ -121,7 +125,8 @@ impl SinsemillaChip { let config = SinsemillaConfig { q_sinsemilla1: meta.selector(), q_sinsemilla2: meta.fixed_column(), - fixed_y_q: meta.fixed_column(), + q_sinsemilla4: meta.selector(), + fixed_y_q, x_a: advices[0], x_p: advices[1], bits: advices[2], @@ -139,8 +144,7 @@ impl SinsemillaChip { // Set up lookup argument GeneratorTableConfig::configure(meta, config.clone()); - // Constant expressions - let two = Expression::Constant(pallas::Base::from_u64(2)); + let two = pallas::Base::from_u64(2); // Closures for expressions that are derived multiple times // x_r = lambda_1^2 - x_a - x_p @@ -159,14 +163,28 @@ impl SinsemillaChip { (lambda_1 + lambda_2) * (x_a - x_r(meta, rotation)) }; + // Check that the initial x_A, x_P, lambda_1, lambda_2 are consistent with y_Q. + meta.create_gate("Initial y_Q", |meta| { + let q_s4 = meta.query_selector(config.q_sinsemilla4); + let y_q = meta.query_fixed(config.fixed_y_q, Rotation::cur()); + + // Y_A = (lambda_1 + lambda_2) * (x_a - x_r) + let Y_A_cur = Y_A(meta, Rotation::cur()); + + // 2 * y_q - Y_{A,0} = 0 + let init_y_q_check = y_q * two - Y_A_cur; + + vec![q_s4 * init_y_q_check] + }); + meta.create_gate("Sinsemilla gate", |meta| { let q_s1 = meta.query_selector(config.q_sinsemilla1); - let q_s2 = meta.query_fixed(config.q_sinsemilla2, Rotation::cur()); + // q_s3 = (q_s2) * (q_s2 - 1) let q_s3 = { let one = Expression::Constant(pallas::Base::one()); + let q_s2 = meta.query_fixed(config.q_sinsemilla2, Rotation::cur()); q_s2.clone() * (q_s2 - one) }; - let fixed_y_q = meta.query_fixed(config.fixed_y_q, Rotation::cur()); let lambda_1_next = meta.query_advice(config.lambda_1, Rotation::next()); let lambda_2_cur = meta.query_advice(config.lambda_2, Rotation::cur()); @@ -182,10 +200,6 @@ impl SinsemillaChip { // Y_A = (lambda_1 + lambda_2) * (x_a - x_r) let Y_A_next = Y_A(meta, Rotation::next()); - // Check that the initial x_A, x_P, lambda_1, lambda_2 are consistent with y_Q. - // fixed_y_q * (2 * fixed_y_q - Y_{A,0}) = 0 - let init_y_q_check = fixed_y_q.clone() * (two.clone() * fixed_y_q - Y_A_cur.clone()); - // lambda2^2 - (x_a_next + x_r + x_a_cur) = 0 let secant_line = lambda_2_cur.clone().square() - (x_a_next.clone() + x_r + x_a_cur.clone()); @@ -202,15 +216,14 @@ impl SinsemillaChip { // y_a_final is assigned to the lambda1 column on the next offset. let y_a_final = lambda_1_next; - two.clone() * Y_A_cur - + (two.clone() - q_s3.clone()) * Y_A_next - + two * q_s3 * y_a_final + Y_A_cur * two + + (Expression::Constant(two) - q_s3.clone()) * Y_A_next + + q_s3 * two * y_a_final }; lhs - rhs }; vec![ - ("Initial y_q", init_y_q_check), ("Secant line", q_s1.clone() * secant_line), ("y check", q_s1 * y_check), ] diff --git a/src/circuit/gadget/sinsemilla/chip/hash_to_point.rs b/src/circuit/gadget/sinsemilla/chip/hash_to_point.rs index 1e6c7f79..e36b87a1 100644 --- a/src/circuit/gadget/sinsemilla/chip/hash_to_point.rs +++ b/src/circuit/gadget/sinsemilla/chip/hash_to_point.rs @@ -35,34 +35,25 @@ impl SinsemillaChip { let x_q = *Q.coordinates().unwrap().x(); let y_q = *Q.coordinates().unwrap().y(); - // Initialize the accumulator to `Q`. - let (mut x_a, mut y_a): (X, Y) = { - // Constrain the initial x_q to equal the x-coordinate of the domain's `Q`. + // Constrain the initial x_a, lambda_1, lambda_2, x_p using the q_sinsemilla4 + // selector. + let mut y_a: Y = { + // Enable `q_sinsemilla4` on the first row. + config.q_sinsemilla4.enable(region, offset)?; + region.assign_fixed(|| "fixed y_q", config.fixed_y_q, offset, || Ok(y_q))?; + + (Some(y_q)).into() + }; + + // Constrain the initial x_q to equal the x-coordinate of the domain's `Q`. + let mut x_a: X = { let x_a = { let cell = region.assign_advice_from_constant(|| "fixed x_q", config.x_a, offset, x_q)?; CellValue::new(cell, Some(x_q)) }; - // Constrain the initial x_a, lambda_1, lambda_2, x_p using the fixed y_q - // initializer. Assign `fixed_y_q` to be zero on every other row. - { - region.assign_fixed(|| "fixed y_q", config.fixed_y_q, offset, || Ok(y_q))?; - - let total_num_words = message.iter().map(|piece| piece.num_words()).sum(); - for row in 1..total_num_words { - region.assign_fixed( - || "fixed y_q", - config.fixed_y_q, - offset + row, - || Ok(pallas::Base::zero()), - )?; - } - } - - let y_a = Some(y_q); - - (x_a.into(), y_a.into()) + x_a.into() }; let mut zs_sum: Vec>> = Vec::new(); diff --git a/src/circuit/gadget/sinsemilla/commit_ivk.rs b/src/circuit/gadget/sinsemilla/commit_ivk.rs index d460a152..71e55219 100644 --- a/src/circuit/gadget/sinsemilla/commit_ivk.rs +++ b/src/circuit/gadget/sinsemilla/commit_ivk.rs @@ -695,6 +695,7 @@ mod tests { meta, advices[..5].try_into().unwrap(), advices[2], + lagrange_coeffs[0], lookup, range_check.clone(), ); diff --git a/src/circuit/gadget/sinsemilla/merkle.rs b/src/circuit/gadget/sinsemilla/merkle.rs index 04533bab..0516987a 100644 --- a/src/circuit/gadget/sinsemilla/merkle.rs +++ b/src/circuit/gadget/sinsemilla/merkle.rs @@ -191,6 +191,11 @@ pub mod tests { let constants = meta.fixed_column(); meta.enable_constant(constants); + // NB: In the actual Action circuit, these fixed columns will be reused + // by other chips. For this test, we are creating new fixed columns. + let fixed_y_q_1 = meta.fixed_column(); + let fixed_y_q_2 = meta.fixed_column(); + // Fixed columns for the Sinsemilla generator lookup table let lookup = ( meta.fixed_column(), @@ -204,6 +209,7 @@ pub mod tests { meta, advices[5..].try_into().unwrap(), advices[7], + fixed_y_q_1, lookup, range_check.clone(), ); @@ -213,6 +219,7 @@ pub mod tests { meta, advices[..5].try_into().unwrap(), advices[2], + fixed_y_q_2, lookup, range_check, ); diff --git a/src/circuit/gadget/sinsemilla/note_commit.rs b/src/circuit/gadget/sinsemilla/note_commit.rs index 1f7068a6..502f3b26 100644 --- a/src/circuit/gadget/sinsemilla/note_commit.rs +++ b/src/circuit/gadget/sinsemilla/note_commit.rs @@ -1365,6 +1365,7 @@ mod tests { meta, advices[..5].try_into().unwrap(), advices[2], + lagrange_coeffs[0], lookup, range_check.clone(), );