remainder/
claims.rs

1//! Utilities involving the claims a layer makes.
2
3/// A struct for managing groups of claims originating from the same layer.
4pub mod claim_group;
5
6/// Tests for claim-related things.
7#[cfg(test)]
8pub mod tests;
9
10pub mod claim_aggregation;
11
12use std::{collections::HashMap, fmt};
13
14use shared_types::Field;
15use thiserror::Error;
16
17use serde::{Deserialize, Serialize};
18
19use crate::layer::LayerId;
20
21/// Errors to do with aggregating and collecting claims.
22#[derive(Error, Debug, Clone)]
23pub enum ClaimError {
24    /// MLE indices must all be fixed.
25    #[error("MLE indices must all be fixed")]
26    ClaimMleIndexError,
27
28    /// MLE within MleRef has multiple values within it.
29    #[error("MLE within MleRef has multiple values within it")]
30    MleRefMleError,
31
32    /// Error aggregating claims.
33    #[error("Error aggregating claims")]
34    ClaimAggroError,
35
36    /// All claims in a group should agree on the number of variables.
37    #[error("All claims in a group should agree on the number of variables")]
38    NumVarsMismatch,
39
40    /// All claims in a group should agree the destination layer field.
41    #[error("All claims in a group should agree the destination layer field")]
42    LayerIdMismatch,
43
44    /// Zero MLE refs cannot be used as intermediate values within a circuit!
45    #[error("Zero MLE refs cannot be used as intermediate values within a circuit")]
46    IntermediateZeroMLERefError,
47}
48
49/// A claim without any source/destination layer information.  See related
50/// [Claim] wrapper.
51/// It contains a `point \in F^n` along with the `evaluation \in F` that an
52/// associated layer MLE is expected to evaluate to. In other words, if
53/// `\tilde{V} : F^n -> F` is the MLE of a layer, then this claim asserts:
54/// `\tilde{V}(point) == result`.
55#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
56#[serde(bound = "F: Field")]
57pub struct RawClaim<F: Field> {
58    /// The point in `F^n` at which to evaluate the layer MLE.
59    point: Vec<F>,
60
61    /// The expected result of evaluating a layer's MLE on `point`.
62    evaluation: F,
63}
64
65impl<F: Field> RawClaim<F> {
66    /// Constructs a new [RawClaim] from a given `point` and `evaluation`.
67    pub fn new(point: Vec<F>, evaluation: F) -> Self {
68        Self { point, evaluation }
69    }
70
71    /// Returns the length of the `point` vector.
72    pub fn get_num_vars(&self) -> usize {
73        self.point.len()
74    }
75
76    /// Returns a reference to `point \in F^n`.
77    pub fn get_point(&self) -> &[F] {
78        &self.point
79    }
80
81    /// Returns the expected evaluation.
82    pub fn get_eval(&self) -> F {
83        self.evaluation
84    }
85}
86
87/// A claim with source/destination layer information.
88/// This is a wrapper around [RawClaim] which holds a `point \in F^n` and an
89/// `evaluation \in F`. The claim asserts that the layer MLE `\tilde{V} : F^n ->
90/// F` of the layer with ID `to_layer_id` evaluates to `evaluation` when
91/// computed on `point`: `tilde{V}(point) == result`.
92#[derive(Clone, Serialize, Deserialize, PartialEq)]
93#[serde(bound = "F: Field")]
94pub struct Claim<F: Field> {
95    /// The underlying claim.
96    claim: RawClaim<F>,
97
98    /// The layer ID of the layer that produced this claim; origin layer.
99    from_layer_id: LayerId,
100
101    /// The layer ID of the layer containing the MLE this claim applies to;
102    /// destination layer.
103    to_layer_id: LayerId,
104}
105
106impl<F: Field> Claim<F> {
107    /// Generate a new claim, given a point, an expected evaluation and
108    /// origin/destination information.
109    pub fn new(point: Vec<F>, evaluation: F, from_layer_id: LayerId, to_layer_id: LayerId) -> Self {
110        Self {
111            claim: RawClaim::new(point, evaluation),
112            from_layer_id,
113            to_layer_id,
114        }
115    }
116
117    /// Returns the length of the `point` vector.
118    pub fn get_num_vars(&self) -> usize {
119        self.claim.get_num_vars()
120    }
121
122    /// Returns a reference to the `point \in F^n``.
123    pub fn get_point(&self) -> &[F] {
124        self.claim.get_point()
125    }
126
127    /// Returns the expected evaluation.
128    pub fn get_eval(&self) -> F {
129        self.claim.get_eval()
130    }
131
132    /// Returns the source Layer ID.
133    pub fn get_from_layer_id(&self) -> LayerId {
134        self.from_layer_id
135    }
136
137    /// Returns the destination Layer ID.
138    pub fn get_to_layer_id(&self) -> LayerId {
139        self.to_layer_id
140    }
141
142    /// Returns a reference to the underlying [RawClaim].
143    pub fn get_raw_claim(&self) -> &RawClaim<F> {
144        &self.claim
145    }
146}
147
148impl<F: Field> From<Claim<F>> for RawClaim<F> {
149    fn from(value: Claim<F>) -> Self {
150        Self {
151            point: value.claim.point,
152            evaluation: value.claim.evaluation,
153        }
154    }
155}
156
157impl<F: fmt::Debug + Field> fmt::Debug for Claim<F> {
158    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
159        f.debug_struct("Claim")
160            .field("point", &self.get_point().to_vec())
161            .field("result", &self.claim.get_eval())
162            .field("from_layer_id", &self.from_layer_id)
163            .field("to_layer_id", &self.to_layer_id)
164            .finish()
165    }
166}
167
168/// Keeps track of claims made on layers by mapping [LayerId]s to a collection
169/// of [Claim]s made on that layer.
170/// This is a wrapper type around a [HashMap] with a more convenient
171/// interface for inserting and querying claims.
172pub struct ClaimTracker<F: Field> {
173    /// Maps layer IDs to vectors of claims.
174    claim_map: HashMap<LayerId, Vec<Claim<F>>>,
175}
176
177impl<F: Field> ClaimTracker<F> {
178    /// Generate an empty [ClaimTracker].
179    pub fn new() -> Self {
180        Self {
181            claim_map: HashMap::<LayerId, Vec<Claim<F>>>::new(),
182        }
183    }
184
185    /// Generate an empty [ClaimTracker] with a given initial capacity for
186    /// better performance.
187    pub fn new_with_capacity(capacity: usize) -> Self {
188        Self {
189            claim_map: HashMap::<LayerId, Vec<Claim<F>>>::with_capacity(capacity),
190        }
191    }
192
193    /// Inserts `claim` into the list of claims made *on* the layer with ID
194    /// `layer_id`.
195    pub fn insert(&mut self, layer_id: LayerId, claim: Claim<F>) {
196        debug_assert_eq!(claim.get_to_layer_id(), layer_id);
197
198        if let Some(claims) = self.claim_map.get_mut(&layer_id) {
199            claims.push(claim);
200        } else {
201            self.claim_map.insert(layer_id, vec![claim]);
202        }
203    }
204
205    /// Returns a reference to a vector of all the claims made so far on layer
206    /// with ID `layer_id`, if any. If no claims were ever made to `layer_id`,
207    /// it returns `None`.
208    pub fn get(&self, layer_id: LayerId) -> Option<&Vec<Claim<F>>> {
209        self.claim_map.get(&layer_id)
210    }
211
212    /// Removes all claims made on layer with ID `layer_id` and returns them.
213    pub fn remove(&mut self, layer_id: LayerId) -> Option<Vec<Claim<F>>> {
214        self.claim_map.remove(&layer_id)
215    }
216
217    /// Returns whether the claim tracker is empty.
218    pub fn is_empty(&self) -> bool {
219        self.claim_map.is_empty()
220    }
221}
222
223/// Clippy suggested this.
224/// See: <https://rust-lang.github.io/rust-clippy/master/index.html#new_without_default>.
225impl<F: Field> Default for ClaimTracker<F> {
226    fn default() -> Self {
227        ClaimTracker::new()
228    }
229}