arnaucube
arnaucube/testudoPublic Self-hosted repository
testudo/src/r1csinstance.rs
src/r1csinstance.rsRaw
  1use super::dense_mlpoly::DensePolynomial;
  2use super::errors::ProofVerifyError;
  3use super::math::Math;
  4use super::random::RandomTape;
  5use super::scalar::Scalar;
  6use super::sparse_mlpoly::{
  7  MultiSparseMatPolynomialAsDense, SparseMatEntry, SparseMatPolyCommitment,
  8  SparseMatPolyCommitmentGens, SparseMatPolyEvalProof, SparseMatPolynomial,
  9};
 10use super::timer::Timer;
 11use merlin::Transcript;
 12use rand::rngs::OsRng;
 13use serde::{Deserialize, Serialize};
 14
 15#[derive(Debug)]
 16pub struct R1CSInstance {
 17  num_cons: usize,
 18  num_vars: usize,
 19  num_inputs: usize,
 20  A: SparseMatPolynomial,
 21  B: SparseMatPolynomial,
 22  C: SparseMatPolynomial,
 23}
 24
 25pub struct R1CSCommitmentGens {
 26  gens: SparseMatPolyCommitmentGens,
 27}
 28
 29impl R1CSCommitmentGens {
 30  pub fn new(
 31    label: &'static [u8],
 32    num_cons: usize,
 33    num_vars: usize,
 34    num_inputs: usize,
 35    num_nz_entries: usize,
 36  ) -> R1CSCommitmentGens {
 37    assert!(num_inputs < num_vars);
 38    let num_poly_vars_x = num_cons.log2();
 39    let num_poly_vars_y = (2 * num_vars).log2();
 40    let gens =
 41      SparseMatPolyCommitmentGens::new(label, num_poly_vars_x, num_poly_vars_y, num_nz_entries, 3);
 42    R1CSCommitmentGens { gens }
 43  }
 44}
 45
 46pub struct R1CSCommitment {
 47  num_cons: usize,
 48  num_vars: usize,
 49  num_inputs: usize,
 50  comm: SparseMatPolyCommitment,
 51}
 52
 53pub struct R1CSDecommitment {
 54  dense: MultiSparseMatPolynomialAsDense,
 55}
 56
 57impl R1CSCommitment {
 58  pub fn get_num_cons(&self) -> usize {
 59    self.num_cons
 60  }
 61
 62  pub fn get_num_vars(&self) -> usize {
 63    self.num_vars
 64  }
 65
 66  pub fn get_num_inputs(&self) -> usize {
 67    self.num_inputs
 68  }
 69}
 70
 71impl R1CSInstance {
 72  pub fn new(
 73    num_cons: usize,
 74    num_vars: usize,
 75    num_inputs: usize,
 76    A: &Vec<(usize, usize, Scalar)>,
 77    B: &Vec<(usize, usize, Scalar)>,
 78    C: &Vec<(usize, usize, Scalar)>,
 79  ) -> R1CSInstance {
 80    Timer::print(&format!("number_of_constraints {}", num_cons));
 81    Timer::print(&format!("number_of_variables {}", num_vars));
 82    Timer::print(&format!("number_of_inputs {}", num_inputs));
 83    Timer::print(&format!("number_non-zero_entries_A {}", A.len()));
 84    Timer::print(&format!("number_non-zero_entries_B {}", B.len()));
 85    Timer::print(&format!("number_non-zero_entries_C {}", C.len()));
 86
 87    // check that num_cons is a power of 2
 88    assert_eq!(num_cons.next_power_of_two(), num_cons);
 89
 90    // check that num_vars is a power of 2
 91    assert_eq!(num_vars.next_power_of_two(), num_vars);
 92
 93    // check that number_inputs + 1 <= num_vars
 94    assert!(num_inputs < num_vars);
 95
 96    // no errors, so create polynomials
 97    let num_poly_vars_x = num_cons.log2();
 98    let num_poly_vars_y = (2 * num_vars).log2();
 99
100    let mat_A = (0..A.len())
101      .map(|i| SparseMatEntry::new(A[i].0, A[i].1, A[i].2))
102      .collect::<Vec<SparseMatEntry>>();
103    let mat_B = (0..B.len())
104      .map(|i| SparseMatEntry::new(B[i].0, B[i].1, B[i].2))
105      .collect::<Vec<SparseMatEntry>>();
106    let mat_C = (0..C.len())
107      .map(|i| SparseMatEntry::new(C[i].0, C[i].1, C[i].2))
108      .collect::<Vec<SparseMatEntry>>();
109
110    let poly_A = SparseMatPolynomial::new(num_poly_vars_x, num_poly_vars_y, mat_A);
111    let poly_B = SparseMatPolynomial::new(num_poly_vars_x, num_poly_vars_y, mat_B);
112    let poly_C = SparseMatPolynomial::new(num_poly_vars_x, num_poly_vars_y, mat_C);
113
114    let inst = R1CSInstance {
115      num_cons,
116      num_vars,
117      num_inputs,
118      A: poly_A,
119      B: poly_B,
120      C: poly_C,
121    };
122
123    inst
124  }
125
126  pub fn get_num_vars(&self) -> usize {
127    self.num_vars
128  }
129
130  pub fn get_num_cons(&self) -> usize {
131    self.num_cons
132  }
133
134  pub fn get_num_inputs(&self) -> usize {
135    self.num_inputs
136  }
137
138  pub fn produce_synthetic_r1cs(
139    num_cons: usize,
140    num_vars: usize,
141    num_inputs: usize,
142  ) -> (R1CSInstance, Vec<Scalar>, Vec<Scalar>) {
143    Timer::print(&format!("number_of_constraints {}", num_cons));
144    Timer::print(&format!("number_of_variables {}", num_vars));
145    Timer::print(&format!("number_of_inputs {}", num_inputs));
146
147    let mut csprng: OsRng = OsRng;
148
149    // assert num_cons and num_vars are power of 2
150    assert_eq!(num_cons.log2().pow2(), num_cons);
151    assert_eq!(num_vars.log2().pow2(), num_vars);
152
153    // num_inputs + 1 <= num_vars
154    assert!(num_inputs < num_vars);
155
156    // z is organized as [vars,1,io]
157    let size_z = num_vars + num_inputs + 1;
158
159    // produce a random satisfying assignment
160    let Z = {
161      let mut Z: Vec<Scalar> = (0..size_z)
162        .map(|_i| Scalar::random(&mut csprng))
163        .collect::<Vec<Scalar>>();
164      Z[num_vars] = Scalar::one(); // set the constant term to 1
165      Z
166    };
167
168    // three sparse matrices
169    let mut A: Vec<SparseMatEntry> = Vec::new();
170    let mut B: Vec<SparseMatEntry> = Vec::new();
171    let mut C: Vec<SparseMatEntry> = Vec::new();
172    let one = Scalar::one();
173    for i in 0..num_cons {
174      let A_idx = i % size_z;
175      let B_idx = (i + 2) % size_z;
176      A.push(SparseMatEntry::new(i, A_idx, one));
177      B.push(SparseMatEntry::new(i, B_idx, one));
178      let AB_val = Z[A_idx] * Z[B_idx];
179
180      let C_idx = (i + 3) % size_z;
181      let C_val = Z[C_idx];
182
183      if C_val == Scalar::zero() {
184        C.push(SparseMatEntry::new(i, num_vars, AB_val));
185      } else {
186        C.push(SparseMatEntry::new(
187          i,
188          C_idx,
189          AB_val * C_val.invert().unwrap(),
190        ));
191      }
192    }
193
194    Timer::print(&format!("number_non-zero_entries_A {}", A.len()));
195    Timer::print(&format!("number_non-zero_entries_B {}", B.len()));
196    Timer::print(&format!("number_non-zero_entries_C {}", C.len()));
197
198    let num_poly_vars_x = num_cons.log2();
199    let num_poly_vars_y = (2 * num_vars).log2();
200    let poly_A = SparseMatPolynomial::new(num_poly_vars_x, num_poly_vars_y, A);
201    let poly_B = SparseMatPolynomial::new(num_poly_vars_x, num_poly_vars_y, B);
202    let poly_C = SparseMatPolynomial::new(num_poly_vars_x, num_poly_vars_y, C);
203
204    let inst = R1CSInstance {
205      num_cons,
206      num_vars,
207      num_inputs,
208      A: poly_A,
209      B: poly_B,
210      C: poly_C,
211    };
212
213    assert_eq!(
214      inst.is_sat(&Z[0..num_vars].to_vec(), &Z[num_vars + 1..].to_vec()),
215      true,
216    );
217
218    (inst, Z[0..num_vars].to_vec(), Z[num_vars + 1..].to_vec())
219  }
220
221  pub fn is_sat(&self, vars: &[Scalar], input: &[Scalar]) -> bool {
222    assert_eq!(vars.len(), self.num_vars);
223    assert_eq!(input.len(), self.num_inputs);
224
225    let z = {
226      let mut z = vars.to_vec();
227      z.extend(&vec![Scalar::one()]);
228      z.extend(input);
229      z
230    };
231
232    // verify if Az * Bz - Cz = [0...]
233    let Az = self
234      .A
235      .multiply_vec(self.num_cons, self.num_vars + self.num_inputs + 1, &z);
236    let Bz = self
237      .B
238      .multiply_vec(self.num_cons, self.num_vars + self.num_inputs + 1, &z);
239    let Cz = self
240      .C
241      .multiply_vec(self.num_cons, self.num_vars + self.num_inputs + 1, &z);
242
243    assert_eq!(Az.len(), self.num_cons);
244    assert_eq!(Bz.len(), self.num_cons);
245    assert_eq!(Cz.len(), self.num_cons);
246    let res: usize = (0..self.num_cons)
247      .map(|i| if Az[i] * Bz[i] == Cz[i] { 0 } else { 1 })
248      .sum();
249
250    res == 0
251  }
252
253  pub fn multiply_vec(
254    &self,
255    num_rows: usize,
256    num_cols: usize,
257    z: &[Scalar],
258  ) -> (DensePolynomial, DensePolynomial, DensePolynomial) {
259    assert_eq!(num_rows, self.num_cons);
260    assert_eq!(z.len(), num_cols);
261    assert!(num_cols > self.num_vars);
262    (
263      DensePolynomial::new(self.A.multiply_vec(num_rows, num_cols, z)),
264      DensePolynomial::new(self.B.multiply_vec(num_rows, num_cols, z)),
265      DensePolynomial::new(self.C.multiply_vec(num_rows, num_cols, z)),
266    )
267  }
268
269  pub fn compute_eval_table_sparse(
270    &self,
271    num_rows: usize,
272    num_cols: usize,
273    evals: &[Scalar],
274  ) -> (Vec<Scalar>, Vec<Scalar>, Vec<Scalar>) {
275    assert_eq!(num_rows, self.num_cons);
276    assert!(num_cols > self.num_vars);
277
278    let evals_A = self.A.compute_eval_table_sparse(&evals, num_rows, num_cols);
279    let evals_B = self.B.compute_eval_table_sparse(&evals, num_rows, num_cols);
280    let evals_C = self.C.compute_eval_table_sparse(&evals, num_rows, num_cols);
281
282    (evals_A, evals_B, evals_C)
283  }
284
285  pub fn evaluate(&self, rx: &[Scalar], ry: &[Scalar]) -> (Scalar, Scalar, Scalar) {
286    let evals = SparseMatPolynomial::multi_evaluate(&[&self.A, &self.B, &self.C], rx, ry);
287    (evals[0], evals[1], evals[2])
288  }
289
290  pub fn commit(&self, gens: &R1CSCommitmentGens) -> (R1CSCommitment, R1CSDecommitment) {
291    let (comm, dense) = SparseMatPolynomial::multi_commit(&[&self.A, &self.B, &self.C], &gens.gens);
292    let r1cs_comm = R1CSCommitment {
293      num_cons: self.num_cons,
294      num_vars: self.num_vars,
295      num_inputs: self.num_inputs,
296      comm,
297    };
298
299    let r1cs_decomm = R1CSDecommitment { dense };
300
301    (r1cs_comm, r1cs_decomm)
302  }
303}
304
305#[derive(Debug, Serialize, Deserialize)]
306pub struct R1CSEvalProof {
307  proof: SparseMatPolyEvalProof,
308}
309
310impl R1CSEvalProof {
311  pub fn prove(
312    decomm: &R1CSDecommitment,
313    rx: &[Scalar], // point at which the polynomial is evaluated
314    ry: &[Scalar],
315    evals: &(Scalar, Scalar, Scalar),
316    gens: &R1CSCommitmentGens,
317    transcript: &mut Transcript,
318    random_tape: &mut RandomTape,
319  ) -> R1CSEvalProof {
320    let timer = Timer::new("R1CSEvalProof::prove");
321    let proof = SparseMatPolyEvalProof::prove(
322      &decomm.dense,
323      rx,
324      ry,
325      &[evals.0, evals.1, evals.2],
326      &gens.gens,
327      transcript,
328      random_tape,
329    );
330    timer.stop();
331
332    R1CSEvalProof { proof }
333  }
334
335  pub fn verify(
336    &self,
337    comm: &R1CSCommitment,
338    rx: &[Scalar], // point at which the R1CS matrix polynomials are evaluated
339    ry: &[Scalar],
340    evals: &(Scalar, Scalar, Scalar),
341    gens: &R1CSCommitmentGens,
342    transcript: &mut Transcript,
343  ) -> Result<(), ProofVerifyError> {
344    assert!(self
345      .proof
346      .verify(
347        &comm.comm,
348        rx,
349        ry,
350        &[evals.0, evals.1, evals.2],
351        &gens.gens,
352        transcript
353      )
354      .is_ok());
355
356    Ok(())
357  }
358}