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
35 changes: 8 additions & 27 deletions provekit/prover/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
#[cfg(test)]
use crate::r1cs::R1CSSolver;
use {
crate::{
r1cs::{CompressedLayers, CompressedR1CS},
whir_r1cs::WhirR1CSProver,
},
crate::whir_r1cs::WhirR1CSProver,
acir::native_types::{Witness, WitnessMap},
anyhow::{Context, Result},
provekit_common::{
Expand Down Expand Up @@ -122,12 +119,9 @@ impl Prove for Prover {
drop(self.program);
drop(self.witness_generator);

// R1CS matrices are only needed at sumcheck; compress to free memory during
// commits.
let compressed_r1cs =
CompressedR1CS::compress(self.r1cs).context("While compressing R1CS")?;
let num_witnesses = compressed_r1cs.num_witnesses();
let num_constraints = compressed_r1cs.num_constraints();
let r1cs = self.r1cs;
let num_witnesses = r1cs.num_witnesses();
let num_constraints = r1cs.num_constraints();

// Set up transcript with public inputs bound to the instance.
let instance = public_inputs.hash_bytes();
Expand All @@ -153,22 +147,17 @@ impl Prove for Prover {
.context("While solving w1 witnesses")?;
}

// Compress w2 layers to free memory during w1 commit (only when
// challenges exist; otherwise just drop them).
// Hold w2 layers across the w1 commit only when challenges exist.
let has_challenges = self.whir_for_witness.num_challenges > 0;
let compressed_w2_layers = if has_challenges {
Some(
CompressedLayers::compress(self.split_witness_builders.w2_layers)
.context("While compressing w2 layers")?,
)
let w2_layers = if has_challenges {
Some(self.split_witness_builders.w2_layers)
} else {
drop(self.split_witness_builders.w2_layers);
None
};

debug!(
witness_heap_bytes = witness.capacity() * size_of::<Option<FieldElement>>(),
compressed_r1cs_blob_bytes = compressed_r1cs.blob_len(),
"component sizes after solve_w1"
);

Expand Down Expand Up @@ -199,10 +188,7 @@ impl Prove for Prover {
.context("While committing to w1")?;

let commitments = if has_challenges {
let w2_layers = compressed_w2_layers
.unwrap()
.decompress()
.context("While decompressing w2 layers")?;
let w2_layers = w2_layers.expect("w2_layers is Some whenever has_challenges is true");
{
let _s = info_span!("solve_w2").entered();
crate::r1cs::solve_witness_vec(
Expand Down Expand Up @@ -234,11 +220,6 @@ impl Prove for Prover {
vec![commitment_1]
};

// Decompress R1CS for the sumcheck and matrix operations.
let r1cs = compressed_r1cs
.decompress()
.context("While decompressing R1CS")?;

#[cfg(test)]
r1cs.test_witness_satisfaction(&witness.iter().map(|w| w.unwrap()).collect::<Vec<_>>())
.context("While verifying R1CS instance")?;
Expand Down
68 changes: 4 additions & 64 deletions provekit/prover/src/r1cs.rs
Original file line number Diff line number Diff line change
@@ -1,78 +1,18 @@
#[cfg(test)]
use provekit_common::R1CS;
use {
crate::witness::witness_builder::WitnessBuilderSolver,
acir::native_types::WitnessMap,
anyhow::{Context, Result},
anyhow::Result,
provekit_common::{
utils::batch_inverse_montgomery,
witness::{LayerType, LayeredWitnessBuilders, WitnessBuilder},
FieldElement, NoirElement, TranscriptSponge, R1CS,
FieldElement, NoirElement, TranscriptSponge,
},
tracing::instrument,
whir::transcript::ProverState,
};

/// Serialized R1CS matrices held as a compact postcard blob.
///
/// The R1CS is only needed during the sumcheck phase. Compressing it
/// into a serialized blob frees that memory during the commit phase,
/// then decompresses when the sumcheck begins.
pub struct CompressedR1CS {
num_constraints: usize,
num_witnesses: usize,
blob: Vec<u8>,
}

/// Serialized witness builder layers held as a compact postcard blob.
///
/// Same strategy as [`CompressedR1CS`]: the w2 layers are not needed
/// until challenge-dependent witness solving, so we compress them to
/// free memory during the w1 commit.
pub struct CompressedLayers {
blob: Vec<u8>,
}

impl CompressedLayers {
pub fn compress(layers: LayeredWitnessBuilders) -> Result<Self> {
let blob = postcard::to_allocvec(&layers)
.context("LayeredWitnessBuilders serialization failed")?;
Ok(Self { blob })
}

pub fn decompress(self) -> Result<LayeredWitnessBuilders> {
postcard::from_bytes(&self.blob).context("LayeredWitnessBuilders deserialization failed")
}
}

impl CompressedR1CS {
pub fn compress(r1cs: R1CS) -> Result<Self> {
let num_constraints = r1cs.num_constraints();
let num_witnesses = r1cs.num_witnesses();
let blob = postcard::to_allocvec(&r1cs).context("R1CS serialization failed")?;
drop(r1cs);
Ok(Self {
num_constraints,
num_witnesses,
blob,
})
}

pub fn decompress(self) -> Result<R1CS> {
postcard::from_bytes(&self.blob).context("R1CS deserialization failed")
}

pub const fn num_constraints(&self) -> usize {
self.num_constraints
}

pub const fn num_witnesses(&self) -> usize {
self.num_witnesses
}

pub fn blob_len(&self) -> usize {
self.blob.len()
}
}

#[cfg(test)]
pub trait R1CSSolver {
fn test_witness_satisfaction(&self, witness: &[FieldElement]) -> anyhow::Result<()>;
Expand Down
Loading