1use alloc::vec::Vec;
4
5use p3_challenger::{CanSample, CanSampleBits, CanSampleUniformBits};
6use p3_field::{BasedVectorSpace, Field};
7use thiserror::Error;
8
9use crate::{
10 TranscriptData,
11 channel::{Channel, TranscriptChallenger},
12};
13
14#[derive(Clone, Debug)]
16pub struct VerifierTranscript<'a, F, C, Ch> {
17 challenger: Ch,
18 fields: &'a [F],
19 commitments: &'a [C],
20}
21
22impl<'a, F, C, Ch> VerifierTranscript<'a, F, C, Ch> {
23 pub fn new(challenger: Ch, fields: &'a [F], commitments: &'a [C]) -> Self {
25 Self { challenger, fields, commitments }
26 }
27
28 pub fn from_data(challenger: Ch, data: &'a TranscriptData<F, C>) -> Self {
30 let (fields, commitments) = data.as_slices();
31 Self::new(challenger, fields, commitments)
32 }
33
34 pub fn finalize(self) -> Result<Ch::Digest, TranscriptError>
41 where
42 F: Field,
43 C: Clone,
44 Ch: TranscriptChallenger<F, C>,
45 {
46 if !self.fields.is_empty() || !self.commitments.is_empty() {
47 return Err(TranscriptError::TrailingData);
48 }
49 Ok(self.challenger.finalize())
50 }
51
52 pub fn size_in_bytes(&self) -> usize {
54 size_of_val(self.fields) + size_of_val(self.commitments)
55 }
56}
57
58pub trait VerifierChannel: Channel {
60 fn receive_field_slice(&mut self, count: usize) -> Result<&[Self::F], TranscriptError>;
61
62 fn receive_commitment_slice(
63 &mut self,
64 count: usize,
65 ) -> Result<&[Self::Commitment], TranscriptError>;
66
67 fn receive_field(&mut self) -> Result<&Self::F, TranscriptError> {
68 self.receive_field_slice(1).map(|values| values.first().unwrap())
69 }
70
71 fn receive_algebra_element<A>(&mut self) -> Result<A, TranscriptError>
72 where
73 Self::F: Field,
74 A: BasedVectorSpace<Self::F>,
75 {
76 let coeffs = self.receive_field_slice(A::DIMENSION)?;
77 Ok(A::from_basis_coefficients_slice(coeffs).unwrap())
78 }
79
80 fn receive_algebra_slice<A>(&mut self, count: usize) -> Result<Vec<A>, TranscriptError>
81 where
82 Self::F: Field,
83 A: BasedVectorSpace<Self::F>,
84 {
85 let mut values = Vec::with_capacity(count);
86 for _ in 0..count {
87 let coeffs = self.receive_field_slice(A::DIMENSION)?;
88 values.push(A::from_basis_coefficients_slice(coeffs).unwrap());
89 }
90 Ok(values)
91 }
92
93 fn receive_commitment(&mut self) -> Result<&Self::Commitment, TranscriptError> {
94 self.receive_commitment_slice(1).map(|values| values.first().unwrap())
95 }
96
97 fn receive_hint_field_slice(&mut self, count: usize) -> Result<&[Self::F], TranscriptError>;
98
99 fn receive_hint_commitment_slice(
100 &mut self,
101 count: usize,
102 ) -> Result<&[Self::Commitment], TranscriptError>;
103
104 fn receive_hint_field(&mut self) -> Result<&Self::F, TranscriptError> {
105 self.receive_hint_field_slice(1).map(|values| values.first().unwrap())
106 }
107
108 fn receive_hint_field_array<const N: usize>(&mut self) -> Result<[Self::F; N], TranscriptError>
110 where
111 Self::F: Copy,
112 {
113 self.receive_hint_field_slice(N)?
114 .try_into()
115 .map_err(|_| TranscriptError::NoMoreFields)
116 }
117
118 fn receive_hint_commitment(&mut self) -> Result<&Self::Commitment, TranscriptError> {
119 self.receive_hint_commitment_slice(1).map(|values| values.first().unwrap())
120 }
121
122 fn grind(&mut self, bits: usize) -> Result<Self::F, TranscriptError>;
123
124 fn is_empty(&self) -> bool;
125}
126
127impl<'a, F, C, Ch> Channel for VerifierTranscript<'a, F, C, Ch>
128where
129 F: Field,
130 C: Clone,
131 Ch: TranscriptChallenger<F, C>,
132{
133 type F = F;
134 type Commitment = C;
135 type Challenger = Ch;
136
137 fn sample(&mut self) -> F {
138 CanSample::<F>::sample(&mut self.challenger)
139 }
140
141 fn sample_bits(&mut self, bits: usize) -> usize {
142 self.challenger.sample_bits(bits)
143 }
144}
145
146impl<'a, F, C, Ch> VerifierChannel for VerifierTranscript<'a, F, C, Ch>
147where
148 F: Field,
149 C: Clone,
150 Ch: TranscriptChallenger<F, C>,
151{
152 fn receive_field_slice(&mut self, count: usize) -> Result<&'a [Self::F], TranscriptError> {
154 let values = pop_slice(&mut self.fields, count).ok_or(TranscriptError::NoMoreFields)?;
155 self.challenger.observe_slice(values);
156 Ok(values)
157 }
158
159 fn receive_commitment_slice(
160 &mut self,
161 count: usize,
162 ) -> Result<&'a [Self::Commitment], TranscriptError> {
163 let values =
164 pop_slice(&mut self.commitments, count).ok_or(TranscriptError::NoMoreCommitments)?;
165 self.challenger.observe_slice(values);
166 Ok(values)
167 }
168
169 fn receive_hint_field_slice(&mut self, count: usize) -> Result<&'a [Self::F], TranscriptError> {
170 pop_slice(&mut self.fields, count).ok_or(TranscriptError::NoMoreFields)
171 }
172
173 fn receive_hint_commitment_slice(
174 &mut self,
175 count: usize,
176 ) -> Result<&'a [Self::Commitment], TranscriptError> {
177 pop_slice(&mut self.commitments, count).ok_or(TranscriptError::NoMoreCommitments)
178 }
179
180 fn grind(&mut self, bits: usize) -> Result<Self::F, TranscriptError> {
181 let (witness, rest) = self.fields.split_first().ok_or(TranscriptError::NoMoreFields)?;
182 self.fields = rest;
183 if self.challenger.check_witness(bits, *witness) {
184 Ok(*witness)
185 } else {
186 Err(TranscriptError::InvalidGrinding)
187 }
188 }
189
190 fn is_empty(&self) -> bool {
191 self.fields.is_empty() && self.commitments.is_empty()
192 }
193}
194
195impl<'a, F, C, Ch, T> CanSample<T> for VerifierTranscript<'a, F, C, Ch>
196where
197 Ch: CanSample<T>,
198{
199 #[inline]
200 fn sample(&mut self) -> T {
201 self.challenger.sample()
202 }
203}
204
205impl<'a, F, C, Ch> CanSampleBits<usize> for VerifierTranscript<'a, F, C, Ch>
206where
207 Ch: CanSampleBits<usize>,
208{
209 #[inline]
210 fn sample_bits(&mut self, bits: usize) -> usize {
211 self.challenger.sample_bits(bits)
212 }
213}
214
215impl<'a, F, C, Ch> CanSampleUniformBits<F> for VerifierTranscript<'a, F, C, Ch>
216where
217 Ch: CanSampleUniformBits<F>,
218{
219 #[inline]
220 fn sample_uniform_bits<const RESAMPLE: bool>(
221 &mut self,
222 bits: usize,
223 ) -> Result<usize, p3_challenger::ResamplingError> {
224 self.challenger.sample_uniform_bits::<RESAMPLE>(bits)
225 }
226}
227
228fn pop_slice<'a, T>(values: &mut &'a [T], count: usize) -> Option<&'a [T]> {
229 if values.len() < count {
230 return None;
231 }
232 let (slice, rest) = values.split_at(count);
233 *values = rest;
234 Some(slice)
235}
236
237#[derive(Debug, Clone, Copy, PartialEq, Eq, Error)]
239pub enum TranscriptError {
240 #[error("no more field elements in transcript")]
241 NoMoreFields,
242 #[error("no more commitments in transcript")]
243 NoMoreCommitments,
244 #[error("invalid grinding witness")]
245 InvalidGrinding,
246 #[error("trailing data in transcript")]
247 TrailingData,
248}