winter_fri/
proof.rs

1// Copyright (c) Facebook, Inc. and its affiliates.
2//
3// This source code is licensed under the MIT license found in the
4// LICENSE file in the root directory of this source tree.
5
6use alloc::{string::ToString, vec::Vec};
7
8use crypto::{ElementHasher, Hasher, VectorCommitment};
9use math::FieldElement;
10use utils::{
11    ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable, SliceReader,
12};
13
14// FRI PROOF
15// ================================================================================================
16
17/// A proof generated by a FRI prover.
18///
19/// A FRI proof contains information proving that a function *f* is a polynomial of some bounded
20/// degree *d*. FRI proofs cannot be instantiated directly - they must be generated by an instance
21/// of a [FriProver](crate::FriProver), and can be verified by an instance of a
22/// [FriVerifier](crate::FriVerifier) via [VerifierChannel](crate::VerifierChannel) interface.
23///
24/// A proof consists of zero or more layers and a remainder polynomial. Each layer contains a set of
25/// polynomial evaluations at positions queried by the verifier, a vector commitment to LDE of
26/// each polynomial, as well as opening proofs for the evaluations against the vector commitments.
27/// The remainder polynomial is given by its list of coefficients i.e. field elements.
28///
29/// All values in a proof are stored as vectors of bytes. Thus, the values must be parsed before
30/// they can be returned to the user. To do this, [parse_layers()](FriProof::parse_layers())
31/// and [parse_remainder()](FriProof::parse_remainder()) methods can be used.
32#[derive(Debug, Clone, Eq, PartialEq)]
33pub struct FriProof {
34    layers: Vec<FriProofLayer>,
35    remainder: Vec<u8>,
36    num_partitions: u8, // stored as power of 2
37}
38
39impl FriProof {
40    // CONSTRUCTOR
41    // --------------------------------------------------------------------------------------------
42    /// Creates a new FRI proof from the provided layers and remainder polynomial.
43    ///
44    /// # Panics
45    /// Panics if:
46    /// * Number of remainder elements zero or is not a power of two.
47    /// * `num_partitions` is zero or is not a power of two.
48    pub(crate) fn new<E: FieldElement>(
49        layers: Vec<FriProofLayer>,
50        remainder: Vec<E>,
51        num_partitions: usize,
52    ) -> Self {
53        assert!(!remainder.is_empty(), "number of remainder elements must be greater than zero");
54        assert!(
55            remainder.len().is_power_of_two(),
56            "size of the remainder must be a power of two, but was {}",
57            remainder.len()
58        );
59        assert!(num_partitions > 0, "number of partitions must be greater than zero");
60        assert!(
61            num_partitions.is_power_of_two(),
62            "number of partitions must be a power of two, but was {num_partitions}"
63        );
64
65        let mut remainder_bytes = Vec::with_capacity(E::ELEMENT_BYTES * remainder.len());
66        remainder_bytes.write_many(&remainder);
67
68        FriProof {
69            layers,
70            remainder: remainder_bytes,
71            num_partitions: num_partitions.trailing_zeros() as u8,
72        }
73    }
74
75    /// Creates a dummy `FriProof` for use in tests.
76    pub fn new_dummy() -> Self {
77        Self {
78            layers: Vec::new(),
79            remainder: Vec::new(),
80            num_partitions: 0,
81        }
82    }
83
84    // PUBLIC ACCESSORS
85    // --------------------------------------------------------------------------------------------
86
87    /// Returns the number of layers in this proof.
88    pub fn num_layers(&self) -> usize {
89        self.layers.len()
90    }
91
92    /// Returns the number of remainder elements in this proof.
93    ///
94    /// The number of elements is computed by dividing the number of remainder bytes by the size
95    /// of the field element specified by `E` type parameter.
96    pub fn num_remainder_elements<E: FieldElement>(&self) -> usize {
97        self.remainder.len() / E::ELEMENT_BYTES
98    }
99
100    /// Returns the number of partitions used during proof generation.
101    pub fn num_partitions(&self) -> usize {
102        2usize.pow(self.num_partitions as u32)
103    }
104
105    /// Returns the size of this proof in bytes.
106    pub fn size(&self) -> usize {
107        // +1 for number of layers, +1 for remainder length, +1 for number of partitions
108        self.layers
109            .iter()
110            .fold(self.remainder.len() + 3, |acc, layer| acc + layer.size())
111    }
112
113    // PARSING
114    // --------------------------------------------------------------------------------------------
115
116    /// Decomposes this proof into vectors of query values for each layer and corresponding batch
117    /// opening proofs.
118    ///
119    /// # Panics
120    /// Panics if:
121    /// * `domain_size` is not a power of two.
122    /// * `folding_factor` is smaller than two or is not a power of two.
123    ///
124    /// # Errors
125    /// Returns an error if:
126    /// * This proof is not consistent with the specified `domain_size` and `folding_factor`.
127    /// * Any of the layers could not be parsed successfully.
128    #[allow(clippy::type_complexity)]
129    pub fn parse_layers<E, H, V>(
130        self,
131        mut domain_size: usize,
132        folding_factor: usize,
133    ) -> Result<(Vec<Vec<E>>, Vec<<V as VectorCommitment<H>>::MultiProof>), DeserializationError>
134    where
135        E: FieldElement,
136        H: ElementHasher<BaseField = E::BaseField>,
137        V: VectorCommitment<H>,
138    {
139        assert!(domain_size.is_power_of_two(), "domain size must be a power of two");
140        assert!(folding_factor.is_power_of_two(), "folding factor must be a power of two");
141        assert!(folding_factor > 1, "folding factor must be greater than 1");
142
143        let mut layer_proofs = Vec::new();
144        let mut layer_queries = Vec::new();
145
146        // parse all layers
147        for (i, layer) in self.layers.into_iter().enumerate() {
148            domain_size /= folding_factor;
149            let (qv, op) = layer.parse::<_, H, V>(folding_factor).map_err(|err| {
150                DeserializationError::InvalidValue(format!("failed to parse FRI layer {i}: {err}"))
151            })?;
152
153            // check that the opening proof matches the domain length
154            if <V as VectorCommitment<H>>::get_multiproof_domain_len(&op) != domain_size {
155                return Err(DeserializationError::InvalidValue(format!(
156                    "expected a domain of size {} but was {}",
157                    domain_size,
158                    <V as VectorCommitment<H>>::get_multiproof_domain_len(&op),
159                )));
160            }
161
162            layer_proofs.push(op);
163            layer_queries.push(qv);
164        }
165
166        Ok((layer_queries, layer_proofs))
167    }
168
169    /// Returns a vector of remainder values (last FRI layer) parsed from this proof.
170    ///
171    /// # Errors
172    /// Returns an error if:
173    /// * The number of remainder values implied by a combination of `E` type parameter and the
174    ///   number of remainder bytes in this proof is not a power of two.
175    /// * Any of the remainder values could not be parsed correctly.
176    /// * Not all bytes have been consumed while parsing remainder values.
177    pub fn parse_remainder<E: FieldElement>(&self) -> Result<Vec<E>, DeserializationError> {
178        let num_elements = self.num_remainder_elements::<E>();
179        if !num_elements.is_power_of_two() {
180            return Err(DeserializationError::InvalidValue(format!(
181                "number of remainder values must be a power of two, but {num_elements} was implied"
182            )));
183        }
184        let mut reader = SliceReader::new(&self.remainder);
185        let remainder = reader.read_many(num_elements).map_err(|err| {
186            DeserializationError::InvalidValue(format!("failed to parse FRI remainder: {err}"))
187        })?;
188        if reader.has_more_bytes() {
189            return Err(DeserializationError::UnconsumedBytes);
190        }
191        Ok(remainder)
192    }
193}
194
195// SERIALIZATION / DESERIALIZATION
196// ------------------------------------------------------------------------------------------------
197
198impl Serializable for FriProof {
199    /// Serializes `self` and writes the resulting bytes into the `target` writer.
200    fn write_into<W: ByteWriter>(&self, target: &mut W) {
201        // write layers
202        target.write_u8(self.layers.len() as u8);
203        for layer in self.layers.iter() {
204            layer.write_into(target);
205        }
206
207        // write remainder
208        target.write_u16(self.remainder.len() as u16);
209        target.write_bytes(&self.remainder);
210
211        // write number of partitions
212        target.write_u8(self.num_partitions);
213    }
214}
215
216impl Deserializable for FriProof {
217    /// Reads a FRI proof from the specified `source` and returns the result.
218    ///
219    /// # Errors
220    /// Returns an error if a valid proof could not be read from the source.
221    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
222        // read layers
223        let num_layers = source.read_u8()? as usize;
224        let layers = source.read_many(num_layers)?;
225
226        // read remainder
227        let num_remainder_bytes = source.read_u16()? as usize;
228        let remainder = source.read_vec(num_remainder_bytes)?;
229
230        // read number of partitions
231        let num_partitions = source.read_u8()?;
232
233        Ok(FriProof { layers, remainder, num_partitions })
234    }
235}
236
237// FRI PROOF LAYER
238// ================================================================================================
239
240#[derive(Debug, Clone, Eq, PartialEq)]
241pub struct FriProofLayer {
242    values: Vec<u8>,
243    paths: Vec<u8>,
244}
245
246impl FriProofLayer {
247    // CONSTRUCTOR
248    // --------------------------------------------------------------------------------------------
249    /// Creates a new proof layer from the specified query values and the corresponding batch
250    /// opening proof.
251    ///
252    /// # Panics
253    /// Panics if `query_values` is an empty slice.
254    pub(crate) fn new<E: FieldElement, H: Hasher, V: VectorCommitment<H>, const N: usize>(
255        query_values: Vec<[E; N]>,
256        proof: <V as VectorCommitment<H>>::MultiProof,
257    ) -> Self {
258        assert!(!query_values.is_empty(), "query values cannot be empty");
259
260        // TODO: add debug check that values actually hash into the leaf nodes of the batch proof
261
262        let mut value_bytes = Vec::with_capacity(E::ELEMENT_BYTES * N * query_values.len());
263        value_bytes.write_many(&query_values);
264
265        let mut proof_bytes = Vec::new();
266        proof.write_into(&mut proof_bytes);
267
268        FriProofLayer { values: value_bytes, paths: proof_bytes }
269    }
270
271    // PUBLIC ACCESSORS
272    // --------------------------------------------------------------------------------------------
273
274    /// Returns the size of this proof layer in bytes.
275    pub fn size(&self) -> usize {
276        // +4 for length of values, +4 for length of paths
277        self.values.len() + 4 + self.paths.len() + 4
278    }
279
280    // PARSING
281    // --------------------------------------------------------------------------------------------
282    /// Decomposes this layer into a combination of query values and corresponding batch opening
283    /// proof.
284    ///
285    /// # Errors
286    /// Returns an error if:
287    /// * This layer does not contain at least one query.
288    /// * Parsing of any of the query values or the corresponding batch opening proof fails.
289    /// * Not all bytes have been consumed while parsing this layer.
290    pub fn parse<E, H, V>(
291        self,
292        folding_factor: usize,
293    ) -> Result<(Vec<E>, <V as VectorCommitment<H>>::MultiProof), DeserializationError>
294    where
295        E: FieldElement,
296        H: ElementHasher<BaseField = E::BaseField>,
297        V: VectorCommitment<H>,
298    {
299        // make sure the number of value bytes can be parsed into a whole number of queries
300        let num_query_bytes = E::ELEMENT_BYTES * folding_factor;
301        if self.values.len() % num_query_bytes != 0 {
302            return Err(DeserializationError::InvalidValue(format!(
303                "number of value bytes ({}) does not divide into whole number of queries",
304                self.values.len(),
305            )));
306        }
307
308        let num_queries = self.values.len() / num_query_bytes;
309        if num_queries == 0 {
310            return Err(DeserializationError::InvalidValue(
311                "a FRI layer must contain at least one query".to_string(),
312            ));
313        }
314        let mut hashed_queries = vec![H::Digest::default(); num_queries];
315        let mut query_values = Vec::with_capacity(num_queries * folding_factor);
316
317        // read bytes corresponding to each query, convert them into field elements,
318        // and also hash them to build leaf nodes of the batch opening proof
319        let mut reader = SliceReader::new(&self.values);
320        for query_hash in hashed_queries.iter_mut() {
321            let mut qe = reader.read_many(folding_factor)?;
322            *query_hash = H::hash_elements(&qe);
323            query_values.append(&mut qe);
324        }
325        if reader.has_more_bytes() {
326            return Err(DeserializationError::UnconsumedBytes);
327        }
328
329        // build batch opening proof
330        let mut reader = SliceReader::new(&self.paths);
331        let multi_proof = <V::MultiProof as Deserializable>::read_from(&mut reader)?;
332        if reader.has_more_bytes() {
333            return Err(DeserializationError::UnconsumedBytes);
334        }
335
336        Ok((query_values, multi_proof))
337    }
338}
339
340// SERIALIZATION / DESERIALIZATION
341// ------------------------------------------------------------------------------------------------
342
343impl Serializable for FriProofLayer {
344    /// Serializes this proof layer and writes the resulting bytes to the specified `target`.
345    fn write_into<W: ByteWriter>(&self, target: &mut W) {
346        // write value bytes
347        target.write_u32(self.values.len() as u32);
348        target.write_bytes(&self.values);
349
350        // write path bytes
351        target.write_u32(self.paths.len() as u32);
352        target.write_bytes(&self.paths);
353    }
354}
355
356impl Deserializable for FriProofLayer {
357    /// Reads a single proof layer form the `source` and returns it.
358    ///
359    /// # Errors
360    /// Returns an error if a valid layer could not be read from the specified source.
361    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
362        // read values
363        let num_value_bytes = source.read_u32()?;
364        if num_value_bytes == 0 {
365            return Err(DeserializationError::InvalidValue(
366                "a FRI proof layer must contain at least one queried evaluation".to_string(),
367            ));
368        }
369        let values = source.read_vec(num_value_bytes as usize)?;
370
371        // read paths
372        let num_paths_bytes = source.read_u32()?;
373        let paths = source.read_vec(num_paths_bytes as usize)?;
374
375        Ok(FriProofLayer { values, paths })
376    }
377}