diff --git a/jolt-core/src/poly/commitment/dory.rs b/jolt-core/src/poly/commitment/dory.rs new file mode 100644 index 000000000..13c31677e --- /dev/null +++ b/jolt-core/src/poly/commitment/dory.rs @@ -0,0 +1,267 @@ +#![allow(dead_code)] + +use crate::field::JoltField; +use crate::msm::Icicle; +use crate::poly::commitment::commitment_scheme::BatchType; +use crate::poly::commitment::commitment_scheme::CommitShape; +use crate::poly::commitment::commitment_scheme::CommitmentScheme; +use crate::poly::dense_mlpoly::DensePolynomial; +use crate::utils::errors::ProofVerifyError; +use crate::utils::transcript::{AppendToTranscript, Transcript}; +use ark_ec::{CurveGroup, pairnig::Pairing, AffineRepr, CurveGroup}; +use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; +use std::marker::PhantomData; + + +/// Computes an Inner-Pairing-Product commitment as described in ____: +/// This leverages arkworks Pairing::multi_pairing method. +fn inner_pairing_product(g1: &[P::G1Affine], g2: &[P::G2Affine]) -> P::PairingOutput { + // todo(pat): try to move these checks to a larger context. + if g1.len() != g2.len() { + panic(fmt.Sprintf("length mismatch")) + } + + if g1.len() == 0 || g2.len() == 0 { + panic("empty vectors") + } + + // todo(pat): Confirm this isn't the same as performing a multi_miller_loop. + P::multi_pairing(g1, g2) +} + +#[derive(Default, Debug, PartialEq, CanonicalSerialize, CanonicalDeserialize)] +pub struct DoryCommitment { + pub c: P::PairingOutput, + pub d1: P::PairingOutput, + pub d2: P::PairingOutput +} + +impl AppendToTranscript for DoryCommitment

{ + fn append_to_transcript(&self, _transcript: &mut ProofTranscript) { + todo!() + } +} + +#[derive(CanonicalSerialize, CanonicalDeserialize)] +pub struct DoryPublicParameters { + pub h: P::G1, + pub pp: Vec>, + pub gens: PedersenGenerators // todo(pat): these should be generated at each instance of the protocol I believe. They are just pedersen generators needed for the inner-product opposite the h^a_i points. +} + +#[derive(CanonicalSerialize, CanonicalDeserialize, Default)] +pub struct PublicParameters { + pub reducePP: ReducePublicParams

, + pub Γ1: Vec, + pub Γ2: Vec, + pub χ: P::PairingOutput +} + +impl PublicParameters

