Skip to content

Commit

Permalink
refactor: Minimize distraction to Nova module organization
Browse files Browse the repository at this point in the history
- 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 committed May 2, 2024
1 parent 35449ac commit 3d73656
Show file tree
Hide file tree
Showing 5 changed files with 268 additions and 436 deletions.
43 changes: 30 additions & 13 deletions src/provider/hyperkzg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@
#![allow(non_snake_case)]
use crate::{
errors::NovaError,
provider::{traits::DlogGroup,
provider::{
kzg_commitment::{KZGCommitmentEngine, KZGProverKey, KZGVerifierKey, UniversalKZGParam},
pedersen::Commitment,
kzg_commitment::KZGCommitmentEngine, non_hiding_kzg::{KZGProverKey, KZGVerifierKey, UniversalKZGParam}},
traits::DlogGroup,
},
spartan::polys::univariate::UniPoly,
traits::{
commitment::{CommitmentEngineTrait, Len},
Expand Down Expand Up @@ -434,37 +436,52 @@ mod tests {
fn test_hyperkzg_eval() {
// Test with poly(X1, X2) = 1 + X1 + X2 + X1*X2
let n = 4;
let ck: CommitmentKey<NE> =
<KZGCommitmentEngine<E> as CommitmentEngineTrait<NE>>::setup(b"test", n);
let (pk, _vk): (KZGProverKey<E>, KZGVerifierKey<E>) = EvaluationEngine::<E, NE>::setup(&ck);
let ck = <KZGCommitmentEngine<Bn256> as CommitmentEngineTrait<NE>>::setup(b"test", n);
let (pk, vk) = EvaluationEngine::<Bn256, NE>::setup(&ck);

// 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::<Bn256, NE>::prove(&ck, &pk, &mut tr, &C, &poly, &point, &eval).unwrap();
let mut tr = Keccak256Transcript::<NE>::new(b"TestEval");
EvaluationEngine::<Bn256, 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
163 changes: 155 additions & 8 deletions src/provider/kzg_commitment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,169 @@

use std::marker::PhantomData;

use group::{prime::PrimeCurveAffine, Curve};
use ff::Field;
use group::{prime::PrimeCurveAffine, Curve, Group as _};
use halo2curves::pairing::Engine;
use rand::rngs::StdRng;
use rand_core::SeedableRng;
use rand_core::{CryptoRng, RngCore, SeedableRng};
use serde::{Deserialize, Serialize};

use crate::traits::{
commitment::{CommitmentEngineTrait, Len},
Engine as NovaEngine, Group,
Engine as NovaEngine, Group, TranscriptReprTrait,
};

use crate::provider::{
non_hiding_kzg::{UVKZGCommitment, UniversalKZGParam},
pedersen::Commitment,
traits::DlogGroup,
};
use crate::provider::{pedersen::Commitment, traits::DlogGroup};

/// `UniversalParams` are the universal parameters for the KZG10 scheme.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(bound(
serialize = "E::G1Affine: Serialize, E::G2Affine: Serialize",
deserialize = "E::G1Affine: Deserialize<'de>, E::G2Affine: Deserialize<'de>"
))]
pub struct UniversalKZGParam<E: Engine> {
/// Group elements of the form `{ β^i G }`, where `i` ranges from 0 to
/// `degree`.
pub powers_of_g: Vec<E::G1Affine>,
/// Group elements of the form `{ β^i H }`, where `i` ranges from 0 to
/// `degree`.
pub powers_of_h: Vec<E::G2Affine>,
}

// 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, Serialize, Deserialize)]
#[serde(bound(
serialize = "E::G1Affine: Serialize",
deserialize = "E::G1Affine: Deserialize<'de>"
))]
pub struct KZGProverKey<E: Engine> {
/// generators
pub powers_of_g: Vec<E::G1Affine>,
}

/// `UVKZGVerifierKey` is used to check evaluation proofs for a given
/// commitment.
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(bound(
serialize = "E::G1Affine: Serialize, E::G2Affine: Serialize",
deserialize = "E::G1Affine: Deserialize<'de>, E::G2Affine: Deserialize<'de>"
))]
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> 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(&self, supported_size: usize) -> (KZGProverKey<E>, KZGVerifierKey<E>) {
let powers_of_g = self.powers_of_g[..=supported_size].to_vec();

let pk = KZGProverKey { powers_of_g };
let vk = KZGVerifierKey {
g: self.powers_of_g[0],
h: self.powers_of_h[0],
beta_h: self.powers_of_h[1],
};
(pk, vk)
}
}

impl<E: Engine> UniversalKZGParam<E> {
/// 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 (powers_of_g_projective, powers_of_h_projective) = rayon::join(
|| {
(0..=max_degree)
.scan(g, |acc, _| {
let val = *acc;
*acc *= beta;
Some(val)
})
.collect::<Vec<E::G1>>()
},
|| {
(0..=max_degree)
.scan(h, |acc, _| {
let val = *acc;
*acc *= beta;
Some(val)
})
.collect::<Vec<E::G2>>()
},
);

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, Serialize, Deserialize)]
Expand Down
2 changes: 1 addition & 1 deletion src/provider/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ pub(crate) mod secp_secq;
pub(crate) mod traits;
// a non-hiding variant of {kzg, zeromorph}
pub(crate) mod kzg_commitment;
pub(crate) mod non_hiding_kzg;

#[cfg(test)]
pub(crate) mod test_utils;

Expand Down
Loading

0 comments on commit 3d73656

Please sign in to comment.