diff --git a/Cargo.toml b/Cargo.toml
index 878d1c5e9c118e24f1dcb07aeff005fe43c311df..5c8dd380e88447db018f2bf737899eb687f8737a 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "poly-commit"
-version = "0.1.0"
+version = "0.1.1-alpha.0"
 authors = [
   "Alessandro Chiesa <alexch@berkeley.edu>",
   "Mary Maller <mary.maller.15@ucl.ac.uk>",
@@ -20,9 +20,9 @@ license = "MIT/Apache-2.0"
 edition = "2018"
 
 [dependencies]
-algebra-core = { git = "https://github.com/scipr-lab/zexe/", default-features = false }
-ff-fft = { git = "https://github.com/scipr-lab/zexe/", default-features = false }
-bench-utils = { git = "https://github.com/scipr-lab/zexe/" }
+algebra-core = { git = "https://github.com/scipr-lab/zexe", version = "0.1.1-alpha.0", default-features = false }
+ff-fft = { git = "https://github.com/scipr-lab/zexe", version = "0.1.1-alpha.0", default-features = false }
+bench-utils = { git = "https://github.com/scipr-lab/zexe", version = "0.1.1-alpha.0" }
 rand_core = { version = "0.5", default-features = false }
 digest = "0.8"
 rayon = { version = "1", optional = true }
@@ -30,7 +30,7 @@ derivative = { version = "2", features = [ "use_core" ] }
 
 [dev-dependencies]
 rand = { version = "0.7", default-features = false }
-algebra = { git = "https://github.com/scipr-lab/zexe/", default-features = false, features = ["ed_on_bls12_381", "bls12_381", "bls12_377"] }
+algebra = { git = "https://github.com/scipr-lab/zexe", version = "0.1.1-alpha.0", default-features = false, features = ["ed_on_bls12_381", "bls12_381", "bls12_377"] }
 blake2 = { version = "0.8", default-features = false }
 
 [profile.release]
diff --git a/src/ipa_pc/mod.rs b/src/ipa_pc/mod.rs
index 80e76663c851b3e9f17be91cb6ae50c3319e498e..32b913157ceb7f9f732383ab912b8aa6a6f9e14f 100644
--- a/src/ipa_pc/mod.rs
+++ b/src/ipa_pc/mod.rs
@@ -4,8 +4,8 @@ use crate::{LabeledCommitment, LabeledPolynomial, LinearCombination};
 use crate::{PCCommitterKey, PCRandomness, PCUniversalParams, Polynomial, PolynomialCommitment};
 
 use algebra_core::{
-    to_bytes, AffineCurve, Field, One, PrimeField, ProjectiveCurve, ToBytes, UniformRand,
-    VariableBaseMSM, Zero,
+    to_bytes, AffineCurve, Field, One, PrimeField, ProjectiveCurve, UniformRand, VariableBaseMSM,
+    Zero,
 };
 use core::{convert::TryInto, marker::PhantomData};
 use rand_core::RngCore;
@@ -340,6 +340,7 @@ impl<G: AffineCurve, D: Digest> PolynomialCommitment<G::ScalarField> for InnerPr
     fn trim(
         pp: &Self::UniversalParams,
         supported_degree: usize,
+        _supported_hiding_bound: usize,
         _enforced_degree_bounds: Option<&[usize]>,
     ) -> Result<(Self::CommitterKey, Self::VerifierKey), Self::Error> {
         // Ensure that supported_degree + 1 is a power of two
diff --git a/src/kzg10/data_structures.rs b/src/kzg10/data_structures.rs
index 9f88c5f8f9a09cba1769624e662361a1d8ec32d0..7891cece5c765dd232cd36e98a26b250888b3fb4 100644
--- a/src/kzg10/data_structures.rs
+++ b/src/kzg10/data_structures.rs
@@ -9,13 +9,13 @@ pub struct UniversalParams<E: PairingEngine> {
     /// Group elements of the form `{ \beta^i G }`, where `i` ranges from 0 to `degree`.
     pub powers_of_g: Vec<E::G1Affine>,
     /// Group elements of the form `{ \beta^i \gamma G }`, where `i` ranges from 0 to `degree`.
-    pub powers_of_gamma_g: Vec<E::G1Affine>,
+    pub powers_of_gamma_g: BTreeMap<usize, E::G1Affine>,
     /// The generator of G2.
     pub h: E::G2Affine,
     /// \beta times the above generator of G2.
     pub beta_h: E::G2Affine,
     /// Group elements of the form `{ \beta^i G2 }`, where `i` ranges from `0` to `-degree`.
-    pub prepared_neg_powers_of_h: Option<Vec<E::G2Prepared>>,
+    pub prepared_neg_powers_of_h: BTreeMap<usize, E::G2Prepared>,
     /// The generator of G2, prepared for use in pairings.
     #[derivative(Debug = "ignore")]
     pub prepared_h: E::G2Prepared,
diff --git a/src/kzg10/mod.rs b/src/kzg10/mod.rs
index 1fa2a8b8b0a2a1f11121e70ef59f6fb5ca8d91dd..93d39ed00487ab18885818193031d77c105ee219 100644
--- a/src/kzg10/mod.rs
+++ b/src/kzg10/mod.rs
@@ -5,7 +5,7 @@
 //! proposed by Kate, Zaverucha, and Goldberg ([KZG11](http://cacr.uwaterloo.ca/techreports/2010/cacr2010-10.pdf)).
 //! This construction achieves extractability in the algebraic group model (AGM).
 
-use crate::{Error, LabeledPolynomial, PCRandomness, Polynomial, ToString, Vec};
+use crate::{BTreeMap, Error, LabeledPolynomial, PCRandomness, Polynomial, ToString, Vec};
 use algebra_core::msm::{FixedBaseMSM, VariableBaseMSM};
 use algebra_core::{
     AffineCurve, Group, One, PairingEngine, PrimeField, ProjectiveCurve, UniformRand, Zero,
@@ -79,7 +79,10 @@ impl<E: PairingEngine> KZG10<E> {
 
         let powers_of_g = E::G1Projective::batch_normalization_into_affine(&powers_of_g);
         let powers_of_gamma_g =
-            E::G1Projective::batch_normalization_into_affine(&powers_of_gamma_g);
+            E::G1Projective::batch_normalization_into_affine(&powers_of_gamma_g)
+                .into_iter()
+                .enumerate()
+                .collect();
 
         let prepared_neg_powers_of_h_time =
             start_timer!(|| "Generating negative powers of h in G2");
@@ -100,9 +103,17 @@ impl<E: PairingEngine> KZG10<E> {
             );
 
             let affines = E::G2Projective::batch_normalization_into_affine(&neg_powers_of_h);
-            Some(affines.into_iter().map(|a| a.into()).collect())
+            let mut affines_map = BTreeMap::new();
+            affines
+                .into_iter()
+                .enumerate()
+                .map(|(i, a)| (i, a.into()))
+                .for_each(|(i, a)| {
+                    affines_map.insert(i, a);
+                });
+            affines_map
         } else {
-            None
+            BTreeMap::new()
         };
 
         end_timer!(prepared_neg_powers_of_h_time);
@@ -477,7 +488,9 @@ mod tests {
                 supported_degree += 1;
             }
             let powers_of_g = pp.powers_of_g[..=supported_degree].to_vec();
-            let powers_of_gamma_g = pp.powers_of_gamma_g[..=supported_degree].to_vec();
+            let powers_of_gamma_g = (0..=supported_degree)
+                .map(|i| pp.powers_of_gamma_g[&i])
+                .collect();
 
             let powers = Powers {
                 powers_of_g: Cow::Owned(powers_of_g),
@@ -485,7 +498,7 @@ mod tests {
             };
             let vk = VerifierKey {
                 g: pp.powers_of_g[0],
-                gamma_g: pp.powers_of_gamma_g[0],
+                gamma_g: pp.powers_of_gamma_g[&0],
                 h: pp.h,
                 beta_h: pp.beta_h,
                 prepared_h: pp.prepared_h.clone(),
diff --git a/src/lib.rs b/src/lib.rs
index 3fa9b38f1a05324ede7747213c52e1454cfc8d1d..92d44e17e968edd37cd10d2707cb4645de4bcd33 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -145,6 +145,7 @@ pub trait PolynomialCommitment<F: Field>: Sized {
     fn trim(
         pp: &Self::UniversalParams,
         supported_degree: usize,
+        supported_hiding_bound: usize,
         enforced_degree_bounds: Option<&[usize]>,
     ) -> Result<(Self::CommitterKey, Self::VerifierKey), Self::Error>;
 
@@ -519,8 +520,19 @@ pub mod tests {
                 ))
             }
 
+            let supported_hiding_bound = polynomials
+                .iter()
+                .map(|p| p.hiding_bound().unwrap_or(0))
+                .max()
+                .unwrap_or(0);
             println!("supported degree: {:?}", supported_degree);
-            let (ck, vk) = PC::trim(&pp, supported_degree, Some(degree_bounds.as_slice()))?;
+            println!("supported hiding bound: {:?}", supported_hiding_bound);
+            let (ck, vk) = PC::trim(
+                &pp,
+                supported_degree,
+                supported_hiding_bound,
+                Some(degree_bounds.as_slice()),
+            )?;
             println!("Trimmed");
 
             let (comms, rands) = PC::commit(&ck, &polynomials, Some(rng))?;
@@ -628,11 +640,18 @@ pub mod tests {
                     hiding_bound,
                 ))
             }
+            let supported_hiding_bound = polynomials
+                .iter()
+                .map(|p| p.hiding_bound().unwrap_or(0))
+                .max()
+                .unwrap_or(0);
             println!("supported degree: {:?}", supported_degree);
+            println!("supported hiding bound: {:?}", supported_hiding_bound);
             println!("num_points_in_query_set: {:?}", num_points_in_query_set);
             let (ck, vk) = PC::trim(
                 &pp,
                 supported_degree,
+                supported_hiding_bound,
                 degree_bounds.as_ref().map(|s| s.as_slice()),
             )?;
             println!("Trimmed");
@@ -769,6 +788,7 @@ pub mod tests {
             let (ck, vk) = PC::trim(
                 &pp,
                 supported_degree,
+                supported_degree,
                 degree_bounds.as_ref().map(|s| s.as_slice()),
             )?;
             println!("Trimmed");
diff --git a/src/marlin_pc/mod.rs b/src/marlin_pc/mod.rs
index c24332bde19a3827fa351789c1718ef2e1122b60..18da2f74cc8a1f4d7a675b03b5fc4576abaf9b49 100644
--- a/src/marlin_pc/mod.rs
+++ b/src/marlin_pc/mod.rs
@@ -168,12 +168,10 @@ impl<E: PairingEngine> PolynomialCommitment<E::Fr> for MarlinKZG10<E> {
         kzg10::KZG10::setup(max_degree, false, rng).map_err(Into::into)
     }
 
-    // TODO: should trim also take in the hiding_bounds? That way we don't
-    // have to store many powers of gamma_g.
-    // TODO: add an optional hiding_bound.
     fn trim(
         pp: &Self::UniversalParams,
         supported_degree: usize,
+        supported_hiding_bound: usize,
         enforced_degree_bounds: Option<&[usize]>,
     ) -> Result<(Self::CommitterKey, Self::VerifierKey), Self::Error> {
         let max_degree = pp.max_degree();
@@ -187,15 +185,17 @@ impl<E: PairingEngine> PolynomialCommitment<E::Fr> for MarlinKZG10<E> {
             supported_degree
         ));
         let powers = pp.powers_of_g[..=supported_degree].to_vec();
-        // We want to support making up to supported_degree queries to committed
+        // We want to support making up to `supported_hiding_bound` queries to committed
         // polynomials.
-        let powers_of_gamma_g = pp.powers_of_gamma_g[..=(supported_degree + 1)].to_vec();
+        let powers_of_gamma_g = (0..=supported_hiding_bound + 1)
+            .map(|i| pp.powers_of_gamma_g[&i])
+            .collect::<Vec<_>>();
         end_timer!(ck_time);
 
         // Construct the core KZG10 verifier key.
         let vk = kzg10::VerifierKey {
             g: pp.powers_of_g[0],
-            gamma_g: pp.powers_of_gamma_g[0],
+            gamma_g: pp.powers_of_gamma_g[&0],
             h: pp.h,
             beta_h: pp.beta_h,
             prepared_h: pp.prepared_h.clone(),
diff --git a/src/sonic_pc/data_structures.rs b/src/sonic_pc/data_structures.rs
index 03d33298417fee2756eee4393aa0d6400ced6401..c4030f3236158f6acaca6cf661c8ed90cc07c23f 100644
--- a/src/sonic_pc/data_structures.rs
+++ b/src/sonic_pc/data_structures.rs
@@ -1,5 +1,5 @@
 use crate::kzg10;
-use crate::{PCCommitterKey, PCVerifierKey, Vec};
+use crate::{BTreeMap, PCCommitterKey, PCVerifierKey, Vec};
 use algebra_core::PairingEngine;
 
 /// `UniversalParams` are the universal parameters for the KZG10 scheme.
@@ -33,7 +33,7 @@ pub struct CommitterKey<E: PairingEngine> {
 
     /// The powers used to commit to shifted hiding polynomials.
     /// This is `None` if `self` does not support enforcing any degree bounds.
-    pub shifted_powers_of_gamma_g: Option<Vec<E::G1Affine>>,
+    pub shifted_powers_of_gamma_g: Option<BTreeMap<usize, Vec<E::G1Affine>>>,
 
     /// The degree bounds that are supported by `self`.
     /// Sorted in ascending order from smallest bound to largest bound.
@@ -60,26 +60,26 @@ impl<E: PairingEngine> CommitterKey<E> {
     ) -> Option<kzg10::Powers<E>> {
         match (&self.shifted_powers_of_g, &self.shifted_powers_of_gamma_g) {
             (Some(shifted_powers_of_g), Some(shifted_powers_of_gamma_g)) => {
-                let powers_range = if let Some(degree_bound) = degree_bound.into() {
+                let max_bound = self
+                    .enforced_degree_bounds
+                    .as_ref()
+                    .unwrap()
+                    .last()
+                    .unwrap();
+                let (bound, powers_range) = if let Some(degree_bound) = degree_bound.into() {
                     assert!(self
                         .enforced_degree_bounds
                         .as_ref()
                         .unwrap()
                         .contains(&degree_bound));
-                    let max_bound = self
-                        .enforced_degree_bounds
-                        .as_ref()
-                        .unwrap()
-                        .last()
-                        .unwrap();
-                    (max_bound - degree_bound)..
+                    (degree_bound, (max_bound - degree_bound)..)
                 } else {
-                    0..
+                    (*max_bound, 0..)
                 };
 
                 let ck = kzg10::Powers {
                     powers_of_g: shifted_powers_of_g[powers_range.clone()].into(),
-                    powers_of_gamma_g: shifted_powers_of_gamma_g[powers_range].into(),
+                    powers_of_gamma_g: shifted_powers_of_gamma_g[&bound].clone().into(),
                 };
 
                 Some(ck)
diff --git a/src/sonic_pc/mod.rs b/src/sonic_pc/mod.rs
index 0ef9f2a22d9ba56de0a879eadbc9e463dd7ebcb8..aed2cc0b33b80bbc809154f3540b1e5079a7eecf 100644
--- a/src/sonic_pc/mod.rs
+++ b/src/sonic_pc/mod.rs
@@ -143,10 +143,11 @@ impl<E: PairingEngine> PolynomialCommitment<E::Fr> for SonicKZG10<E> {
     fn trim(
         pp: &Self::UniversalParams,
         supported_degree: usize,
+        supported_hiding_bound: usize,
         enforced_degree_bounds: Option<&[usize]>,
     ) -> Result<(Self::CommitterKey, Self::VerifierKey), Self::Error> {
         let trim_time = start_timer!(|| "Trimming public parameters");
-        let prepared_neg_powers_of_h = pp.prepared_neg_powers_of_h.as_ref().unwrap();
+        let prepared_neg_powers_of_h = &pp.prepared_neg_powers_of_h;
         let max_degree = pp.max_degree();
         if supported_degree > max_degree {
             return Err(Error::TrimmingDegreeTooLarge);
@@ -180,8 +181,19 @@ impl<E: PairingEngine> PolynomialCommitment<E::Fr> for SonicKZG10<E> {
                 ));
 
                 let shifted_powers_of_g = pp.powers_of_g[lowest_shift_degree..].to_vec();
-                let shifted_powers_of_gamma_g =
-                    pp.powers_of_gamma_g[lowest_shift_degree..].to_vec();
+                let mut shifted_powers_of_gamma_g = BTreeMap::new();
+                // Also add degree 0.
+                for degree_bound in enforced_degree_bounds {
+                    let shift_degree = max_degree - degree_bound;
+                    let mut powers_for_degree_bound = vec![];
+                    for i in 0..=(supported_hiding_bound + 1) {
+                        // We have an additional degree in `powers_of_gamma_g` beyond `powers_of_g`.
+                        if shift_degree + i < max_degree + 2 {
+                            powers_for_degree_bound.push(pp.powers_of_gamma_g[&(shift_degree + i)]);
+                        }
+                    }
+                    shifted_powers_of_gamma_g.insert(*degree_bound, powers_for_degree_bound);
+                }
 
                 end_timer!(shifted_ck_time);
 
@@ -195,7 +207,7 @@ impl<E: PairingEngine> PolynomialCommitment<E::Fr> for SonicKZG10<E> {
                     .map(|bound| {
                         (
                             *bound,
-                            prepared_neg_powers_of_h[max_degree - *bound].clone(),
+                            prepared_neg_powers_of_h[&(max_degree - *bound)].clone(),
                         )
                     })
                     .collect();
@@ -213,7 +225,9 @@ impl<E: PairingEngine> PolynomialCommitment<E::Fr> for SonicKZG10<E> {
         };
 
         let powers_of_g = pp.powers_of_g[..=supported_degree].to_vec();
-        let powers_of_gamma_g = pp.powers_of_gamma_g[..=(supported_degree + 1)].to_vec();
+        let powers_of_gamma_g = (0..=(supported_hiding_bound + 1))
+            .map(|i| pp.powers_of_gamma_g[&i])
+            .collect();
 
         let ck = CommitterKey {
             powers_of_g,
@@ -227,7 +241,7 @@ impl<E: PairingEngine> PolynomialCommitment<E::Fr> for SonicKZG10<E> {
         let g = pp.powers_of_g[0];
         let h = pp.h;
         let beta_h = pp.beta_h;
-        let gamma_g = pp.powers_of_gamma_g[0];
+        let gamma_g = pp.powers_of_gamma_g[&0];
         let prepared_h = (&pp.prepared_h).clone();
         let prepared_beta_h = (&pp.prepared_beta_h).clone();