Skip to main content

snarkvm_algorithms/polycommit/sonic_pc/
data_structures.rs

1// Copyright (c) 2019-2026 Provable Inc.
2// This file is part of the snarkVM library.
3
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at:
7
8// http://www.apache.org/licenses/LICENSE-2.0
9
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16use super::{LabeledPolynomial, PolynomialInfo};
17use crate::{crypto_hash::sha256::sha256, fft::EvaluationDomain, polycommit::kzg10};
18use snarkvm_curves::PairingEngine;
19use snarkvm_fields::{ConstraintFieldError, Field, PrimeField, ToConstraintField};
20use snarkvm_parameters::mainnet::MAX_NUM_POWERS;
21use snarkvm_utilities::{FromBytes, ToBytes, error, into_io_error, serialize::*};
22
23use hashbrown::HashMap;
24use std::{
25    borrow::{Borrow, Cow},
26    collections::{BTreeMap, BTreeSet},
27    fmt,
28    io,
29    ops::{AddAssign, Deref, MulAssign, Range, SubAssign},
30    sync::Arc,
31};
32
33/// `UniversalParams` are the universal parameters for the KZG10 scheme.
34pub type UniversalParams<E> = kzg10::UniversalParams<E>;
35
36/// `Randomness` is the randomness for the KZG10 scheme.
37pub type Randomness<E> = kzg10::KZGRandomness<E>;
38
39/// `Commitment` is the commitment for the KZG10 scheme.
40pub type Commitment<E> = kzg10::KZGCommitment<E>;
41
42/// A committer key's bases: points it owns, or a range of an SRS snapshot it
43/// shares. A snapshot never changes once made, so a shared range stays valid
44/// for as long as the key holds it.
45#[derive(Clone)]
46pub enum Bases<G> {
47    Owned(Vec<G>),
48    Shared { store: Arc<Vec<G>>, range: Range<usize> },
49}
50
51/// The key's own points, not the whole snapshot a shared range is cut from,
52/// which can be millions of them.
53impl<G: fmt::Debug> fmt::Debug for Bases<G> {
54    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55        fmt::Debug::fmt(&**self, f)
56    }
57}
58
59impl<G> Deref for Bases<G> {
60    type Target = [G];
61
62    fn deref(&self) -> &[G] {
63        match self {
64            Self::Owned(points) => points,
65            Self::Shared { store, range } => &store[range.clone()],
66        }
67    }
68}
69
70impl<G> Bases<G> {
71    /// A range of `store`, checked here rather than on first use.
72    pub fn shared(store: Arc<Vec<G>>, range: Range<usize>) -> Self {
73        assert!(
74            range.start <= range.end && range.end <= store.len(),
75            "a shared range {range:?} outside a snapshot of {} points",
76            store.len()
77        );
78        Self::Shared { store, range }
79    }
80}
81
82impl<G: Clone> Bases<G> {
83    /// Points this key allocated itself: none when it shares them, which is
84    /// what a key cache should budget for. A shared key can still keep an
85    /// older snapshot alive after the SRS grows past it; that is bounded by
86    /// the SRS, not by the key, and is not counted here.
87    pub fn owned_capacity(&self) -> usize {
88        match self {
89            Self::Owned(points) => points.capacity(),
90            Self::Shared { .. } => 0,
91        }
92    }
93
94    /// The points, to edit; a shared range becomes an owned copy first.
95    pub fn to_mut(&mut self) -> &mut Vec<G> {
96        if let Self::Shared { .. } = self {
97            *self = Self::Owned(self.to_vec());
98        }
99        match self {
100            Self::Owned(points) => points,
101            Self::Shared { .. } => unreachable!("made owned above"),
102        }
103    }
104}
105
106/// Written as a `Vec` of the points is, so a key's bytes and hash don't depend
107/// on whether it shares them.
108impl<G: ToBytes> ToBytes for Bases<G> {
109    fn write_le<W: Write>(&self, writer: W) -> io::Result<()> {
110        (&**self).write_le(writer)
111    }
112}
113
114impl<G> From<Vec<G>> for Bases<G> {
115    fn from(points: Vec<G>) -> Self {
116        Self::Owned(points)
117    }
118}
119
120/// `CommitterKey` is used to commit to, and create evaluation proofs for, a
121/// given polynomial.
122#[derive(Debug)]
123pub struct CommitterKey<E: PairingEngine> {
124    /// The key used to commit to polynomials.
125    pub powers_of_beta_g: Bases<E::G1Affine>,
126
127    /// The key used to commit to polynomials in Lagrange basis.
128    pub lagrange_bases_at_beta_g: BTreeMap<usize, Vec<E::G1Affine>>,
129
130    /// The key used to commit to hiding polynomials.
131    pub powers_of_beta_times_gamma_g: Vec<E::G1Affine>,
132
133    /// The powers used to commit to shifted polynomials.
134    /// This is `None` if `self` does not support enforcing any degree bounds.
135    pub shifted_powers_of_beta_g: Option<Bases<E::G1Affine>>,
136
137    /// The powers used to commit to shifted hiding polynomials.
138    /// This is `None` if `self` does not support enforcing any degree bounds.
139    pub shifted_powers_of_beta_times_gamma_g: Option<BTreeMap<usize, Vec<E::G1Affine>>>,
140
141    /// The degree bounds that are supported by `self`.
142    /// Sorted in ascending order from smallest bound to largest bound.
143    /// This is `None` if `self` does not support enforcing any degree bounds.
144    pub enforced_degree_bounds: Option<Vec<usize>>,
145}
146
147impl<E: PairingEngine> FromBytes for CommitterKey<E> {
148    fn read_le<R: Read>(mut reader: R) -> io::Result<Self> {
149        // Deserialize `powers`.
150        let powers_len: u32 = FromBytes::read_le(&mut reader)?;
151        // Ensure the number of powers is within bounds.
152        if powers_len as usize > MAX_NUM_POWERS {
153            return Err(error(format!(
154                "CommitterKey (from 'read_le') has too many points ({powers_len} > {MAX_NUM_POWERS})"
155            )));
156        }
157        let mut powers_of_beta_g = Vec::with_capacity(powers_len as usize);
158        for _ in 0..powers_len {
159            let power: E::G1Affine = FromBytes::read_le(&mut reader)?;
160            powers_of_beta_g.push(power);
161        }
162
163        // Deserialize `lagrange_basis_at_beta`.
164        let lagrange_bases_at_beta_len: u32 = FromBytes::read_le(&mut reader)?;
165        let mut lagrange_bases_at_beta_g = BTreeMap::new();
166        for _ in 0..lagrange_bases_at_beta_len {
167            let size: u32 = FromBytes::read_le(&mut reader)?;
168            let mut basis = Vec::with_capacity(size as usize);
169            for _ in 0..size {
170                let power: E::G1Affine = FromBytes::read_le(&mut reader)?;
171                basis.push(power);
172            }
173            lagrange_bases_at_beta_g.insert(size as usize, basis);
174        }
175
176        // Deserialize `powers_of_beta_times_gamma_g`.
177        let powers_of_beta_times_gamma_g_len: u32 = FromBytes::read_le(&mut reader)?;
178        let mut powers_of_beta_times_gamma_g = Vec::with_capacity(powers_of_beta_times_gamma_g_len as usize);
179        for _ in 0..powers_of_beta_times_gamma_g_len {
180            let powers_of_g: E::G1Affine = FromBytes::read_le(&mut reader)?;
181            powers_of_beta_times_gamma_g.push(powers_of_g);
182        }
183
184        // Deserialize `shifted_powers_of_beta_g`.
185        let has_shifted_powers_of_beta_g: bool = FromBytes::read_le(&mut reader)?;
186        let shifted_powers_of_beta_g = match has_shifted_powers_of_beta_g {
187            true => {
188                let shifted_powers_len: u32 = FromBytes::read_le(&mut reader)?;
189                let mut shifted_powers_of_beta_g = Vec::with_capacity(shifted_powers_len as usize);
190                for _ in 0..shifted_powers_len {
191                    let shifted_power: E::G1Affine = FromBytes::read_le(&mut reader)?;
192                    shifted_powers_of_beta_g.push(shifted_power);
193                }
194
195                Some(shifted_powers_of_beta_g)
196            }
197            false => None,
198        };
199
200        // Deserialize `shifted_powers_of_beta_times_gamma_g`.
201        let has_shifted_powers_of_beta_times_gamma_g: bool = FromBytes::read_le(&mut reader)?;
202        let shifted_powers_of_beta_times_gamma_g = match has_shifted_powers_of_beta_times_gamma_g {
203            true => {
204                let mut shifted_powers_of_beta_times_gamma_g = BTreeMap::new();
205                let shifted_powers_of_beta_times_gamma_g_num_elements: u32 = FromBytes::read_le(&mut reader)?;
206                for _ in 0..shifted_powers_of_beta_times_gamma_g_num_elements {
207                    let key: u32 = FromBytes::read_le(&mut reader)?;
208
209                    let value_len: u32 = FromBytes::read_le(&mut reader)?;
210                    let mut value = Vec::with_capacity(value_len as usize);
211                    for _ in 0..value_len {
212                        let val: E::G1Affine = FromBytes::read_le(&mut reader)?;
213                        value.push(val);
214                    }
215
216                    shifted_powers_of_beta_times_gamma_g.insert(key as usize, value);
217                }
218
219                Some(shifted_powers_of_beta_times_gamma_g)
220            }
221            false => None,
222        };
223
224        // Deserialize `enforced_degree_bounds`.
225        let has_enforced_degree_bounds: bool = FromBytes::read_le(&mut reader)?;
226        let enforced_degree_bounds = match has_enforced_degree_bounds {
227            true => {
228                let enforced_degree_bounds_len: u32 = FromBytes::read_le(&mut reader)?;
229                let mut enforced_degree_bounds = Vec::with_capacity(enforced_degree_bounds_len as usize);
230                for _ in 0..enforced_degree_bounds_len {
231                    let enforced_degree_bound: u32 = FromBytes::read_le(&mut reader)?;
232                    enforced_degree_bounds.push(enforced_degree_bound as usize);
233                }
234
235                Some(enforced_degree_bounds)
236            }
237            false => None,
238        };
239
240        // Construct the hash of the group elements.
241        let mut hash_input = powers_of_beta_g.to_bytes_le().map_err(|_| error("Could not serialize powers"))?;
242        powers_of_beta_times_gamma_g
243            .write_le(&mut hash_input)
244            .map_err(|_| error("Could not serialize powers_of_beta_times_gamma_g"))?;
245
246        if let Some(shifted_powers_of_beta_g) = &shifted_powers_of_beta_g {
247            shifted_powers_of_beta_g
248                .write_le(&mut hash_input)
249                .map_err(|_| error("Could not serialize shifted_powers_of_beta_g"))?;
250        }
251
252        if let Some(shifted_powers_of_beta_times_gamma_g) = &shifted_powers_of_beta_times_gamma_g {
253            for value in shifted_powers_of_beta_times_gamma_g.values() {
254                value.write_le(&mut hash_input).map_err(|_| error("Could not serialize shifted_power_of_gamma_g"))?;
255            }
256        }
257
258        // Deserialize `hash`.
259        let hash = sha256(&hash_input);
260        let expected_hash: [u8; 32] = FromBytes::read_le(&mut reader)?;
261
262        // Enforce the group elements construct the expected hash.
263        if expected_hash != hash {
264            return Err(error("Mismatching group elements"));
265        }
266
267        Ok(Self {
268            powers_of_beta_g: powers_of_beta_g.into(),
269            lagrange_bases_at_beta_g,
270            powers_of_beta_times_gamma_g,
271            shifted_powers_of_beta_g: shifted_powers_of_beta_g.map(Bases::from),
272            shifted_powers_of_beta_times_gamma_g,
273            enforced_degree_bounds,
274        })
275    }
276}
277
278impl<E: PairingEngine> ToBytes for CommitterKey<E> {
279    fn write_le<W: Write>(&self, mut writer: W) -> io::Result<()> {
280        // Serialize `powers`.
281        (self.powers_of_beta_g.len() as u32).write_le(&mut writer)?;
282        for power in self.powers_of_beta_g.iter() {
283            power.write_le(&mut writer)?;
284        }
285
286        // Serialize `powers`.
287        (self.lagrange_bases_at_beta_g.len() as u32).write_le(&mut writer)?;
288        for (size, powers) in &self.lagrange_bases_at_beta_g {
289            (*size as u32).write_le(&mut writer)?;
290            for power in powers {
291                power.write_le(&mut writer)?;
292            }
293        }
294
295        // Serialize `powers_of_beta_times_gamma_g`.
296        (self.powers_of_beta_times_gamma_g.len() as u32).write_le(&mut writer)?;
297        for power_of_gamma_g in &self.powers_of_beta_times_gamma_g {
298            power_of_gamma_g.write_le(&mut writer)?;
299        }
300
301        // Serialize `shifted_powers_of_beta_g`.
302        self.shifted_powers_of_beta_g.is_some().write_le(&mut writer)?;
303        if let Some(shifted_powers_of_beta_g) = &self.shifted_powers_of_beta_g {
304            (shifted_powers_of_beta_g.len() as u32).write_le(&mut writer)?;
305            for shifted_power in shifted_powers_of_beta_g.iter() {
306                shifted_power.write_le(&mut writer)?;
307            }
308        }
309
310        // Serialize `shifted_powers_of_beta_times_gamma_g`.
311        self.shifted_powers_of_beta_times_gamma_g.is_some().write_le(&mut writer)?;
312        if let Some(shifted_powers_of_beta_times_gamma_g) = &self.shifted_powers_of_beta_times_gamma_g {
313            (shifted_powers_of_beta_times_gamma_g.len() as u32).write_le(&mut writer)?;
314            for (key, shifted_powers_of_beta_g) in shifted_powers_of_beta_times_gamma_g {
315                (*key as u32).write_le(&mut writer)?;
316                (shifted_powers_of_beta_g.len() as u32).write_le(&mut writer)?;
317                for shifted_power in shifted_powers_of_beta_g {
318                    shifted_power.write_le(&mut writer)?;
319                }
320            }
321        }
322
323        // Serialize `enforced_degree_bounds`.
324        self.enforced_degree_bounds.is_some().write_le(&mut writer)?;
325        if let Some(enforced_degree_bounds) = &self.enforced_degree_bounds {
326            (enforced_degree_bounds.len() as u32).write_le(&mut writer)?;
327            for enforced_degree_bound in enforced_degree_bounds {
328                (*enforced_degree_bound as u32).write_le(&mut writer)?;
329            }
330        }
331
332        // Construct the hash of the group elements.
333        let mut hash_input = self.powers_of_beta_g.to_bytes_le().map_err(|_| error("Could not serialize powers"))?;
334        self.powers_of_beta_times_gamma_g
335            .write_le(&mut hash_input)
336            .map_err(|_| error("Could not serialize powers_of_beta_times_gamma_g"))?;
337
338        if let Some(shifted_powers_of_beta_g) = &self.shifted_powers_of_beta_g {
339            shifted_powers_of_beta_g
340                .write_le(&mut hash_input)
341                .map_err(|_| error("Could not serialize shifted_powers_of_beta_g"))?;
342        }
343
344        if let Some(shifted_powers_of_beta_times_gamma_g) = &self.shifted_powers_of_beta_times_gamma_g {
345            for value in shifted_powers_of_beta_times_gamma_g.values() {
346                value.write_le(&mut hash_input).map_err(|_| error("Could not serialize shifted_power_of_gamma_g"))?;
347            }
348        }
349
350        // Serialize `hash`
351        let hash = sha256(&hash_input);
352        hash.write_le(&mut writer)
353    }
354}
355
356/// `CommitterUnionKey` is a union of `CommitterKey`s, useful for multi-circuit
357/// batch proofs.
358#[derive(Debug)]
359pub struct CommitterUnionKey<'a, E: PairingEngine> {
360    /// The key used to commit to polynomials.
361    pub powers_of_beta_g: Option<&'a [E::G1Affine]>,
362
363    /// The key used to commit to polynomials in Lagrange basis.
364    pub lagrange_bases_at_beta_g: BTreeMap<usize, &'a Vec<E::G1Affine>>,
365
366    /// The key used to commit to hiding polynomials.
367    pub powers_of_beta_times_gamma_g: Option<&'a [E::G1Affine]>,
368
369    /// The powers used to commit to shifted polynomials.
370    /// This is `None` if `self` does not support enforcing any degree bounds.
371    pub shifted_powers_of_beta_g: Option<&'a [E::G1Affine]>,
372
373    /// The powers used to commit to shifted hiding polynomials.
374    /// This is `None` if `self` does not support enforcing any degree bounds.
375    pub shifted_powers_of_beta_times_gamma_g: Option<BTreeMap<usize, &'a [E::G1Affine]>>,
376
377    /// The degree bounds that are supported by `self`.
378    /// Sorted in ascending order from smallest bound to largest bound.
379    /// This is `None` if `self` does not support enforcing any degree bounds.
380    pub enforced_degree_bounds: Option<Vec<usize>>,
381}
382
383impl<'a, E: PairingEngine> CommitterUnionKey<'a, E> {
384    /// Obtain powers for the underlying KZG10 construction
385    pub fn powers(&self) -> kzg10::Powers<'_, E> {
386        kzg10::Powers {
387            powers_of_beta_g: self.powers_of_beta_g.unwrap().into(),
388            powers_of_beta_times_gamma_g: self.powers_of_beta_times_gamma_g.unwrap().into(),
389        }
390    }
391
392    /// Obtain powers for committing to shifted polynomials.
393    pub fn shifted_powers_of_beta_g(&self, degree_bound: impl Into<Option<usize>>) -> Option<kzg10::Powers<'_, E>> {
394        match (&self.shifted_powers_of_beta_g, &self.shifted_powers_of_beta_times_gamma_g) {
395            (Some(shifted_powers_of_beta_g), Some(shifted_powers_of_beta_times_gamma_g)) => {
396                let max_bound = self.enforced_degree_bounds.as_ref().unwrap().last().unwrap();
397                let (bound, powers_range) = if let Some(degree_bound) = degree_bound.into() {
398                    assert!(self.enforced_degree_bounds.as_ref().unwrap().contains(&degree_bound));
399                    (degree_bound, (max_bound - degree_bound)..)
400                } else {
401                    (*max_bound, 0..)
402                };
403
404                let ck = kzg10::Powers {
405                    powers_of_beta_g: shifted_powers_of_beta_g[powers_range].into(),
406                    powers_of_beta_times_gamma_g: shifted_powers_of_beta_times_gamma_g[&bound].into(),
407                };
408
409                Some(ck)
410            }
411
412            (_, _) => None,
413        }
414    }
415
416    /// Obtain elements of the SRS in the lagrange basis powers, for use with
417    /// the underlying KZG10 construction.
418    pub fn lagrange_basis(&self, domain: EvaluationDomain<E::Fr>) -> Option<kzg10::LagrangeBasis<'_, E>> {
419        self.lagrange_bases_at_beta_g.get(&domain.size()).map(|basis| kzg10::LagrangeBasis {
420            lagrange_basis_at_beta_g: Cow::Borrowed(basis),
421            powers_of_beta_times_gamma_g: Cow::Borrowed(self.powers_of_beta_times_gamma_g.unwrap()),
422            domain,
423        })
424    }
425
426    pub fn union<T: IntoIterator<Item = &'a CommitterKey<E>>>(committer_keys: T) -> Self {
427        let mut ck_union = CommitterUnionKey::<E> {
428            powers_of_beta_g: None,
429            lagrange_bases_at_beta_g: BTreeMap::new(),
430            powers_of_beta_times_gamma_g: None,
431            shifted_powers_of_beta_g: None,
432            shifted_powers_of_beta_times_gamma_g: None,
433            enforced_degree_bounds: None,
434        };
435        let mut enforced_degree_bounds = vec![];
436        // Every key's arrays are cut from one SRS, whose top degree is the constant
437        // `MAX_NUM_POWERS - 1`: its prefix and hiding powers from the start, its
438        // shifted powers from the end, and each bound's shifted hiding powers from
439        // that bound's shift. So the longest of each array, across keys, contains the
440        // others, and one key need not hold the longest of all of them.
441        let mut shifted_powers_of_beta_times_gamma_g: BTreeMap<usize, &'a [E::G1Affine]> = BTreeMap::new();
442        for ck in committer_keys {
443            keep_longer(ck_union.powers_of_beta_g.get_or_insert(&ck.powers_of_beta_g), &ck.powers_of_beta_g);
444            keep_longer(
445                ck_union.powers_of_beta_times_gamma_g.get_or_insert(&ck.powers_of_beta_times_gamma_g),
446                &ck.powers_of_beta_times_gamma_g,
447            );
448            if let Some(shifted_powers) = ck.shifted_powers_of_beta_g.as_ref() {
449                keep_longer(ck_union.shifted_powers_of_beta_g.get_or_insert(shifted_powers), shifted_powers);
450            }
451            let lagrange_bases = &ck.lagrange_bases_at_beta_g;
452            for (bound_base, bases) in lagrange_bases.iter() {
453                ck_union.lagrange_bases_at_beta_g.entry(*bound_base).or_insert(bases);
454            }
455            if let Some(shifted_powers) = ck.shifted_powers_of_beta_times_gamma_g.as_ref() {
456                for (bound_power, powers) in shifted_powers.iter() {
457                    keep_longer(shifted_powers_of_beta_times_gamma_g.entry(*bound_power).or_insert(powers), powers);
458                }
459            }
460            if let Some(degree_bounds) = &ck.enforced_degree_bounds {
461                enforced_degree_bounds.extend_from_slice(degree_bounds);
462            }
463        }
464        assert!(ck_union.powers_of_beta_g.is_some(), "a union needs at least one committer key");
465
466        if !enforced_degree_bounds.is_empty() {
467            enforced_degree_bounds.sort();
468            enforced_degree_bounds.dedup();
469            // `shifted_powers_of_beta_g(bound)` slices from `max_bound - bound`, which
470            // is only right if the array starts at the largest bound's shift.
471            assert_eq!(
472                ck_union.shifted_powers_of_beta_g.map(<[_]>::len),
473                enforced_degree_bounds.last().map(|max_bound| max_bound + 1),
474                "the longest shifted powers do not start at the largest degree bound's shift"
475            );
476            ck_union.enforced_degree_bounds = Some(enforced_degree_bounds);
477            ck_union.shifted_powers_of_beta_times_gamma_g = Some(shifted_powers_of_beta_times_gamma_g);
478        }
479
480        ck_union
481    }
482}
483
484fn keep_longer<'a, T>(kept: &mut &'a [T], candidate: &'a [T]) {
485    if kept.len() < candidate.len() {
486        *kept = candidate;
487    }
488}
489
490/// Evaluation proof at a query set.
491#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, CanonicalSerialize, CanonicalDeserialize)]
492pub struct BatchProof<E: PairingEngine>(pub(crate) Vec<kzg10::KZGProof<E>>);
493
494impl<E: PairingEngine> BatchProof<E> {
495    pub fn is_hiding(&self) -> bool {
496        self.0.iter().any(|c| c.is_hiding())
497    }
498}
499
500/// Labels a `LabeledPolynomial` or a `LabeledCommitment`.
501pub type PolynomialLabel = String;
502
503/// A commitment along with information about its degree bound (if any).
504#[derive(Clone, Debug, CanonicalSerialize, PartialEq, Eq)]
505pub struct LabeledCommitment<C: CanonicalSerialize + 'static> {
506    label: PolynomialLabel,
507    commitment: C,
508    degree_bound: Option<usize>,
509}
510
511impl<F: Field, C: CanonicalSerialize + ToConstraintField<F>> ToConstraintField<F> for LabeledCommitment<C> {
512    fn to_field_elements(&self) -> Result<Vec<F>, ConstraintFieldError> {
513        self.commitment.to_field_elements()
514    }
515}
516
517// NOTE: Serializing the LabeledCommitments struct is done by serializing
518// _WITHOUT_ the labels or the degree bound. Deserialization is _NOT_ supported,
519// and you should construct the struct via the `LabeledCommitment::new` method
520// after deserializing the Commitment.
521impl<C: CanonicalSerialize + ToBytes> ToBytes for LabeledCommitment<C> {
522    fn write_le<W: Write>(&self, mut writer: W) -> io::Result<()> {
523        CanonicalSerialize::serialize_compressed(&self.commitment, &mut writer)
524            .map_err(|_| error("could not serialize struct"))
525    }
526}
527
528impl<C: CanonicalSerialize> LabeledCommitment<C> {
529    /// Instantiate a new polynomial_context.
530    pub fn new(label: PolynomialLabel, commitment: C, degree_bound: Option<usize>) -> Self {
531        Self { label, commitment, degree_bound }
532    }
533
534    pub fn new_with_info(info: &PolynomialInfo, commitment: C) -> Self {
535        Self { label: info.label().to_string(), commitment, degree_bound: info.degree_bound() }
536    }
537
538    /// Return the label for `self`.
539    pub fn label(&self) -> &str {
540        &self.label
541    }
542
543    /// Retrieve the commitment from `self`.
544    pub fn commitment(&self) -> &C {
545        &self.commitment
546    }
547
548    /// Retrieve the degree bound in `self`.
549    pub fn degree_bound(&self) -> Option<usize> {
550        self.degree_bound
551    }
552}
553
554/// A term in a linear combination.
555#[derive(Hash, Ord, PartialOrd, Clone, Eq, PartialEq)]
556pub enum LCTerm {
557    /// The constant term representing `one`.
558    One,
559    /// Label for a polynomial.
560    PolyLabel(String),
561}
562
563impl fmt::Debug for LCTerm {
564    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
565        match self {
566            LCTerm::One => write!(f, "1"),
567            LCTerm::PolyLabel(label) => write!(f, "{label}"),
568        }
569    }
570}
571
572impl LCTerm {
573    /// Returns `true` if `self == LCTerm::One`
574    #[inline]
575    pub fn is_one(&self) -> bool {
576        matches!(self, LCTerm::One)
577    }
578}
579
580impl From<PolynomialLabel> for LCTerm {
581    fn from(other: PolynomialLabel) -> Self {
582        Self::PolyLabel(other)
583    }
584}
585
586impl From<&'_ str> for LCTerm {
587    fn from(other: &str) -> Self {
588        Self::PolyLabel(other.into())
589    }
590}
591
592impl core::convert::TryInto<PolynomialLabel> for LCTerm {
593    type Error = ();
594
595    fn try_into(self) -> Result<PolynomialLabel, ()> {
596        match self {
597            Self::One => Err(()),
598            Self::PolyLabel(l) => Ok(l),
599        }
600    }
601}
602
603impl<'a> core::convert::TryInto<&'a PolynomialLabel> for &'a LCTerm {
604    type Error = ();
605
606    fn try_into(self) -> Result<&'a PolynomialLabel, ()> {
607        match self {
608            LCTerm::One => Err(()),
609            LCTerm::PolyLabel(l) => Ok(l),
610        }
611    }
612}
613
614impl<B: Borrow<String>> PartialEq<B> for LCTerm {
615    fn eq(&self, other: &B) -> bool {
616        match self {
617            Self::One => false,
618            Self::PolyLabel(l) => l == other.borrow(),
619        }
620    }
621}
622
623/// A labeled linear combinations of polynomials.
624#[derive(Clone, Debug)]
625pub struct LinearCombination<F> {
626    /// The label.
627    pub label: String,
628    /// The linear combination of `(poly_label, coeff)` pairs.
629    pub terms: BTreeMap<LCTerm, F>,
630}
631
632#[allow(clippy::or_fun_call)]
633impl<F: Field> LinearCombination<F> {
634    /// Construct an empty labeled linear combination.
635    pub fn empty(label: impl Into<String>) -> Self {
636        Self { label: label.into(), terms: BTreeMap::new() }
637    }
638
639    /// Construct a new labeled linear combination.
640    /// with the terms specified in `term`.
641    pub fn new(label: impl Into<String>, _terms: impl IntoIterator<Item = (F, impl Into<LCTerm>)>) -> Self {
642        let mut terms = BTreeMap::new();
643        for (c, l) in _terms.into_iter().map(|(c, t)| (c, t.into())) {
644            *terms.entry(l).or_insert(F::zero()) += c;
645        }
646
647        Self { label: label.into(), terms }
648    }
649
650    /// Returns the label of the linear combination.
651    pub fn label(&self) -> &str {
652        &self.label
653    }
654
655    /// Returns `true` if the linear combination has no terms.
656    pub fn is_empty(&self) -> bool {
657        self.terms.is_empty()
658    }
659
660    /// Add a term to the linear combination.
661    pub fn add(&mut self, c: F, t: impl Into<LCTerm>) -> &mut Self {
662        let t = t.into();
663        *self.terms.entry(t.clone()).or_insert(F::zero()) += c;
664        if self.terms[&t].is_zero() {
665            self.terms.remove(&t);
666        }
667        self
668    }
669
670    pub fn len(&self) -> usize {
671        self.terms.len()
672    }
673
674    pub fn iter(&self) -> impl Iterator<Item = (&F, &LCTerm)> {
675        self.terms.iter().map(|(t, c)| (c, t))
676    }
677}
678
679impl<'a, F: Field> AddAssign<(F, &'a LinearCombination<F>)> for LinearCombination<F> {
680    #[allow(clippy::suspicious_op_assign_impl)]
681    fn add_assign(&mut self, (coeff, other): (F, &'a LinearCombination<F>)) {
682        for (t, c) in other.terms.iter() {
683            self.add(coeff * c, t.clone());
684        }
685    }
686}
687
688impl<'a, F: Field> SubAssign<(F, &'a LinearCombination<F>)> for LinearCombination<F> {
689    #[allow(clippy::suspicious_op_assign_impl)]
690    fn sub_assign(&mut self, (coeff, other): (F, &'a LinearCombination<F>)) {
691        for (t, c) in other.terms.iter() {
692            self.add(-coeff * c, t.clone());
693        }
694    }
695}
696
697impl<'a, F: Field> AddAssign<&'a LinearCombination<F>> for LinearCombination<F> {
698    fn add_assign(&mut self, other: &'a LinearCombination<F>) {
699        for (t, c) in other.terms.iter() {
700            self.add(*c, t.clone());
701        }
702    }
703}
704
705impl<'a, F: Field> SubAssign<&'a LinearCombination<F>> for LinearCombination<F> {
706    fn sub_assign(&mut self, other: &'a LinearCombination<F>) {
707        for (t, &c) in other.terms.iter() {
708            self.add(-c, t.clone());
709        }
710    }
711}
712
713impl<F: Field> AddAssign<F> for LinearCombination<F> {
714    fn add_assign(&mut self, coeff: F) {
715        self.add(coeff, LCTerm::One);
716    }
717}
718
719impl<F: Field> SubAssign<F> for LinearCombination<F> {
720    fn sub_assign(&mut self, coeff: F) {
721        self.add(-coeff, LCTerm::One);
722    }
723}
724
725impl<F: Field> MulAssign<F> for LinearCombination<F> {
726    fn mul_assign(&mut self, coeff: F) {
727        self.terms.values_mut().for_each(|c| *c *= &coeff);
728    }
729}
730
731/// `QuerySet` is the set of queries that are to be made to a set of labeled
732/// polynomials/equations `p` that have previously been committed to. Each
733/// element of a `QuerySet` is a `(label, query)` pair, where `label` is the
734/// label of a polynomial in `p`, and `query` is the field element
735/// that `p[label]` is to be queried at.
736///
737/// Added the third field: the point name.
738pub type QuerySet<T> = BTreeSet<(String, (String, T))>;
739
740/// `Evaluations` is the result of querying a set of labeled polynomials or
741/// equations `p` at a `QuerySet` `Q`. It maps each element of `Q` to the
742/// resulting evaluation. That is, if `(label, query)` is an element of `Q`,
743/// then `evaluation.get((label, query))` should equal
744/// `p[label].evaluate(query)`.
745pub type Evaluations<F> = BTreeMap<(String, F), F>;
746
747/// Evaluate the given polynomials at `query_set`.
748pub fn evaluate_query_set<'a, F: PrimeField>(
749    polys: impl IntoIterator<Item = &'a LabeledPolynomial<F>>,
750    query_set: &QuerySet<F>,
751) -> Evaluations<F> {
752    let polys: HashMap<_, _> = polys.into_iter().map(|p| (p.label(), p)).collect();
753    let mut evaluations = Evaluations::new();
754    for (label, (_point_name, point)) in query_set {
755        let poly = polys.get(label as &str).expect("polynomial in evaluated lc is not found");
756        let eval = poly.evaluate(*point);
757        evaluations.insert((label.clone(), *point), eval);
758    }
759    evaluations
760}
761
762/// A proof of satisfaction of linear combinations.
763#[derive(Clone, Debug, PartialEq, Eq, CanonicalSerialize, CanonicalDeserialize)]
764pub struct BatchLCProof<E: PairingEngine> {
765    /// Evaluation proof.
766    pub proof: BatchProof<E>,
767}
768
769impl<E: PairingEngine> BatchLCProof<E> {
770    pub fn is_hiding(&self) -> bool {
771        self.proof.is_hiding()
772    }
773}
774
775impl<E: PairingEngine> FromBytes for BatchLCProof<E> {
776    fn read_le<R: Read>(mut reader: R) -> io::Result<Self> {
777        CanonicalDeserialize::deserialize_compressed(&mut reader)
778            .map_err(|err| into_io_error(anyhow::Error::from(err).context("could not deserialize struct")))
779    }
780
781    fn read_le_unchecked<R: Read>(mut reader: R) -> io::Result<Self> {
782        CanonicalDeserialize::deserialize_compressed_unchecked(&mut reader)
783            .map_err(|err| into_io_error(anyhow::Error::from(err).context("could not deserialize struct")))
784    }
785}
786
787impl<E: PairingEngine> ToBytes for BatchLCProof<E> {
788    fn write_le<W: Write>(&self, mut writer: W) -> io::Result<()> {
789        CanonicalSerialize::serialize_compressed(self, &mut writer)
790            .map_err(|err| into_io_error(anyhow::Error::from(err).context("could not serialize struct")))
791    }
792}