Skip to content
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
13 changes: 8 additions & 5 deletions crates/jolt-dory/benches/dory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -227,12 +227,14 @@ fn bench_open_zk(c: &mut Criterion) {
.map(|_| <Fr as RandomSampling>::random(&mut rng))
.collect();
let eval = poly.evaluate(&point);
(poly, point, eval)
let (_, hint) =
<DoryScheme as ZkOpeningScheme>::commit_zk(poly.evaluations(), &setup);
(poly, point, eval, hint)
},
|(poly, point, eval)| {
|(poly, point, eval, hint)| {
let mut transcript =
jolt_transcript::Blake2bTranscript::new(b"bench-open-zk");
DoryScheme::open_zk(&poly, &point, eval, &setup, None, &mut transcript)
DoryScheme::open_zk(&poly, &point, eval, &setup, hint, &mut transcript)
},
criterion::BatchSize::SmallInput,
);
Expand All @@ -259,11 +261,12 @@ fn bench_verify_zk(c: &mut Criterion) {
.map(|_| <Fr as RandomSampling>::random(&mut rng))
.collect();
let eval = poly.evaluate(&point);
let (commitment, _) = DoryScheme::commit(poly.evaluations(), &setup);
let (commitment, hint) =
<DoryScheme as ZkOpeningScheme>::commit_zk(poly.evaluations(), &setup);
let mut transcript =
jolt_transcript::Blake2bTranscript::new(b"bench-verify-zk");
let (proof, _eval_com, _blind) =
DoryScheme::open_zk(&poly, &point, eval, &setup, None, &mut transcript);
DoryScheme::open_zk(&poly, &point, eval, &setup, hint, &mut transcript);
(commitment, point, proof)
},
|(commitment, point, proof)| {
Expand Down
6 changes: 4 additions & 2 deletions crates/jolt-dory/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,17 @@
//! # Public API
//!
//! - [`DoryScheme`] — implements the four PCS traits. Static methods:
//! `setup_prover`, `setup_verifier`. Also implements
//! `setup_prover` and `setup_verifier`. Use
//! [`ZkOpeningScheme::commit_zk`](jolt_openings::ZkOpeningScheme::commit_zk)
//! for hiding commitments. Also implements
//! [`DeriveSetup<DoryProverSetup>`](jolt_crypto::DeriveSetup) for
//! [`PedersenSetup<Bn254G1>`](jolt_crypto::PedersenSetup) (use
//! `PedersenSetup::derive(&prover_setup, capacity)`).
//! - [`DoryCommitment`] — BN254 pairing target element (GT).
//! - [`DoryProof`] — single opening proof.
//! - [`DoryProverSetup`] / [`DoryVerifierSetup`] — prover and verifier SRS.
//! - [`DoryPartialCommitment`] — intermediate state for streaming commitment.
//! - [`DoryHint`] — row commitments reusable as opening proof hint.
//! - [`DoryHint`] — row commitments and commitment blind reusable as opening proof hint.

mod scheme;
mod streaming;
Expand Down
130 changes: 89 additions & 41 deletions crates/jolt-dory/src/scheme.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use dory::primitives::arithmetic::{
DoryRoutines, Field as DoryField, Group as DoryGroup, PairingCurve,
};
use dory::primitives::poly::{MultilinearLagrange, Polynomial as DoryPolynomial};
use dory::Mode;
use jolt_crypto::{Bn254G1, Bn254GT, Commitment, DeriveSetup, JoltGroup, PedersenSetup};
use jolt_field::Fr;
use jolt_openings::{AdditivelyHomomorphic, CommitmentScheme, OpeningsError, ZkOpeningScheme};
Expand Down Expand Up @@ -92,6 +93,23 @@ impl DoryScheme {
let prover_setup = Self::setup_prover(max_num_vars);
DoryVerifierSetup(prover_setup.0.to_verifier_setup())
}

fn commit_with_mode<P, M>(poly: &P, setup: &DoryProverSetup) -> (DoryCommitment, DoryHint)
where
P: MultilinearPoly<Fr> + ?Sized,
M: Mode,
{
let row_commitments = compute_row_commitments(poly, setup);
let (tier_2, commit_blind) = commit_rows_tier_2::<M>(&row_commitments, setup);

(
DoryCommitment(ark_to_jolt_gt(&tier_2)),
DoryHint::new(
ark_to_jolt_g1_vec(row_commitments),
ark_to_jolt_fr(&commit_blind),
),
)
}
}

