binius_iop/channel/
naive.rs1use binius_field::Field;
6use binius_ip::channel::IPVerifierChannel;
7use binius_math::{
8 FieldBuffer, inner_product::inner_product_buffers, multilinear::evaluate::evaluate_inplace,
9};
10use binius_transcript::{
11 VerifierTranscript,
12 fiat_shamir::{CanSample, Challenger},
13};
14
15use crate::channel::{Error, IOPVerifierChannel, OracleSpec, TransparentEvalFn};
16
17#[derive(Debug, Clone, Copy)]
19pub struct NaiveOracle {
20 index: usize,
21}
22
23pub struct NaiveVerifierChannel<'a, F, Challenger_>
34where
35 F: Field,
36 Challenger_: Challenger,
37{
38 transcript: &'a mut VerifierTranscript<Challenger_>,
40 oracle_specs: &'a [OracleSpec],
42 stored_polynomials: Vec<FieldBuffer<F>>,
46 next_oracle_index: usize,
48}
49
50impl<'a, F, Challenger_> NaiveVerifierChannel<'a, F, Challenger_>
51where
52 F: Field,
53 Challenger_: Challenger,
54{
55 pub const fn new(
62 transcript: &'a mut VerifierTranscript<Challenger_>,
63 oracle_specs: &'a [OracleSpec],
64 ) -> Self {
65 Self {
66 transcript,
67 oracle_specs,
68 stored_polynomials: Vec::new(),
69 next_oracle_index: 0,
70 }
71 }
72
73 pub const fn transcript(&self) -> &VerifierTranscript<Challenger_> {
75 self.transcript
76 }
77
78 pub fn finish(self) {
80 let n_remaining = self.oracle_specs.len() - self.next_oracle_index;
81 assert!(n_remaining == 0, "finish called but {n_remaining} oracle specs remaining",);
82 }
83}
84
85impl<F, Challenger_> IPVerifierChannel<F> for NaiveVerifierChannel<'_, F, Challenger_>
86where
87 F: Field,
88 Challenger_: Challenger,
89{
90 type Elem = F;
91
92 fn recv_one(&mut self) -> Result<F, binius_ip::channel::Error> {
93 self.transcript
94 .message()
95 .read_scalar()
96 .map_err(|_| binius_ip::channel::Error::ProofEmpty)
97 }
98
99 fn recv_many(&mut self, n: usize) -> Result<Vec<F>, binius_ip::channel::Error> {
100 self.transcript
101 .message()
102 .read_scalar_slice(n)
103 .map_err(|_| binius_ip::channel::Error::ProofEmpty)
104 }
105
106 fn recv_array<const N: usize>(&mut self) -> Result<[F; N], binius_ip::channel::Error> {
107 self.transcript
108 .message()
109 .read()
110 .map_err(|_| binius_ip::channel::Error::ProofEmpty)
111 }
112
113 fn sample(&mut self) -> F {
114 CanSample::sample(&mut self.transcript)
115 }
116
117 fn observe_one(&mut self, val: F) -> F {
118 self.transcript.observe().write_scalar(val);
119 val
120 }
121
122 fn observe_many(&mut self, vals: &[F]) -> Vec<F> {
123 self.transcript.observe().write_scalar_slice(vals);
124 vals.to_vec()
125 }
126
127 fn assert_zero(&mut self, val: F) -> Result<(), binius_ip::channel::Error> {
128 if val == F::ZERO {
129 Ok(())
130 } else {
131 Err(binius_ip::channel::Error::InvalidAssert)
132 }
133 }
134}
135
136impl<F, Challenger_> IOPVerifierChannel<F> for NaiveVerifierChannel<'_, F, Challenger_>
137where
138 F: Field,
139 Challenger_: Challenger,
140{
141 type Oracle = NaiveOracle;
142
143 fn remaining_oracle_specs(&self) -> &[OracleSpec] {
144 &self.oracle_specs[self.next_oracle_index..]
145 }
146
147 fn recv_oracle(
148 &mut self,
149 log_msg_len: usize,
150 _is_witness_dependent: bool,
151 ) -> Result<Self::Oracle, Error> {
152 assert!(
153 !self.remaining_oracle_specs().is_empty(),
154 "recv_oracle called but no remaining oracle specs"
155 );
156
157 let index = self.next_oracle_index;
158 debug_assert_eq!(log_msg_len, self.oracle_specs[index].log_msg_len);
159
160 let buffer_len = 1 << log_msg_len;
161
162 let values = self
164 .transcript
165 .message()
166 .read_scalar_slice(buffer_len)
167 .map_err(|_| Error::ProofEmpty)?;
168
169 self.stored_polynomials
170 .push(FieldBuffer::from_values(&values));
171 self.next_oracle_index += 1;
172
173 Ok(NaiveOracle { index })
174 }
175
176 fn verify_oracle_relation(
177 &mut self,
178 oracle: Self::Oracle,
179 transparent: TransparentEvalFn<F>,
180 claim: F,
181 ) -> Result<(), Error> {
182 let index = oracle.index;
183 assert!(index < self.stored_polynomials.len(), "oracle index {index} out of bounds");
184
185 let log_msg_len = self.oracle_specs[index].log_msg_len;
187
188 let transparent_len = 1 << log_msg_len;
191 let transparent_values = self
192 .transcript
193 .message()
194 .read_scalar_slice(transparent_len)
195 .map_err(|_| Error::ProofEmpty)?;
196 let transparent_poly = FieldBuffer::from_values(&transparent_values);
197
198 let stored_poly = &self.stored_polynomials[index];
200 let witness_poly = stored_poly.as_view();
201 let actual_inner_product: F = inner_product_buffers(&witness_poly, &transparent_poly);
202
203 assert_eq!(
204 actual_inner_product, claim,
205 "NaiveVerifierChannel: inner product verification failed"
206 );
207
208 let point: Vec<F> = CanSample::sample_vec(&mut self.transcript, log_msg_len);
210
211 let transparent_eval = transparent(&point);
213
214 self.assert_zero(transparent_eval - evaluate_inplace(transparent_poly, &point))?;
216
217 Ok(())
218 }
219}