1#![allow(non_snake_case)]
2
3use crate::ahp::{
4 constraint_systems::{arithmetize_matrix, MatrixArithmetization},
5 AHPForR1CS, Error, LabeledPolynomial,
6};
7use crate::Vec;
8use ark_ff::PrimeField;
9use ark_poly::{EvaluationDomain, GeneralEvaluationDomain};
10use ark_relations::r1cs::{
11 ConstraintSynthesizer, ConstraintSystem, OptimizationGoal, SynthesisError, SynthesisMode,
12};
13use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, SerializationError};
14use ark_std::{
15 io::{Read, Write},
16 marker::PhantomData,
17};
18use derivative::Derivative;
19
20use crate::ahp::constraint_systems::{
21 balance_matrices, make_matrices_square_for_indexer, num_non_zero,
22 pad_input_for_indexer_and_prover,
23};
24
25#[derive(Derivative, CanonicalSerialize, CanonicalDeserialize)]
29#[derivative(Clone(bound = ""), Copy(bound = ""))]
30pub struct IndexInfo<F> {
31 pub num_variables: usize,
33 pub num_constraints: usize,
35 pub num_non_zero: usize,
37 pub num_instance_variables: usize,
39
40 #[doc(hidden)]
41 f: PhantomData<F>,
42}
43
44impl<F: PrimeField> ark_ff::ToBytes for IndexInfo<F> {
45 fn write<W: Write>(&self, mut w: W) -> ark_std::io::Result<()> {
46 (self.num_variables as u64).write(&mut w)?;
47 (self.num_constraints as u64).write(&mut w)?;
48 (self.num_non_zero as u64).write(&mut w)
49 }
50}
51
52impl<F: PrimeField> IndexInfo<F> {
53 pub fn max_degree(&self) -> usize {
56 AHPForR1CS::<F>::max_degree(self.num_constraints, self.num_variables, self.num_non_zero)
57 .unwrap()
58 }
59}
60
61pub type Matrix<F> = Vec<Vec<(F, usize)>>;
63
64#[derive(Derivative)]
65#[derivative(Clone(bound = "F: PrimeField"))]
66#[derive(CanonicalSerialize, CanonicalDeserialize)]
74pub struct Index<F: PrimeField> {
75 pub index_info: IndexInfo<F>,
77
78 pub a: Matrix<F>,
80 pub b: Matrix<F>,
82 pub c: Matrix<F>,
84
85 pub a_star_arith: MatrixArithmetization<F>,
87 pub b_star_arith: MatrixArithmetization<F>,
89 pub c_star_arith: MatrixArithmetization<F>,
91}
92
93impl<F: PrimeField> Index<F> {
94 pub fn max_degree(&self) -> usize {
96 self.index_info.max_degree()
97 }
98
99 pub fn iter(&self) -> impl Iterator<Item = &LabeledPolynomial<F>> {
101 ark_std::vec![
102 &self.a_star_arith.row,
103 &self.a_star_arith.col,
104 &self.a_star_arith.val,
105 &self.a_star_arith.row_col,
106 &self.b_star_arith.row,
107 &self.b_star_arith.col,
108 &self.b_star_arith.val,
109 &self.b_star_arith.row_col,
110 &self.c_star_arith.row,
111 &self.c_star_arith.col,
112 &self.c_star_arith.val,
113 &self.c_star_arith.row_col,
114 ]
115 .into_iter()
116 }
117}
118
119impl<F: PrimeField> AHPForR1CS<F> {
120 pub fn index<C: ConstraintSynthesizer<F>>(c: C) -> Result<Index<F>, Error> {
122 let index_time = start_timer!(|| "AHP::Index");
123
124 let constraint_time = start_timer!(|| "Generating constraints");
125 let ics = ConstraintSystem::new_ref();
126 ics.set_optimization_goal(OptimizationGoal::Weight);
127 ics.set_mode(SynthesisMode::Setup);
128 c.generate_constraints(ics.clone())?;
129 end_timer!(constraint_time);
130
131 let padding_time = start_timer!(|| "Padding matrices to make them square");
132 pad_input_for_indexer_and_prover(ics.clone());
133 end_timer!(padding_time);
134 let matrix_processing_time = start_timer!(|| "Processing matrices");
135 ics.finalize();
136 make_matrices_square_for_indexer(ics.clone());
137 let matrices = ics.to_matrices().expect("should not be `None`");
138 let num_non_zero_val = num_non_zero::<F>(&matrices);
139 let (mut a, mut b, mut c) = (matrices.a, matrices.b, matrices.c);
140 balance_matrices(&mut a, &mut b);
141 end_timer!(matrix_processing_time);
142
143 let (num_formatted_input_variables, num_witness_variables, num_constraints, num_non_zero) = (
144 ics.num_instance_variables(),
145 ics.num_witness_variables(),
146 ics.num_constraints(),
147 num_non_zero_val,
148 );
149 let num_variables = num_formatted_input_variables + num_witness_variables;
150
151 if num_constraints != num_formatted_input_variables + num_witness_variables {
152 eprintln!(
153 "number of (formatted) input_variables: {}",
154 num_formatted_input_variables
155 );
156 eprintln!("number of witness_variables: {}", num_witness_variables);
157 eprintln!("number of num_constraints: {}", num_constraints);
158 eprintln!("number of num_non_zero: {}", num_non_zero);
159 return Err(Error::NonSquareMatrix);
160 }
161
162 if !Self::num_formatted_public_inputs_is_admissible(num_formatted_input_variables) {
163 return Err(Error::InvalidPublicInputLength);
164 }
165
166 let index_info = IndexInfo {
167 num_variables,
168 num_constraints,
169 num_non_zero,
170 num_instance_variables: num_formatted_input_variables,
171
172 f: PhantomData,
173 };
174
175 let domain_h = GeneralEvaluationDomain::new(num_constraints)
176 .ok_or(SynthesisError::PolynomialDegreeTooLarge)?;
177 let domain_k = GeneralEvaluationDomain::new(num_non_zero)
178 .ok_or(SynthesisError::PolynomialDegreeTooLarge)?;
179 let x_domain = GeneralEvaluationDomain::<F>::new(num_formatted_input_variables)
180 .ok_or(SynthesisError::PolynomialDegreeTooLarge)?;
181 let b_domain = GeneralEvaluationDomain::<F>::new(3 * domain_k.size() - 3)
182 .ok_or(SynthesisError::PolynomialDegreeTooLarge)?;
183
184 let a_arithmetization_time = start_timer!(|| "Arithmetizing A");
185 let a_star_arith = arithmetize_matrix("a", &mut a, domain_k, domain_h, x_domain, b_domain);
186 end_timer!(a_arithmetization_time);
187
188 let b_arithmetization_time = start_timer!(|| "Arithmetizing B");
189 let b_star_arith = arithmetize_matrix("b", &mut b, domain_k, domain_h, x_domain, b_domain);
190 end_timer!(b_arithmetization_time);
191
192 let c_arithmetization_time = start_timer!(|| "Arithmetizing C");
193 let c_star_arith = arithmetize_matrix("c", &mut c, domain_k, domain_h, x_domain, b_domain);
194 end_timer!(c_arithmetization_time);
195
196 end_timer!(index_time);
197 Ok(Index {
198 index_info,
199
200 a,
201 b,
202 c,
203
204 a_star_arith,
205 b_star_arith,
206 c_star_arith,
207 })
208 }
209}