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 }