1use 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
33pub type UniversalParams<E> = kzg10::UniversalParams<E>;
35
36pub type Randomness<E> = kzg10::KZGRandomness<E>;
38
39pub type Commitment<E> = kzg10::KZGCommitment<E>;
41
42#[derive(Clone)]
46pub enum Bases<G> {
47 Owned(Vec<G>),
48 Shared { store: Arc<Vec<G>>, range: Range<usize> },
49}
50
51impl<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 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 pub fn owned_capacity(&self) -> usize {
88 match self {
89 Self::Owned(points) => points.capacity(),
90 Self::Shared { .. } => 0,
91 }
92 }
93
94 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
106impl<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#[derive(Debug)]
123pub struct CommitterKey<E: PairingEngine> {
124 pub powers_of_beta_g: Bases<E::G1Affine>,
126
127 pub lagrange_bases_at_beta_g: BTreeMap<usize, Vec<E::G1Affine>>,
129
130 pub powers_of_beta_times_gamma_g: Vec<E::G1Affine>,
132
133 pub shifted_powers_of_beta_g: Option<Bases<E::G1Affine>>,
136
137 pub shifted_powers_of_beta_times_gamma_g: Option<BTreeMap<usize, Vec<E::G1Affine>>>,
140
141 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 let powers_len: u32 = FromBytes::read_le(&mut reader)?;
151 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 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 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 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 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 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 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 let hash = sha256(&hash_input);
260 let expected_hash: [u8; 32] = FromBytes::read_le(&mut reader)?;
261
262 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 (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 (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 (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 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 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 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 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 let hash = sha256(&hash_input);
352 hash.write_le(&mut writer)
353 }
354}
355
356#[derive(Debug)]
359pub struct CommitterUnionKey<'a, E: PairingEngine> {
360 pub powers_of_beta_g: Option<&'a [E::G1Affine]>,
362
363 pub lagrange_bases_at_beta_g: BTreeMap<usize, &'a Vec<E::G1Affine>>,
365
366 pub powers_of_beta_times_gamma_g: Option<&'a [E::G1Affine]>,
368
369 pub shifted_powers_of_beta_g: Option<&'a [E::G1Affine]>,
372
373 pub shifted_powers_of_beta_times_gamma_g: Option<BTreeMap<usize, &'a [E::G1Affine]>>,
376
377 pub enforced_degree_bounds: Option<Vec<usize>>,
381}
382
383impl<'a, E: PairingEngine> CommitterUnionKey<'a, E> {
384 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 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(°ree_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 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 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 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#[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
500pub type PolynomialLabel = String;
502
503#[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
517impl<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 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 pub fn label(&self) -> &str {
540 &self.label
541 }
542
543 pub fn commitment(&self) -> &C {
545 &self.commitment
546 }
547
548 pub fn degree_bound(&self) -> Option<usize> {
550 self.degree_bound
551 }
552}
553
554#[derive(Hash, Ord, PartialOrd, Clone, Eq, PartialEq)]
556pub enum LCTerm {
557 One,
559 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 #[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#[derive(Clone, Debug)]
625pub struct LinearCombination<F> {
626 pub label: String,
628 pub terms: BTreeMap<LCTerm, F>,
630}
631
632#[allow(clippy::or_fun_call)]
633impl<F: Field> LinearCombination<F> {
634 pub fn empty(label: impl Into<String>) -> Self {
636 Self { label: label.into(), terms: BTreeMap::new() }
637 }
638
639 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 pub fn label(&self) -> &str {
652 &self.label
653 }
654
655 pub fn is_empty(&self) -> bool {
657 self.terms.is_empty()
658 }
659
660 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
731pub type QuerySet<T> = BTreeSet<(String, (String, T))>;
739
740pub type Evaluations<F> = BTreeMap<(String, F), F>;
746
747pub 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#[derive(Clone, Debug, PartialEq, Eq, CanonicalSerialize, CanonicalDeserialize)]
764pub struct BatchLCProof<E: PairingEngine> {
765 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}