Skip to content

Commit 8b847f4

Browse files
authored
feat(mpcs): share jagged inner Basefold opening (#61)
feat(mpcs): share jagged inner opening
1 parent 8ef2189 commit 8b847f4

4 files changed

Lines changed: 185 additions & 41 deletions

File tree

crates/mpcs/src/basefold.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,46 @@ where
477477
) -> Vec<ArcMultilinearExtension<'static, E>> {
478478
commitment.polys.iter().flatten().cloned().collect_vec()
479479
}
480+
481+
fn proof_size_breakdown(proof: &Self::Proof) -> Vec<(String, u64)> {
482+
let mut breakdown = vec![
483+
(
484+
"total".to_string(),
485+
bincode::serialized_size(proof).unwrap_or(0),
486+
),
487+
(
488+
"commits".to_string(),
489+
bincode::serialized_size(&proof.commits).unwrap_or(0),
490+
),
491+
(
492+
"final_message".to_string(),
493+
bincode::serialized_size(&proof.final_message).unwrap_or(0),
494+
),
495+
(
496+
"query_opening_proof".to_string(),
497+
bincode::serialized_size(&proof.query_opening_proof).unwrap_or(0),
498+
),
499+
(
500+
"sumcheck_proof".to_string(),
501+
bincode::serialized_size(&proof.sumcheck_proof).unwrap_or(0),
502+
),
503+
(
504+
"pow_witness".to_string(),
505+
bincode::serialized_size(&proof.pow_witness).unwrap_or(0),
506+
),
507+
];
508+
for (query_idx, query_proof) in proof.query_opening_proof.iter().enumerate() {
509+
breakdown.push((
510+
format!("query_opening_proof[{query_idx}].input_proofs"),
511+
bincode::serialized_size(&query_proof.input_proofs).unwrap_or(0),
512+
));
513+
breakdown.push((
514+
format!("query_opening_proof[{query_idx}].commit_phase_openings"),
515+
bincode::serialized_size(&query_proof.commit_phase_openings).unwrap_or(0),
516+
));
517+
}
518+
breakdown
519+
}
480520
}
481521

482522
#[cfg(test)]

crates/mpcs/src/jagged/mod.rs

