From 16e90760807a0260b854f74fbd7593582d3e58ce Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 29 Jul 2021 02:10:32 +0100 Subject: [PATCH 01/12] Add names to some nameless constraints --- src/circuit/gadget/ecc/chip/add_incomplete.rs | 3 +- src/circuit/gadget/ecc/chip/mul.rs | 8 ++- src/circuit/gadget/ecc/chip/mul/overflow.rs | 12 ++--- src/circuit/gadget/ecc/chip/witness_point.rs | 4 +- src/circuit/gadget/poseidon/pow5t3.rs | 53 +++++++++++++------ src/circuit/gadget/sinsemilla/commit_ivk.rs | 30 +++++------ 6 files changed, 67 insertions(+), 43 deletions(-) diff --git a/src/circuit/gadget/ecc/chip/add_incomplete.rs b/src/circuit/gadget/ecc/chip/add_incomplete.rs index e846f19a..5016230c 100644 --- a/src/circuit/gadget/ecc/chip/add_incomplete.rs +++ b/src/circuit/gadget/ecc/chip/add_incomplete.rs @@ -60,7 +60,8 @@ impl Config { // (y_r + y_q)(x_p − x_q) − (y_p − y_q)(x_q − x_r) = 0 let poly2 = (y_r + y_q.clone()) * (x_p - x_q.clone()) - (y_p - y_q) * (x_q - x_r); - array::IntoIter::new([poly1, poly2]).map(move |poly| q_add_incomplete.clone() * poly) + array::IntoIter::new([("x_r", poly1), ("y_r", poly2)]) + .map(move |(name, poly)| (name, q_add_incomplete.clone() * poly)) }); } diff --git a/src/circuit/gadget/ecc/chip/mul.rs b/src/circuit/gadget/ecc/chip/mul.rs index be384f37..bd74b43d 100644 --- a/src/circuit/gadget/ecc/chip/mul.rs +++ b/src/circuit/gadget/ecc/chip/mul.rs @@ -118,8 +118,12 @@ impl Config { let lsb_x = (lsb.clone() * x_p.clone()) + one_minus_lsb.clone() * (x_p - base_x); let lsb_y = (lsb * y_p.clone()) + one_minus_lsb * (y_p + base_y); - std::array::IntoIter::new([bool_check, lsb_x, lsb_y]) - .map(move |poly| q_mul_lsb.clone() * poly) + std::array::IntoIter::new([ + ("bool_check", bool_check), + ("lsb_x", lsb_x), + ("lsb_y", lsb_y), + ]) + .map(move |(name, poly)| (name, q_mul_lsb.clone() * poly)) }); self.hi_config.create_gate(meta); diff --git a/src/circuit/gadget/ecc/chip/mul/overflow.rs b/src/circuit/gadget/ecc/chip/mul/overflow.rs index 4b17d6bc..109616b8 100644 --- a/src/circuit/gadget/ecc/chip/mul/overflow.rs +++ b/src/circuit/gadget/ecc/chip/mul/overflow.rs @@ -81,12 +81,12 @@ impl Config { let canonicity = (one.clone() - k_254) * (one - z_130 * eta) * s_minus_lo_130; iter::empty() - .chain(Some(s_check)) - .chain(Some(recovery)) - .chain(Some(lo_zero)) - .chain(Some(s_minus_lo_130_check)) - .chain(Some(canonicity)) - .map(|poly| q_mul_overflow.clone() * poly) + .chain(Some(("s_check", s_check))) + .chain(Some(("recovery", recovery))) + .chain(Some(("lo_zero", lo_zero))) + .chain(Some(("s_minus_lo_130_check", s_minus_lo_130_check))) + .chain(Some(("canonicity", canonicity))) + .map(|(name, poly)| (name, q_mul_overflow.clone() * poly)) .collect::>() }); } diff --git a/src/circuit/gadget/ecc/chip/witness_point.rs b/src/circuit/gadget/ecc/chip/witness_point.rs index c9267963..d3edad49 100644 --- a/src/circuit/gadget/ecc/chip/witness_point.rs +++ b/src/circuit/gadget/ecc/chip/witness_point.rs @@ -45,8 +45,8 @@ impl Config { - Expression::Constant(pallas::Affine::b()); vec![ - q_point.clone() * x * curve_eqn.clone(), - q_point * y * curve_eqn, + ("x == 0 ∨ on_curve", q_point.clone() * x * curve_eqn.clone()), + ("y == 0 ∨ on_curve", q_point * y * curve_eqn), ] }); } diff --git a/src/circuit/gadget/poseidon/pow5t3.rs b/src/circuit/gadget/poseidon/pow5t3.rs index 833adfd0..00c590cb 100644 --- a/src/circuit/gadget/poseidon/pow5t3.rs +++ b/src/circuit/gadget/poseidon/pow5t3.rs @@ -110,10 +110,14 @@ impl Pow5T3Chip { - next[next_idx].clone()) }; - vec![full_round(0), full_round(1), full_round(2)] + vec![ + ("state[0]", full_round(0)), + ("state[1]", full_round(1)), + ("state[2]", full_round(2)), + ] }); - meta.create_gate("partial round", |meta| { + meta.create_gate("partial rounds", |meta| { let cur_0 = meta.query_advice(state[0], Rotation::cur()); let cur_1 = meta.query_advice(state[1], Rotation::cur()); let cur_2 = meta.query_advice(state[2], Rotation::cur()); @@ -143,18 +147,24 @@ impl Pow5T3Chip { }; vec![ - s_partial.clone() * (pow_5(cur_0 + rc_a0) - mid_0.clone()), - s_partial.clone() - * (pow_5( - mid_0.clone() * m_reg[0][0] - + (cur_1.clone() + rc_a1.clone()) * m_reg[0][1] - + (cur_2.clone() + rc_a2.clone()) * m_reg[0][2] - + rc_b0, - ) - (next_0.clone() * m_inv[0][0] - + next_1.clone() * m_inv[0][1] - + next_2.clone() * m_inv[0][2])), - partial_round_linear(1, rc_b1), - partial_round_linear(2, rc_b2), + ( + "state[0] round a", + s_partial.clone() * (pow_5(cur_0 + rc_a0) - mid_0.clone()), + ), + ( + "state[0] round b", + s_partial.clone() + * (pow_5( + mid_0.clone() * m_reg[0][0] + + (cur_1.clone() + rc_a1.clone()) * m_reg[0][1] + + (cur_2.clone() + rc_a2.clone()) * m_reg[0][2] + + rc_b0, + ) - (next_0.clone() * m_inv[0][0] + + next_1.clone() * m_inv[0][1] + + next_2.clone() * m_inv[0][2])), + ), + ("state[1]", partial_round_linear(1, rc_b1)), + ("state[2]", partial_round_linear(2, rc_b2)), ] }); @@ -177,10 +187,19 @@ impl Pow5T3Chip { }; vec![ - pad_and_add(initial_state_0, input_0, output_state_0), - pad_and_add(initial_state_1, input_1, output_state_1), + ( + "state[0]", + pad_and_add(initial_state_0, input_0, output_state_0), + ), + ( + "state[1]", + pad_and_add(initial_state_1, input_1, output_state_1), + ), // The capacity element is never altered by the input. - s_pad_and_add * (initial_state_2 - output_state_2), + ( + "state[2]", + s_pad_and_add * (initial_state_2 - output_state_2), + ), ] }); diff --git a/src/circuit/gadget/sinsemilla/commit_ivk.rs b/src/circuit/gadget/sinsemilla/commit_ivk.rs index 35014384..0f0fb74c 100644 --- a/src/circuit/gadget/sinsemilla/commit_ivk.rs +++ b/src/circuit/gadget/sinsemilla/commit_ivk.rs @@ -159,10 +159,10 @@ impl CommitIvkConfig { }; std::iter::empty() - .chain(Some(b0_canon_check)) - .chain(Some(z13_a_check)) - .chain(Some(a_prime_check)) - .chain(Some(z13_a_prime)) + .chain(Some(("b0_canon_check", b0_canon_check))) + .chain(Some(("z13_a_check", z13_a_check))) + .chain(Some(("a_prime_check", a_prime_check))) + .chain(Some(("z13_a_prime", z13_a_prime))) }; // nk = b_2 (5 bits) || c (240 bits) || d_0 (9 bits) || d_1 (1 bit) @@ -197,22 +197,22 @@ impl CommitIvkConfig { }; std::iter::empty() - .chain(Some(c0_canon_check)) - .chain(Some(z13_c_check)) - .chain(Some(b2_c_prime_check)) - .chain(Some(z14_b2_c_prime)) + .chain(Some(("c0_canon_check", c0_canon_check))) + .chain(Some(("z13_c_check", z13_c_check))) + .chain(Some(("b2_c_prime_check", b2_c_prime_check))) + .chain(Some(("z14_b2_c_prime", z14_b2_c_prime))) }; std::iter::empty() - .chain(Some(b1_bool_check)) - .chain(Some(d1_bool_check)) - .chain(Some(b_decomposition_check)) - .chain(Some(d_decomposition_check)) - .chain(Some(ak_decomposition_check)) - .chain(Some(nk_decomposition_check)) + .chain(Some(("b1_bool_check", b1_bool_check))) + .chain(Some(("d1_bool_check", d1_bool_check))) + .chain(Some(("b_decomposition_check", b_decomposition_check))) + .chain(Some(("d_decomposition_check", d_decomposition_check))) + .chain(Some(("ak_decomposition_check", ak_decomposition_check))) + .chain(Some(("nk_decomposition_check", nk_decomposition_check))) .chain(ak_canonicity_checks) .chain(nk_canonicity_checks) - .map(move |poly| q_commit_ivk.clone() * poly) + .map(move |(name, poly)| (name, q_commit_ivk.clone() * poly)) }); config From 00090703589709a85d4ba51d81c6d3cdb0e9f23d Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 29 Jul 2021 14:54:36 +0100 Subject: [PATCH 02/12] circuit: Rotate`q_mul_lsb` selector up by one row This ensures the "LSB check" gate only queries `cur` and `next` rows. --- src/circuit/gadget/ecc/chip/mul.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/circuit/gadget/ecc/chip/mul.rs b/src/circuit/gadget/ecc/chip/mul.rs index bd74b43d..05c03bd3 100644 --- a/src/circuit/gadget/ecc/chip/mul.rs +++ b/src/circuit/gadget/ecc/chip/mul.rs @@ -99,12 +99,12 @@ impl Config { meta.create_gate("LSB check", |meta| { let q_mul_lsb = meta.query_selector(self.q_mul_lsb); - let z_1 = meta.query_advice(self.complete_config.z_complete, Rotation::prev()); - let z_0 = meta.query_advice(self.complete_config.z_complete, Rotation::cur()); - let x_p = meta.query_advice(self.add_config.x_p, Rotation::prev()); - let y_p = meta.query_advice(self.add_config.y_p, Rotation::prev()); - let base_x = meta.query_advice(self.add_config.x_p, Rotation::cur()); - let base_y = meta.query_advice(self.add_config.y_p, Rotation::cur()); + let z_1 = meta.query_advice(self.complete_config.z_complete, Rotation::cur()); + let z_0 = meta.query_advice(self.complete_config.z_complete, Rotation::next()); + let x_p = meta.query_advice(self.add_config.x_p, Rotation::cur()); + let y_p = meta.query_advice(self.add_config.y_p, Rotation::cur()); + let base_x = meta.query_advice(self.add_config.x_p, Rotation::next()); + let base_y = meta.query_advice(self.add_config.y_p, Rotation::next()); // z_0 = 2 * z_1 + k_0 // => k_0 = z_0 - 2 * z_1 @@ -275,8 +275,8 @@ impl Config { /// addition subregion. /// /// ```text - /// | x_p | y_p | acc_x | acc_y | complete addition | z_1 | - /// |base_x|base_y| res_x | res_y | | | | | | z_0 | q_mul_lsb = 1 + /// | x_p | y_p | acc_x | acc_y | complete addition | z_1 | q_mul_lsb = 1 + /// |base_x|base_y| res_x | res_y | | | | | | z_0 | /// ``` fn process_lsb( &self, @@ -288,7 +288,7 @@ impl Config { lsb: Option, ) -> Result<(EccPoint, Z), Error> { // Enforce switching logic on LSB using a custom gate - self.q_mul_lsb.enable(region, offset + 1)?; + self.q_mul_lsb.enable(region, offset)?; // z_1 has been assigned at (z_complete, offset). // Assign z_0 = 2⋅z_1 + k_0 From 2198675f9d2930c2b9b20e82e8289830d4e62378 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 29 Jul 2021 14:55:55 +0100 Subject: [PATCH 03/12] circuit: Rotate `q_commit_ivk` selector up by one row This ensures the Commit^ivk gate only queries `cur` and `next` rows. --- src/circuit/gadget/sinsemilla/commit_ivk.rs | 46 ++++++++++----------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/circuit/gadget/sinsemilla/commit_ivk.rs b/src/circuit/gadget/sinsemilla/commit_ivk.rs index 0f0fb74c..476691e9 100644 --- a/src/circuit/gadget/sinsemilla/commit_ivk.rs +++ b/src/circuit/gadget/sinsemilla/commit_ivk.rs @@ -59,8 +59,8 @@ impl CommitIvkConfig { | A_0 | A_1 | A_2 | A_3 | A_4 | A_5 | A_6 | A_7 | A_8 | q_commit_ivk | ----------------------------------------------------------------------------------------------------- - | ak | a | b | b_0 | b_1 | b_2 | z13_a | a_prime | z13_a_prime | 0 | - | nk | c | d | d_0 | d_1 | | z13_c | b2_c_prime| z14_b2_c_prime | 1 | + | ak | a | b | b_0 | b_1 | b_2 | z13_a | a_prime | z13_a_prime | 1 | + | nk | c | d | d_0 | d_1 | | z13_c | b2_c_prime| z14_b2_c_prime | 0 | */ meta.create_gate("CommitIvk canonicity check", |meta| { @@ -73,27 +73,27 @@ impl CommitIvkConfig { let two_pow_250 = pallas::Base::from_u128(1 << 125).square(); let two_pow_254 = two_pow_250 * two_pow_4; - let ak = meta.query_advice(config.advices[0], Rotation::prev()); - let nk = meta.query_advice(config.advices[0], Rotation::cur()); + let ak = meta.query_advice(config.advices[0], Rotation::cur()); + let nk = meta.query_advice(config.advices[0], Rotation::next()); // `a` is constrained by the Sinsemilla hash to be 250 bits. - let a = meta.query_advice(config.advices[1], Rotation::prev()); + let a = meta.query_advice(config.advices[1], Rotation::cur()); // `b` is constrained by the Sinsemilla hash to be 10 bits. - let b_whole = meta.query_advice(config.advices[2], Rotation::prev()); + let b_whole = meta.query_advice(config.advices[2], Rotation::cur()); // `c` is constrained by the Sinsemilla hash to be 240 bits. - let c = meta.query_advice(config.advices[1], Rotation::cur()); + let c = meta.query_advice(config.advices[1], Rotation::next()); // `d` is constrained by the Sinsemilla hash to be 10 bits. - let d_whole = meta.query_advice(config.advices[2], Rotation::cur()); + let d_whole = meta.query_advice(config.advices[2], Rotation::next()); // b = b_0||b_1||b_2` // = (bits 250..=253 of `ak`) || (bit 254 of `ak`) || (bits 0..=4 of `nk`) // // b_0 has been constrained outside this gate to be a four-bit value. - let b_0 = meta.query_advice(config.advices[3], Rotation::prev()); + let b_0 = meta.query_advice(config.advices[3], Rotation::cur()); // This gate constrains b_1 to be a one-bit value. - let b_1 = meta.query_advice(config.advices[4], Rotation::prev()); + let b_1 = meta.query_advice(config.advices[4], Rotation::cur()); // b_2 has been constrained outside this gate to be a five-bit value. - let b_2 = meta.query_advice(config.advices[5], Rotation::prev()); + let b_2 = meta.query_advice(config.advices[5], Rotation::cur()); // Check that b_whole is consistent with the witnessed subpieces. let b_decomposition_check = b_whole - (b_0.clone() + b_1.clone() * two_pow_4 + b_2.clone() * two_pow_5); @@ -101,9 +101,9 @@ impl CommitIvkConfig { // d = d_0||d_1` = (bits 245..=253 of `nk`) || (bit 254 of `nk`) // // d_0 has been constrained outside this gate to be a nine-bit value. - let d_0 = meta.query_advice(config.advices[3], Rotation::cur()); + let d_0 = meta.query_advice(config.advices[3], Rotation::next()); // This gate constrains d_1 to be a one-bit value. - let d_1 = meta.query_advice(config.advices[4], Rotation::cur()); + let d_1 = meta.query_advice(config.advices[4], Rotation::next()); // Check that d_whole is consistent with the witnessed subpieces. let d_decomposition_check = d_whole - (d_0.clone() + d_1.clone() * two_pow_9); @@ -137,14 +137,14 @@ impl CommitIvkConfig { // z13_a is the 13th running sum output by the 10-bit Sinsemilla decomposition of `a`. // b_1 = 1 => z13_a = 0 let z13_a_check = { - let z13_a = meta.query_advice(config.advices[6], Rotation::prev()); + let z13_a = meta.query_advice(config.advices[6], Rotation::cur()); b_1.clone() * z13_a }; // Check that a_prime = a + 2^130 - t_P. // This is checked regardless of the value of b_1. let a_prime_check = { - let a_prime = meta.query_advice(config.advices[7], Rotation::prev()); + let a_prime = meta.query_advice(config.advices[7], Rotation::cur()); let two_pow_130 = Expression::Constant(pallas::Base::from_u128(1 << 65).square()); let t_p = Expression::Constant(pallas::Base::from_u128(T_P)); @@ -154,7 +154,7 @@ impl CommitIvkConfig { // Check that the running sum output by the 130-bit little-endian decomposition of // `a_prime` is zero. let z13_a_prime = { - let z13_a_prime = meta.query_advice(config.advices[8], Rotation::prev()); + let z13_a_prime = meta.query_advice(config.advices[8], Rotation::cur()); b_1 * z13_a_prime }; @@ -174,7 +174,7 @@ impl CommitIvkConfig { // d_1 = 1 => z13_c = 0, where z13_c is the 13th running sum // output by the 10-bit Sinsemilla decomposition of `c`. let z13_c_check = { - let z13_c = meta.query_advice(config.advices[6], Rotation::cur()); + let z13_c = meta.query_advice(config.advices[6], Rotation::next()); d_1.clone() * z13_c }; @@ -185,14 +185,14 @@ impl CommitIvkConfig { let two_pow_140 = Expression::Constant(pallas::Base::from_u128(1 << 70).square()); let t_p = Expression::Constant(pallas::Base::from_u128(T_P)); - let b2_c_prime = meta.query_advice(config.advices[7], Rotation::cur()); + let b2_c_prime = meta.query_advice(config.advices[7], Rotation::next()); b_2 + c * two_pow_5 + two_pow_140 - t_p - b2_c_prime }; // Check that the running sum output by the 140-bit little- // endian decomposition of b2_c_prime is zero. let z14_b2_c_prime = { - let z14_b2_c_prime = meta.query_advice(config.advices[8], Rotation::cur()); + let z14_b2_c_prime = meta.query_advice(config.advices[8], Rotation::next()); d_1 * z14_b2_c_prime }; @@ -455,8 +455,8 @@ impl CommitIvkConfig { | A_0 | A_1 | A_2 | A_3 | A_4 | A_5 | A_6 | A_7 | A_8 | q_commit_ivk | ----------------------------------------------------------------------------------------------------- - | ak | a | b | b_0 | b_1 | b_2 | z13_a | a_prime | z13_a_prime | 0 | - | nk | c | d | d_0 | d_1 | | z13_c | b2_c_prime| z14_b2_c_prime | 1 | + | ak | a | b | b_0 | b_1 | b_2 | z13_a | a_prime | z13_a_prime | 1 | + | nk | c | d | d_0 | d_1 | | z13_c | b2_c_prime| z14_b2_c_prime | 0 | */ fn assign_gate( @@ -467,8 +467,8 @@ impl CommitIvkConfig { layouter.assign_region( || "Assign cells used in canonicity gate", |mut region| { - // Enable selector on offset 1 - self.q_commit_ivk.enable(&mut region, 1)?; + // Enable selector on offset 0 + self.q_commit_ivk.enable(&mut region, 0)?; // Offset 0 { From 6aa85fcdfe5e97c8e0ef8616caec4430098b909d Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 29 Jul 2021 20:05:20 +0100 Subject: [PATCH 04/12] circuit: Refactor NoteCommit input processing into multiple regions The new regions take up more cells overall, but across fewer columns, and the gates now only query `cur` and `next` rows. --- src/circuit/gadget/sinsemilla/note_commit.rs | 1281 +++++++++--------- 1 file changed, 629 insertions(+), 652 deletions(-) diff --git a/src/circuit/gadget/sinsemilla/note_commit.rs b/src/circuit/gadget/sinsemilla/note_commit.rs index caf612cc..9a332bf4 100644 --- a/src/circuit/gadget/sinsemilla/note_commit.rs +++ b/src/circuit/gadget/sinsemilla/note_commit.rs @@ -37,8 +37,16 @@ use super::{ #[allow(non_snake_case)] #[derive(Clone, Debug)] pub struct NoteCommitConfig { - q_canon_1: Selector, - q_canon_2: Selector, + q_notecommit_b: Selector, + q_notecommit_d: Selector, + q_notecommit_e: Selector, + q_notecommit_g: Selector, + q_notecommit_h: Selector, + q_notecommit_g_d: Selector, + q_notecommit_pk_d: Selector, + q_notecommit_value: Selector, + q_notecommit_rho: Selector, + q_notecommit_psi: Selector, q_y_canon: Selector, advices: [Column; 10], sinsemilla_config: SinsemillaConfig, @@ -52,13 +60,29 @@ impl NoteCommitConfig { advices: [Column; 10], sinsemilla_config: SinsemillaConfig, ) -> Self { - let q_canon_1 = meta.selector(); - let q_canon_2 = meta.selector(); + let q_notecommit_b = meta.selector(); + let q_notecommit_d = meta.selector(); + let q_notecommit_e = meta.selector(); + let q_notecommit_g = meta.selector(); + let q_notecommit_h = meta.selector(); + let q_notecommit_g_d = meta.selector(); + let q_notecommit_pk_d = meta.selector(); + let q_notecommit_value = meta.selector(); + let q_notecommit_rho = meta.selector(); + let q_notecommit_psi = meta.selector(); let q_y_canon = meta.selector(); let config = Self { - q_canon_1, - q_canon_2, + q_notecommit_b, + q_notecommit_d, + q_notecommit_e, + q_notecommit_g, + q_notecommit_h, + q_notecommit_g_d, + q_notecommit_pk_d, + q_notecommit_value, + q_notecommit_rho, + q_notecommit_psi, q_y_canon, advices, sinsemilla_config, @@ -80,6 +104,349 @@ impl NoteCommitConfig { let t_p = Expression::Constant(pallas::Base::from_u128(T_P)); + // Columns used for MessagePiece and message input gates. + let col_l = config.advices[6]; + let col_m = config.advices[7]; + let col_r = config.advices[8]; + let col_z = config.advices[9]; + + // | A_6 | A_7 | A_8 | q_notecommit_b | + // ------------------------------------ + // | b | b_0 | b_1 | 1 | + // | | b_2 | b_3 | 0 | + meta.create_gate("NoteCommit MessagePiece b", |meta| { + let q_notecommit_b = meta.query_selector(config.q_notecommit_b); + + // b has been constrained to 10 bits by the Sinsemilla hash. + let b = meta.query_advice(col_l, Rotation::cur()); + // b_0 has been constrained to be 4 bits outside this gate. + let b_0 = meta.query_advice(col_m, Rotation::cur()); + // This gate constrains b_1 to be boolean. + let b_1 = meta.query_advice(col_r, Rotation::cur()); + // This gate constrains b_2 to be boolean. + let b_2 = meta.query_advice(col_m, Rotation::next()); + // b_3 has been constrained to 4 bits outside this gate. + let b_3 = meta.query_advice(col_r, Rotation::next()); + + // b = b_0 + (2^4) b_1 + (2^5) b_2 + (2^6) b_3 + let decomposition_check = + b - (b_0 + b_1.clone() * two_pow_4 + b_2.clone() * two_pow_5 + b_3 * two_pow_6); + + std::iter::empty() + .chain(Some(("bool_check b_1", bool_check(b_1)))) + .chain(Some(("bool_check b_2", bool_check(b_2)))) + .chain(Some(("decomposition", decomposition_check))) + .map(move |(name, poly)| (name, q_notecommit_b.clone() * poly)) + }); + + // | A_6 | A_7 | A_8 | q_notecommit_d | + // ------------------------------------ + // | d | d_0 | d_1 | 1 | + // | | d_2 | d_3 | 0 | + meta.create_gate("NoteCommit MessagePiece d", |meta| { + let q_notecommit_d = meta.query_selector(config.q_notecommit_d); + + // d has been constrained to 10 bits by the Sinsemilla hash. + let d = meta.query_advice(col_l, Rotation::cur()); + // This gate constrains d_0 to be boolean. + let d_0 = meta.query_advice(col_m, Rotation::cur()); + // This gate constrains d_1 to be boolean. + let d_1 = meta.query_advice(col_r, Rotation::cur()); + // d_2 has been constrained to 8 bits outside this gate. + let d_2 = meta.query_advice(col_m, Rotation::next()); + // d_3 is set to z1_d. + let d_3 = meta.query_advice(col_r, Rotation::next()); + + // d = d_0 + (2) d_1 + (2^2) d_2 + (2^10) d_3 + let decomposition_check = + d - (d_0.clone() + d_1.clone() * two + d_2 * two_pow_2 + d_3 * two_pow_10); + + std::iter::empty() + .chain(Some(("bool_check d_0", bool_check(d_0)))) + .chain(Some(("bool_check d_1", bool_check(d_1)))) + .chain(Some(("decomposition", decomposition_check))) + .map(move |(name, poly)| (name, q_notecommit_d.clone() * poly)) + }); + + // | A_6 | A_7 | A_8 | q_notecommit_e | + // ------------------------------------ + // | e | e_0 | e_1 | 1 | + meta.create_gate("NoteCommit MessagePiece e", |meta| { + let q_notecommit_e = meta.query_selector(config.q_notecommit_e); + + // e has been constrained to 10 bits by the Sinsemilla hash. + let e = meta.query_advice(col_l, Rotation::cur()); + // e_0 has been constrained to 6 bits outside this gate. + let e_0 = meta.query_advice(col_m, Rotation::cur()); + // e_1 has been constrained to 4 bits outside this gate. + let e_1 = meta.query_advice(col_r, Rotation::cur()); + + // e = e_0 + (2^6) e_1 + let decomposition_check = e - (e_0 + e_1 * two_pow_6); + + std::iter::empty() + .chain(Some(("decomposition", decomposition_check))) + .map(move |(name, poly)| (name, q_notecommit_e.clone() * poly)) + }); + + // | A_6 | A_7 | q_notecommit_g | + // ------------------------------ + // | g | g_0 | 1 | + // | g_1 | g_2 | 0 | + meta.create_gate("NoteCommit MessagePiece g", |meta| { + let q_notecommit_g = meta.query_selector(config.q_notecommit_g); + + // g has been constrained to 250 bits by the Sinsemilla hash. + let g = meta.query_advice(col_l, Rotation::cur()); + // This gate constrains g_0 to be boolean. + let g_0 = meta.query_advice(col_m, Rotation::cur()); + // g_1 has been constrained to 9 bits outside this gate. + let g_1 = meta.query_advice(col_l, Rotation::next()); + // g_2 is set to z1_g. + let g_2 = meta.query_advice(col_m, Rotation::next()); + + // g = g_0 + (2) g_1 + (2^10) g_2 + let decomposition_check = g - (g_0.clone() + g_1 * two + g_2 * two_pow_10); + + std::iter::empty() + .chain(Some(("bool_check g_0", bool_check(g_0)))) + .chain(Some(("decomposition", decomposition_check))) + .map(move |(name, poly)| (name, q_notecommit_g.clone() * poly)) + }); + + // | A_6 | A_7 | A_8 | q_notecommit_h | + // ------------------------------------ + // | h | h_0 | h_1 | 1 | + meta.create_gate("NoteCommit MessagePiece h", |meta| { + let q_notecommit_h = meta.query_selector(config.q_notecommit_h); + + // h has been constrained to 10 bits by the Sinsemilla hash. + let h = meta.query_advice(col_l, Rotation::cur()); + // h_0 has been constrained to be 5 bits outside this gate. + let h_0 = meta.query_advice(col_m, Rotation::cur()); + // This gate constrains h_1 to be boolean. + let h_1 = meta.query_advice(col_r, Rotation::cur()); + + // h = h_0 + (2^5) h_1 + let decomposition_check = h - (h_0 + h_1.clone() * two_pow_5); + + std::iter::empty() + .chain(Some(("bool_check h_1", bool_check(h_1)))) + .chain(Some(("decomposition", decomposition_check))) + .map(move |(name, poly)| (name, q_notecommit_h.clone() * poly)) + }); + + // | A_6 | A_7 | A_8 | A_9 | q_notecommit_g_d | + // ----------------------------------------------------------- + // | x(g_d) | b_0 | a | z13_a | 1 | + // | | b_1 | a_prime | z13_a_prime | 0 | + meta.create_gate("NoteCommit input g_d", |meta| { + let q_notecommit_g_d = meta.query_selector(config.q_notecommit_g_d); + + let gd_x = meta.query_advice(col_l, Rotation::cur()); + + // b_0 has been constrained to be 4 bits outside this gate. + let b_0 = meta.query_advice(col_m, Rotation::cur()); + // b_1 has been constrained to be boolean outside this gate. + let b_1 = meta.query_advice(col_m, Rotation::next()); + + // a has been constrained to 250 bits by the Sinsemilla hash. + let a = meta.query_advice(col_r, Rotation::cur()); + let a_prime = meta.query_advice(col_r, Rotation::next()); + + let z13_a = meta.query_advice(col_z, Rotation::cur()); + let z13_a_prime = meta.query_advice(col_z, Rotation::next()); + + // x(g_d) = a + (2^250)b_0 + (2^254)b_1 + let decomposition_check = { + let sum = a.clone() + b_0.clone() * two_pow_250 + b_1.clone() * two_pow_254; + sum - gd_x + }; + + // a_prime = a + 2^130 - t_P + let a_prime_check = a + two_pow_130.clone() - t_p.clone() - a_prime; + + // The gd_x_canonicity_checks are enforced if and only if `b_1` = 1. + // x(g_d) = a (250 bits) || b_0 (4 bits) || b_1 (1 bit) + let canonicity_checks = std::iter::empty() + .chain(Some(("b_1 = 1 => b_0", b_0))) + .chain(Some(("b_1 = 1 => z13_a", z13_a))) + .chain(Some(("b_1 = 1 => z13_a_prime", z13_a_prime))) + .map(move |(name, poly)| (name, b_1.clone() * poly)); + + std::iter::empty() + .chain(Some(("decomposition", decomposition_check))) + .chain(Some(("a_prime_check", a_prime_check))) + .chain(canonicity_checks) + .map(move |(name, poly)| (name, q_notecommit_g_d.clone() * poly)) + }); + + // | A_6 | A_7 | A_8 | A_9 | q_notecommit_pk_d | + // ------------------------------------------------------------------- + // | x(pk_d) | b_3 | c | z13_c | 1 | + // | | d_0 | b3_c_prime | z14_b3_c_prime | 0 | + meta.create_gate("NoteCommit input pk_d", |meta| { + let q_notecommit_pk_d = meta.query_selector(config.q_notecommit_pk_d); + + let pkd_x = meta.query_advice(col_l, Rotation::cur()); + + // `b_3` has been constrained to 4 bits outside this gate. + let b_3 = meta.query_advice(col_m, Rotation::cur()); + // d_0 has been constrained to be boolean outside this gate. + let d_0 = meta.query_advice(col_m, Rotation::next()); + + // `c` has been constrained to 250 bits by the Sinsemilla hash. + let c = meta.query_advice(col_r, Rotation::cur()); + let b3_c_prime = meta.query_advice(col_r, Rotation::next()); + + let z13_c = meta.query_advice(col_z, Rotation::cur()); + let z14_b3_c_prime = meta.query_advice(col_z, Rotation::next()); + + // x(pk_d) = b_3 + (2^4)c + (2^254)d_0 + let decomposition_check = { + let sum = b_3.clone() + c.clone() * two_pow_4 + d_0.clone() * two_pow_254; + sum - pkd_x + }; + + // b3_c_prime = b_3 + (2^4)c + 2^140 - t_P + let b3_c_prime_check = b_3.clone() + (c.clone() * two_pow_4) + two_pow_140.clone() + - t_p.clone() + - b3_c_prime; + + // The pkd_x_canonicity_checks are enforced if and only if `d_0` = 1. + // `x(pk_d)` = `b_3 (4 bits) || c (250 bits) || d_0 (1 bit)` + let canonicity_checks = std::iter::empty() + .chain(Some(("d_0 = 1 => z13_c", z13_c))) + .chain(Some(("d_0 = 1 => z14_b3_c_prime", z14_b3_c_prime))) + .map(move |(name, poly)| (name, d_0.clone() * poly)); + + std::iter::empty() + .chain(Some(("decomposition", decomposition_check))) + .chain(Some(("b3_c_prime_check", b3_c_prime_check))) + .chain(canonicity_checks) + .map(move |(name, poly)| (name, q_notecommit_pk_d.clone() * poly)) + }); + + // | value | d_2 | d_3 | e_0 | + meta.create_gate("NoteCommit input value", |meta| { + let q_notecommit_value = meta.query_selector(config.q_notecommit_value); + + let value = meta.query_advice(col_l, Rotation::cur()); + // d_2 has been constrained to 8 bits outside this gate. + let d_2 = meta.query_advice(col_m, Rotation::cur()); + // z1_d has been constrained to 50 bits by the Sinsemilla hash. + let z1_d = meta.query_advice(col_r, Rotation::cur()); + let d_3 = z1_d; + // `e_0` has been constrained to 6 bits outside this gate. + let e_0 = meta.query_advice(col_z, Rotation::cur()); + + // value = d_2 + (2^8)d_3 + (2^58)e_0 + let value_check = { + let two_pow_8 = pallas::Base::from_u64(1 << 8); + let two_pow_58 = pallas::Base::from_u64(1 << 58); + d_2 + d_3 * two_pow_8 + e_0 * two_pow_58 - value + }; + + std::iter::empty() + .chain(Some(("value_check", value_check))) + .map(move |(name, poly)| (name, q_notecommit_value.clone() * poly)) + }); + + // | A_6 | A_7 | A_8 | A_9 | q_notecommit_rho | + // -------------------------------------------------------------- + // | rho | e_1 | f | z13_f | 1 | + // | | g_0 | e1_f_prime | z14_e1_f_prime | 0 | + meta.create_gate("NoteCommit input rho", |meta| { + let q_notecommit_rho = meta.query_selector(config.q_notecommit_rho); + + let rho = meta.query_advice(col_l, Rotation::cur()); + + // `e_1` has been constrained to 4 bits outside this gate. + let e_1 = meta.query_advice(col_m, Rotation::cur()); + let g_0 = meta.query_advice(col_m, Rotation::next()); + + // `f` has been constrained to 250 bits by the Sinsemilla hash. + let f = meta.query_advice(col_r, Rotation::cur()); + let e1_f_prime = meta.query_advice(col_r, Rotation::next()); + + let z13_f = meta.query_advice(col_z, Rotation::cur()); + let z14_e1_f_prime = meta.query_advice(col_z, Rotation::next()); + + // rho = e_1 + (2^4) f + (2^254) g_0 + let decomposition_check = { + let sum = e_1.clone() + f.clone() * two_pow_4 + g_0.clone() * two_pow_254; + sum - rho + }; + + // e1_f_prime = e_1 + (2^4)f + 2^140 - t_P + let e1_f_prime_check = e_1 + (f * two_pow_4) + two_pow_140 - t_p.clone() - e1_f_prime; + + // The rho_canonicity_checks are enforced if and only if `g_0` = 1. + // rho = e_1 (4 bits) || f (250 bits) || g_0 (1 bit) + let canonicity_checks = std::iter::empty() + .chain(Some(("g_0 = 1 => z13_f", z13_f))) + .chain(Some(("g_0 = 1 => z14_e1_f_prime", z14_e1_f_prime))) + .map(move |(name, poly)| (name, g_0.clone() * poly)); + + std::iter::empty() + .chain(Some(("decomposition", decomposition_check))) + .chain(Some(("e1_f_prime_check", e1_f_prime_check))) + .chain(canonicity_checks) + .map(move |(name, poly)| (name, q_notecommit_rho.clone() * poly)) + }); + + // | A_6 | A_7 | A_8 | A_9 | q_notecommit_psi | + // ---------------------------------------------------------------- + // | psi | g_1 | g_2 | z13_g | 1 | + // | h_0 | h_1 | g1_g2_prime | z13_g1_g2_prime | 0 | + meta.create_gate("NoteCommit input psi", |meta| { + let q_notecommit_psi = meta.query_selector(config.q_notecommit_psi); + + let psi = meta.query_advice(col_l, Rotation::cur()); + let h_0 = meta.query_advice(col_l, Rotation::next()); + + let g_1 = meta.query_advice(col_m, Rotation::cur()); + let h_1 = meta.query_advice(col_m, Rotation::next()); + + let z1_g = meta.query_advice(col_r, Rotation::cur()); + let g_2 = z1_g; + let g1_g2_prime = meta.query_advice(col_r, Rotation::next()); + + let z13_g = meta.query_advice(col_z, Rotation::cur()); + let z13_g1_g2_prime = meta.query_advice(col_z, Rotation::next()); + + // psi = g_1 + (2^9) g_2 + (2^249) h_0 + (2^254) h_1 + let decomposition_check = { + let two_pow_249 = + pallas::Base::from_u128(1 << 124).square() * pallas::Base::from_u128(2); + let sum = g_1.clone() + + g_2.clone() * pallas::Base::from_u64(1 << 9) + + h_0.clone() * two_pow_249 + + h_1.clone() * two_pow_254; + sum - psi + }; + + // g1_g2_prime = g_1 + (2^9)g_2 + 2^130 - t_P + let g1_g2_prime_check = { + let two_pow_9 = two_pow_4 * two_pow_5; + g_1 + (g_2 * two_pow_9) + two_pow_130.clone() - t_p.clone() - g1_g2_prime + }; + + // The psi_canonicity_checks are enforced if and only if `h_1` = 1. + // `psi` = `g_1 (9 bits) || g_2 (240 bits) || h_0 (5 bits) || h_1 (1 bit)` + let canonicity_checks = std::iter::empty() + .chain(Some(("h_1 = 1 => h_0", h_0))) + .chain(Some(("h_1 = 1 => z13_g", z13_g))) + .chain(Some(("h_1 = 1 => z13_g1_g2_prime", z13_g1_g2_prime))) + .map(move |(name, poly)| (name, h_1.clone() * poly)); + + std::iter::empty() + .chain(Some(("decomposition", decomposition_check))) + .chain(Some(("g1_g2_prime_check", g1_g2_prime_check))) + .chain(canonicity_checks) + .map(move |(name, poly)| (name, q_notecommit_psi.clone() * poly)) + }); + /* Check decomposition and canonicity of y-coordinates. This is used for both y(g_d) and y(pk_d). @@ -127,7 +494,7 @@ impl NoteCommitConfig { let y_check = y - (j.clone() + k_2.clone() * two_pow_250 + k_3.clone() * two_pow_254); // Check that j_prime = j + 2^130 - t_P - let j_prime_check = j + two_pow_130.clone() - t_p.clone() - j_prime; + let j_prime_check = j + two_pow_130 - t_p.clone() - j_prime; std::iter::empty() .chain(Some(("k3_check", k3_check))) @@ -150,319 +517,6 @@ impl NoteCommitConfig { .map(move |(name, poly)| (name, q_y_canon.clone() * poly)) }); - meta.create_gate("NoteCommit decomposition check", |meta| { - /* - All bit ranges are inclusive. - - a (250 bits) = bits 0..=249 of x(g_d) - b (10 bits) = b_0 || b_1 || b_2 || b_3 - = (bits 250..=253 of x(g_d)) || (bit 254 of x(g_d)) || (ỹ bit of g_d) || (bits 0..=3 of pk★_d) - c (250 bits) = bits 4..=253 of pk★_d - d (60 bits) = d_0 || d_1 || d_2 || d_3 - = (bit 254 of x(pk_d)) || (ỹ bit of pk_d) || (0..=7 of v) || (8..=57 of v) - e (10 bits) = e_0 || e_1 - = (bits 58..=63 of v) || (bits 0..=3 of rho) - f (250 bits) = bits 4..=253 inclusive of rho - g (250 bits) = g_0 || g_1 || g_2 - = (bit 254 of rho) || (bits 0..=8 of psi) || (bits 9..=248 of psi) - h (10 bits) = h_0 || h_1 || h_2 - = (bits 249..=253 of psi) || (bit 254 of psi) || 4 zero bits - - | A_0 | A_1 | A_2 | A_3 | A_4 | A_5 | A_6 | A_7 | A_8 | A_9 | q_canon_1 | q_canon_2 | - ----------------------------------------------------------------------------------------------------------------------------------------------- - | b | d | e | g | h | d_1 | x(pk_d) | b_3 |a_prime| b_2 | 0 | 0 | - |e1_f_prime|g1_g2_prime| value | d_2 | z1_d | e_0 |b3_c_prime| c | a | x(g_d) | 1 | 0 | - | e_1 | f | g_0 | g_1 | z1_g | h_0 | h_1 | d_0 | b_0 | b_1 | 0 | 1 | - | rho | z13_f |z14_e1_f_prime| psi | z13_g |z13_g1_g2_prime| z13_c |z14_b3_c_prime| z13_a |z13_a_prime| 0 | 0 | - - q_canon_1 checks that: - - piece decomposition: - - b = b_0 + (2^4) b_1 + (2^5) b_2 + (2^6) b_3 - - b_1 is boolean - - b_2 is boolean - - d = d_0 + (2) d_1 + (2^2) d_2 + (2^10) d_3 - - d_0 is boolean - - d_1 is boolean - - e = e_0 + (2^6) e_1 - - g = g_0 + (2) g_1 + (2^10) g_2 - - g_0 is boolean - - h = h_0 + (2^5) h_1 - - h_1 is boolean - - field element decomposition: - - x(g_d) = a + (2^250) b_0 + (2^254) b_1 - - x(pk_d) = b_3 + (2^4) c + (2^254) d_0 - - value = d_2 + (2^8) d_3 + (2^58) e_0 - - *_prime derivations: - - a_prime = a + 2^130 - t_P - - b3_c_prime = b_3 + (2^4)c + 2^140 - t_P - - e1_f_prime = e_1 + (2^4)g + 2^140 - t_P - - g1_g2_prime = g_1 + (2^9) g_2 + 2^140 - t_P - */ - let q_canon_1 = meta.query_selector(config.q_canon_1); - - // Offset prev - // `b` has been constrained to 10 bits by the Sinsemilla hash. - let b_whole = meta.query_advice(config.advices[0], Rotation::prev()); - // `d` has been constrained to 10 bits by the Sinsemilla hash. - let d_whole = meta.query_advice(config.advices[1], Rotation::prev()); - // `e` has been constrained to 10 bits by the Sinsemilla hash. - let e_whole = meta.query_advice(config.advices[2], Rotation::prev()); - // `g` has been constrained to 250 bits by the Sinsemilla hash. - let g_whole = meta.query_advice(config.advices[3], Rotation::prev()); - // `h` has been constrained to 10 bits by the Sinsemilla hash. - let h_whole = meta.query_advice(config.advices[4], Rotation::prev()); - // This gate constrains d_1 to be boolean. - let d_1 = meta.query_advice(config.advices[5], Rotation::prev()); - let pkd_x = meta.query_advice(config.advices[6], Rotation::prev()); - // `b_3` has been constrained to 4 bits outside this gate. - let b_3 = meta.query_advice(config.advices[7], Rotation::prev()); - let a_prime = meta.query_advice(config.advices[8], Rotation::prev()); - // This gate constrains b_2 to be boolean. - let b_2 = meta.query_advice(config.advices[9], Rotation::prev()); - - // Offset cur - let e1_f_prime = meta.query_advice(config.advices[0], Rotation::cur()); - let g1_g2_prime = meta.query_advice(config.advices[1], Rotation::cur()); - // `z1_d` has been constrained to 50 bits by the Sinsemilla hash. - let value = meta.query_advice(config.advices[2], Rotation::cur()); - // `d_2` has been constrained to 8 bits outside this gate. - let d_2 = meta.query_advice(config.advices[3], Rotation::cur()); - let z1_d = meta.query_advice(config.advices[4], Rotation::cur()); - let d_3 = z1_d; - // `e_0` has been constrained to 6 bits outside this gate. - let e_0 = meta.query_advice(config.advices[5], Rotation::cur()); - let b3_c_prime = meta.query_advice(config.advices[6], Rotation::cur()); - // `c` has been constrained to 250 bits by the Sinsemilla hash. - let c = meta.query_advice(config.advices[7], Rotation::cur()); - // `a` has been constrained to 250 bits by the Sinsemilla hash. - let a = meta.query_advice(config.advices[8], Rotation::cur()); - let gd_x = meta.query_advice(config.advices[9], Rotation::cur()); - - // Offset next - // `e_1` has been constrained to 4 bits outside this gate. - let e_1 = meta.query_advice(config.advices[0], Rotation::next()); - // `f` has been constrained to 250 bits by the Sinsemilla hash. - let f = meta.query_advice(config.advices[1], Rotation::next()); - // This gate constrains g_0 to be boolean. - let g_0 = meta.query_advice(config.advices[2], Rotation::next()); - // `g_1` has been constrained to 9 bits outside this gate. - let g_1 = meta.query_advice(config.advices[3], Rotation::next()); - // z1_g has been constrained to 240 bits by the Sinsemilla hash. - let z1_g = meta.query_advice(config.advices[4], Rotation::next()); - let g_2 = z1_g; - // h_0 has been constrained to be 5 bits outside this gate. - let h_0 = meta.query_advice(config.advices[5], Rotation::next()); - // This gate constrains h_1 to be boolean. - let h_1 = meta.query_advice(config.advices[6], Rotation::next()); - // This gate constrains d_0 to be boolean. - let d_0 = meta.query_advice(config.advices[7], Rotation::next()); - // b_0 has been constrained to be 4 bits outside this gate. - let b_0 = meta.query_advice(config.advices[8], Rotation::next()); - // This gate constrains b_1 to be boolean. - let b_1 = meta.query_advice(config.advices[9], Rotation::next()); - - // Boolean checks on 1-bit pieces. - let boolean_checks = std::iter::empty() - .chain(Some(("bool_check b_1", bool_check(b_1.clone())))) - .chain(Some(("bool_check b_2", bool_check(b_2.clone())))) - .chain(Some(("bool_check d_0", bool_check(d_0.clone())))) - .chain(Some(("bool_check d_1", bool_check(d_1.clone())))) - .chain(Some(("bool_check g_0", bool_check(g_0.clone())))) - .chain(Some(("bool_check h_1", bool_check(h_1.clone())))); - - // b = b_0 + (2^4) b_1 + (2^5) b_2 + (2^6) b_3 - let b_check = b_whole - - (b_0.clone() - + b_1.clone() * two_pow_4 - + b_2 * two_pow_5 - + b_3.clone() * two_pow_6); - // d = d_0 + (2) d_1 + (2^2) d_2 + (2^10) d_3 - let d_check = d_whole - - (d_0.clone() + d_1 * two + d_2.clone() * two_pow_2 + d_3.clone() * two_pow_10); - // e = e_0 + (2^6) e_1 - let e_check = e_whole - (e_0.clone() + e_1.clone() * two_pow_6); - // g = g_0 + (2) g_1 + (2^10) g_2 - let g_check = g_whole - (g_0 + g_1.clone() * two + g_2.clone() * two_pow_10); - // h = h_0 + (2^5) h_1 - let h_check = h_whole - (h_0 + h_1 * two_pow_5); - - // Check that *_prime pieces were correctly derived. - // a_prime = a + 2^130 - t_P - let a_prime_check = a.clone() + two_pow_130.clone() - t_p.clone() - a_prime; - - // b3_c_prime = b_3 + (2^4)c + 2^140 - t_P - let b3_c_prime_check = b_3.clone() + (c.clone() * two_pow_4) + two_pow_140.clone() - - t_p.clone() - - b3_c_prime; - - // e1_f_prime = e_1 + (2^4)f + 2^140 - t_P - let e1_f_prime_check = e_1 + (f * two_pow_4) + two_pow_140 - t_p.clone() - e1_f_prime; - - // g1_g2_prime = g_1 + (2^9)g_2 + 2^130 - t_P - let g1_g2_prime_check = { - let two_pow_9 = two_pow_4 * two_pow_5; - g_1 + (g_2 * two_pow_9) + two_pow_130 - t_p.clone() - g1_g2_prime - }; - - // x(g_d) = a + (2^250)b_0 + (2^254)b_1 - let gd_x_check = { - let sum = a + b_0 * two_pow_250 + b_1 * two_pow_254; - sum - gd_x - }; - - // x(pk_d) = b_3 + (2^4)c + (2^254)d_0 - let pkd_x_check = { - let sum = b_3 + c * two_pow_4 + d_0 * two_pow_254; - sum - pkd_x - }; - - // value = d_2 + (2^8)d_3 + (2^58)e_0 - let value_check = { - let two_pow_8 = pallas::Base::from_u64(1 << 8); - let two_pow_58 = pallas::Base::from_u64(1 << 58); - d_2 + d_3 * two_pow_8 + e_0 * two_pow_58 - value - }; - - std::iter::empty() - .chain(boolean_checks) - .chain(Some(("a_prime_check", a_prime_check))) - .chain(Some(("b3_c_prime_check", b3_c_prime_check))) - .chain(Some(("e1_f_prime_check", e1_f_prime_check))) - .chain(Some(("g1_g2_prime_check", g1_g2_prime_check))) - .chain(Some(("b_check", b_check))) - .chain(Some(("d_check", d_check))) - .chain(Some(("e_check", e_check))) - .chain(Some(("g_check", g_check))) - .chain(Some(("h_check", h_check))) - .chain(Some(("gd_x_check", gd_x_check))) - .chain(Some(("pkd_x_check", pkd_x_check))) - .chain(Some(("value_check", value_check))) - .map(move |(name, poly)| (name, q_canon_1.clone() * poly)) - }); - - meta.create_gate("Canonicity checks", |meta| { - /* - a (250 bits) = bits 0..=249 of x(g_d) - b (10 bits) = b_0 || b_1 || b_2 || b_3 - = (bits 250..=253 of x(g_d)) || (bit 254 of x(g_d)) || (ỹ bit of g_d) || (bits 0..=3 of pk★_d) - c (250 bits) = bits 4..=253 of pk★_d - d (60 bits) = d_0 || d_1 || d_2 || d_3 - = (bit 254 of x(pk_d)) || (ỹ bit of pk_d) || (0..=7 of v) || (8..=57 of v) - e (10 bits) = e_0 || e_1 - = (bits 58..=63 of v) || (bits 0..=3 of rho) - f (250 bits) = bits 4..=253 inclusive of rho - g (250 bits) = g_0 || g_1 || g_2 - = (bit 254 of rho) || (bits 0..=8 of psi) || (bits 9..=248 of psi) - h (10 bits) = h_0 || h_1 || h_2 - = (bits 249..=253 of psi) || (bit 254 of psi) || 4 zero bits - - | A_0 | A_1 | A_2 | A_3 | A_4 | A_5 | A_6 | A_7 | A_8 | A_9 | q_canon_1 | q_canon_2 | - ----------------------------------------------------------------------------------------------------------------------------------------------- - | b | d | e | g | h | d_1 | x(pk_d) | b_3 |a_prime| b_2 | 0 | 0 | - |e1_f_prime|g1_g2_prime| value | d_2 | z1_d | e_0 |b3_c_prime| c | a | x(g_d) | 1 | 0 | - | e_1 | f | g_0 | g_1 | z1_g | h_0 | h_1 | d_0 | b_0 | b_1 | 0 | 1 | - | rho | z13_f |z14_e1_f_prime| psi | z13_g |z13_g1_g2_prime| z13_c |z14_b3_c_prime| z13_a |z13_a_prime| 0 | 0 | - */ - - // q_canon_2 checks that: - // - field element decomposition: - // - rho = e_1 + (2^4) f + (2^254) g_0 - // - psi = g_1 + (2^9) g_2 + (2^249) h_0 + (2^254) h_1 - // - canonicity: - // - b_1 = 1 => b_0 = 0 - // && z13_a = 0 - // && z13_a_prime = 0 - // - d_0 = 1 => z13_c = 0 - // && z14_b3_c_prime = 0 - // - g_0 = 1 => z13_f = 0 - // && z14_e1_f_prime = 0 - // - h_1 = 1 => h_0 = 0 - // && z13_g1_g2_prime = 0 - - let q_canon_2 = meta.query_selector(config.q_canon_2); - - // Offset cur - let e_1 = meta.query_advice(config.advices[0], Rotation::cur()); - let f = meta.query_advice(config.advices[1], Rotation::cur()); - let g_0 = meta.query_advice(config.advices[2], Rotation::cur()); - let g_1 = meta.query_advice(config.advices[3], Rotation::cur()); - let z1_g = meta.query_advice(config.advices[4], Rotation::cur()); - let g_2 = z1_g; - let h_0 = meta.query_advice(config.advices[5], Rotation::cur()); - let h_1 = meta.query_advice(config.advices[6], Rotation::cur()); - let d_0 = meta.query_advice(config.advices[7], Rotation::cur()); - let b_0 = meta.query_advice(config.advices[8], Rotation::cur()); - let b_1 = meta.query_advice(config.advices[9], Rotation::cur()); - - // Offset next - let rho = meta.query_advice(config.advices[0], Rotation::next()); - let z13_f = meta.query_advice(config.advices[1], Rotation::next()); - let z14_e1_f_prime = meta.query_advice(config.advices[2], Rotation::next()); - let psi = meta.query_advice(config.advices[3], Rotation::next()); - let z13_g = meta.query_advice(config.advices[4], Rotation::next()); - let z13_g1_g2_prime = meta.query_advice(config.advices[5], Rotation::next()); - let z13_c = meta.query_advice(config.advices[6], Rotation::next()); - let z14_b3_c_prime = meta.query_advice(config.advices[7], Rotation::next()); - let z13_a = meta.query_advice(config.advices[8], Rotation::next()); - let z13_a_prime = meta.query_advice(config.advices[9], Rotation::next()); - - // rho = e_1 + (2^4) f + (2^254) g_0 - let rho_decomposition_check = { - let sum = e_1 + f * two_pow_4 + g_0.clone() * two_pow_254; - sum - rho - }; - - // psi = g_1 + (2^9) g_2 + (2^249) h_0 + (2^254) h_1 - let psi_decomposition_check = { - let two_pow_249 = - pallas::Base::from_u128(1 << 124).square() * pallas::Base::from_u128(2); - let sum = g_1 - + g_2 * pallas::Base::from_u64(1 << 9) - + h_0.clone() * two_pow_249 - + h_1.clone() * two_pow_254; - sum - psi - }; - - // The gd_x_canonicity_checks are enforced if and only if `b_1` = 1. - // x(g_d) = a (250 bits) || b_0 (4 bits) || b_1 (1 bit) - let gd_x_canonicity_checks = std::iter::empty() - .chain(Some(("b_1 = 1 => b_0", b_0))) - .chain(Some(("b_1 = 1 => z13_a", z13_a))) - .chain(Some(("b_1 = 1 => z13_a_prime", z13_a_prime))) - .map(move |(name, poly)| (name, b_1.clone() * poly)); - - // The pkd_x_canonicity_checks are enforced if and only if `d_0` = 1. - // `x(pk_d)` = `b_3 (4 bits) || c (250 bits) || d_0 (1 bit)` - let pkd_x_canonicity_checks = std::iter::empty() - .chain(Some(("d_0 = 1 => z13_c", z13_c))) - .chain(Some(("d_0 = 1 => z14_b3_c_prime", z14_b3_c_prime))) - .map(move |(name, poly)| (name, d_0.clone() * poly)); - - // The rho_canonicity_checks are enforced if and only if `g_0` = 1. - // rho = e_1 (4 bits) || f (250 bits) || g_0 (1 bit) - let rho_canonicity_checks = std::iter::empty() - .chain(Some(("g_0 = 1 => z13_f", z13_f))) - .chain(Some(("g_0 = 1 => z14_e1_f_prime", z14_e1_f_prime))) - .map(move |(name, poly)| (name, g_0.clone() * poly)); - - // The psi_canonicity_checks are enforced if and only if `h_1` = 1. - // `psi` = `g_1 (9 bits) || g_2 (240 bits) || h_0 (5 bits) || h_1 (1 bit)` - let psi_canonicity_checks = std::iter::empty() - .chain(Some(("h_1 = 1 => h_0", h_0))) - .chain(Some(("h_1 = 1 => z13_g", z13_g))) - .chain(Some(("h_1 = 1 => z13_g1_g2_prime", z13_g1_g2_prime))) - .map(move |(name, poly)| (name, h_1.clone() * poly)); - - std::iter::empty() - .chain(Some(("rho_decomposition_check", rho_decomposition_check))) - .chain(Some(("psi_decomposition_check", psi_decomposition_check))) - .chain(gd_x_canonicity_checks) - .chain(pkd_x_canonicity_checks) - .chain(rho_canonicity_checks) - .chain(psi_canonicity_checks) - .map(move |(name, poly)| (name, q_canon_2.clone() * poly)) - }); - config } @@ -1058,354 +1112,277 @@ impl NoteCommitConfig { mut layouter: impl Layouter, gate_cells: GateCells, ) -> Result<(), Error> { - /* - The pieces are witnessed in the below configuration, such that no gate has to query an - offset greater than +/- 1 from its relative row. + // Columns used for MessagePiece gates. + let col_l = self.advices[6]; + let col_m = self.advices[7]; + let col_r = self.advices[8]; + let col_z = self.advices[9]; - | A_0 | A_1 | A_2 | A_3 | A_4 | A_5 | A_6 | A_7 | A_8 | A_9 | q_canon_1 | q_canon_2 | - ----------------------------------------------------------------------------------------------------------------------------------------------- - | b | d | e | g | h | d_1 | x(pk_d) | b_3 |a_prime| b_2 | 0 | 0 | - |e1_f_prime|g1_g2_prime| value | d_2 | z1_d | e_0 |b3_c_prime| c | a | x(g_d) | 1 | 0 | - | e_1 | f | g_0 | g_1 | z1_g | h_0 | h_1 | d_0 | b_0 | b_1 | 0 | 1 | - | rho | z13_f |z14_e1_f_prime| psi | z13_g |z13_g1_g2_prime| z13_c |z14_b3_c_prime| z13_a |z13_a_prime| 0 | 0 | - */ - layouter.assign_region( - || "Assign gate cells", + // | A_6 | A_7 | A_8 | q_notecommit_b | + // ------------------------------------ + // | b | b_0 | b_1 | 1 | + // | | b_2 | b_3 | 0 | + let b_1 = layouter.assign_region( + || "NoteCommit MessagePiece b", |mut region| { - // Assign fixed column the correct values - self.q_canon_1.enable(&mut region, 1)?; - self.q_canon_2.enable(&mut region, 2)?; + self.q_notecommit_b.enable(&mut region, 0)?; - // Offset 0 - { - let offset = 0; - - // advices[0] - copy(&mut region, || "b", self.advices[0], offset, &gate_cells.b)?; - - // advices[1] - copy(&mut region, || "d", self.advices[1], offset, &gate_cells.d)?; - - // advices[2] - copy(&mut region, || "e", self.advices[2], offset, &gate_cells.e)?; - - // advices[3] - copy(&mut region, || "g", self.advices[3], offset, &gate_cells.g)?; - - // advices[4] - copy(&mut region, || "h", self.advices[4], offset, &gate_cells.h)?; - - // advices[5] - copy( - &mut region, - || "d_1", - self.advices[5], - offset, - &gate_cells.d_1, - )?; - - // advices[6] - copy( - &mut region, - || "pkd_x", - self.advices[6], - offset, - &gate_cells.pkd_x, - )?; - - // advices[7] - copy( - &mut region, - || "b_3", - self.advices[7], - offset, - &gate_cells.b_3, - )?; - - // advices[8] - copy( - &mut region, - || "a_prime", - self.advices[8], - offset, - &gate_cells.a_prime, - )?; - - // advices[9] - copy( - &mut region, - || "b_2", - self.advices[9], - offset, - &gate_cells.b_2, - )?; - } - - // Offset 1 - { - let offset = 1; - - // advices[0] - copy( - &mut region, - || "e1_f_prime", - self.advices[0], - offset, - &gate_cells.e1_f_prime, - )?; - - // advices[1] - copy( - &mut region, - || "g1_g2_prime", - self.advices[1], - offset, - &gate_cells.g1_g2_prime, - )?; - - // advices[2] - copy( - &mut region, - || "value", - self.advices[2], - offset, - &gate_cells.value, - )?; - - // advices[3] - copy( - &mut region, - || "d_2", - self.advices[3], - offset, - &gate_cells.d_2, - )?; - - // advices[4] - copy( - &mut region, - || "z1_d", - self.advices[4], - offset, - &gate_cells.z1_d, - )?; - - // advices[5] - copy( - &mut region, - || "e_0", - self.advices[5], - offset, - &gate_cells.e_0, - )?; - - // advices[6] - copy( - &mut region, - || "b3_c_prime", - self.advices[6], - offset, - &gate_cells.b3_c_prime, - )?; - - // advices[7] - copy(&mut region, || "c", self.advices[7], offset, &gate_cells.c)?; - - // advices[8] - copy(&mut region, || "a", self.advices[8], offset, &gate_cells.a)?; - - // advices[9] - copy( - &mut region, - || "gd_x", - self.advices[9], - offset, - &gate_cells.gd_x, - )?; - } - - // Offset 2 - { - let offset = 2; - - // advices[0] - copy( - &mut region, - || "e_1", - self.advices[0], - offset, - &gate_cells.e_1, - )?; - - // advices[1] - copy(&mut region, || "f", self.advices[1], offset, &gate_cells.f)?; - - // advices[2] - region.assign_advice( - || "g_0", - self.advices[2], - offset, - || gate_cells.g_0.ok_or(Error::SynthesisError), - )?; - - // advices[3] - copy( - &mut region, - || "g_1", - self.advices[3], - offset, - &gate_cells.g_1, - )?; - - // advices[4] - copy( - &mut region, - || "z1_g", - self.advices[4], - offset, - &gate_cells.z1_g, - )?; - - // advices[5] - copy( - &mut region, - || "h_0", - self.advices[5], - offset, - &gate_cells.h_0, - )?; - - // advices[6] - region.assign_advice( - || "h_1", - self.advices[6], - offset, - || gate_cells.h_1.ok_or(Error::SynthesisError), - )?; - - // advices[7] - region.assign_advice( - || "d_0", - self.advices[7], - offset, - || gate_cells.d_0.ok_or(Error::SynthesisError), - )?; - - // advices[8] - copy( - &mut region, - || "b_0", - self.advices[8], - offset, - &gate_cells.b_0, - )?; - - // advices[9] - region.assign_advice( + copy(&mut region, || "b", col_l, 0, &gate_cells.b)?; + copy(&mut region, || "b_0", col_m, 0, &gate_cells.b_0)?; + let b_1 = { + let cell = region.assign_advice( || "b_1", - self.advices[9], - offset, + col_r, + 0, || gate_cells.b_1.ok_or(Error::SynthesisError), )?; - } + CellValue::new(cell, gate_cells.b_1) + }; - // Offset 3 - { - let offset = 3; + copy(&mut region, || "b_2", col_m, 1, &gate_cells.b_2)?; + copy(&mut region, || "b_3", col_r, 1, &gate_cells.b_3)?; - // advices[0] - copy( - &mut region, - || "rho", - self.advices[0], - offset, - &gate_cells.rho, + Ok(b_1) + }, + )?; + + // | A_6 | A_7 | A_8 | q_notecommit_d | + // ------------------------------------ + // | d | d_0 | d_1 | 1 | + // | | d_2 | d_3 | 0 | + let d_0 = layouter.assign_region( + || "NoteCommit MessagePiece d", + |mut region| { + self.q_notecommit_d.enable(&mut region, 0)?; + + copy(&mut region, || "d", col_l, 0, &gate_cells.d)?; + let d_0 = { + let cell = region.assign_advice( + || "d_0", + col_m, + 0, + || gate_cells.d_0.ok_or(Error::SynthesisError), )?; + CellValue::new(cell, gate_cells.d_0) + }; + copy(&mut region, || "d_1", col_r, 0, &gate_cells.d_1)?; - // advices[1] - copy( - &mut region, - || "z13_f", - self.advices[1], - offset, - &gate_cells.z13_f, - )?; + copy(&mut region, || "d_2", col_m, 1, &gate_cells.d_2)?; + copy(&mut region, || "d_3 = z1_d", col_r, 1, &gate_cells.z1_d)?; - // advices[2] - copy( - &mut region, - || "z14_e1_f_prime", - self.advices[2], - offset, - &gate_cells.z14_e1_f_prime, - )?; + Ok(d_0) + }, + )?; - // advices[3] - copy( - &mut region, - || "psi", - self.advices[3], - offset, - &gate_cells.psi, - )?; + // | A_6 | A_7 | A_8 | q_notecommit_e | + // ------------------------------------ + // | e | e_0 | e_1 | 1 | + layouter.assign_region( + || "NoteCommit MessagePiece e", + |mut region| { + self.q_notecommit_e.enable(&mut region, 0)?; - // advices[4] - copy( - &mut region, - || "z13_g", - self.advices[4], - offset, - &gate_cells.z13_g, - )?; - - // advices[5] - copy( - &mut region, - || "z13_g1_g2_prime", - self.advices[5], - offset, - &gate_cells.z13_g1_g2_prime, - )?; - - // advices[6] - copy( - &mut region, - || "z13_c", - self.advices[6], - offset, - &gate_cells.z13_c, - )?; - - // advices[7] - copy( - &mut region, - || "z14_b3_c_prime", - self.advices[7], - offset, - &gate_cells.z14_b3_c_prime, - )?; - - // advices[8] - copy( - &mut region, - || "z13_a", - self.advices[8], - offset, - &gate_cells.z13_a, - )?; - - // advices[9] - copy( - &mut region, - || "z13_a_prime", - self.advices[9], - offset, - &gate_cells.z13_a_prime, - )?; - } + copy(&mut region, || "e", col_l, 0, &gate_cells.e)?; + copy(&mut region, || "e_0", col_m, 0, &gate_cells.e_0)?; + copy(&mut region, || "e_1", col_r, 0, &gate_cells.e_1)?; Ok(()) }, + )?; + + // | A_6 | A_7 | q_notecommit_g | + // ------------------------------ + // | g | g_0 | 1 | + // | g_1 | g_2 | 0 | + let g_0 = layouter.assign_region( + || "NoteCommit MessagePiece g", + |mut region| { + self.q_notecommit_g.enable(&mut region, 0)?; + + copy(&mut region, || "g", col_l, 0, &gate_cells.g)?; + let g_0 = { + let cell = region.assign_advice( + || "g_0", + col_m, + 0, + || gate_cells.g_0.ok_or(Error::SynthesisError), + )?; + CellValue::new(cell, gate_cells.g_0) + }; + + copy(&mut region, || "g_1", col_l, 1, &gate_cells.g_1)?; + copy(&mut region, || "g_2 = z1_g", col_m, 1, &gate_cells.z1_g)?; + + Ok(g_0) + }, + )?; + + // | A_6 | A_7 | A_8 | q_notecommit_h | + // ------------------------------------ + // | h | h_0 | h_1 | 1 | + let h_1 = layouter.assign_region( + || "NoteCommit MessagePiece h", + |mut region| { + self.q_notecommit_h.enable(&mut region, 0)?; + + copy(&mut region, || "h", col_l, 0, &gate_cells.h)?; + copy(&mut region, || "h_0", col_m, 0, &gate_cells.h_0)?; + let h_1 = { + let cell = region.assign_advice( + || "h_1", + col_r, + 0, + || gate_cells.h_1.ok_or(Error::SynthesisError), + )?; + CellValue::new(cell, gate_cells.h_1) + }; + + Ok(h_1) + }, + )?; + + // | A_6 | A_7 | A_8 | A_9 | q_notecommit_g_d | + // ----------------------------------------------------------- + // | x(g_d) | b_0 | a | z13_a | 1 | + // | | b_1 | a_prime | z13_a_prime | 0 | + layouter.assign_region( + || "NoteCommit input g_d", + |mut region| { + copy(&mut region, || "gd_x", col_l, 0, &gate_cells.gd_x)?; + + copy(&mut region, || "b_0", col_m, 0, &gate_cells.b_0)?; + copy(&mut region, || "b_1", col_m, 1, &b_1)?; + + copy(&mut region, || "a", col_r, 0, &gate_cells.a)?; + copy(&mut region, || "a_prime", col_r, 1, &gate_cells.a_prime)?; + + copy(&mut region, || "z13_a", col_z, 0, &gate_cells.z13_a)?; + copy( + &mut region, + || "z13_a_prime", + col_z, + 1, + &gate_cells.z13_a_prime, + )?; + + self.q_notecommit_g_d.enable(&mut region, 0) + }, + )?; + + // | A_6 | A_7 | A_8 | A_9 | q_notecommit_pk_d | + // ------------------------------------------------------------------- + // | x(pk_d) | b_3 | c | z13_c | 1 | + // | | d_0 | b3_c_prime | z14_b3_c_prime | 0 | + layouter.assign_region( + || "NoteCommit input pk_d", + |mut region| { + copy(&mut region, || "pkd_x", col_l, 0, &gate_cells.pkd_x)?; + + copy(&mut region, || "b_3", col_m, 0, &gate_cells.b_3)?; + copy(&mut region, || "d_0", col_m, 1, &d_0)?; + + copy(&mut region, || "c", col_r, 0, &gate_cells.c)?; + copy( + &mut region, + || "b3_c_prime", + col_r, + 1, + &gate_cells.b3_c_prime, + )?; + + copy(&mut region, || "z13_c", col_z, 0, &gate_cells.z13_c)?; + copy( + &mut region, + || "z14_b3_c_prime", + col_z, + 1, + &gate_cells.z14_b3_c_prime, + )?; + + self.q_notecommit_pk_d.enable(&mut region, 0) + }, + )?; + + // | value | d_2 | d_3 | e_0 | + layouter.assign_region( + || "NoteCommit input value", + |mut region| { + copy(&mut region, || "value", col_l, 0, &gate_cells.value)?; + copy(&mut region, || "d_2", col_m, 0, &gate_cells.d_2)?; + copy(&mut region, || "z1_d", col_r, 0, &gate_cells.z1_d)?; + copy(&mut region, || "e_0", col_z, 0, &gate_cells.e_0)?; + + self.q_notecommit_value.enable(&mut region, 0) + }, + )?; + + // | A_6 | A_7 | A_8 | A_9 | q_notecommit_rho | + // -------------------------------------------------------------- + // | rho | e_1 | f | z13_f | 1 | + // | | g_0 | e1_f_prime | z14_e1_f_prime | 0 | + layouter.assign_region( + || "NoteCommit input rho", + |mut region| { + copy(&mut region, || "rho", col_l, 0, &gate_cells.rho)?; + + copy(&mut region, || "e_1", col_m, 0, &gate_cells.e_1)?; + copy(&mut region, || "g_0", col_m, 1, &g_0)?; + + copy(&mut region, || "f", col_r, 0, &gate_cells.f)?; + copy( + &mut region, + || "e1_f_prime", + col_r, + 1, + &gate_cells.e1_f_prime, + )?; + + copy(&mut region, || "z13_f", col_z, 0, &gate_cells.z13_f)?; + copy( + &mut region, + || "z14_e1_f_prime", + col_z, + 1, + &gate_cells.z14_e1_f_prime, + )?; + + self.q_notecommit_rho.enable(&mut region, 0) + }, + )?; + + // | A_6 | A_7 | A_8 | A_9 | q_notecommit_psi | + // ---------------------------------------------------------------- + // | psi | g_1 | g_2 | z13_g | 1 | + // | h_0 | h_1 | g1_g2_prime | z13_g1_g2_prime | 0 | + layouter.assign_region( + || "NoteCommit input psi", + |mut region| { + copy(&mut region, || "psi", col_l, 0, &gate_cells.psi)?; + copy(&mut region, || "h_0", col_l, 1, &gate_cells.h_0)?; + + copy(&mut region, || "g_1", col_m, 0, &gate_cells.g_1)?; + copy(&mut region, || "h_1", col_m, 1, &h_1)?; + + copy(&mut region, || "g_2 = z1_g", col_r, 0, &gate_cells.z1_g)?; + copy( + &mut region, + || "g1_g2_prime", + col_r, + 1, + &gate_cells.g1_g2_prime, + )?; + + copy(&mut region, || "z13_g", col_z, 0, &gate_cells.z13_g)?; + copy( + &mut region, + || "z13_g1_g2_prime", + col_z, + 1, + &gate_cells.z13_g1_g2_prime, + )?; + + self.q_notecommit_psi.enable(&mut region, 0) + }, ) } } From 9af22a8cbc617ba4f485a8c1674ce1e0f89321a4 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Thu, 29 Jul 2021 20:57:09 +0100 Subject: [PATCH 05/12] circuit: Add region layout diagrams for y_switch constraint Helps to see why we can't optimise it to remove the `prev` query. --- src/circuit/gadget/ecc/chip/mul/complete.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/circuit/gadget/ecc/chip/mul/complete.rs b/src/circuit/gadget/ecc/chip/mul/complete.rs index 67521560..030f6f95 100644 --- a/src/circuit/gadget/ecc/chip/mul/complete.rs +++ b/src/circuit/gadget/ecc/chip/mul/complete.rs @@ -42,6 +42,11 @@ impl Config { /// addition gate (controlled by `q_mul`) already checks scalar decomposition for /// the other bits. pub(super) fn create_gate(&self, meta: &mut ConstraintSystem) { + // | y_p | z_complete | + // -------------------- + // | y_p | z_{i + 1} | + // | | base_y | + // | | z_i | meta.create_gate( "Decompose scalar for complete bits of variable-base mul", |meta| { @@ -122,6 +127,12 @@ impl Config { // Each iteration uses 2 rows (two complete additions) let row = 2 * iter; + // | x_p | y_p | x_qr | y_qr | z_complete | + // ------------------------------------------ + // | U_x | U_y | acc_x | acc_y | z_{i + 1} | row + offset + // |acc_x|acc_y|acc+U_x|acc+U_y| base_y | + // | | | res_x | res_y | z_i | + // Update `z`. z = { // z_next = z_cur * 2 + k_next From ac900148ed976fb333a67ea1a0d157e2a0c7d387 Mon Sep 17 00:00:00 2001 From: str4d Date: Thu, 19 Aug 2021 14:33:52 +0100 Subject: [PATCH 06/12] Fix typo in gate documentation Co-authored-by: ying tong --- src/circuit/gadget/sinsemilla/note_commit.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/circuit/gadget/sinsemilla/note_commit.rs b/src/circuit/gadget/sinsemilla/note_commit.rs index 9a332bf4..b61e1322 100644 --- a/src/circuit/gadget/sinsemilla/note_commit.rs +++ b/src/circuit/gadget/sinsemilla/note_commit.rs @@ -146,7 +146,7 @@ impl NoteCommitConfig { meta.create_gate("NoteCommit MessagePiece d", |meta| { let q_notecommit_d = meta.query_selector(config.q_notecommit_d); - // d has been constrained to 10 bits by the Sinsemilla hash. + // d has been constrained to 60 bits by the Sinsemilla hash. let d = meta.query_advice(col_l, Rotation::cur()); // This gate constrains d_0 to be boolean. let d_0 = meta.query_advice(col_m, Rotation::cur()); From bac22d9b197280b5b2d1c359ac42c2ce9b4bbc5e Mon Sep 17 00:00:00 2001 From: str4d Date: Thu, 19 Aug 2021 14:34:15 +0100 Subject: [PATCH 07/12] clippy: Remove redundant clones Co-authored-by: ying tong --- src/circuit/gadget/sinsemilla/note_commit.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/circuit/gadget/sinsemilla/note_commit.rs b/src/circuit/gadget/sinsemilla/note_commit.rs index b61e1322..2d65f195 100644 --- a/src/circuit/gadget/sinsemilla/note_commit.rs +++ b/src/circuit/gadget/sinsemilla/note_commit.rs @@ -309,7 +309,7 @@ impl NoteCommitConfig { }; // b3_c_prime = b_3 + (2^4)c + 2^140 - t_P - let b3_c_prime_check = b_3.clone() + (c.clone() * two_pow_4) + two_pow_140.clone() + let b3_c_prime_check = b_3 + (c * two_pow_4) + two_pow_140.clone() - t_p.clone() - b3_c_prime; From f2400baa01700e0439ba12021809acfbf469b9ae Mon Sep 17 00:00:00 2001 From: str4d Date: Thu, 19 Aug 2021 14:35:56 +0100 Subject: [PATCH 08/12] Improve NoteCommit input value gate doc Brings it in line with the other gate docs. Co-authored-by: ying tong --- src/circuit/gadget/sinsemilla/note_commit.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/circuit/gadget/sinsemilla/note_commit.rs b/src/circuit/gadget/sinsemilla/note_commit.rs index 2d65f195..44545ad1 100644 --- a/src/circuit/gadget/sinsemilla/note_commit.rs +++ b/src/circuit/gadget/sinsemilla/note_commit.rs @@ -327,7 +327,9 @@ impl NoteCommitConfig { .map(move |(name, poly)| (name, q_notecommit_pk_d.clone() * poly)) }); - // | value | d_2 | d_3 | e_0 | + // | A_6 | A_7 | A_8 | A_9 | q_notecommit_value | + // ------------------------------------------------ + // | value | d_2 | d_3 | e_0 | 1 | meta.create_gate("NoteCommit input value", |meta| { let q_notecommit_value = meta.query_selector(config.q_notecommit_value); From c24c67d5f041cd894f1a758be378421418b71fb7 Mon Sep 17 00:00:00 2001 From: Daira Hopwood Date: Wed, 1 Sep 2021 14:11:08 +0100 Subject: [PATCH 09/12] cargo fmt Signed-off-by: Daira Hopwood --- src/circuit/gadget/sinsemilla/note_commit.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/circuit/gadget/sinsemilla/note_commit.rs b/src/circuit/gadget/sinsemilla/note_commit.rs index 44545ad1..0af21fdb 100644 --- a/src/circuit/gadget/sinsemilla/note_commit.rs +++ b/src/circuit/gadget/sinsemilla/note_commit.rs @@ -309,9 +309,8 @@ impl NoteCommitConfig { }; // b3_c_prime = b_3 + (2^4)c + 2^140 - t_P - let b3_c_prime_check = b_3 + (c * two_pow_4) + two_pow_140.clone() - - t_p.clone() - - b3_c_prime; + let b3_c_prime_check = + b_3 + (c * two_pow_4) + two_pow_140.clone() - t_p.clone() - b3_c_prime; // The pkd_x_canonicity_checks are enforced if and only if `d_0` = 1. // `x(pk_d)` = `b_3 (4 bits) || c (250 bits) || d_0 (1 bit)` From faddaf9e30b16f3ffbd716050e100ab728cbadee Mon Sep 17 00:00:00 2001 From: Daira Hopwood Date: Tue, 7 Sep 2021 00:52:37 +0100 Subject: [PATCH 10/12] note_commit.rs: make two_pow_* definitions more consistent. Signed-off-by: Daira Hopwood --- src/circuit/gadget/sinsemilla/note_commit.rs | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/circuit/gadget/sinsemilla/note_commit.rs b/src/circuit/gadget/sinsemilla/note_commit.rs index 0af21fdb..17ea21b4 100644 --- a/src/circuit/gadget/sinsemilla/note_commit.rs +++ b/src/circuit/gadget/sinsemilla/note_commit.rs @@ -97,9 +97,11 @@ impl NoteCommitConfig { let two_pow_8 = two_pow_4.square(); let two_pow_9 = two_pow_8 * two; let two_pow_10 = two_pow_9 * two; + let two_pow_58 = pallas::Base::from_u64(1 << 58); let two_pow_130 = Expression::Constant(pallas::Base::from_u128(1 << 65).square()); let two_pow_140 = Expression::Constant(pallas::Base::from_u128(1 << 70).square()); - let two_pow_250 = pallas::Base::from_u128(1 << 125).square(); + let two_pow_249 = pallas::Base::from_u128(1 << 124).square() * two; + let two_pow_250 = two_pow_249 * two; let two_pow_254 = pallas::Base::from_u128(1 << 127).square(); let t_p = Expression::Constant(pallas::Base::from_u128(T_P)); @@ -342,11 +344,7 @@ impl NoteCommitConfig { let e_0 = meta.query_advice(col_z, Rotation::cur()); // value = d_2 + (2^8)d_3 + (2^58)e_0 - let value_check = { - let two_pow_8 = pallas::Base::from_u64(1 << 8); - let two_pow_58 = pallas::Base::from_u64(1 << 58); - d_2 + d_3 * two_pow_8 + e_0 * two_pow_58 - value - }; + let value_check = d_2 + d_3 * two_pow_8 + e_0 * two_pow_58 - value; std::iter::empty() .chain(Some(("value_check", value_check))) @@ -418,8 +416,6 @@ impl NoteCommitConfig { // psi = g_1 + (2^9) g_2 + (2^249) h_0 + (2^254) h_1 let decomposition_check = { - let two_pow_249 = - pallas::Base::from_u128(1 << 124).square() * pallas::Base::from_u128(2); let sum = g_1.clone() + g_2.clone() * pallas::Base::from_u64(1 << 9) + h_0.clone() * two_pow_249 @@ -428,10 +424,8 @@ impl NoteCommitConfig { }; // g1_g2_prime = g_1 + (2^9)g_2 + 2^130 - t_P - let g1_g2_prime_check = { - let two_pow_9 = two_pow_4 * two_pow_5; - g_1 + (g_2 * two_pow_9) + two_pow_130.clone() - t_p.clone() - g1_g2_prime - }; + let g1_g2_prime_check = + g_1 + (g_2 * two_pow_9) + two_pow_130.clone() - t_p.clone() - g1_g2_prime; // The psi_canonicity_checks are enforced if and only if `h_1` = 1. // `psi` = `g_1 (9 bits) || g_2 (240 bits) || h_0 (5 bits) || h_1 (1 bit)` From 97e18a819044af2cad3ca6dd3c26fe3cc99d0007 Mon Sep 17 00:00:00 2001 From: Daira Hopwood Date: Tue, 7 Sep 2021 00:56:22 +0100 Subject: [PATCH 11/12] Apply suggestions from code review --- src/circuit/gadget/sinsemilla/note_commit.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/circuit/gadget/sinsemilla/note_commit.rs b/src/circuit/gadget/sinsemilla/note_commit.rs index 17ea21b4..8dd95196 100644 --- a/src/circuit/gadget/sinsemilla/note_commit.rs +++ b/src/circuit/gadget/sinsemilla/note_commit.rs @@ -417,7 +417,7 @@ impl NoteCommitConfig { // psi = g_1 + (2^9) g_2 + (2^249) h_0 + (2^254) h_1 let decomposition_check = { let sum = g_1.clone() - + g_2.clone() * pallas::Base::from_u64(1 << 9) + + g_2.clone() * two_pow_9 + h_0.clone() * two_pow_249 + h_1.clone() * two_pow_254; sum - psi From ee44d2ccf0972da9675d3b5d767fba414004a36f Mon Sep 17 00:00:00 2001 From: Daira Hopwood Date: Tue, 7 Sep 2021 02:45:10 +0100 Subject: [PATCH 12/12] Apply suggestions from code review --- src/circuit/gadget/sinsemilla/note_commit.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/circuit/gadget/sinsemilla/note_commit.rs b/src/circuit/gadget/sinsemilla/note_commit.rs index 8dd95196..d0032161 100644 --- a/src/circuit/gadget/sinsemilla/note_commit.rs +++ b/src/circuit/gadget/sinsemilla/note_commit.rs @@ -1304,7 +1304,7 @@ impl NoteCommitConfig { |mut region| { copy(&mut region, || "value", col_l, 0, &gate_cells.value)?; copy(&mut region, || "d_2", col_m, 0, &gate_cells.d_2)?; - copy(&mut region, || "z1_d", col_r, 0, &gate_cells.z1_d)?; + copy(&mut region, || "d3 = z1_d", col_r, 0, &gate_cells.z1_d)?; copy(&mut region, || "e_0", col_z, 0, &gate_cells.e_0)?; self.q_notecommit_value.enable(&mut region, 0)