/ parameters / src / mainnet / powers.rs
powers.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::*;
 20  use alphavm_curves::traits::{PairingCurve, PairingEngine};
 21  use alphavm_utilities::{
 22      dev_println,
 23      CanonicalDeserialize,
 24      CanonicalSerialize,
 25      Compress,
 26      FromBytes,
 27      Read,
 28      SerializationError,
 29      ToBytes,
 30      Valid,
 31      Validate,
 32      Write,
 33  };
 34  
 35  use anyhow::{anyhow, bail, ensure, Result};
 36  #[cfg(feature = "locktick")]
 37  use locktick::parking_lot::RwLock;
 38  #[cfg(not(feature = "locktick"))]
 39  use parking_lot::RwLock;
 40  use std::{collections::BTreeMap, ops::Range, sync::Arc};
 41  
 42  const NUM_POWERS_15: usize = 1 << 15;
 43  const NUM_POWERS_16: usize = 1 << 16;
 44  const NUM_POWERS_17: usize = 1 << 17;
 45  const NUM_POWERS_18: usize = 1 << 18;
 46  const NUM_POWERS_19: usize = 1 << 19;
 47  const NUM_POWERS_20: usize = 1 << 20;
 48  const NUM_POWERS_21: usize = 1 << 21;
 49  const NUM_POWERS_22: usize = 1 << 22;
 50  const NUM_POWERS_23: usize = 1 << 23;
 51  const NUM_POWERS_24: usize = 1 << 24;
 52  const NUM_POWERS_25: usize = 1 << 25;
 53  // TODO(ACDC): Powers 26-27 (64M/128M elements) disabled in CI for performance.
 54  // Trade-off: Enabling `large_params` feature would add ~10-30min CI time and require 16GB+ RAM.
 55  // These powers are only needed for very large circuits not currently in use.
 56  // To test: `cargo test --features large_params` (locally, not CI).
 57  #[cfg(feature = "large_params")]
 58  const NUM_POWERS_26: usize = 1 << 26;
 59  #[cfg(feature = "large_params")]
 60  const NUM_POWERS_27: usize = 1 << 27;
 61  const NUM_POWERS_28: usize = 1 << 28;
 62  
 63  /// The maximum degree supported by the SRS.
 64  pub const MAX_NUM_POWERS: usize = NUM_POWERS_28;
 65  
 66  lazy_static::lazy_static! {
 67      static ref POWERS_OF_BETA_G_15: Vec<u8> = Degree15::load_bytes().expect("Failed to load powers of beta in universal SRS");
 68      static ref SHIFTED_POWERS_OF_BETA_G_15: Vec<u8> = ShiftedDegree15::load_bytes().expect("Failed to load powers of beta in universal SRS");
 69      static ref POWERS_OF_BETA_GAMMA_G: Vec<u8> = Gamma::load_bytes().expect("Failed to load powers of beta wrt gamma * G in universal SRS");
 70      static ref NEG_POWERS_OF_BETA_H: Vec<u8> = NegBeta::load_bytes().expect("Failed to load negative powers of beta in universal SRS");
 71      static ref BETA_H: Vec<u8> = BetaH::load_bytes().expect("Failed to load negative powers of beta in universal SRS");
 72  }
 73  
 74  /// A vector of powers of beta G.
 75  #[derive(Debug)]
 76  pub struct PowersOfG<E: PairingEngine> {
 77      /// The powers of beta G.
 78      powers_of_beta_g: RwLock<PowersOfBetaG<E>>,
 79      /// Group elements of form `{ \beta^i \gamma G }`, where `i` is from 0 to `degree`,
 80      /// This is used for hiding.
 81      powers_of_beta_times_gamma_g: BTreeMap<usize, E::G1Affine>,
 82      /// Group elements of form `{ \beta^{max_degree - i} H }`, where `i`
 83      /// is of the form `2^k - 1` for `k` in `1` to `log_2(max_degree)`.
 84      negative_powers_of_beta_h: BTreeMap<usize, E::G2Affine>,
 85      /// Information required to enforce degree bounds. Each pair is of the form `(degree_bound, shifting_advice)`.
 86      /// Each pair is in the form `(degree_bound, \beta^{max_degree - i} H),` where `H` is the generator of G2,
 87      /// and `i` is of the form `2^k - 1` for `k` in `1` to `log_2(max_degree)`.
 88      prepared_negative_powers_of_beta_h: Arc<BTreeMap<usize, <E::G2Affine as PairingCurve>::Prepared>>,
 89      /// beta * h
 90      beta_h: E::G2Affine,
 91  }
 92  
 93  impl<E: PairingEngine> PowersOfG<E> {
 94      /// Initializes the hard-coded instance of the powers.
 95      pub fn load() -> Result<Self> {
 96          let powers_of_beta_g = RwLock::new(PowersOfBetaG::load()?);
 97  
 98          // Reconstruct powers of beta_times_gamma_g.
 99          let powers_of_beta_times_gamma_g = BTreeMap::deserialize_uncompressed_unchecked(&**POWERS_OF_BETA_GAMMA_G)?;
100  
101          // Reconstruct negative powers of beta_h.
102          let negative_powers_of_beta_h: BTreeMap<usize, E::G2Affine> =
103              BTreeMap::deserialize_uncompressed_unchecked(&**NEG_POWERS_OF_BETA_H)?;
104  
105          // Compute the prepared negative powers of beta_h.
106          let prepared_negative_powers_of_beta_h: Arc<BTreeMap<usize, <E::G2Affine as PairingCurve>::Prepared>> =
107              Arc::new(negative_powers_of_beta_h.iter().map(|(d, affine)| (*d, affine.prepare())).collect());
108  
109          let beta_h = E::G2Affine::deserialize_uncompressed_unchecked(&**BETA_H)?;
110  
111          // Return the powers.
112          Ok(Self {
113              powers_of_beta_g,
114              powers_of_beta_times_gamma_g,
115              negative_powers_of_beta_h,
116              prepared_negative_powers_of_beta_h,
117              beta_h,
118          })
119      }
120  
121      /// Download the powers of beta G specified by `range`.
122      pub fn download_powers_for(&self, range: Range<usize>) -> Result<()> {
123          self.powers_of_beta_g.write().download_powers_for(&range)
124      }
125  
126      /// Returns the number of contiguous powers of beta G starting from the 0-th power.
127      pub fn num_powers(&self) -> usize {
128          self.powers_of_beta_g.read().num_powers()
129      }
130  
131      /// Returns the maximum possible number of contiguous powers of beta G starting from the 0-th power.
132      pub fn max_num_powers(&self) -> usize {
133          MAX_NUM_POWERS
134      }
135  
136      /// Returns the powers of beta * gamma G.
137      pub fn powers_of_beta_gamma_g(&self) -> &BTreeMap<usize, E::G1Affine> {
138          &self.powers_of_beta_times_gamma_g
139      }
140  
141      /// Returns the `index`-th power of beta * G.
142      pub fn power_of_beta_g(&self, index: usize) -> Result<E::G1Affine> {
143          self.powers_of_beta_g.write().power(index)
144      }
145  
146      /// Returns the powers of `beta * G` that lie within `range`.
147      pub fn powers_of_beta_g(&self, range: Range<usize>) -> Result<Vec<E::G1Affine>> {
148          Ok(self.powers_of_beta_g.write().powers(range)?.to_vec())
149      }
150  
151      pub fn negative_powers_of_beta_h(&self) -> &BTreeMap<usize, E::G2Affine> {
152          &self.negative_powers_of_beta_h
153      }
154  
155      pub fn prepared_negative_powers_of_beta_h(&self) -> Arc<BTreeMap<usize, <E::G2Affine as PairingCurve>::Prepared>> {
156          self.prepared_negative_powers_of_beta_h.clone()
157      }
158  
159      pub fn beta_h(&self) -> E::G2Affine {
160          self.beta_h
161      }
162  }
163  
164  impl<E: PairingEngine> CanonicalSerialize for PowersOfG<E> {
165      fn serialize_with_mode<W: Write>(&self, mut writer: W, mode: Compress) -> Result<(), SerializationError> {
166          self.powers_of_beta_g.read().serialize_with_mode(&mut writer, mode)?;
167          self.powers_of_beta_times_gamma_g.serialize_with_mode(&mut writer, mode)?;
168          self.negative_powers_of_beta_h.serialize_with_mode(&mut writer, mode)?;
169          self.beta_h.serialize_with_mode(&mut writer, mode)?;
170          Ok(())
171      }
172  
173      fn serialized_size(&self, mode: Compress) -> usize {
174          self.powers_of_beta_g.read().serialized_size(mode)
175              + self.powers_of_beta_times_gamma_g.serialized_size(mode)
176              + self.negative_powers_of_beta_h.serialized_size(mode)
177              + self.beta_h.serialized_size(mode)
178      }
179  }
180  
181  impl<E: PairingEngine> CanonicalDeserialize for PowersOfG<E> {
182      fn deserialize_with_mode<R: Read>(mut reader: R, compress: Compress, validate: Validate) -> Result<Self, SerializationError> {
183          let powers_of_beta_g = RwLock::new(PowersOfBetaG::deserialize_with_mode(&mut reader, compress, Validate::No)?);
184  
185          // Reconstruct powers of beta_times_gamma_g.
186          let powers_of_beta_times_gamma_g = BTreeMap::deserialize_with_mode(&mut reader, compress, Validate::No)?;
187  
188          // Reconstruct negative powers of beta_h.
189          let negative_powers_of_beta_h: BTreeMap<usize, E::G2Affine> =
190              BTreeMap::deserialize_with_mode(&mut reader, compress, Validate::No)?;
191  
192          // Compute the prepared negative powers of beta_h.
193          let prepared_negative_powers_of_beta_h: Arc<BTreeMap<usize, <E::G2Affine as PairingCurve>::Prepared>> =
194              Arc::new(negative_powers_of_beta_h.iter().map(|(d, affine)| (*d, affine.prepare())).collect());
195  
196          let beta_h = E::G2Affine::deserialize_with_mode(&mut reader, compress, Validate::No)?;
197  
198          let powers = Self {
199              powers_of_beta_g,
200              powers_of_beta_times_gamma_g,
201              negative_powers_of_beta_h,
202              prepared_negative_powers_of_beta_h,
203              beta_h,
204          };
205          if let Validate::Yes = validate {
206              powers.check()?;
207          }
208          Ok(powers)
209      }
210  }
211  
212  impl<E: PairingEngine> Valid for PowersOfG<E> {
213      fn check(&self) -> Result<(), SerializationError> {
214          self.powers_of_beta_g.read().check()?;
215          self.powers_of_beta_times_gamma_g.check()?;
216          self.negative_powers_of_beta_h.check()?;
217          self.prepared_negative_powers_of_beta_h.check()?;
218          self.beta_h.check()
219      }
220  }
221  
222  impl<E: PairingEngine> FromBytes for PowersOfG<E> {
223      /// Reads the powers from the buffer.
224      fn read_le<R: Read>(reader: R) -> std::io::Result<Self> {
225          Self::deserialize_with_mode(reader, Compress::No, Validate::No).map_err(|e| e.into())
226      }
227  }
228  
229  impl<E: PairingEngine> ToBytes for PowersOfG<E> {
230      /// Writes the powers to the buffer.
231      fn write_le<W: Write>(&self, writer: W) -> std::io::Result<()> {
232          self.serialize_with_mode(writer, Compress::No).map_err(|e| e.into())
233      }
234  }
235  
236  #[derive(Debug, CanonicalSerialize, CanonicalDeserialize)]
237  pub struct PowersOfBetaG<E: PairingEngine> {
238      /// Group elements of form `[G, \beta * G, \beta^2 * G, ..., \beta^d G]`.
239      powers_of_beta_g: Vec<E::G1Affine>,
240      /// Group elements of form `[\beta^i * G, \beta^2 * G, ..., \beta^D G]`.
241      /// where D is the maximum degree supported by the SRS.
242      shifted_powers_of_beta_g: Vec<E::G1Affine>,
243  }
244  
245  impl<E: PairingEngine> PowersOfBetaG<E> {
246      /// Returns the number of contiguous powers of beta G starting from the 0-th power.
247      pub fn num_powers(&self) -> usize {
248          self.powers_of_beta_g.len()
249      }
250  
251      /// Initializes the hard-coded instance of the powers.
252      fn load() -> Result<Self> {
253          // Deserialize the group elements.
254          let powers_of_beta_g = Vec::deserialize_uncompressed_unchecked(&**POWERS_OF_BETA_G_15)?;
255  
256          // Ensure the number of elements is correct.
257          ensure!(powers_of_beta_g.len() == NUM_POWERS_15, "Incorrect number of powers in the recovered SRS");
258  
259          let shifted_powers_of_beta_g = Vec::deserialize_uncompressed_unchecked(&**SHIFTED_POWERS_OF_BETA_G_15)?;
260          ensure!(shifted_powers_of_beta_g.len() == NUM_POWERS_15, "Incorrect number of powers in the recovered SRS");
261          Ok(PowersOfBetaG { powers_of_beta_g, shifted_powers_of_beta_g })
262      }
263  
264      /// Returns the range of powers of beta G.
265      /// In detail, it returns the range of the available "normal" powers of beta G, i.e. the
266      /// contiguous range of powers of beta G starting from G, and, the range of shifted_powers.
267      ///
268      /// For example, if the output of this function is `(0..8, 24..32)`, then `self`
269      /// contains the powers
270      /// * `beta^0 * G, beta^1 * G, ..., beta^7 * G`, and
271      /// * `beta^24 * G, ..., beta^31 * G`.
272      pub fn available_powers(&self) -> (Range<usize>, Range<usize>) {
273          if !self.shifted_powers_of_beta_g.is_empty() {
274              let lower_shifted_bound = MAX_NUM_POWERS - self.shifted_powers_of_beta_g.len();
275              ((0..self.powers_of_beta_g.len()), (lower_shifted_bound..MAX_NUM_POWERS))
276          } else {
277              // We can only be in this case if have downloaded all possible powers.
278              assert_eq!(self.powers_of_beta_g.len(), MAX_NUM_POWERS, "Incorrect number of powers in the recovered SRS");
279              ((0..MAX_NUM_POWERS), (0..MAX_NUM_POWERS))
280          }
281      }
282  
283      fn contains_in_normal_powers(&self, range: &Range<usize>) -> bool {
284          let (normal, _) = self.available_powers();
285          normal.contains(&range.start) && (normal.end >= range.end)
286      }
287  
288      fn contains_in_shifted_powers(&self, range: &Range<usize>) -> bool {
289          let (_, shifted) = self.available_powers();
290          shifted.contains(&range.start) && (shifted.end >= range.end)
291      }
292  
293      fn contains_powers(&self, range: &Range<usize>) -> bool {
294          self.contains_in_normal_powers(range) || self.contains_in_shifted_powers(range)
295      }
296  
297      fn distance_from_normal_of(&self, range: &Range<usize>) -> usize {
298          (range.end as isize - self.available_powers().0.end as isize).unsigned_abs()
299      }
300  
301      fn distance_from_shifted_of(&self, range: &Range<usize>) -> usize {
302          (range.start as isize - self.available_powers().1.start as isize).unsigned_abs()
303      }
304  
305      /// Assumes that we have the requisite powers.
306      fn shifted_powers(&self, range: Range<usize>) -> Result<&[E::G1Affine]> {
307          ensure!(self.contains_in_shifted_powers(&range), "Requested range is not contained in the available shifted powers");
308  
309          if range.start < MAX_NUM_POWERS / 2 {
310              ensure!(self.shifted_powers_of_beta_g.is_empty());
311              // In this case, we have downloaded all the powers, and so
312              // all the powers reside in self.powers_of_beta_g.
313              Ok(&self.powers_of_beta_g[range])
314          } else {
315              // In this case, the shifted powers still reside in self.shifted_powers_of_beta_g.
316              let lower = self.shifted_powers_of_beta_g.len() - (MAX_NUM_POWERS - range.start);
317              let upper = self.shifted_powers_of_beta_g.len() - (MAX_NUM_POWERS - range.end);
318              Ok(&self.shifted_powers_of_beta_g[lower..upper])
319          }
320      }
321  
322      /// Assumes that we have the requisite powers.
323      fn normal_powers(&self, range: Range<usize>) -> Result<&[E::G1Affine]> {
324          ensure!(self.contains_in_normal_powers(&range), "Requested range is not contained in the available powers");
325          Ok(&self.powers_of_beta_g[range])
326      }
327  
328      /// Returns the power of beta times G specified by `target`.
329      fn power(&mut self, target: usize) -> Result<E::G1Affine> {
330          self.powers(target..(target + 1)).map(|s| s[0])
331      }
332  
333      /// Slices the underlying file to return a vector of affine elements between `lower` and `upper`.
334      fn powers(&mut self, range: Range<usize>) -> Result<&[E::G1Affine]> {
335          if range.is_empty() {
336              return Ok(&self.powers_of_beta_g[0..0]);
337          }
338          ensure!(range.start < range.end, "Lower power must be less than upper power");
339          ensure!(range.end <= MAX_NUM_POWERS, "Upper bound must be less than the maximum number of powers");
340          if !self.contains_powers(&range) {
341              // We must download the powers.
342              self.download_powers_for(&range)?;
343          }
344          match self.contains_in_normal_powers(&range) {
345              true => self.normal_powers(range),
346              false => self.shifted_powers(range),
347          }
348      }
349  
350      pub fn download_powers_for(&mut self, range: &Range<usize>) -> Result<()> {
351          if self.contains_in_normal_powers(range) || self.contains_in_shifted_powers(range) {
352              return Ok(());
353          }
354          let half_max = MAX_NUM_POWERS / 2;
355          if (range.start <= half_max) && (range.end > half_max) {
356              // If the range contains the midpoint, then we must download all the powers.
357              // (because we round up to the next power of two).
358              self.download_powers_up_to(range.end)?;
359              self.shifted_powers_of_beta_g = Vec::new();
360          } else if self.distance_from_shifted_of(range) < self.distance_from_normal_of(range) {
361              // If the range is closer to the shifted powers, then we download the shifted powers.
362              self.download_shifted_powers_from(range.start)?;
363          } else {
364              // Otherwise, we download the normal powers.
365              self.download_powers_up_to(range.end)?;
366          }
367          Ok(())
368      }
369  
370      /// This method downloads the universal SRS powers up to the `next_power_of_two(target_degree)`,
371      /// and updates `Self` in place with the new powers.
372      fn download_powers_up_to(&mut self, end: usize) -> Result<()> {
373          // Determine the new power of two.
374          let final_power_of_two = end.checked_next_power_of_two().ok_or_else(|| anyhow!("Requesting too many powers"))?;
375          // Ensure the total number of powers is less than the maximum number of powers.
376          ensure!(final_power_of_two <= MAX_NUM_POWERS, "Requesting more powers than exist in the SRS");
377  
378          // Retrieve the current power of two.
379          let current_power_of_two =
380              self.powers_of_beta_g.len().checked_next_power_of_two().ok_or_else(|| anyhow!("The current degree is too large"))?;
381  
382          // Initialize a vector for the powers of two to be downloaded.
383          let mut download_queue = Vec::with_capacity(14);
384  
385          // Initialize the first degree to download.
386          let mut accumulator = current_power_of_two * 2;
387          // Determine the powers of two to download.
388          while accumulator <= final_power_of_two {
389              download_queue.push(accumulator);
390              accumulator = accumulator.checked_mul(2).ok_or_else(|| anyhow!("Overflowed while requesting a larger degree"))?;
391          }
392          ensure!(final_power_of_two * 2 == accumulator, "Ensure the loop terminates at the right power of two");
393  
394          // Reserve capacity for the new powers of two.
395          let additional_size = final_power_of_two
396              .checked_sub(self.powers_of_beta_g.len())
397              .ok_or_else(|| anyhow!("final_power_of_two is smaller than existing powers"))?;
398          self.powers_of_beta_g.reserve(additional_size);
399  
400          // Download the powers of two.
401          for num_powers in &download_queue {
402              dev_println!("Loading {num_powers} powers");
403  
404              // Download the universal SRS powers if they're not already on disk.
405              let additional_bytes = match *num_powers {
406                  NUM_POWERS_16 => Degree16::load_bytes()?,
407                  NUM_POWERS_17 => Degree17::load_bytes()?,
408                  NUM_POWERS_18 => Degree18::load_bytes()?,
409                  NUM_POWERS_19 => Degree19::load_bytes()?,
410                  NUM_POWERS_20 => Degree20::load_bytes()?,
411                  NUM_POWERS_21 => Degree21::load_bytes()?,
412                  NUM_POWERS_22 => Degree22::load_bytes()?,
413                  NUM_POWERS_23 => Degree23::load_bytes()?,
414                  NUM_POWERS_24 => Degree24::load_bytes()?,
415                  NUM_POWERS_25 => Degree25::load_bytes()?,
416                  // TODO(ACDC): Degree 26-28 gated behind large_params feature for CI performance.
417                  #[cfg(feature = "large_params")]
418                  NUM_POWERS_26 => Degree26::load_bytes()?,
419                  #[cfg(feature = "large_params")]
420                  NUM_POWERS_27 => Degree27::load_bytes()?,
421                  #[cfg(feature = "large_params")]
422                  NUM_POWERS_28 => Degree28::load_bytes()?,
423                  _ => bail!("Cannot download an invalid degree of '{num_powers}'"),
424              };
425  
426              // Deserialize the group elements.
427              let additional_powers = Vec::deserialize_uncompressed_unchecked(&*additional_bytes)?;
428              // Extend the powers.
429              self.powers_of_beta_g.extend(&additional_powers);
430          }
431          ensure!(self.powers_of_beta_g.len() == final_power_of_two, "Loaded an incorrect number of powers");
432          Ok(())
433      }
434  
435      /// This method downloads the universal SRS powers from
436      /// `start` up to `MAXIMUM_NUM_POWERS - self.shifted_powers_of_beta_g.len()`,
437      /// and updates `Self` in place with the new powers.
438      fn download_shifted_powers_from(&mut self, start: usize) -> Result<()> {
439          // Ensure the total number of powers is less than the maximum number of powers.
440          ensure!(start <= MAX_NUM_POWERS, "Requesting more powers than exist in the SRS");
441  
442          // The possible powers are:
443          // (2^28 - 2^15)..=(2^28)       = 2^15 powers
444          // (2^28 - 2^16)..(2^28 - 2^15) = 2^15 powers
445          // (2^28 - 2^17)..(2^28 - 2^16) = 2^16 powers
446          // (2^28 - 2^18)..(2^28 - 2^17) = 2^17 powers
447          // (2^28 - 2^19)..(2^28 - 2^18) = 2^18 powers
448          // (2^28 - 2^20)..(2^28 - 2^19) = 2^19 powers
449          // (2^28 - 2^21)..(2^28 - 2^20) = 2^20 powers
450          // (2^28 - 2^22)..(2^28 - 2^21) = 2^21 powers
451          // (2^28 - 2^23)..(2^28 - 2^22) = 2^22 powers
452          // (2^28 - 2^24)..(2^28 - 2^23) = 2^23 powers
453          // (2^28 - 2^25)..(2^28 - 2^24) = 2^24 powers
454          // (2^28 - 2^26)..(2^28 - 2^25) = 2^25 powers
455          // (2^28 - 2^27)..(2^28 - 2^26) = 2^26 powers
456  
457          // Figure out the number of powers to download, as follows:
458          // Let `start := 2^28 - k`.
459          // We know that `shifted_powers_of_beta_g.len() = 2^s` such that `2^s < k`.
460          // That is, we have already downloaded the powers `2^28 - 2^s` up to `2^28`.
461          // Then, we have to download the powers 2^s..k.next_power_of_two().
462          let final_num_powers = MAX_NUM_POWERS
463              .checked_sub(start)
464              .ok_or_else(|| anyhow!("Requesting too many powers: `start ({start}) > MAX_NUM_POWERS ({MAX_NUM_POWERS})`"))?
465              .checked_next_power_of_two()
466              .ok_or_else(|| anyhow!("Requesting too many powers"))?; // Calculated k.next_power_of_two().
467  
468          let mut download_queue = Vec::with_capacity(14);
469          let mut existing_num_powers = self.shifted_powers_of_beta_g.len();
470          while existing_num_powers < final_num_powers {
471              existing_num_powers =
472                  existing_num_powers.checked_mul(2).ok_or_else(|| anyhow!("Overflowed while requesting additional powers"))?;
473              download_queue.push(existing_num_powers);
474          }
475          download_queue.reverse(); // We want to download starting from the smallest power.
476  
477          let mut final_powers = Vec::with_capacity(final_num_powers);
478          // If the `target_degree` exceeds the current `degree`, proceed to download the new powers.
479          for num_powers in &download_queue {
480              dev_println!("Loading {num_powers} shifted powers");
481  
482              // Download the universal SRS powers if they're not already on disk.
483              let additional_bytes = match *num_powers {
484                  NUM_POWERS_16 => ShiftedDegree16::load_bytes()?,
485                  NUM_POWERS_17 => ShiftedDegree17::load_bytes()?,
486                  NUM_POWERS_18 => ShiftedDegree18::load_bytes()?,
487                  NUM_POWERS_19 => ShiftedDegree19::load_bytes()?,
488                  NUM_POWERS_20 => ShiftedDegree20::load_bytes()?,
489                  NUM_POWERS_21 => ShiftedDegree21::load_bytes()?,
490                  NUM_POWERS_22 => ShiftedDegree22::load_bytes()?,
491                  NUM_POWERS_23 => ShiftedDegree23::load_bytes()?,
492                  NUM_POWERS_24 => ShiftedDegree24::load_bytes()?,
493                  NUM_POWERS_25 => ShiftedDegree25::load_bytes()?,
494                  // TODO(ACDC): ShiftedDegree 26-27 gated behind large_params feature for CI performance.
495                  #[cfg(feature = "large_params")]
496                  NUM_POWERS_26 => ShiftedDegree26::load_bytes()?,
497                  #[cfg(feature = "large_params")]
498                  NUM_POWERS_27 => ShiftedDegree27::load_bytes()?,
499                  _ => bail!("Cannot download an invalid degree of '{num_powers}'"),
500              };
501  
502              // Deserialize the group elements.
503              let additional_powers = Vec::deserialize_uncompressed_unchecked(&*additional_bytes)?;
504  
505              final_powers.extend(additional_powers.iter());
506          }
507          final_powers.extend(self.shifted_powers_of_beta_g.iter());
508          self.shifted_powers_of_beta_g = final_powers;
509  
510          ensure!(self.shifted_powers_of_beta_g.len() == final_num_powers, "Loaded an incorrect number of shifted powers");
511          Ok(())
512      }
513  }
514  
515  impl<E: PairingEngine> FromBytes for PowersOfBetaG<E> {
516      /// Reads the powers from the buffer.
517      fn read_le<R: Read>(reader: R) -> std::io::Result<Self> {
518          Self::deserialize_with_mode(reader, Compress::No, Validate::No).map_err(|e| e.into())
519      }
520  }
521  
522  impl<E: PairingEngine> ToBytes for PowersOfBetaG<E> {
523      /// Writes the powers to the buffer.
524      fn write_le<W: Write>(&self, writer: W) -> std::io::Result<()> {
525          self.serialize_with_mode(writer, Compress::No).map_err(|e| e.into())
526      }
527  }