1use std::{
6 iter::{Product, Sum},
7 marker::PhantomData,
8 ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign},
9};
10
11use binius_core::word::Word;
12use binius_field::{
13 BinaryField, ExtensionField, Field, FieldOps,
14 arithmetic_traits::{InvertOrZero, Square},
15};
16use binius_ip::channel::{IPVerifierChannel, WordIPVerifierChannel};
17
18use crate::channel::{Error, IOPVerifierChannel, OracleSchedule, OracleSpec, TransparentEvalFn};
19
20#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
27pub struct DummyElem<F>(PhantomData<F>);
28
29macro_rules! dummy_binop {
30 ($trait:ident, $method:ident) => {
31 impl<F> $trait for DummyElem<F> {
32 type Output = Self;
33 fn $method(self, _rhs: Self) -> Self {
34 self
35 }
36 }
37 impl<F> $trait<&DummyElem<F>> for DummyElem<F> {
38 type Output = Self;
39 fn $method(self, _rhs: &Self) -> Self {
40 self
41 }
42 }
43 };
44}
45dummy_binop!(Add, add);
46dummy_binop!(Sub, sub);
47dummy_binop!(Mul, mul);
48
49macro_rules! dummy_assign {
50 ($trait:ident, $method:ident) => {
51 impl<F> $trait for DummyElem<F> {
52 fn $method(&mut self, _rhs: Self) {}
53 }
54 impl<F> $trait<&DummyElem<F>> for DummyElem<F> {
55 fn $method(&mut self, _rhs: &Self) {}
56 }
57 };
58}
59dummy_assign!(AddAssign, add_assign);
60dummy_assign!(SubAssign, sub_assign);
61dummy_assign!(MulAssign, mul_assign);
62
63impl<F> Neg for DummyElem<F> {
64 type Output = Self;
65 fn neg(self) -> Self {
66 self
67 }
68}
69
70impl<F> Sum for DummyElem<F> {
71 fn sum<I: Iterator<Item = Self>>(_iter: I) -> Self {
72 Self(PhantomData)
73 }
74}
75impl<'a, F> Sum<&'a DummyElem<F>> for DummyElem<F> {
76 fn sum<I: Iterator<Item = &'a Self>>(_iter: I) -> Self {
77 Self(PhantomData)
78 }
79}
80impl<F> Product for DummyElem<F> {
81 fn product<I: Iterator<Item = Self>>(_iter: I) -> Self {
82 Self(PhantomData)
83 }
84}
85impl<'a, F> Product<&'a DummyElem<F>> for DummyElem<F> {
86 fn product<I: Iterator<Item = &'a Self>>(_iter: I) -> Self {
87 Self(PhantomData)
88 }
89}
90
91impl<F> Square for DummyElem<F> {
92 fn square(self) -> Self {
93 self
94 }
95}
96impl<F> InvertOrZero for DummyElem<F> {
97 fn invert_or_zero(self) -> Self {
98 self
99 }
100}
101
102impl<F> From<F> for DummyElem<F> {
103 fn from(_value: F) -> Self {
104 Self(PhantomData)
105 }
106}
107
108impl<F: Field> FieldOps for DummyElem<F> {
109 type Scalar = F;
110
111 fn zero() -> Self {
112 Self(PhantomData)
113 }
114
115 fn one() -> Self {
116 Self(PhantomData)
117 }
118
119 fn square_transpose<FSub: Field>(_elems: &mut [Self])
120 where
121 F: ExtensionField<FSub>,
122 {
123 }
124}
125
126#[derive(Debug, Default, Clone)]
149pub struct OracleSetupChannel {
150 is_zk: bool,
151 schedule: OracleSchedule,
152}
153
154impl OracleSetupChannel {
155 pub const fn new(is_zk: bool) -> Self {
157 Self {
158 is_zk,
159 schedule: OracleSchedule::new(),
160 }
161 }
162
163 pub fn oracle_specs(&self) -> &[OracleSpec] {
165 self.schedule.specs()
166 }
167
168 pub fn into_oracle_specs(self) -> Vec<OracleSpec> {
170 self.schedule.into_specs()
171 }
172
173 pub fn into_oracle_schedule(mut self) -> OracleSchedule {
179 self.schedule.end_round();
180 self.schedule
181 }
182}
183
184impl<F: Field> IPVerifierChannel<F> for OracleSetupChannel {
185 type Elem = DummyElem<F>;
186
187 fn recv_one(&mut self) -> Result<DummyElem<F>, binius_ip::channel::Error> {
188 Ok(DummyElem(PhantomData))
189 }
190
191 fn recv_many(&mut self, n: usize) -> Result<Vec<DummyElem<F>>, binius_ip::channel::Error> {
192 Ok(vec![DummyElem(PhantomData); n])
193 }
194
195 fn recv_array<const N: usize>(
196 &mut self,
197 ) -> Result<[DummyElem<F>; N], binius_ip::channel::Error> {
198 Ok([DummyElem(PhantomData); N])
199 }
200
201 fn sample(&mut self) -> DummyElem<F> {
202 self.schedule.end_round();
204 DummyElem(PhantomData)
205 }
206
207 fn observe_one(&mut self, _val: F) -> DummyElem<F> {
208 DummyElem(PhantomData)
209 }
210
211 fn observe_many(&mut self, vals: &[F]) -> Vec<DummyElem<F>> {
212 vec![DummyElem(PhantomData); vals.len()]
213 }
214
215 fn assert_zero(&mut self, _val: DummyElem<F>) -> Result<(), binius_ip::channel::Error> {
216 Ok(())
217 }
218}
219
220impl<F: BinaryField> WordIPVerifierChannel<F> for OracleSetupChannel {
221 type Word = Word;
222
223 fn observe_words(&mut self, words: &[Word]) -> Vec<Word> {
225 words.to_vec()
226 }
227
228 fn subset_sum(&mut self, _elems: &[DummyElem<F>], _word: &Word) -> DummyElem<F> {
229 DummyElem(PhantomData)
230 }
231
232 fn select(&mut self, _elems: &[DummyElem<F>], _word: &Word) -> DummyElem<F> {
233 DummyElem(PhantomData)
234 }
235
236 fn sample_bits(&mut self, _bits: usize) -> Word {
238 self.schedule.end_round();
240 Word::ZERO
241 }
242
243 fn pack_words(&mut self, words: &[Word]) -> Vec<DummyElem<F>> {
245 let words_per_elem = F::N_BITS / Word::BITS;
246 vec![DummyElem(PhantomData); words.len().div_ceil(words_per_elem)]
247 }
248}
249
250impl<F: Field> IOPVerifierChannel<F> for OracleSetupChannel {
251 type Oracle = ();
252
253 fn remaining_oracle_specs(&self) -> &[OracleSpec] {
254 &[]
256 }
257
258 fn recv_oracle(
259 &mut self,
260 log_msg_len: usize,
261 is_witness_dependent: bool,
262 ) -> Result<Self::Oracle, Error> {
263 self.schedule.push(OracleSpec {
265 log_msg_len,
266 is_zk: self.is_zk && is_witness_dependent,
267 });
268 Ok(())
269 }
270
271 fn verify_oracle_relation(
272 &mut self,
273 _oracle: Self::Oracle,
274 _transparent: TransparentEvalFn<Self::Elem>,
275 _claim: Self::Elem,
276 ) -> Result<(), Error> {
277 self.schedule.end_round();
279 Ok(())
280 }
281}
282
283#[cfg(test)]
284mod tests {
285 use binius_field::Ghash128b;
286
287 use super::*;
288
289 type F = Ghash128b;
290
291 fn sample(channel: &mut OracleSetupChannel) {
293 IPVerifierChannel::<F>::sample(channel);
294 }
295
296 fn recv(channel: &mut OracleSetupChannel, log_msg_len: usize) {
298 IOPVerifierChannel::<F>::recv_oracle(channel, log_msg_len, true)
299 .expect("the setup channel never fails");
300 }
301
302 #[test]
303 fn a_challenge_ends_the_open_round() {
304 let mut channel = OracleSetupChannel::new(false);
305
306 recv(&mut channel, 3);
312 recv(&mut channel, 3);
313 sample(&mut channel);
314 recv(&mut channel, 4);
315 sample(&mut channel);
316
317 let schedule = channel.into_oracle_schedule();
318 assert_eq!(schedule.n_rounds(), 2);
319 assert_eq!(
320 schedule.rounds().collect::<Vec<_>>(),
321 vec![
322 [OracleSpec::new(3), OracleSpec::new(3)].as_slice(),
323 [OracleSpec::new(4)].as_slice(),
324 ]
325 );
326 }
327
328 #[test]
329 fn the_final_round_closes_without_a_challenge() {
330 let mut channel = OracleSetupChannel::new(false);
331
332 recv(&mut channel, 2);
335 sample(&mut channel);
336 recv(&mut channel, 5);
337
338 let schedule = channel.into_oracle_schedule();
339 assert_eq!(schedule.n_rounds(), 2);
340 assert_eq!(schedule.rounds().last(), Some([OracleSpec::new(5)].as_slice()));
341 }
342
343 #[test]
344 fn a_sampled_word_ends_the_open_round_too() {
345 let mut channel = OracleSetupChannel::new(false);
346
347 recv(&mut channel, 3);
350 WordIPVerifierChannel::<F>::sample_bits(&mut channel, 4);
351 recv(&mut channel, 2);
352
353 assert_eq!(channel.into_oracle_schedule().n_rounds(), 2);
354 }
355
356 #[test]
357 fn back_to_back_challenges_make_no_empty_round() {
358 let mut channel = OracleSetupChannel::new(false);
359
360 recv(&mut channel, 3);
363 sample(&mut channel);
364 sample(&mut channel);
365 sample(&mut channel);
366
367 assert_eq!(channel.into_oracle_schedule().n_rounds(), 1);
368 }
369
370 #[test]
371 fn a_run_with_no_oracles_has_no_rounds() {
372 let mut channel = OracleSetupChannel::new(false);
373
374 sample(&mut channel);
376
377 let schedule = channel.into_oracle_schedule();
378 assert_eq!(schedule.n_rounds(), 0);
379 assert!(schedule.specs().is_empty());
380 }
381
382 #[test]
383 fn dropping_the_boundaries_leaves_the_flat_sequence() {
384 let mut channel = OracleSetupChannel::new(false);
385
386 recv(&mut channel, 3);
389 sample(&mut channel);
390 recv(&mut channel, 1);
391 recv(&mut channel, 4);
392
393 let flat = channel.clone().into_oracle_specs();
394 assert_eq!(channel.into_oracle_schedule().into_specs(), flat);
395 }
396
397 #[test]
398 fn a_round_is_masked_if_any_of_its_oracles_is() {
399 let mut channel = OracleSetupChannel::new(true);
404 IOPVerifierChannel::<F>::recv_oracle(&mut channel, 3, false).unwrap();
405 IOPVerifierChannel::<F>::recv_oracle(&mut channel, 3, true).unwrap();
406 sample(&mut channel);
407 IOPVerifierChannel::<F>::recv_oracle(&mut channel, 2, false).unwrap();
408
409 let merged = channel.into_oracle_schedule().merged_specs();
410 assert_eq!(merged, vec![OracleSpec::new_zk(4), OracleSpec::new(2)]);
411 }
412}