Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fold the non_hiding_kzg module in relevant files #328

Merged
merged 2 commits into from
Feb 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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