Lines changed: 134 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -478,13 +478,12 @@ fn compute_f_at_point<E: ExtensionField>(
478478
/// 1. Batch the K column claims via a random column challenge `z_col`.
479479
/// 2. Run the jagged sumcheck to reduce to a single evaluation of q'.
480480
/// 3. Open q' at the sumcheck output point via the inner PCS.
481-
pub fn jagged_batch_open<E: ExtensionField, InnerPcs: PolynomialCommitmentScheme<E>>(
482-
pp: &InnerPcs::ProverParam,
481+
fn jagged_batch_open_round<E: ExtensionField, InnerPcs: PolynomialCommitmentScheme<E>>(
483482
comm: &JaggedCommitmentWithWitness<E, InnerPcs>,
484483
point: &[E],
485484
evals: &[E],
486485
transcript: &mut impl Transcript<E>,
487-
) -> Result<JaggedBatchOpenProof<E, InnerPcs>, Error> {
486+
) -> Result<(JaggedBatchOpenProof<E, InnerPcs>, InnerOpenings<E>), Error> {
488487
let num_polys = comm.num_polys();
489488
if evals.len() != num_polys {
490489
return Err(Error::InvalidPcsParam(format!(
@@ -593,38 +592,44 @@ pub fn jagged_batch_open<E: ExtensionField, InnerPcs: PolynomialCommitmentScheme
593592
transcript,
594593
);
595594

596-
// Open column MLEs at ρ_row via inner PCS.
597-
let inner_proof = InnerPcs::batch_open(
598-
pp,
599-
vec![(
600-
&comm.inner,
601-
inner_openings_for_col_evals(rho_row, &col_evals),
602-
)],
603-
transcript,
604-
)?;
595+
let inner_openings = inner_openings_for_col_evals(rho_row, &col_evals);
605596

606-
Ok(JaggedBatchOpenProof {
607-
sumcheck_proof,
608-
col_evals,
609-
f_at_rho,
610-
assist_proof,
597+
Ok((
598+
JaggedBatchOpenProof {
599+
sumcheck_proof,
600+
col_evals,
601+
f_at_rho,
602+
assist_proof,
603+
marker: PhantomData,
604+
},
605+
inner_openings,
606+
))
607+
}
608+
609+
pub fn jagged_batch_open<E: ExtensionField, InnerPcs: PolynomialCommitmentScheme<E>>(
610+
pp: &InnerPcs::ProverParam,
611+
comm: &JaggedCommitmentWithWitness<E, InnerPcs>,
612+
point: &[E],
613+
evals: &[E],
614+
transcript: &mut impl Transcript<E>,
615+
) -> Result<JaggedProof<E, InnerPcs>, Error> {
616+
let (round, inner_openings) =
617+
jagged_batch_open_round::<E, InnerPcs>(comm, point, evals, transcript)?;
618+
let inner_proof = InnerPcs::batch_open(pp, vec![(&comm.inner, inner_openings)], transcript)?;
619+
Ok(JaggedProof {
620+
rounds: vec![round],
611621
inner_proof,
612622
})
613623
}
614624

615-
/// Verify that evaluation claims `evals[i] = p_i(point_i)` are consistent with a
616-
/// jagged commitment.
617-
///
618-
/// Polynomials may have different heights. `point` has length `max_s`. Polynomial
619-
/// `i` with `s_i` variables is evaluated at the prefix `point[..s_i]`.
620-
pub fn jagged_batch_verify<E: ExtensionField, InnerPcs: PolynomialCommitmentScheme<E>>(
621-
vp: &InnerPcs::VerifierParam,
625+
fn jagged_batch_verify_without_inner<E: ExtensionField, InnerPcs: PolynomialCommitmentScheme<E>>(
626+
_vp: &InnerPcs::VerifierParam,
622627
comm: &JaggedCommitment<E, InnerPcs>,
623628
point: &[E],
624629
evals: &[E],
625630
proof: &JaggedBatchOpenProof<E, InnerPcs>,
626631
transcript: &mut impl Transcript<E>,
627-
) -> Result<(), Error> {
632+
) -> Result<(InnerPcs::Commitment, InnerVerifyOpenings<E>), Error> {
628633
let num_polys = comm.cumulative_heights.len() - 1;
629634
if evals.len() != num_polys {
630635
return Err(Error::InvalidPcsOpen(format!(
@@ -734,16 +739,40 @@ pub fn jagged_batch_verify<E: ExtensionField, InnerPcs: PolynomialCommitmentSche
734739
));
735740
}
736741

737-
// Verify the inner PCS opening at ρ_row with col_evals.
738-
InnerPcs::batch_verify(
742+
Ok((
743+
comm.inner.clone(),
744+
inner_verify_openings_for_col_evals(log_h, rho_row, &proof.col_evals),
745+
))
746+
}
747+
748+
/// Verify that evaluation claims `evals[i] = p_i(point_i)` are consistent with a
749+
/// jagged commitment.
750+
///
751+
/// Polynomials may have different heights. `point` has length `max_s`. Polynomial
752+
/// `i` with `s_i` variables is evaluated at the prefix `point[..s_i]`.
753+
pub fn jagged_batch_verify<E: ExtensionField, InnerPcs: PolynomialCommitmentScheme<E>>(
754+
vp: &InnerPcs::VerifierParam,
755+
comm: &JaggedCommitment<E, InnerPcs>,
756+
point: &[E],
757+
evals: &[E],
758+
proof: &JaggedProof<E, InnerPcs>,
759+
transcript: &mut impl Transcript<E>,
760+
) -> Result<(), Error> {
761+
if proof.rounds.len() != 1 {
762+
return Err(Error::InvalidPcsOpeningProof(format!(
763+
"jagged: expected one proof round, got {}",
764+
proof.rounds.len()
765+
)));
766+
}
767+
let inner_round = jagged_batch_verify_without_inner::<E, InnerPcs>(
739768
vp,
740-
vec![(
741-
comm.inner.clone(),
742-
inner_verify_openings_for_col_evals(log_h, rho_row, &proof.col_evals),
743-
)],
744-
&proof.inner_proof,
769+
comm,
770+
point,
771+
evals,
772+
&proof.rounds[0],
745773
transcript,
746774
)?;
775+
InnerPcs::batch_verify(vp, vec![inner_round], &proof.inner_proof, transcript)?;
747776

748777
Ok(())
749778
}
@@ -825,13 +854,19 @@ where
825854
transcript: &mut impl Transcript<E>,
826855
) -> Result<Self::Proof, Error> {
827856
let mut proofs = Vec::with_capacity(rounds.len());
857+
let mut inner_rounds = Vec::with_capacity(rounds.len());
828858
for (comm, openings) in rounds {
829859
let (point, evals) = flatten_padded_openings_as_native(&comm.poly_heights, openings)?;
830-
proofs.push(jagged_batch_open::<E, InnerPcs>(
831-
pp, comm, &point, &evals, transcript,
832-
)?);
860+
let (proof, inner_openings) =
861+
jagged_batch_open_round::<E, InnerPcs>(comm, &point, &evals, transcript)?;
862+
proofs.push(proof);
863+
inner_rounds.push((&comm.inner, inner_openings));
833864
}
834-
Ok(JaggedProof { rounds: proofs })
865+
let inner_proof = InnerPcs::batch_open(pp, inner_rounds, transcript)?;
866+
Ok(JaggedProof {
867+
rounds: proofs,
868+
inner_proof,
869+
})
835870
}
836871

837872
fn simple_batch_open(
@@ -869,6 +904,7 @@ where
869904
proof.rounds.len()
870905
)));
871906
}
907+
let mut inner_rounds = Vec::with_capacity(rounds.len());
872908
for ((comm, openings), round_proof) in rounds.into_iter().zip_eq(proof.rounds.iter()) {
873909
let poly_heights = comm
874910
.cumulative_heights
@@ -880,8 +916,17 @@ where
880916
.map(|(_, (point, evals))| (point, evals))
881917
.collect_vec();
882918
let (point, evals) = flatten_padded_openings_as_native(&poly_heights, openings)?;
883-
jagged_batch_verify::<E, InnerPcs>(vp, &comm, &point, &evals, round_proof, transcript)?;
919+
let inner_round = jagged_batch_verify_without_inner::<E, InnerPcs>(
920+
vp,
921+
&comm,
922+
&point,
923+
&evals,
924+
round_proof,
925+
transcript,
926+
)?;
927+
inner_rounds.push(inner_round);
884928
}
929+
InnerPcs::batch_verify(vp, inner_rounds, &proof.inner_proof, transcript)?;
885930
Ok(())
886931
}
887932

@@ -901,6 +946,55 @@ where
901946
) -> Vec<ArcMultilinearExtension<'static, E>> {
902947
commitment.polys.clone()
903948
}
949+
950+
fn proof_size_breakdown(proof: &Self::Proof) -> Vec<(String, u64)> {
951+
let mut breakdown = vec![
952+
(
953+
"total".to_string(),
954+
bincode::serialized_size(proof).unwrap_or(0),
955+
),
956+
(
957+
"rounds".to_string(),
958+
bincode::serialized_size(&proof.rounds).unwrap_or(0),
959+
),
960+
(
961+
"inner_proof".to_string(),
962+
bincode::serialized_size(&proof.inner_proof).unwrap_or(0),
963+
),
964+
];
965+
966+
for (round_idx, round) in proof.rounds.iter().enumerate() {
967+
breakdown.extend([
968+
(
969+
format!("round[{round_idx}].total"),
970+
bincode::serialized_size(round).unwrap_or(0),
971+
),
972+
(
973+
format!("round[{round_idx}].sumcheck_proof"),
974+
bincode::serialized_size(&round.sumcheck_proof).unwrap_or(0),
975+
),
976+
(
977+
format!("round[{round_idx}].col_evals"),
978+
bincode::serialized_size(&round.col_evals).unwrap_or(0),
979+
),
980+
(
981+
format!("round[{round_idx}].f_at_rho"),
982+
bincode::serialized_size(&round.f_at_rho).unwrap_or(0),
983+
),
984+
(
985+
format!("round[{round_idx}].assist_proof"),
986+
bincode::serialized_size(&round.assist_proof).unwrap_or(0),
987+
),
988+
]);
989+
}
990+
991+
breakdown.extend(
992+
InnerPcs::proof_size_breakdown(&proof.inner_proof)
993+
.into_iter()
994+
.map(|(name, size)| (format!("inner_proof.{name}"), size)),
995+
);
996+
breakdown
997+
}
904998
}
905999

9061000
#[cfg(test)]
@@ -1274,7 +1368,7 @@ mod tests {
12741368

12751369
let proof = jagged_batch_open::<E, Pcs>(&pp, &comm, &point, &evals, &mut transcript_p)
12761370
.expect("batch open");
1277-
assert_eq!(proof.col_evals.len(), w);
1371+
assert_eq!(proof.rounds[0].col_evals.len(), w);
12781372

12791373
let mut transcript_v = BasicTranscript::<E>::new(b"jagged_reshape_single");
12801374
Pcs::write_commitment(&comm.to_commitment().inner, &mut transcript_v).unwrap();
@@ -1325,7 +1419,7 @@ mod tests {
13251419

13261420
let proof = jagged_batch_open::<E, Pcs>(&pp, &comm, &point, &evals, &mut transcript_p)
13271421
.expect("batch open should succeed");
1328-
assert_eq!(proof.col_evals.len(), w);
1422+
assert_eq!(proof.rounds[0].col_evals.len(), w);
13291423

13301424
let mut transcript_v = BasicTranscript::<E>::new(b"jagged_reshape_multi");
13311425
Pcs::write_commitment(&comm.to_commitment().inner, &mut transcript_v).unwrap();
@@ -1374,7 +1468,7 @@ mod tests {
13741468

13751469
let proof = jagged_batch_open::<E, Pcs>(&pp, &comm, &point, &evals, &mut transcript_p)
13761470
.expect("batch open");
1377-
assert_eq!(proof.col_evals.len(), w);
1471+
assert_eq!(proof.rounds[0].col_evals.len(), w);
13781472

13791473
let mut transcript_v = BasicTranscript::<E>::new(b"jagged_reshape_non_power");
13801474
Pcs::write_commitment(&comm.to_commitment().inner, &mut transcript_v).unwrap();

crates/mpcs/src/jagged/types.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use ::sumcheck::structs::IOPProof;
33
use ff_ext::ExtensionField;
44
use multilinear_extensions::mle::ArcMultilinearExtension;
55
use serde::{Deserialize, Serialize};
6+
use std::marker::PhantomData;
67

78
/// Commitment to a jagged polynomial `q'`, together with all witness data needed
89
/// for opening proofs.
@@ -76,13 +77,15 @@ pub struct JaggedBatchOpenProof<E: ExtensionField, InnerPcs: PolynomialCommitmen
7677
pub col_evals: Vec<E>,
7778
pub f_at_rho: E,
7879
pub assist_proof: IOPProof<E>,
79-
pub inner_proof: InnerPcs::Proof,
80+
#[serde(skip)]
81+
pub marker: PhantomData<InnerPcs>,
8082
}
8183

8284
#[derive(Clone, Serialize, Deserialize)]
8385
#[serde(bound(serialize = "", deserialize = ""))]
8486
pub struct JaggedProof<E: ExtensionField, InnerPcs: PolynomialCommitmentScheme<E>> {
8587
pub rounds: Vec<JaggedBatchOpenProof<E, InnerPcs>>,
88+
pub inner_proof: InnerPcs::Proof,
8689
}
8790

8891
/// Convert a `usize` to its little-endian binary representation as field elements.

crates/mpcs/src/lib.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,13 @@ pub trait PolynomialCommitmentScheme<E: ExtensionField>: Clone {
201201
fn get_arc_mle_witness_from_commitment(
202202
commitment: &Self::CommitmentWithWitness,
203203
) -> Vec<ArcMultilinearExtension<'static, E>>;
204+
205+
fn proof_size_breakdown(proof: &Self::Proof) -> Vec<(String, u64)> {
206+
vec![(
207+
"total".to_string(),
208+
bincode::serialized_size(proof).unwrap_or(0),
209+
)]
210+
}
204211
}
205212

206213
#[derive(

0 commit comments

Comments
 (0)