1use field_cat::{Field, FieldBytes};
13use plonkish_cat::{Constraint, ConstraintSet, Expression, Wire};
14
15use crate::commit::merkle::{MerkleProof, MerkleRoot, MerkleTree};
16use crate::error::Error;
17use crate::poly::MultilinearPoly;
18use crate::sumcheck::{SumcheckClaim, SumcheckProof, sumcheck_prove, sumcheck_verify};
19use crate::transcript::Transcript;
20
21const TRANSCRIPT_LABEL: &[u8] = b"proof-cat-v0.1";
23
24#[derive(Debug, Clone)]
43pub struct Witness<F: Field> {
44 values: Vec<F>,
45}
46
47impl<F: Field> Witness<F> {
48 #[must_use]
50 pub fn new(values: Vec<F>) -> Self {
51 Self { values }
52 }
53
54 #[must_use]
56 pub fn values(&self) -> &[F] {
57 &self.values
58 }
59
60 fn assignment(&self) -> impl Fn(Wire) -> Result<F, plonkish_cat::Error> + '_ {
62 |wire| {
63 self.values
64 .get(wire.index())
65 .cloned()
66 .ok_or(plonkish_cat::Error::WireOutOfBounds {
67 wire_index: wire.index(),
68 allocated: self.values.len(),
69 })
70 }
71 }
72}
73
74#[derive(Debug, Clone)]
76pub struct WireOpening<F: Field> {
77 wire_index: usize,
78 value: F,
79 merkle_proof: MerkleProof,
80}
81
82impl<F: Field> WireOpening<F> {
83 #[must_use]
85 pub fn wire_index(&self) -> usize {
86 self.wire_index
87 }
88
89 #[must_use]
91 pub fn value(&self) -> &F {
92 &self.value
93 }
94
95 #[must_use]
97 pub fn merkle_proof(&self) -> &MerkleProof {
98 &self.merkle_proof
99 }
100}
101
102#[derive(Debug, Clone)]
104pub struct Proof<F: Field> {
105 witness_commitment: MerkleRoot,
106 sumcheck: SumcheckProof<F>,
107 wire_openings: Vec<WireOpening<F>>,
108}
109
110impl<F: Field> Proof<F> {
111 #[must_use]
113 pub fn witness_commitment(&self) -> &MerkleRoot {
114 &self.witness_commitment
115 }
116
117 #[must_use]
119 pub fn sumcheck_proof(&self) -> &SumcheckProof<F> {
120 &self.sumcheck
121 }
122
123 #[must_use]
125 pub fn wire_openings(&self) -> &[WireOpening<F>] {
126 &self.wire_openings
127 }
128}
129
130pub fn prove<F: FieldBytes>(
173 constraints: &ConstraintSet<F>,
174 witness: &Witness<F>,
175) -> Result<Proof<F>, Error> {
176 let all_constraints = flatten_constraints(constraints);
178
179 if all_constraints.is_empty() {
180 Err(Error::EmptyConstraintSet)
181 } else {
182 validate_witness(&all_constraints, witness)?;
184
185 let tree = MerkleTree::from_field_values(witness.values());
187
188 let evals = evaluate_constraints(&all_constraints, witness)?;
190
191 let padded = pad_to_power_of_two(evals);
193 let poly = MultilinearPoly::from_evals(padded)?;
194
195 let transcript = Transcript::new(TRANSCRIPT_LABEL)
197 .absorb_bytes(tree.root().as_bytes())
198 .absorb_bytes(&all_constraints.len().to_le_bytes());
199
200 let (sumcheck, _, _) = sumcheck_prove(&SumcheckClaim::new(poly, F::zero()), transcript)?;
201
202 let wire_openings: Result<Vec<WireOpening<F>>, Error> = (0..witness.values().len())
204 .map(|i| {
205 let merkle_proof = tree.open(i)?;
206 Ok(WireOpening {
207 wire_index: i,
208 value: witness.values()[i].clone(),
209 merkle_proof,
210 })
211 })
212 .collect();
213
214 Ok(Proof {
215 witness_commitment: tree.root(),
216 sumcheck,
217 wire_openings: wire_openings?,
218 })
219 }
220}
221
222pub fn verify<F: FieldBytes>(
269 constraints: &ConstraintSet<F>,
270 proof: &Proof<F>,
271) -> Result<bool, Error> {
272 let all_constraints = flatten_constraints(constraints);
274
275 if all_constraints.is_empty() {
276 Err(Error::EmptyConstraintSet)
277 } else {
278 let padded_len = pad_to_power_of_two_len(all_constraints.len());
280 let num_vars = usize::try_from(padded_len.trailing_zeros())
281 .map_err(|_| Error::NotPowerOfTwo { value: padded_len })?;
282
283 let transcript = Transcript::new(TRANSCRIPT_LABEL)
284 .absorb_bytes(proof.witness_commitment.as_bytes())
285 .absorb_bytes(&all_constraints.len().to_le_bytes());
286
287 let (final_eval, challenges, _) = sumcheck_verify(
288 &proof.sumcheck,
289 &F::zero(),
290 crate::poly::NumVars::new(num_vars),
291 transcript,
292 )?;
293
294 let all_openings_valid = proof.wire_openings.iter().all(|opening| {
296 MerkleTree::verify_opening(
297 &proof.witness_commitment,
298 opening.wire_index,
299 &opening.value,
300 &opening.merkle_proof,
301 )
302 });
303
304 if all_openings_valid {
305 let assignment = build_assignment_from_openings(&proof.wire_openings);
307
308 let evals = evaluate_constraints_with(&all_constraints, &assignment)?;
310 let padded = pad_to_power_of_two(evals);
311 let poly = MultilinearPoly::from_evals(padded)?;
312
313 let expected_eval = poly.evaluate(&challenges)?;
315 Ok(expected_eval == final_eval)
316 } else {
317 Err(Error::MerkleVerificationFailed)
318 }
319 }
320}
321
322fn flatten_constraints<F: Field>(cs: &ConstraintSet<F>) -> Vec<Constraint<F>> {
327 let polynomial: Vec<Constraint<F>> = cs.constraints().to_vec();
328 let from_copies: Vec<Constraint<F>> = cs
329 .copy_constraints()
330 .iter()
331 .map(|cc| {
332 let expr = Expression::Wire(cc.left()) - Expression::Wire(cc.right());
333 Constraint::new(expr)
334 })
335 .collect();
336 polynomial.into_iter().chain(from_copies).collect()
337}
338
339fn validate_witness<F: Field>(
341 constraints: &[Constraint<F>],
342 witness: &Witness<F>,
343) -> Result<(), Error> {
344 let assign = witness.assignment();
345 constraints.iter().enumerate().try_for_each(|(i, c)| {
346 c.is_satisfied(&assign).map_err(Error::from).and_then(|ok| {
347 if ok {
348 Ok(())
349 } else {
350 Err(Error::UnsatisfiedConstraint { index: i })
351 }
352 })
353 })
354}
355
356fn evaluate_constraints<F: Field>(
358 constraints: &[Constraint<F>],
359 witness: &Witness<F>,
360) -> Result<Vec<F>, Error> {
361 let assign = witness.assignment();
362 constraints
363 .iter()
364 .map(|c| c.expression().evaluate(&assign).map_err(Error::from))
365 .collect()
366}
367
368fn evaluate_constraints_with<F: Field>(
370 constraints: &[Constraint<F>],
371 assignment: &impl Fn(Wire) -> Result<F, plonkish_cat::Error>,
372) -> Result<Vec<F>, Error> {
373 constraints
374 .iter()
375 .map(|c| c.expression().evaluate(assignment).map_err(Error::from))
376 .collect()
377}
378
379fn build_assignment_from_openings<F: Field>(
381 openings: &[WireOpening<F>],
382) -> impl Fn(Wire) -> Result<F, plonkish_cat::Error> + '_ {
383 move |wire| {
384 openings
385 .iter()
386 .find(|o| o.wire_index == wire.index())
387 .map(|o| o.value.clone())
388 .ok_or(plonkish_cat::Error::WireOutOfBounds {
389 wire_index: wire.index(),
390 allocated: openings.len(),
391 })
392 }
393}
394
395fn pad_to_power_of_two<F: Field>(v: Vec<F>) -> Vec<F> {
397 let target = pad_to_power_of_two_len(v.len());
398 let padding_count = target - v.len();
399 v.into_iter()
400 .chain((0..padding_count).map(|_| F::zero()))
401 .collect()
402}
403
404fn pad_to_power_of_two_len(n: usize) -> usize {
406 if n <= 1 { 1 } else { n.next_power_of_two() }
407}
408
409#[cfg(test)]
410mod tests {
411 use super::*;
412 use field_cat::F101;
413 use plonkish_cat::{CopyConstraint, Expression, Wire};
414
415 #[test]
416 fn add_gate_prove_verify() -> Result<(), Error> {
417 let expr = Expression::Wire(Wire::new(2))
420 - Expression::Wire(Wire::new(0))
421 - Expression::Wire(Wire::new(1));
422 let cs = ConstraintSet::empty().with_constraint(Constraint::new(expr));
423
424 let witness = Witness::new(vec![F101::new(3), F101::new(4), F101::new(7)]);
426 let proof = prove(&cs, &witness)?;
427 let valid = verify(&cs, &proof)?;
428 assert!(valid);
429 Ok(())
430 }
431
432 #[test]
433 fn mul_gate_prove_verify() -> Result<(), Error> {
434 let expr = Expression::Wire(Wire::new(2))
436 - Expression::Wire(Wire::new(0)) * Expression::Wire(Wire::new(1));
437 let cs = ConstraintSet::empty().with_constraint(Constraint::new(expr));
438
439 let witness = Witness::new(vec![F101::new(5), F101::new(6), F101::new(30)]);
441 let proof = prove(&cs, &witness)?;
442 assert!(verify(&cs, &proof)?);
443 Ok(())
444 }
445
446 #[test]
447 fn invalid_witness_rejected() {
448 let expr = Expression::Wire(Wire::new(2))
449 - Expression::Wire(Wire::new(0))
450 - Expression::Wire(Wire::new(1));
451 let cs = ConstraintSet::empty().with_constraint(Constraint::new(expr));
452
453 let witness = Witness::new(vec![F101::new(3), F101::new(4), F101::new(8)]);
455 let result = prove(&cs, &witness);
456 assert!(result.is_err());
457 }
458
459 #[test]
460 fn copy_constraint_prove_verify() -> Result<(), Error> {
461 let cs = ConstraintSet::empty().with_copy(CopyConstraint::new(Wire::new(0), Wire::new(1)));
463
464 let witness = Witness::new(vec![F101::new(42), F101::new(42)]);
465 let proof = prove(&cs, &witness)?;
466 assert!(verify(&cs, &proof)?);
467 Ok(())
468 }
469
470 #[test]
471 fn copy_constraint_invalid_rejected() {
472 let cs = ConstraintSet::empty().with_copy(CopyConstraint::new(Wire::new(0), Wire::new(1)));
473
474 let witness = Witness::new(vec![F101::new(1), F101::new(2)]);
475 let result = prove(&cs, &witness);
476 assert!(result.is_err());
477 }
478
479 #[test]
480 fn const_gate_prove_verify() -> Result<(), Error> {
481 let expr = Expression::Wire(Wire::new(0)) - Expression::Constant(F101::new(42));
483 let cs = ConstraintSet::empty().with_constraint(Constraint::new(expr));
484
485 let witness = Witness::new(vec![F101::new(42)]);
486 let proof = prove(&cs, &witness)?;
487 assert!(verify(&cs, &proof)?);
488 Ok(())
489 }
490}