{ + pub fn new(n: usize) -> Self { + if self.Γ1.len() != 2 * n || self.Γ2.len() != 2 * n { + panic("recursive public parameters should be twice as the public parameters it is derived from") + } + + let χ = inner_pairing_product(self.reducePP.Γ1Prime, self.reduce.Γ2Prime); + let reducePP = Self::reducePP(self.Γ1, self.Γ2, n); + + Self { + reducePP, + Γ1: self.reducePP.Γ1Prime, + Γ2: self.reduce.Γ2Prime, + χ + } + } + + pub fn reducePP(Γ1: &[P::G1], Γ2: &[P::G2], n: usize) -> ReducePublicParams

{ + if n == 1 { + return ReducePP::Default() + } + let m = n / 2; + + let Γ1L = &Γ1[..m]; + let Γ1R = &Γ1[m..]; + let Γ2L = &Γ2[..m]; + let Γ2R = &Γ2[m..]; + + // TODO(pat): make the seed phrases depend on m so they are random per reduction. + let Γ1Prime = PedersenGenerators::::new(m, b"Jolt v1 Dory Public Parameters r1Prime").generators; + let Γ2Prime = PedersenGenerators::::new(m, b"Jolt Dory Public Paramerets r2Prime").generators; + let Δ1L = inner_pairing_product(Γ1L, Γ2Prime); + let Δ1R = inner_pairing_product(Γ1R,Γ2Prime); + let Δ2L = inner_pairing_product(Γ1Prime, Γ2L); + let Δ2R = inner_pairing_product(Γ1Prime,Γ2R); + + ReducePublicParams { + Γ1Prime, + Γ2Prime, + Δ1R, + Δ1L, + Δ2R, + Δ2L, + } + } +} + +// Parameters used within the reduction +#[derive(CanonicalSerialize, CanonicalDeserialize)] +pub struct ReducePublicParams { + pub Γ1Prime: Vec, + pub Γ2Prime: Vec, + pub Δ1R: P::PairingOutput, + pub Δ1L: P::PairingOutput, + pub Δ2R: P::PairingOutput, + pub Δ2L: P::PairingOutput +} + +#[derive(CanonicalSerialize, CanonicalDeserialize)] +pub struct DoryProof { + +} + +#[derive(CanonicalSerialize, CanonicalDeserialize)] +pub struct DoryBatchedProof {} + +#[derive(Clone)] +pub struct DoryScheme { + _phantom: PhantomData<(P, ProofTranscript)>, +} + +impl CommitmentScheme + for DoryScheme +where +

::ScalarField: JoltField, +

::G1: Icicle, +{ + type Field = P::ScalarField; + type Setup = DoryPublicParams

; + type Commitment = DoryCommitment

; + type Proof = DoryProof

; + type BatchedProof = DoryBatchedProof

; + + fn setup(shapes: &[CommitShape]) -> Self::Setup { + let res = Vec::new(); + + // Dory's setup procedure initializes + let mut max_len: usize = 0; + for shape in shapes { + let len = shape.input_length.log_2(); + if len > max_len { + max_len = len; + } + } + + let Γ1 = PedersenGenerators::::new(max_len, b"Jolt v1 Dory G1 generators").generators; + let Γ2 = PedersenGenerators::::new(max_len, b"Jolt v1 Dory G2 generators").generators; + + let χ = inner_pairing_product(g1, g2); + let reducePP = PublicParameters::reducePP(Γ1, Γ2, max_len); + + let mut pp = DoryPublicParams { + reducePP, + Γ1, + Γ2, + χ + }; + + while max_len > 0 { + res.append(pp); + if n/2 == 0 { + break; + } + pp = pp.new(max_len / 2); + max_len /= 2; + } + + let h = Γ1[0]; + + Self::Setup { + h, + pp: res + } + } + + fn commit(poly: &DensePolynomial, setup: &Self::Setup) -> Self::Commitment { + Self::commit_slice(poly.evals_ref(), setup) + } + + fn batch_commit( + _evals: &[&[Self::Field]], + _gens: &Self::Setup, + _batch_type: BatchType, + ) -> Vec { + todo!() + } + + fn commit_slice(evals_slice: &[Self::Field], setup: &Self::Setup) -> Self::Commitment { + let v1 = eval_slice + .par_iter + .map(|eval| + setup.h * eval + ).collect(); + let d1 = P::multi_pairing(v1, setup.Γ2); + //todo(pat): We can precompute this I think? Hard to distinguish between inner product protocol and Multilinear PCS. Follow up with Micheal. + let d2 = P::multi_pairing(setup.gens, setup.Γ1); + let c = P::multi_pairing(v2, setup.gens); + + Self::Commitment { + d1, + d2, + c + } + } + + fn prove( + _none: &Self::Setup, + _poly: &DensePolynomial, + _opening_point: &[Self::Field], + _transcript: &mut ProofTranscript, + ) -> Self::Proof { + todo!() + } + fn batch_prove( + _none: &Self::Setup, + _polynomials: &[&DensePolynomial], + _opening_point: &[Self::Field], + _openings: &[Self::Field], + _batch_type: BatchType, + _transcript: &mut ProofTranscript, + ) -> Self::BatchedProof { + todo!() + } + + fn verify( + _proof: &Self::Proof, + _setup: &Self::Setup, + transcript: &mut ProofTranscript, + _opening_point: &[Self::Field], + _opening: &Self::Field, + _commitment: &Self::Commitment, + ) -> Result<(), ProofVerifyError> { + + // Final Pairing Verification + /* + let d = transcript.challenge_scalar(); + let dInv = d.inv(); + + let left = P::multi_pairing(); + */ + todo!() + } + + fn batch_verify( + _batch_proof: &Self::BatchedProof, + _setup: &Self::Setup, + _opening_point: &[Self::Field], + _openings: &[Self::Field], + _commitments: &[&Self::Commitment], + _transcript: &mut ProofTranscript, + ) -> Result<(), ProofVerifyError> { + todo!() + } + + fn protocol_name() -> &'static [u8] { + b"dory" + } +} diff --git a/jolt-core/src/poly/commitment/mod.rs b/jolt-core/src/poly/commitment/mod.rs index 05278ecf2..7eff9e592 100644 --- a/jolt-core/src/poly/commitment/mod.rs +++ b/jolt-core/src/poly/commitment/mod.rs @@ -5,6 +5,7 @@ pub mod hyrax; pub mod kzg; pub mod pedersen; pub mod zeromorph; +pub mod dory; #[cfg(test)] pub mod mock;