Skip to content

Commit

Permalink
Fold the non_hiding_kzg module in relevant files (microsoft#328)
Browse files Browse the repository at this point in the history
* Revert "feat: Implement batch operations in non_hiding_kzg module (microsoft#269)"

This reverts commit db4375f.

* refactor: remove non_hiding_kzg module, split code where dependents need it

- Moved `UniversalParams` and several dependent structures for the KZG10 scheme in the `kzg_commitment.rs` file.
- Deleted the `non_hiding_kzg.rs` file,
- Consolidated KZG related structs under the `kzg_commitment` module,
- Updated `mod.rs` to reflect the removal of the `non_hiding_kzg` module.
  • Loading branch information
huitseeker authored Feb 19, 2024
1 parent 5bdc0ee commit e1a69d4
Show file tree
Hide file tree
Showing 6 changed files with 342 additions and 565 deletions.
39 changes: 27 additions & 12 deletions src/provider/hyperkzg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@
use crate::{
errors::NovaError,
provider::{
kzg_commitment::KZGCommitmentEngine,
non_hiding_kzg::{trim, KZGProverKey, KZGVerifierKey, UniversalKZGParam},
kzg_commitment::{KZGCommitmentEngine, KZGProverKey, KZGVerifierKey, UniversalKZGParam},
pedersen::Commitment,
traits::DlogGroup,
util::iterators::DoubleEndedIteratorExt as _,
Expand Down Expand Up @@ -127,7 +126,7 @@ where

fn setup(ck: Arc<UniversalKZGParam<E>>) -> (Self::ProverKey, Self::VerifierKey) {
let len = ck.length() - 1;
trim(ck, len)
UniversalKZGParam::trim(ck, len)
}

fn prove(
Expand Down Expand Up @@ -437,36 +436,52 @@ mod tests {
let ck: CommitmentKey<NE> =
<KZGCommitmentEngine<E> as CommitmentEngineTrait<NE>>::setup(b"test", n);
let ck = Arc::new(ck);
let (pk, _vk): (KZGProverKey<E>, KZGVerifierKey<E>) =
let (pk, vk): (KZGProverKey<E>, KZGVerifierKey<E>) =
EvaluationEngine::<E, NE>::setup(ck.clone());

// poly is in eval. representation; evaluated at [(0,0), (0,1), (1,0), (1,1)]
let poly = vec![Fr::from(1), Fr::from(2), Fr::from(2), Fr::from(4)];

let C = <KZGCommitmentEngine<E> as CommitmentEngineTrait<NE>>::commit(&ck, &poly);
let mut tr = Keccak256Transcript::<NE>::new(b"TestEval");

// Call the prover with a (point, eval) pair. The prover recomputes
// poly(point) = eval', and fails if eval' != eval
let test_inner = |point: Vec<Fr>, eval: Fr| -> Result<(), NovaError> {
let mut tr = Keccak256Transcript::<NE>::new(b"TestEval");
let proof =
EvaluationEngine::<E, NE>::prove(&ck, &pk, &mut tr, &C, &poly, &point, &eval).unwrap();
let mut tr = Keccak256Transcript::new(b"TestEval");
EvaluationEngine::<E, NE>::verify(&vk, &mut tr, &C, &point, &eval, &proof)
};

// Call the prover with a (point, eval) pair.
// The prover does not recompute so it may produce a proof, but it should not verify
let point = vec![Fr::from(0), Fr::from(0)];
let eval = Fr::ONE;
assert!(EvaluationEngine::<E, NE>::prove(&ck, &pk, &mut tr, &C, &poly, &point, &eval).is_ok());
assert!(test_inner(point, eval).is_ok());

let point = vec![Fr::from(0), Fr::from(1)];
let eval = Fr::from(2);
assert!(EvaluationEngine::<E, NE>::prove(&ck, &pk, &mut tr, &C, &poly, &point, &eval).is_ok());
assert!(test_inner(point, eval).is_ok());

let point = vec![Fr::from(1), Fr::from(1)];
let eval = Fr::from(4);
assert!(EvaluationEngine::<E, NE>::prove(&ck, &pk, &mut tr, &C, &poly, &point, &eval).is_ok());
assert!(test_inner(point, eval).is_ok());

let point = vec![Fr::from(0), Fr::from(2)];
let eval = Fr::from(3);
assert!(EvaluationEngine::<E, NE>::prove(&ck, &pk, &mut tr, &C, &poly, &point, &eval).is_ok());
assert!(test_inner(point, eval).is_ok());

let point = vec![Fr::from(2), Fr::from(2)];
let eval = Fr::from(9);
assert!(EvaluationEngine::<E, NE>::prove(&ck, &pk, &mut tr, &C, &poly, &point, &eval).is_ok());
assert!(test_inner(point, eval).is_ok());

// Try a couple incorrect evaluations and expect failure
let point = vec![Fr::from(2), Fr::from(2)];
let eval = Fr::from(50);
assert!(test_inner(point, eval).is_err());

let point = vec![Fr::from(0), Fr::from(2)];
let eval = Fr::from(4);
assert!(test_inner(point, eval).is_err());
}

#[test]
Expand Down
217 changes: 206 additions & 11 deletions src/provider/kzg_commitment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,218 @@

use std::marker::PhantomData;

use ff::PrimeFieldBits;
use group::{prime::PrimeCurveAffine, Curve};
use abomonation_derive::Abomonation;
use ff::{Field, PrimeField, PrimeFieldBits};
use group::{prime::PrimeCurveAffine, Curve, Group as _};
use pairing::Engine;
use rand::rngs::StdRng;
use rand_core::SeedableRng;
use rand_core::{CryptoRng, RngCore, SeedableRng};
use serde::{Deserialize, Serialize};
use std::sync::Arc;

use crate::traits::{
commitment::{CommitmentEngineTrait, Len},
Engine as NovaEngine, Group,
use crate::provider::pedersen::Commitment;
use crate::provider::traits::DlogGroup;
use crate::provider::util::fb_msm;
use crate::{
digest::SimpleDigestible,
traits::{
commitment::{CommitmentEngineTrait, Len},
Engine as NovaEngine, Group, TranscriptReprTrait,
},
};

use crate::provider::{
non_hiding_kzg::{UVKZGCommitment, UniversalKZGParam},
pedersen::Commitment,
traits::DlogGroup,
};
/// `UniversalParams` are the universal parameters for the KZG10 scheme.
#[derive(Debug, Clone, Eq, Serialize, Deserialize, Abomonation)]
#[serde(bound(
serialize = "E::G1Affine: Serialize, E::G2Affine: Serialize",
deserialize = "E::G1Affine: Deserialize<'de>, E::G2Affine: Deserialize<'de>"
))]
#[abomonation_omit_bounds]
pub struct UniversalKZGParam<E: Engine> {
/// Group elements of the form `{ β^i G }`, where `i` ranges from 0 to
/// `degree`.
// this is a hack; we just assume the size of the element.
// Look for the static assertions in provider macros for a justification
#[abomonate_with(Vec<[u64; 8]>)]
pub powers_of_g: Vec<E::G1Affine>,
/// Group elements of the form `{ β^i H }`, where `i` ranges from 0 to
/// `degree`.
// this is a hack; we just assume the size of the element.
// Look for the static assertions in provider macros for a justification
#[abomonate_with(Vec<[u64; 16]>)]
pub powers_of_h: Vec<E::G2Affine>,
}

impl<E: Engine> PartialEq for UniversalKZGParam<E> {
fn eq(&self, other: &Self) -> bool {
self.powers_of_g == other.powers_of_g && self.powers_of_h == other.powers_of_h
}
}
// for the purpose of the Len trait, we count commitment bases, i.e. G1 elements
impl<E: Engine> Len for UniversalKZGParam<E> {
fn length(&self) -> usize {
self.powers_of_g.len()
}
}

/// `UnivariateProverKey` is used to generate a proof
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct KZGProverKey<E: Engine> {
/// generators from the universal parameters
uv_params: Arc<UniversalKZGParam<E>>,
/// offset at which we start reading into the SRS
offset: usize,
/// maximum supported size
supported_size: usize,
}

impl<E: Engine> KZGProverKey<E> {
pub(in crate::provider) fn new(
uv_params: Arc<UniversalKZGParam<E>>,
offset: usize,
supported_size: usize,
) -> Self {
assert!(
uv_params.max_degree() >= offset + supported_size,
"not enough bases (req: {} from offset {}) in the UVKZGParams (length: {})",
supported_size,
offset,
uv_params.max_degree()
);
Self {
uv_params,
offset,
supported_size,
}
}

pub fn powers_of_g(&self) -> &[E::G1Affine] {
&self.uv_params.powers_of_g[self.offset..self.offset + self.supported_size]
}
}

/// `UVKZGVerifierKey` is used to check evaluation proofs for a given
/// commitment.
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
#[serde(bound(serialize = "E::G1Affine: Serialize, E::G2Affine: Serialize",))]
pub struct KZGVerifierKey<E: Engine> {
/// The generator of G1.
pub g: E::G1Affine,
/// The generator of G2.
pub h: E::G2Affine,
/// β times the above generator of G2.
pub beta_h: E::G2Affine,
}

impl<E: Engine> SimpleDigestible for KZGVerifierKey<E>
where
E::G1Affine: Serialize,
E::G2Affine: Serialize,
{
}

impl<E: Engine> UniversalKZGParam<E> {
/// Returns the maximum supported degree
pub fn max_degree(&self) -> usize {
self.powers_of_g.len()
}

/// Trim the universal parameters to specialize the public parameters
/// for univariate polynomials to the given `supported_size`, and
/// returns prover key and verifier key. `supported_size` should
/// be in range `1..params.len()`
///
/// # Panics
/// If `supported_size` is greater than `self.max_degree()`, or `self.max_degree()` is zero.
pub fn trim(ukzg: Arc<Self>, supported_size: usize) -> (KZGProverKey<E>, KZGVerifierKey<E>) {
assert!(ukzg.max_degree() > 0, "max_degree is zero");
let g = ukzg.powers_of_g[0];
let h = ukzg.powers_of_h[0];
let beta_h = ukzg.powers_of_h[1];
let pk = KZGProverKey::new(ukzg, 0, supported_size + 1);
let vk = KZGVerifierKey { g, h, beta_h };
(pk, vk)
}
}

impl<E: Engine> UniversalKZGParam<E>
where
E::Fr: PrimeFieldBits,
{
/// Build SRS for testing.
/// WARNING: THIS FUNCTION IS FOR TESTING PURPOSE ONLY.
/// THE OUTPUT SRS SHOULD NOT BE USED IN PRODUCTION.
pub fn gen_srs_for_testing<R: RngCore + CryptoRng>(mut rng: &mut R, max_degree: usize) -> Self {
let beta = E::Fr::random(&mut rng);
let g = E::G1::random(&mut rng);
let h = E::G2::random(rng);

let nz_powers_of_beta = (0..=max_degree)
.scan(beta, |acc, _| {
let val = *acc;
*acc *= beta;
Some(val)
})
.collect::<Vec<E::Fr>>();

let window_size = fb_msm::get_mul_window_size(max_degree);
let scalar_bits = E::Fr::NUM_BITS as usize;

let (powers_of_g_projective, powers_of_h_projective) = rayon::join(
|| {
let g_table = fb_msm::get_window_table(scalar_bits, window_size, g);
fb_msm::multi_scalar_mul::<E::G1>(scalar_bits, window_size, &g_table, &nz_powers_of_beta)
},
|| {
let h_table = fb_msm::get_window_table(scalar_bits, window_size, h);
fb_msm::multi_scalar_mul::<E::G2>(scalar_bits, window_size, &h_table, &nz_powers_of_beta)
},
);

let mut powers_of_g = vec![E::G1Affine::identity(); powers_of_g_projective.len()];
let mut powers_of_h = vec![E::G2Affine::identity(); powers_of_h_projective.len()];

rayon::join(
|| E::G1::batch_normalize(&powers_of_g_projective, &mut powers_of_g),
|| E::G2::batch_normalize(&powers_of_h_projective, &mut powers_of_h),
);

Self {
powers_of_g,
powers_of_h,
}
}
}

/// Commitments
#[derive(Debug, Clone, Copy, Eq, PartialEq, Default, Serialize, Deserialize)]
#[serde(bound(
serialize = "E::G1Affine: Serialize",
deserialize = "E::G1Affine: Deserialize<'de>"
))]
pub struct UVKZGCommitment<E: Engine>(
/// the actual commitment is an affine point.
pub E::G1Affine,
);

impl<E: Engine> TranscriptReprTrait<E::G1> for UVKZGCommitment<E>
where
E::G1: DlogGroup,
// Note: due to the move of the bound TranscriptReprTrait<G> on G::Base from Group to Engine
<E::G1 as Group>::Base: TranscriptReprTrait<E::G1>,
{
fn to_transcript_bytes(&self) -> Vec<u8> {
// TODO: avoid the round-trip through the group (to_curve .. to_coordinates)
let (x, y, is_infinity) = self.0.to_curve().to_coordinates();
let is_infinity_byte = (!is_infinity).into();
[
x.to_transcript_bytes(),
y.to_transcript_bytes(),
[is_infinity_byte].to_vec(),
]
.concat()
}
}

/// Provides a commitment engine
#[derive(Clone, Debug, PartialEq, Eq)]
Expand Down
1 change: 0 additions & 1 deletion src/provider/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ pub(crate) mod secp_secq;
pub(crate) mod traits;
// a non-hiding variant of {kzg, zeromorph}
mod kzg_commitment;
mod non_hiding_kzg;
pub(crate) mod util;

// crate-private modules
Expand Down
Loading

0 comments on commit e1a69d4

Please sign in to comment.