Skip to main content

binius_spartan_verifier/
wiring.rs

1// Copyright 2025 Irreducible Inc.
2
3use std::{iter, rc::Rc};
4
5use binius_field::field::FieldOps;
6use binius_math::{multilinear::eq::eq_ind_partial_eval_scalars, univariate::evaluate_univariate};
7use binius_spartan_frontend::constraint_system::{MulConstraint, WitnessIndex, WitnessSegment};
8
9/// Returns a closure that evaluates the wiring transparent polynomial for a specific segment.
10///
11/// The closure evaluates the wiring MLE at a challenge point drawn during the BaseFold opening.
12/// The three operand contributions are batched together with the challenge `lambda`.
13/// The multiplication constraints and the eq-indicator evaluation at `r_x` are shared via `Rc`.
14/// Sharing lets the closure own them and be `'static`.
15/// The opening is deferred, so the closure must outlive this call.
16pub fn eval_transparent<F: FieldOps + 'static>(
17	mul_constraints: Rc<[MulConstraint<WitnessIndex>]>,
18	segment: WitnessSegment,
19	r_x_tensor: Rc<[F]>,
20	lambda: F,
21) -> binius_iop::channel::TransparentEvalFn<F> {
22	Box::new(move |r_y: &[F]| {
23		evaluate_segment_wiring_mle(&mul_constraints, segment, &lambda, &r_x_tensor, r_y)
24	})
25}
26
27/// Evaluates the wiring MLE for a specific segment at a point (r_x, r_y).
28///
29/// `r_x_tensor` is the equality indicator expanded at r_x, one scalar per vertex.
30/// Accepting it as a parameter avoids recomputing it for every segment sharing that r_x.
31pub fn evaluate_segment_wiring_mle<F: FieldOps>(
32	mul_constraints: &[MulConstraint<WitnessIndex>],
33	segment: WitnessSegment,
34	lambda: &F,
35	r_x_tensor: &[F],
36	r_y: &[F],
37) -> F {
38	let mut acc = [F::zero(), F::zero(), F::zero()];
39
40	let r_y_tensor = eq_ind_partial_eval_scalars(r_y);
41	for (r_x_tensor_i, MulConstraint { a, b, c }) in iter::zip(r_x_tensor, mul_constraints) {
42		for (dst, operand) in iter::zip(&mut acc, [a, b, c]) {
43			let r_y_tensor_sum = operand
44				.wires()
45				.iter()
46				.flat_map(|index| {
47					if index.segment == segment {
48						Some(r_y_tensor[index.index as usize].clone())
49					} else {
50						None
51					}
52				})
53				.sum::<F>();
54			*dst += r_x_tensor_i.clone() * r_y_tensor_sum;
55		}
56	}
57
58	evaluate_univariate(&acc, lambda)
59}
60
61/// Evaluates the public segment's contribution to the wiring MLE.
62///
63/// `r_x_tensor` is the eq-indicator partial evaluation at r_x.
64pub fn evaluate_wiring_mle_public<F: FieldOps>(
65	mul_constraints: &[MulConstraint<WitnessIndex>],
66	public: &[F],
67	lambda: &F,
68	r_x_tensor: &[F],
69) -> F {
70	let mut acc = [F::zero(), F::zero(), F::zero()];
71	for (r_x_tensor_i, MulConstraint { a, b, c }) in iter::zip(r_x_tensor, mul_constraints) {
72		for (dst, operand) in iter::zip(&mut acc, [a, b, c]) {
73			let public_sum = operand
74				.wires()
75				.iter()
76				.flat_map(|index| {
77					if index.segment == WitnessSegment::Public {
78						Some(public[index.index as usize].clone())
79					} else {
80						None
81					}
82				})
83				.sum::<F>();
84			*dst += r_x_tensor_i.clone() * public_sum;
85		}
86	}
87
88	evaluate_univariate(&acc, lambda)
89}