// Copyright (c) 2023 Espresso Systems (espressosys.com) // This file is part of the HyperPlonk library. // You should have received a copy of the MIT License // along with the HyperPlonk library. If not, see . use ark_std::cmp::max; /// Customized gate is a list of tuples of /// (coefficient, selector_index, wire_indices) /// /// Example: /// q_L(X) * W_1(X)^5 - W_2(X) = 0 /// is represented as /// vec![ /// ( 1, Some(id_qL), vec![id_W1, id_W1, id_W1, id_W1, id_W1]), /// (-1, None, vec![id_W2]) /// ] /// /// CustomizedGates { /// gates: vec![ /// (1, Some(0), vec![0, 0, 0, 0, 0]), /// (-1, None, vec![1]) /// ], /// }; /// where id_qL = 0 // first selector /// id_W1 = 0 // first witness /// id_w2 = 1 // second witness /// /// NOTE: here coeff is a signed integer, instead of a field element #[derive(Clone, Debug, Default, PartialEq, Eq)] pub struct CustomizedGates { pub(crate) gates: Vec<(i64, Option, Vec)>, } impl CustomizedGates { /// The degree of the algebraic customized gate pub fn degree(&self) -> usize { let mut res = 0; for x in self.gates.iter() { res = max(res, x.2.len() + (x.1.is_some() as usize)) } res } /// The number of selectors in a customized gate pub fn num_selector_columns(&self) -> usize { let mut res = 0; for (_coeff, q, _ws) in self.gates.iter() { // a same selector must not be used for multiple monomials. if q.is_some() { res += 1; } } res } /// The number of witnesses in a customized gate pub fn num_witness_columns(&self) -> usize { let mut res = 0; for (_coeff, _q, ws) in self.gates.iter() { // witness list must be ordered // so we just need to compare with the last one if let Some(&p) = ws.last() { if res < p { res = p } } } // add one here because index starts from 0 res + 1 } /// Return a vanilla plonk gate: /// ``` ignore /// q_L w_1 + q_R w_2 + q_O w_3 + q_M w1w2 + q_C = 0 /// ``` /// which is /// ``` ignore /// (1, Some(id_qL), vec![id_W1]), /// (1, Some(id_qR), vec![id_W2]), /// (1, Some(id_qO), vec![id_W3]), /// (1, Some(id_qM), vec![id_W1, id_w2]), /// (1, Some(id_qC), vec![]), /// ``` pub fn vanilla_plonk_gate() -> Self { Self { gates: vec![ (1, Some(0), vec![0]), (1, Some(1), vec![1]), (1, Some(2), vec![2]), (1, Some(3), vec![0, 1]), (1, Some(4), vec![]), ], } } /// Return a jellyfish turbo plonk gate: /// ```ignore /// q_1 w_1 + q_2 w_2 + q_3 w_3 + q_4 w4 /// + q_M1 w1w2 + q_M2 w3w4 /// + q_H1 w1^5 + q_H2 w2^5 + q_H3 w1^5 + q_H4 w2^5 /// + q_E w1w2w3w4 /// + q_O w5 /// + q_C /// = 0 /// ``` /// with /// - w = [w1, w2, w3, w4, w5] /// - q = [ q_1, q_2, q_3, q_4, q_M1, q_M2, q_H1, q_H2, q_H3, q_H4, q_E, /// q_O, q_c ] /// /// which is /// ```ignore /// (1, Some(q[0]), vec![w[0]]), /// (1, Some(q[1]), vec![w[1]]), /// (1, Some(q[2]), vec![w[2]]), /// (1, Some(q[3]), vec![w[3]]), /// (1, Some(q[4]), vec![w[0], w[1]]), /// (1, Some(q[5]), vec![w[2], w[3]]), /// (1, Some(q[6]), vec![w[0], w[0], w[0], w[0], w[0]]), /// (1, Some(q[7]), vec![w[1], w[1], w[1], w[1], w[1]]), /// (1, Some(q[8]), vec![w[2], w[2], w[2], w[2], w[2]]), /// (1, Some(q[9]), vec![w[3], w[3], w[3], w[3], w[3]]), /// (1, Some(q[10]), vec![w[0], w[1], w[2], w[3]]), /// (1, Some(q[11]), vec![w[4]]), /// (1, Some(q[12]), vec![]), /// ``` pub fn jellyfish_turbo_plonk_gate() -> Self { CustomizedGates { gates: vec![ (1, Some(0), vec![0]), (1, Some(1), vec![1]), (1, Some(2), vec![2]), (1, Some(3), vec![3]), (1, Some(4), vec![0, 1]), (1, Some(5), vec![2, 3]), (1, Some(6), vec![0, 0, 0, 0, 0]), (1, Some(7), vec![1, 1, 1, 1, 1]), (1, Some(8), vec![2, 2, 2, 2, 2]), (1, Some(9), vec![3, 3, 3, 3, 3]), (1, Some(10), vec![0, 1, 2, 3]), (1, Some(11), vec![4]), (1, Some(12), vec![]), ], } } /// Generate a random gate for `num_witness` with a highest degree = /// `degree` pub fn mock_gate(num_witness: usize, degree: usize) -> Self { let mut gates = vec![]; let mut high_degree_term = vec![0; degree - 1]; high_degree_term.push(1); gates.push((1, Some(0), high_degree_term)); for i in 0..num_witness { gates.push((1, Some(i + 1), vec![i])) } gates.push((1, Some(num_witness + 1), vec![])); CustomizedGates { gates } } /// Return a plonk gate where #selector > #witness * 2 /// ``` ignore /// q_1 w_1 + q_2 w_2 + q_3 w_3 + /// q_4 w1w2 + q_5 w1w3 + q_6 w2w3 + /// q_7 = 0 /// ``` /// which is /// ``` ignore /// (1, Some(id_qL), vec![id_W1]), /// (1, Some(id_qR), vec![id_W2]), /// (1, Some(id_qO), vec![id_W3]), /// (1, Some(id_qM), vec![id_W1, id_w2]), /// (1, Some(id_qC), vec![]), /// ``` pub fn super_long_selector_gate() -> Self { Self { gates: vec![ (1, Some(0), vec![0]), (1, Some(1), vec![1]), (1, Some(2), vec![2]), (1, Some(3), vec![0, 1]), (1, Some(4), vec![0, 2]), (1, Some(5), vec![1, 2]), (1, Some(6), vec![]), ], } } }