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() as usize;
 39    let num_poly_vars_y = (2 * num_vars).log2() as usize;
 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: &[(usize, usize, Scalar)],
 77    B: &[(usize, usize, Scalar)],
 78    C: &[(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() as usize;
 98    let num_poly_vars_y = (2 * num_vars).log2() as usize;
 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    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
124  pub fn get_num_vars(&self) -> usize {
125    self.num_vars
126  }
127
128  pub fn get_num_cons(&self) -> usize {
129    self.num_cons
130  }
131
132  pub fn get_num_inputs(&self) -> usize {
133    self.num_inputs
134  }
135
136  pub fn produce_synthetic_r1cs(
137    num_cons: usize,
138    num_vars: usize,
139    num_inputs: usize,
140  ) -> (R1CSInstance, Vec<Scalar>, Vec<Scalar>) {
141    Timer::print(&format!("number_of_constraints {}", num_cons));
142    Timer::print(&format!("number_of_variables {}", num_vars));
143    Timer::print(&format!("number_of_inputs {}", num_inputs));
144
145    let mut csprng: OsRng = OsRng;
146
147    // assert num_cons and num_vars are power of 2
148    assert_eq!((num_cons.log2() as usize).pow2(), num_cons);
149    assert_eq!((num_vars.log2() as usize).pow2(), num_vars);
150
151    // num_inputs + 1 <= num_vars
152    assert!(num_inputs < num_vars);
153
154    // z is organized as [vars,1,io]
155    let size_z = num_vars + num_inputs + 1;
156
157    // produce a random satisfying assignment
158    let Z = {
159      let mut Z: Vec<Scalar> = (0..size_z)
160        .map(|_i| Scalar::random(&mut csprng))
161        .collect::<Vec<Scalar>>();
162      Z[num_vars] = Scalar::one(); // set the constant term to 1
163      Z
164    };
165
166    // three sparse matrices
167    let mut A: Vec<SparseMatEntry> = Vec::new();
168    let mut B: Vec<SparseMatEntry> = Vec::new();
169    let mut C: Vec<SparseMatEntry> = Vec::new();
170    let one = Scalar::one();
171    for i in 0..num_cons {
172      let A_idx = i % size_z;
173      let B_idx = (i + 2) % size_z;
174      A.push(SparseMatEntry::new(i, A_idx, one));
175      B.push(SparseMatEntry::new(i, B_idx, one));
176      let AB_val = Z[A_idx] * Z[B_idx];
177
178      let C_idx = (i + 3) % size_z;
179      let C_val = Z[C_idx];
180
181      if C_val == Scalar::zero() {
182        C.push(SparseMatEntry::new(i, num_vars, AB_val));
183      } else {
184        C.push(SparseMatEntry::new(
185          i,
186          C_idx,
187          AB_val * C_val.invert().unwrap(),
188        ));
189      }
190    }
191
192    Timer::print(&format!("number_non-zero_entries_A {}", A.len()));
193    Timer::print(&format!("number_non-zero_entries_B {}", B.len()));
194    Timer::print(&format!("number_non-zero_entries_C {}", C.len()));
195
196    let num_poly_vars_x = num_cons.log2() as usize;
197    let num_poly_vars_y = (2 * num_vars).log2() as usize;
198    let poly_A = SparseMatPolynomial::new(num_poly_vars_x, num_poly_vars_y, A);
199    let poly_B = SparseMatPolynomial::new(num_poly_vars_x, num_poly_vars_y, B);
200    let poly_C = SparseMatPolynomial::new(num_poly_vars_x, num_poly_vars_y, C);
201
202    let inst = R1CSInstance {
203      num_cons,
204      num_vars,
205      num_inputs,
206      A: poly_A,
207      B: poly_B,
208      C: poly_C,
209    };
210
211    assert!(inst.is_sat(&Z[..num_vars].to_vec(), &Z[num_vars + 1..].to_vec()));
212
213    (inst, Z[..num_vars].to_vec(), Z[num_vars + 1..].to_vec())
214  }
215
216  pub fn is_sat(&self, vars: &[Scalar], input: &[Scalar]) -> bool {
217    assert_eq!(vars.len(), self.num_vars);
218    assert_eq!(input.len(), self.num_inputs);
219
220    let z = {
221      let mut z = vars.to_vec();
222      z.extend(&vec![Scalar::one()]);
223      z.extend(input);
224      z
225    };
226
227    // verify if Az * Bz - Cz = [0...]
228    let Az = self
229      .A
230      .multiply_vec(self.num_cons, self.num_vars + self.num_inputs + 1, &z);
231    let Bz = self
232      .B
233      .multiply_vec(self.num_cons, self.num_vars + self.num_inputs + 1, &z);
234    let Cz = self
235      .C
236      .multiply_vec(self.num_cons, self.num_vars + self.num_inputs + 1, &z);
237
238    assert_eq!(Az.len(), self.num_cons);
239    assert_eq!(Bz.len(), self.num_cons);
240    assert_eq!(Cz.len(), self.num_cons);
241    let res: usize = (0..self.num_cons)
242      .map(|i| if Az[i] * Bz[i] == Cz[i] { 0 } else { 1 })
243      .sum();
244
245    res == 0
246  }
247
248  pub fn multiply_vec(
249    &self,
250    num_rows: usize,
251    num_cols: usize,
252    z: &[Scalar],
253  ) -> (DensePolynomial, DensePolynomial, DensePolynomial) {
254    assert_eq!(num_rows, self.num_cons);
255    assert_eq!(z.len(), num_cols);
256    assert!(num_cols > self.num_vars);
257    (
258      DensePolynomial::new(self.A.multiply_vec(num_rows, num_cols, z)),
259      DensePolynomial::new(self.B.multiply_vec(num_rows, num_cols, z)),
260      DensePolynomial::new(self.C.multiply_vec(num_rows, num_cols, z)),
261    )
262  }
263
264  pub fn compute_eval_table_sparse(
265    &self,
266    num_rows: usize,
267    num_cols: usize,
268    evals: &[Scalar],
269  ) -> (Vec<Scalar>, Vec<Scalar>, Vec<Scalar>) {
270    assert_eq!(num_rows, self.num_cons);
271    assert!(num_cols > self.num_vars);
272
273    let evals_A = self.A.compute_eval_table_sparse(evals, num_rows, num_cols);
274    let evals_B = self.B.compute_eval_table_sparse(evals, num_rows, num_cols);
275    let evals_C = self.C.compute_eval_table_sparse(evals, num_rows, num_cols);
276
277    (evals_A, evals_B, evals_C)
278  }
279
280  pub fn evaluate(&self, rx: &[Scalar], ry: &[Scalar]) -> (Scalar, Scalar, Scalar) {
281    let evals = SparseMatPolynomial::multi_evaluate(&[&self.A, &self.B, &self.C], rx, ry);
282    (evals[0], evals[1], evals[2])
283  }
284
285  pub fn commit(&self, gens: &R1CSCommitmentGens) -> (R1CSCommitment, R1CSDecommitment) {
286    let (comm, dense) = SparseMatPolynomial::multi_commit(&[&self.A, &self.B, &self.C], &gens.gens);
287    let r1cs_comm = R1CSCommitment {
288      num_cons: self.num_cons,
289      num_vars: self.num_vars,
290      num_inputs: self.num_inputs,
291      comm,
292    };
293
294    let r1cs_decomm = R1CSDecommitment { dense };
295
296    (r1cs_comm, r1cs_decomm)
297  }
298}
299
300#[derive(Debug, Serialize, Deserialize)]
301pub struct R1CSEvalProof {
302  proof: SparseMatPolyEvalProof,
303}
304
305impl R1CSEvalProof {
306  pub fn prove(
307    decomm: &R1CSDecommitment,
308    rx: &[Scalar], // point at which the polynomial is evaluated
309    ry: &[Scalar],
310    evals: &(Scalar, Scalar, Scalar),
311    gens: &R1CSCommitmentGens,
312    transcript: &mut Transcript,
313    random_tape: &mut RandomTape,
314  ) -> R1CSEvalProof {
315    let timer = Timer::new("R1CSEvalProof::prove");
316    let proof = SparseMatPolyEvalProof::prove(
317      &decomm.dense,
318      rx,
319      ry,
320      &[evals.0, evals.1, evals.2],
321      &gens.gens,
322      transcript,
323      random_tape,
324    );
325    timer.stop();
326
327    R1CSEvalProof { proof }
328  }
329
330  pub fn verify(
331    &self,
332    comm: &R1CSCommitment,
333    rx: &[Scalar], // point at which the R1CS matrix polynomials are evaluated
334    ry: &[Scalar],
335    evals: &(Scalar, Scalar, Scalar),
336    gens: &R1CSCommitmentGens,
337    transcript: &mut Transcript,
338  ) -> Result<(), ProofVerifyError> {
339    self.proof.verify(
340      &comm.comm,
341      rx,
342      ry,
343      &[evals.0, evals.1, evals.2],
344      &gens.gens,
345      transcript,
346    )
347  }
348}