impl DeriveSetup<DoryProverSetup> for PedersenSetup<Bn254G1> {
Expand Down Expand Up @@ -136,24 +154,7 @@ impl CommitmentScheme for DoryScheme {
poly: &P,
setup: &Self::ProverSetup,
) -> (Self::Output, Self::OpeningHint) {
let num_vars = poly.num_vars();
let sigma = num_vars.div_ceil(2);
let num_cols = 1usize << sigma;
let num_rows = 1usize << (num_vars - sigma);

let row_commitments = if poly.is_one_hot() {
commit_rows_one_hot(poly, num_rows, num_cols, &setup.0)
} else {
commit_rows_dense(poly, sigma, &setup.0)
};

let g2_bases = &setup.0.g2_vec[..row_commitments.len()];
let tier_2 = <InnerBN254 as PairingCurve>::multi_pair_g2_setup(&row_commitments, g2_bases);

(
DoryCommitment(ark_to_jolt_gt(&tier_2)),
DoryHint(ark_to_jolt_g1_vec(row_commitments)),
)
Self::commit_with_mode::<P, Transparent>(poly, setup)
}

#[tracing::instrument(skip_all, name = "DoryScheme::open")]
Expand All @@ -169,14 +170,18 @@ impl CommitmentScheme for DoryScheme {
let adapter = DorySourceAdapter::new(poly);
let sigma = num_vars.div_ceil(2);
let nu = num_vars - sigma;
let num_cols = 1usize << sigma;
let num_rows = 1usize << nu;

let row_commitments = match hint {
Some(h) => jolt_g1_vec_to_ark(h.0),
None if poly.is_one_hot() => commit_rows_one_hot(poly, num_rows, num_cols, &setup.0),
None => commit_rows_dense(poly, sigma, &setup.0),
let (row_commitments, commit_blind) = match hint {
Comment thread
moodlezoup marked this conversation as resolved.
Some(h) => h.into_ark_parts(),
None => (
compute_row_commitments(poly, setup),
<ArkFr as DoryField>::zero(),
),
};
debug_assert!(
commit_blind.is_zero(),
"commit_blind should be 0 for transparent mode"
);

let ark_point: Vec<ArkFr> = point.iter().rev().map(jolt_fr_to_ark).collect();
let mut dory_transcript = JoltToDoryTranscript::new(transcript);
Expand All @@ -186,7 +191,7 @@ impl CommitmentScheme for DoryScheme {
&adapter,
&ark_point,
row_commitments,
<ArkFr as DoryField>::zero(),
commit_blind,
nu,
sigma,
&setup.0,
Expand Down Expand Up @@ -255,52 +260,58 @@ impl AdditivelyHomomorphic for DoryScheme {
assert_eq!(hints.len(), scalars.len());
assert!(!hints.is_empty(), "combine_hints: empty hint set");

let num_rows = hints[0].0.len();
let num_rows = hints[0].row_commitments.len();
assert!(
hints.iter().all(|h| h.0.len() == num_rows),
hints.iter().all(|h| h.row_commitments.len() == num_rows),
"combine_hints: ragged hint lengths",
);

let combined_blind = hints
.iter()
.zip(scalars.iter())
.map(|(hint, &scalar)| scalar * hint.commit_blind)
.sum();

let combined: Vec<Bn254G1> = (0..num_rows)
.into_par_iter()
.map(|row| {
let mut acc = Bn254G1::default();
for (hint, &scalar) in hints.iter().zip(scalars.iter()) {
acc += hint.0[row].scalar_mul(&scalar);
acc += hint.row_commitments[row].scalar_mul(&scalar);
}
acc
})
.collect();

DoryHint(combined)
DoryHint::new(combined, combined_blind)
}
}

impl ZkOpeningScheme for DoryScheme {
type HidingCommitment = Bn254G1;
type Blind = Fr;

fn commit_zk<P: MultilinearPoly<Fr> + ?Sized>(
poly: &P,
setup: &Self::ProverSetup,
) -> (Self::Output, Self::OpeningHint) {
Self::commit_with_mode::<P, dory::ZK>(poly, setup)
}

#[tracing::instrument(skip_all, name = "DoryScheme::open_zk")]
fn open_zk(
poly: &Self::Polynomial,
point: &[Fr],
_eval: Fr,
setup: &Self::ProverSetup,
hint: Option<Self::OpeningHint>,
hint: Self::OpeningHint,
transcript: &mut impl Transcript<Challenge = Self::Field>,
) -> (Self::Proof, Self::HidingCommitment, Self::Blind) {
let num_vars = point.len();
let adapter = DorySourceAdapter::new(poly);
let sigma = num_vars.div_ceil(2);
let nu = num_vars - sigma;
let num_cols = 1usize << sigma;
let num_rows = 1usize << nu;

let row_commitments = match hint {
Some(h) => jolt_g1_vec_to_ark(h.0),
None if poly.is_one_hot() => commit_rows_one_hot(poly, num_rows, num_cols, &setup.0),
None => commit_rows_dense(poly, sigma, &setup.0),
};
let (row_commitments, commit_blind) = hint.into_ark_parts();

let ark_point: Vec<ArkFr> = point.iter().rev().map(jolt_fr_to_ark).collect();
let mut dory_transcript = JoltToDoryTranscript::new(transcript);
Expand All @@ -310,7 +321,7 @@ impl ZkOpeningScheme for DoryScheme {
&adapter,
&ark_point,
row_commitments,
<ArkFr as DoryField>::zero(),
commit_blind,
nu,
sigma,
&setup.0,
Expand Down Expand Up @@ -402,6 +413,42 @@ fn commit_rows_one_hot<P: MultilinearPoly<Fr> + ?Sized>(
.collect()
}

fn compute_row_commitments<P: MultilinearPoly<Fr> + ?Sized>(
poly: &P,
setup: &DoryProverSetup,
) -> Vec<ArkG1> {
let num_vars = poly.num_vars();
let sigma = num_vars.div_ceil(2);
let num_cols = 1usize << sigma;
let num_rows = 1usize << (num_vars - sigma);

if poly.is_one_hot() {
commit_rows_one_hot(poly, num_rows, num_cols, &setup.0)
} else {
commit_rows_dense(poly, sigma, &setup.0)
}
}

pub(crate) fn commit_rows_tier_2<M: Mode>(
row_commitments: &[ArkG1],
setup: &DoryProverSetup,
) -> (ArkGT, ArkFr) {
let g2_bases = &setup.0.g2_vec[..row_commitments.len()];
let tier_2 = <InnerBN254 as PairingCurve>::multi_pair_g2_setup(row_commitments, g2_bases);
let commit_blind = M::sample::<ArkFr>();
let tier_2 = M::mask(tier_2, &setup.0.ht, &commit_blind);
(tier_2, commit_blind)
}

impl DoryHint {
fn into_ark_parts(self) -> (Vec<ArkG1>, ArkFr) {
(
jolt_g1_vec_to_ark(self.row_commitments),
jolt_fr_to_ark(&self.commit_blind),
)
}
}

/// Bridges [`MultilinearPoly<Fr>`] to dory-pcs's polynomial traits
/// without materializing the full evaluation table.
struct DorySourceAdapter<'a, S: MultilinearPoly<Fr>> {
Expand Down Expand Up @@ -547,15 +594,16 @@ mod tests {
.collect();
let eval = poly.evaluate(&point);

let (commitment, hint) = DoryScheme::commit(poly.evaluations(), &prover_setup);
let (commitment, hint) =
<DoryScheme as ZkOpeningScheme>::commit_zk(poly.evaluations(), &prover_setup);

let mut prove_transcript = jolt_transcript::Blake2bTranscript::new(b"zk-test");
let (proof, _eval_com, _blinding) = DoryScheme::open_zk(
&poly,
&point,
eval,
&prover_setup,
Some(hint),
hint,
&mut prove_transcript,
);

Expand Down
57 changes: 40 additions & 17 deletions crates/jolt-dory/src/streaming.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,34 @@
//! Streaming (chunked) commitment for the Dory scheme.

use dory::backends::arkworks::G1Routines;
use dory::primitives::arithmetic::{DoryRoutines, PairingCurve};
use dory::primitives::arithmetic::DoryRoutines;
use jolt_field::Fr;
use jolt_openings::StreamingCommitment;

use crate::scheme::{ark_to_jolt_g1, ark_to_jolt_gt, jolt_fr_to_ark, jolt_g1_vec_to_ark, ArkFr};
use crate::types::{DoryCommitment, DoryPartialCommitment};

type InnerBN254 = dory::backends::arkworks::BN254;
use crate::scheme::{
ark_to_jolt_fr, ark_to_jolt_g1, ark_to_jolt_g1_vec, ark_to_jolt_gt, commit_rows_tier_2,
jolt_fr_to_ark, jolt_g1_vec_to_ark, ArkFr,
};
use crate::types::{DoryCommitment, DoryHint, DoryPartialCommitment, DoryProverSetup};

impl crate::DoryScheme {
#[tracing::instrument(skip_all, name = "DoryScheme::stream_finish_zk")]
pub fn finish_zk(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a bit awkward that finish is a method defined on the StreamingCommitment trait, but the implementation is expected to differ depending on whether Dory is ZK or not. We should consider reworking the traits/types here to handle this more gracefully, but we can defer that to a follow-up

partial: DoryPartialCommitment,
setup: &DoryProverSetup,
) -> (DoryCommitment, DoryHint) {
validate_row_count(partial.row_commitments.len(), setup);
let row_commitments = jolt_g1_vec_to_ark(partial.row_commitments);
let (tier_2, commit_blind) = commit_rows_tier_2::<dory::ZK>(&row_commitments, setup);
(
DoryCommitment(ark_to_jolt_gt(&tier_2)),
DoryHint::new(
ark_to_jolt_g1_vec(row_commitments),
ark_to_jolt_fr(&commit_blind),
),
)
}
}

impl StreamingCommitment for crate::DoryScheme {
type PartialCommitment = DoryPartialCommitment;
Expand Down Expand Up @@ -49,24 +69,27 @@ impl StreamingCommitment for crate::DoryScheme {
#[tracing::instrument(skip_all, name = "DoryScheme::stream_finish")]
fn finish(partial: Self::PartialCommitment, setup: &Self::ProverSetup) -> Self::Output {
let num_rows = partial.row_commitments.len();
assert!(
num_rows.is_power_of_two(),
"streaming: row count ({num_rows}) must be a power of two",
);
assert!(
num_rows <= setup.0.g2_vec.len(),
"streaming: row count ({}) exceeds Dory SRS size ({})",
num_rows,
setup.0.g2_vec.len(),
);
validate_row_count(num_rows, setup);

let ark_rows = jolt_g1_vec_to_ark(partial.row_commitments);
let g2_bases = &setup.0.g2_vec[..num_rows];
let tier_2 = <InnerBN254 as PairingCurve>::multi_pair_g2_setup(&ark_rows, g2_bases);
let (tier_2, _) = commit_rows_tier_2::<dory::Transparent>(&ark_rows, setup);
DoryCommitment(ark_to_jolt_gt(&tier_2))
}
}

fn validate_row_count(num_rows: usize, setup: &DoryProverSetup) {
assert!(
num_rows.is_power_of_two(),
"streaming: row count ({num_rows}) must be a power of two",
);
assert!(
num_rows <= setup.0.g2_vec.len(),
"streaming: row count ({}) exceeds Dory SRS size ({})",
num_rows,
setup.0.g2_vec.len(),
);
}

#[cfg(test)]
mod tests {
use jolt_field::RandomSampling;
Expand Down
15 changes: 14 additions & 1 deletion crates/jolt-dory/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use dory::backends::arkworks::{
ArkDoryProof, ArkG1, ArkGT, ArkworksProverSetup, ArkworksVerifierSetup,
};
use jolt_crypto::{Bn254G1, Bn254GT, HomomorphicCommitment};
use jolt_field::Fr;
use jolt_transcript::{AppendToTranscript, Transcript};
use serde::{Deserialize, Deserializer, Serialize, Serializer};

Expand Down Expand Up @@ -85,7 +86,19 @@ impl<'de> Deserialize<'de> for DoryVerifierSetup {
}

#[derive(Clone, Debug, Default)]
pub struct DoryHint(pub Vec<Bn254G1>);
pub struct DoryHint {
pub(crate) row_commitments: Vec<Bn254G1>,
pub(crate) commit_blind: Fr,
}

impl DoryHint {
pub(crate) fn new(row_commitments: Vec<Bn254G1>, commit_blind: Fr) -> Self {
Self {
row_commitments,
commit_blind,
}
}
}

#[derive(Clone)]
pub struct DoryPartialCommitment {
Expand Down
Loading