binius_hal/
sumcheck_multilinear.rs

1// Copyright 2024-2025 Irreducible Inc.
2
3use binius_field::PackedField;
4use binius_math::MultilinearPoly;
5
6/// An individual multilinear polynomial in a multivariate composite.
7#[derive(Debug, Clone)]
8pub enum SumcheckMultilinear<P, M>
9where
10	P: PackedField,
11	M: MultilinearPoly<P>,
12{
13	/// Small field multilinear - to be folded into large field at `switchover` round
14	/// A suffix of constant scalars at the end is provided via `const_suffix` hint.
15	Transparent {
16		multilinear: M,
17		switchover_round: usize,
18		const_suffix: (P::Scalar, usize),
19	},
20	/// Large field multilinear - halved in size each round
21	/// If length is less than expected one for the current round, pad with `suffix_eval` scalars.
22	Folded {
23		large_field_folded_evals: Vec<P>,
24		suffix_eval: P::Scalar,
25	},
26}
27
28impl<P: PackedField, M: MultilinearPoly<P>> SumcheckMultilinear<P, M> {
29	pub fn transparent(multilinear: M, switchover_fn: &impl Fn(usize) -> usize) -> Self {
30		let switchover_round = (*switchover_fn)(1 << multilinear.log_extension_degree());
31
32		Self::Transparent {
33			multilinear,
34			switchover_round,
35			const_suffix: Default::default(),
36		}
37	}
38
39	pub fn folded(large_field_folded_evals: Vec<P>) -> Self {
40		Self::Folded {
41			large_field_folded_evals,
42			suffix_eval: Default::default(),
43		}
44	}
45
46	pub fn const_suffix(&self, n_vars: usize) -> (P::Scalar, usize) {
47		match self {
48			Self::Transparent { const_suffix, .. } => *const_suffix,
49			Self::Folded {
50				large_field_folded_evals,
51				suffix_eval,
52			} => (
53				*suffix_eval,
54				(1usize << n_vars).saturating_sub(large_field_folded_evals.len() << P::LOG_WIDTH),
55			),
56		}
57	}
58
59	pub fn update_const_suffix(&mut self, n_vars: usize, new_const_suffix: (P::Scalar, usize)) {
60		match self {
61			Self::Transparent { const_suffix, .. } => {
62				*const_suffix = new_const_suffix;
63			}
64
65			Self::Folded {
66				large_field_folded_evals,
67				suffix_eval,
68			} => {
69				let (new_suffix_eval, new_suffix_len) = new_const_suffix;
70				*suffix_eval = new_suffix_eval;
71				large_field_folded_evals
72					.truncate(((1 << n_vars) - new_suffix_len).div_ceil(P::WIDTH));
73			}
74		}
75	}
76}