binius_core/ring_switch/
common.rs1use std::sync::Arc;
4
5use binius_field::{Field, TowerField};
6use binius_utils::sparse_index::SparseIndex;
7
8use super::error::Error;
9use crate::{
10 oracle::{MultilinearOracleSet, MultilinearPolyOracle, MultilinearPolyVariant},
11 piop::CommitMeta,
12 protocols::evalcheck::EvalcheckMultilinearClaim,
13};
14
15#[derive(Debug)]
20pub struct EvalClaimPrefixDesc<F: Field> {
21 pub prefix: Vec<F>,
22}
23
24impl<F: Field> EvalClaimPrefixDesc<F> {
25 pub fn kappa(&self) -> usize {
26 self.prefix.len()
27 }
28}
29
30#[derive(Debug)]
35pub struct EvalClaimSuffixDesc<F: Field> {
36 pub suffix: Arc<[F]>,
37 pub kappa: usize,
38}
39
40#[derive(Debug)]
42pub struct PIOPSumcheckClaimDesc<'a, F: Field> {
43 pub committed_idx: usize,
45 pub suffix_desc_idx: usize,
47 pub eval_claim: &'a EvalcheckMultilinearClaim<F>,
48}
49
50#[derive(Debug)]
55pub struct EvalClaimSystem<'a, F: Field> {
56 pub commit_meta: &'a CommitMeta,
57 pub prefix_descs: Vec<EvalClaimPrefixDesc<F>>,
58 pub suffix_descs: Vec<EvalClaimSuffixDesc<F>>,
59 pub sumcheck_claim_descs: Vec<PIOPSumcheckClaimDesc<'a, F>>,
60 pub eval_claim_to_prefix_desc_index: Vec<usize>,
61}
62
63impl<'a, F: TowerField> EvalClaimSystem<'a, F> {
64 pub fn new(
73 oracles: &MultilinearOracleSet<F>,
74 commit_meta: &'a CommitMeta,
75 oracle_to_commit_index: &SparseIndex<usize>,
76 eval_claims: &'a [EvalcheckMultilinearClaim<F>],
77 ) -> Result<Self, Error> {
78 let mut eval_claims = eval_claims.iter().collect::<Vec<_>>();
81 eval_claims.sort_by_key(|claim| match oracles.oracle(claim.id) {
82 MultilinearPolyOracle {
86 n_vars,
87 tower_level,
88 variant: MultilinearPolyVariant::Committed,
89 ..
90 } => n_vars + tower_level,
91 _ => 0,
94 });
95
96 let (
97 prefix_descs,
98 eval_claim_to_prefix_desc_index,
99 suffix_descs,
100 eval_claim_to_suffix_desc_index,
101 ) = group_claims_by_eval_point(oracles, &eval_claims)?;
102
103 let sumcheck_claim_descs = eval_claims
104 .into_iter()
105 .enumerate()
106 .map(|(i, eval_claim)| {
107 let oracle = oracles.oracle(eval_claim.id);
108 if !matches!(oracle.variant, MultilinearPolyVariant::Committed) {
109 return Err(Error::EvalcheckClaimForDerivedPoly { id: eval_claim.id });
110 }
111 let committed_idx = oracle_to_commit_index
112 .get(oracle.id())
113 .copied()
114 .ok_or_else(|| Error::OracleToCommitIndexMissingEntry { id: eval_claim.id })?;
115 let suffix_desc_idx = eval_claim_to_suffix_desc_index[i];
116 Ok(PIOPSumcheckClaimDesc {
117 committed_idx,
118 suffix_desc_idx,
119 eval_claim,
120 })
121 })
122 .collect::<Result<Vec<_>, _>>()?;
123
124 Ok(Self {
125 commit_meta,
126 prefix_descs,
127 suffix_descs,
128 sumcheck_claim_descs,
129 eval_claim_to_prefix_desc_index,
130 })
131 }
132
133 pub fn max_claim_kappa(&self) -> usize {
134 self.prefix_descs
135 .iter()
136 .map(|desc| desc.kappa())
137 .max()
138 .unwrap_or(0)
139 }
140}
141
142#[allow(clippy::type_complexity)]
143fn group_claims_by_eval_point<F: TowerField>(
144 oracles: &MultilinearOracleSet<F>,
145 claims: &[&EvalcheckMultilinearClaim<F>],
146) -> Result<(Vec<EvalClaimPrefixDesc<F>>, Vec<usize>, Vec<EvalClaimSuffixDesc<F>>, Vec<usize>), Error>
147{
148 let mut prefix_descs = Vec::<EvalClaimPrefixDesc<F>>::new();
149 let mut suffix_descs = Vec::<EvalClaimSuffixDesc<F>>::new();
150 let mut claim_to_prefix_index = Vec::with_capacity(claims.len());
151 let mut claim_to_suffix_index = Vec::with_capacity(claims.len());
152 for claim in claims {
153 let MultilinearPolyOracle {
154 id,
155 tower_level,
156 variant: MultilinearPolyVariant::Committed,
157 ..
158 } = oracles.oracle(claim.id)
159 else {
160 return Err(Error::EvalcheckClaimForDerivedPoly { id: claim.id });
161 };
162 let kappa = F::TOWER_LEVEL.checked_sub(tower_level).ok_or_else(|| {
163 Error::OracleTowerLevelTooHigh {
164 id,
165 max: F::TOWER_LEVEL,
166 }
167 })?;
168
169 let (prefix, suffix) = claim.eval_point.split_at(kappa);
170
171 let prefix_id = prefix_descs
172 .iter()
173 .position(|desc| desc.prefix == prefix)
174 .unwrap_or_else(|| {
175 let index = prefix_descs.len();
176 prefix_descs.push(EvalClaimPrefixDesc {
177 prefix: prefix.to_vec(),
178 });
179 index
180 });
181 claim_to_prefix_index.push(prefix_id);
182
183 let suffix_id = suffix_descs
184 .iter()
185 .position(|desc| &*desc.suffix == suffix && desc.kappa == kappa)
186 .unwrap_or_else(|| {
187 let index = suffix_descs.len();
188 suffix_descs.push(EvalClaimSuffixDesc {
189 suffix: suffix.to_vec().into(),
190 kappa,
191 });
192 index
193 });
194 claim_to_suffix_index.push(suffix_id);
195 }
196 Ok((prefix_descs, claim_to_prefix_index, suffix_descs, claim_to_suffix_index))
197}