/ algorithms / src / polycommit / kzg10 / data_structures.rs
data_structures.rs
  1  // Copyright (c) 2025-2026 ACDC Network
  2  // This file is part of the alphavm library.
  3  //
  4  // Alpha Chain | Delta Chain Protocol
  5  // International Monetary Graphite.
  6  //
  7  // Derived from Aleo (https://aleo.org) and ProvableHQ (https://provable.com).
  8  // They built world-class ZK infrastructure. We installed the EASY button.
  9  // Their cryptography: elegant. Our modifications: bureaucracy-compatible.
 10  // Original brilliance: theirs. Robert's Rules: ours. Bugs: definitely ours.
 11  //
 12  // Original Aleo/ProvableHQ code subject to Apache 2.0 https://www.apache.org/licenses/LICENSE-2.0
 13  // All modifications and new work: CC0 1.0 Universal Public Domain Dedication.
 14  // No rights reserved. No permission required. No warranty. No refunds.
 15  //
 16  // https://creativecommons.org/publicdomain/zero/1.0/
 17  // SPDX-License-Identifier: CC0-1.0
 18  
 19  use crate::{
 20      fft::{DensePolynomial, EvaluationDomain},
 21      AlgebraicSponge,
 22  };
 23  use alphavm_curves::{AffineCurve, PairingCurve, PairingEngine, ProjectiveCurve};
 24  use alphavm_fields::{ConstraintFieldError, ToConstraintField, Zero};
 25  use alphavm_parameters::mainnet::PowersOfG;
 26  use alphavm_utilities::{
 27      error,
 28      into_io_error,
 29      serialize::{CanonicalDeserialize, CanonicalSerialize, Compress, SerializationError, Valid, Validate},
 30      FromBytes,
 31      ToBytes,
 32  };
 33  
 34  use crate::srs::{UniversalProver, UniversalVerifier};
 35  use anyhow::Result;
 36  use core::ops::{Add, AddAssign};
 37  use rand::RngCore;
 38  use std::{
 39      borrow::Cow,
 40      collections::BTreeMap,
 41      io,
 42      io::{Read, Write},
 43      ops::Range,
 44      sync::Arc,
 45  };
 46  
 47  /// `UniversalParams` are the universal parameters for the KZG10 scheme.
 48  #[derive(Clone, Debug)]
 49  pub struct UniversalParams<E: PairingEngine> {
 50      /// Group elements of the form `{ \beta^i G }`, where `i` ranges from 0 to
 51      /// `degree`, and group elements of the form `{ \beta^i \gamma G }`,
 52      /// where `i` ranges from 0 to `degree`. This struct provides an
 53      /// abstraction over the powers which are located on-disk
 54      /// to reduce memory usage.
 55      powers: Arc<PowersOfG<E>>,
 56      /// The generator of G2.
 57      pub h: E::G2Affine,
 58      /// The generator of G2, prepared for use in pairings.
 59      pub prepared_h: <E::G2Affine as PairingCurve>::Prepared,
 60      /// \beta times the above generator of G2, prepared for use in pairings.
 61      pub prepared_beta_h: <E::G2Affine as PairingCurve>::Prepared,
 62  }
 63  
 64  impl<E: PairingEngine> UniversalParams<E> {
 65      pub fn load() -> Result<Self> {
 66          let powers = Arc::new(PowersOfG::<E>::load()?);
 67          let h = E::G2Affine::prime_subgroup_generator();
 68          let prepared_h = h.prepare();
 69          let prepared_beta_h = powers.beta_h().prepare();
 70  
 71          Ok(Self { powers, h, prepared_h, prepared_beta_h })
 72      }
 73  
 74      pub fn download_powers_for(&self, range: Range<usize>) -> Result<()> {
 75          self.powers.download_powers_for(range)
 76      }
 77  
 78      pub fn lagrange_basis(&self, domain: EvaluationDomain<E::Fr>) -> Result<Vec<E::G1Affine>> {
 79          let basis = domain
 80              .ifft(&self.powers_of_beta_g(0, domain.size())?.iter().map(|e| (*e).to_projective()).collect::<Vec<_>>());
 81          Ok(E::G1Projective::batch_normalization_into_affine(basis))
 82      }
 83  
 84      pub fn power_of_beta_g(&self, index: usize) -> Result<E::G1Affine> {
 85          self.powers.power_of_beta_g(index)
 86      }
 87  
 88      pub fn powers_of_beta_g(&self, lower: usize, upper: usize) -> Result<Vec<E::G1Affine>> {
 89          self.powers.powers_of_beta_g(lower..upper)
 90      }
 91  
 92      pub fn powers_of_beta_times_gamma_g(&self) -> &BTreeMap<usize, E::G1Affine> {
 93          self.powers.powers_of_beta_gamma_g()
 94      }
 95  
 96      pub fn beta_h(&self) -> E::G2Affine {
 97          self.powers.beta_h()
 98      }
 99  
100      pub fn max_degree(&self) -> usize {
101          self.powers.max_num_powers() - 1
102      }
103  
104      pub fn to_universal_prover(&self) -> Result<UniversalProver<E>> {
105          Ok(UniversalProver::<E> { max_degree: self.max_degree(), _unused: None })
106      }
107  
108      pub fn to_universal_verifier(&self) -> Result<UniversalVerifier<E>> {
109          let g = self.power_of_beta_g(0)?;
110          let h = self.h;
111          let beta_h = self.beta_h();
112          let gamma_g = self.powers_of_beta_times_gamma_g()[&0];
113          let prepared_h = self.prepared_h.clone();
114          let prepared_beta_h = self.prepared_beta_h.clone();
115  
116          Ok(UniversalVerifier {
117              vk: VerifierKey::<E> { g, gamma_g, h, beta_h, prepared_h, prepared_beta_h },
118              prepared_negative_powers_of_beta_h: self.powers.prepared_negative_powers_of_beta_h(),
119          })
120      }
121  }
122  
123  impl<E: PairingEngine> FromBytes for UniversalParams<E> {
124      fn read_le<R: Read>(mut reader: R) -> io::Result<Self> {
125          // Deserialize `powers`.
126          let powers = Arc::new(PowersOfG::read_le(&mut reader)?);
127  
128          // Deserialize `h`.
129          let h: E::G2Affine = FromBytes::read_le(&mut reader)?;
130  
131          // Deserialize `prepared_h`.
132          let prepared_h: <E::G2Affine as PairingCurve>::Prepared = FromBytes::read_le(&mut reader)?;
133  
134          // Deserialize `prepared_beta_h`.
135          let prepared_beta_h: <E::G2Affine as PairingCurve>::Prepared = FromBytes::read_le(&mut reader)?;
136  
137          Ok(Self { powers, h, prepared_h, prepared_beta_h })
138      }
139  }
140  
141  impl<E: PairingEngine> ToBytes for UniversalParams<E> {
142      fn write_le<W: Write>(&self, mut writer: W) -> io::Result<()> {
143          // Serialize powers.
144          self.powers.write_le(&mut writer)?;
145  
146          // Serialize `h`.
147          self.h.write_le(&mut writer)?;
148  
149          // Serialize `prepared_h`.
150          self.prepared_h.write_le(&mut writer)?;
151  
152          // Serialize `prepared_beta_h`.
153          self.prepared_beta_h.write_le(&mut writer)?;
154  
155          Ok(())
156      }
157  }
158  
159  /// `Powers` is used to commit to and create evaluation proofs for a given
160  /// polynomial.
161  #[derive(Clone, Debug, Default, Hash)]
162  pub struct Powers<'a, E: PairingEngine> {
163      /// Group elements of the form `β^i G`, for different values of `i`.
164      pub powers_of_beta_g: Cow<'a, [E::G1Affine]>,
165      /// Group elements of the form `β^i γG`, for different values of `i`.
166      pub powers_of_beta_times_gamma_g: Cow<'a, [E::G1Affine]>,
167  }
168  
169  impl<E: PairingEngine> Powers<'_, E> {
170      /// The number of powers in `self`.
171      pub fn size(&self) -> usize {
172          self.powers_of_beta_g.len()
173      }
174  }
175  /// `LagrangeBasis` is used to commit to and create evaluation proofs for a
176  /// given polynomial.
177  #[derive(Clone, Debug, Hash)]
178  pub struct LagrangeBasis<'a, E: PairingEngine> {
179      /// Group elements of the form `β^i G`, for different values of `i`.
180      pub lagrange_basis_at_beta_g: Cow<'a, [E::G1Affine]>,
181      /// Group elements of the form `β^i γG`, for different values of `i`.
182      pub powers_of_beta_times_gamma_g: Cow<'a, [E::G1Affine]>,
183      /// Domain representing the multiplicative subgroup the powers
184      /// in `self.lagrange_basis_at_beta_g` are defined over.
185      pub domain: EvaluationDomain<E::Fr>,
186  }
187  
188  impl<E: PairingEngine> LagrangeBasis<'_, E> {
189      /// The number of powers in `self`.
190      pub fn size(&self) -> usize {
191          self.lagrange_basis_at_beta_g.len()
192      }
193  }
194  
195  /// `VerifierKey` is used to check evaluation proofs for a given commitment.
196  #[derive(Clone, Debug, Default, PartialEq, Eq)]
197  pub struct VerifierKey<E: PairingEngine> {
198      /// The generator of G1.
199      pub g: E::G1Affine,
200      /// The generator of G1 that is used for making a commitment hiding.
201      pub gamma_g: E::G1Affine,
202      /// The generator of G2.
203      pub h: E::G2Affine,
204      /// \beta times the above generator of G2.
205      pub beta_h: E::G2Affine,
206      /// The generator of G2, prepared for use in pairings.
207      pub prepared_h: <E::G2Affine as PairingCurve>::Prepared,
208      /// \beta times the above generator of G2, prepared for use in pairings.
209      pub prepared_beta_h: <E::G2Affine as PairingCurve>::Prepared,
210  }
211  
212  impl<E: PairingEngine> CanonicalSerialize for VerifierKey<E> {
213      fn serialize_with_mode<W: Write>(&self, mut writer: W, compress: Compress) -> Result<(), SerializationError> {
214          self.g.serialize_with_mode(&mut writer, compress)?;
215          self.gamma_g.serialize_with_mode(&mut writer, compress)?;
216          self.h.serialize_with_mode(&mut writer, compress)?;
217          self.beta_h.serialize_with_mode(&mut writer, compress)?;
218          Ok(())
219      }
220  
221      fn serialized_size(&self, compress: Compress) -> usize {
222          self.g.serialized_size(compress)
223              + self.gamma_g.serialized_size(compress)
224              + self.h.serialized_size(compress)
225              + self.beta_h.serialized_size(compress)
226      }
227  }
228  
229  impl<E: PairingEngine> CanonicalDeserialize for VerifierKey<E> {
230      fn deserialize_with_mode<R: Read>(
231          mut reader: R,
232          compress: Compress,
233          validate: Validate,
234      ) -> Result<Self, SerializationError> {
235          let g = CanonicalDeserialize::deserialize_with_mode(&mut reader, compress, validate)?;
236          let gamma_g = CanonicalDeserialize::deserialize_with_mode(&mut reader, compress, validate)?;
237          let h: E::G2Affine = CanonicalDeserialize::deserialize_with_mode(&mut reader, compress, validate)?;
238          let beta_h: E::G2Affine = CanonicalDeserialize::deserialize_with_mode(&mut reader, compress, validate)?;
239          let prepared_h = h.prepare();
240          let prepared_beta_h = beta_h.prepare();
241          Ok(VerifierKey { g, gamma_g, h, beta_h, prepared_h, prepared_beta_h })
242      }
243  }
244  
245  impl<E: PairingEngine> Valid for VerifierKey<E> {
246      fn check(&self) -> Result<(), SerializationError> {
247          Valid::check(&self.g)?;
248          Valid::check(&self.gamma_g)?;
249          Valid::check(&self.h)?;
250          Valid::check(&self.beta_h)?;
251          Ok(())
252      }
253  
254      fn batch_check<'a>(batch: impl Iterator<Item = &'a Self> + Send) -> Result<(), SerializationError>
255      where
256          Self: 'a,
257      {
258          let batch: Vec<_> = batch.collect();
259          Valid::batch_check(batch.iter().map(|v| &v.g))?;
260          Valid::batch_check(batch.iter().map(|v| &v.gamma_g))?;
261          Valid::batch_check(batch.iter().map(|v| &v.h))?;
262          Valid::batch_check(batch.iter().map(|v| &v.beta_h))?;
263          Ok(())
264      }
265  }
266  
267  impl<E: PairingEngine> FromBytes for VerifierKey<E> {
268      fn read_le<R: Read>(mut reader: R) -> io::Result<Self> {
269          CanonicalDeserialize::deserialize_compressed(&mut reader)
270              .map_err(|_| error("could not deserialize VerifierKey"))
271      }
272  }
273  
274  impl<E: PairingEngine> ToBytes for VerifierKey<E> {
275      fn write_le<W: Write>(&self, mut writer: W) -> io::Result<()> {
276          CanonicalSerialize::serialize_compressed(self, &mut writer)
277              .map_err(|_| error("could not serialize VerifierKey"))
278      }
279  }
280  
281  /// `KZGCommitment` commits to a polynomial. It is output by `KZG10::commit`.
282  #[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash, CanonicalSerialize, CanonicalDeserialize)]
283  pub struct KZGCommitment<E: PairingEngine>(
284      /// The commitment is a group element.
285      pub E::G1Affine,
286  );
287  
288  impl<E: PairingEngine> FromBytes for KZGCommitment<E> {
289      fn read_le<R: Read>(mut reader: R) -> io::Result<Self> {
290          CanonicalDeserialize::deserialize_compressed(&mut reader)
291              .map_err(|_| error("could not deserialize KZGCommitment"))
292      }
293  }
294  
295  impl<E: PairingEngine> ToBytes for KZGCommitment<E> {
296      fn write_le<W: Write>(&self, mut writer: W) -> io::Result<()> {
297          CanonicalSerialize::serialize_compressed(self, &mut writer)
298              .map_err(|_| error("could not serialize KZGCommitment"))
299      }
300  }
301  
302  impl<E: PairingEngine> KZGCommitment<E> {
303      #[inline]
304      pub fn empty() -> Self {
305          KZGCommitment(E::G1Affine::zero())
306      }
307  
308      pub fn has_degree_bound(&self) -> bool {
309          false
310      }
311  
312      pub fn is_in_correct_subgroup_assuming_on_curve(&self) -> bool {
313          self.0.is_in_correct_subgroup_assuming_on_curve()
314      }
315  }
316  
317  impl<E: PairingEngine> ToConstraintField<E::Fq> for KZGCommitment<E> {
318      fn to_field_elements(&self) -> Result<Vec<E::Fq>, ConstraintFieldError> {
319          self.0.to_field_elements()
320      }
321  }
322  
323  /// `KZGRandomness` hides the polynomial inside a commitment. It is output by
324  /// `KZG10::commit`.
325  #[derive(Clone, Debug, Default, PartialEq, Eq, Hash, CanonicalSerialize, CanonicalDeserialize)]
326  pub struct KZGRandomness<E: PairingEngine> {
327      /// For KZG10, the commitment randomness is a random polynomial.
328      pub blinding_polynomial: DensePolynomial<E::Fr>,
329  }
330  impl<E: PairingEngine> FromBytes for KZGRandomness<E> {
331      fn read_le<R: Read>(mut reader: R) -> io::Result<Self> {
332          CanonicalDeserialize::deserialize_compressed(&mut reader)
333              .map_err(|_| error("could not deserialize KZGRandomness"))
334      }
335  }
336  
337  impl<E: PairingEngine> ToBytes for KZGRandomness<E> {
338      fn write_le<W: Write>(&self, mut writer: W) -> io::Result<()> {
339          CanonicalSerialize::serialize_compressed(self, &mut writer)
340              .map_err(|_| error("could not serialize KZGRandomness"))
341      }
342  }
343  
344  impl<E: PairingEngine> KZGRandomness<E> {
345      /// Does `self` provide any hiding properties to the corresponding
346      /// commitment? `self.is_hiding() == true` only if the underlying
347      /// polynomial is non-zero.
348      #[inline]
349      pub fn is_hiding(&self) -> bool {
350          !self.blinding_polynomial.is_zero()
351      }
352  
353      /// What is the degree of the hiding polynomial for a given hiding bound?
354      #[inline]
355      pub fn calculate_hiding_polynomial_degree(hiding_bound: usize) -> usize {
356          hiding_bound + 1
357      }
358  }
359  
360  impl<E: PairingEngine> KZGRandomness<E> {
361      pub fn empty() -> Self {
362          Self { blinding_polynomial: DensePolynomial::zero() }
363      }
364  
365      pub fn rand<R: RngCore>(hiding_bound: usize, _: bool, rng: &mut R) -> Self {
366          let mut randomness = KZGRandomness::empty();
367          let hiding_poly_degree = Self::calculate_hiding_polynomial_degree(hiding_bound);
368          randomness.blinding_polynomial = DensePolynomial::rand(hiding_poly_degree, rng);
369          randomness
370      }
371  }
372  
373  impl<'a, E: PairingEngine> Add<&'a KZGRandomness<E>> for KZGRandomness<E> {
374      type Output = Self;
375  
376      #[inline]
377      fn add(mut self, other: &'a Self) -> Self {
378          self.blinding_polynomial += &other.blinding_polynomial;
379          self
380      }
381  }
382  
383  impl<'a, E: PairingEngine> Add<(E::Fr, &'a KZGRandomness<E>)> for KZGRandomness<E> {
384      type Output = Self;
385  
386      #[inline]
387      fn add(mut self, other: (E::Fr, &'a KZGRandomness<E>)) -> Self {
388          self += other;
389          self
390      }
391  }
392  
393  impl<'a, E: PairingEngine> AddAssign<&'a KZGRandomness<E>> for KZGRandomness<E> {
394      #[inline]
395      fn add_assign(&mut self, other: &'a Self) {
396          self.blinding_polynomial += &other.blinding_polynomial;
397      }
398  }
399  
400  impl<'a, E: PairingEngine> AddAssign<(E::Fr, &'a KZGRandomness<E>)> for KZGRandomness<E> {
401      #[inline]
402      fn add_assign(&mut self, (f, other): (E::Fr, &'a KZGRandomness<E>)) {
403          self.blinding_polynomial += (f, &other.blinding_polynomial);
404      }
405  }
406  
407  /// `KZGProof` is an evaluation proof that is output by `KZG10::open`.
408  #[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash, CanonicalSerialize, CanonicalDeserialize)]
409  pub struct KZGProof<E: PairingEngine> {
410      /// This is a commitment to the witness polynomial; see [\[KZG10\]][kzg] for
411      /// more details.
412      ///
413      /// [kzg]: http://cacr.uwaterloo.ca/techreports/2010/cacr2010-10.pdf
414      pub w: E::G1Affine,
415      /// This is the evaluation of the random polynomial at the point for which
416      /// the evaluation proof was produced.
417      pub random_v: Option<E::Fr>,
418  }
419  
420  impl<E: PairingEngine> KZGProof<E> {
421      pub fn absorb_into_sponge(&self, sponge: &mut impl AlgebraicSponge<E::Fq, 2>) {
422          sponge.absorb_native_field_elements(&self.w.to_field_elements().unwrap());
423          if let Some(random_v) = self.random_v {
424              sponge.absorb_nonnative_field_elements([random_v]);
425          }
426      }
427  }
428  
429  impl<E: PairingEngine> FromBytes for KZGProof<E> {
430      fn read_le<R: Read>(mut reader: R) -> io::Result<Self> {
431          CanonicalDeserialize::deserialize_compressed(&mut reader)
432              .map_err(|err| into_io_error(anyhow::Error::from(err).context("could not deserialize KZG proof")))
433      }
434  }
435  
436  impl<E: PairingEngine> ToBytes for KZGProof<E> {
437      fn write_le<W: Write>(&self, mut writer: W) -> io::Result<()> {
438          CanonicalSerialize::serialize_compressed(self, &mut writer)
439              .map_err(|err| into_io_error(anyhow::Error::from(err).context("could not serialize KZG proof")))
440      }
441  }
442  
443  impl<E: PairingEngine> KZGProof<E> {
444      pub fn is_hiding(&self) -> bool {
445          self.random_v.is_some()
446      }
447  }