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