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
12 changes: 6 additions & 6 deletions crates/iop-prover/src/basefold_channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,12 @@ where
self.transcript
}

/// Consumes the channel, asserting all oracle specs have been consumed.
pub fn finish(self) {
let n_remaining = self.oracle_specs.len() - self.next_oracle_index;
assert!(n_remaining == 0, "finish called but {n_remaining} oracle specs remaining",);
}

/// Creates a new BaseFold prover channel from a compiler with precomputed FRI parameters.
///
/// This constructor borrows the NTT and other parameters from the compiler.
Expand Down Expand Up @@ -260,12 +266,6 @@ where
&mut self,
oracle_relations: impl IntoIterator<Item = (Self::Oracle, FieldBuffer<P>, P::Scalar)>,
) {
assert!(
self.remaining_oracle_specs().is_empty(),
"prove_oracle_relations called but {} oracle specs remaining",
self.remaining_oracle_specs().len()
);

// Process each oracle relation with its own BaseFold proof
for (oracle, transparent_poly, eval_claim) in oracle_relations {
let index = oracle.index;
Expand Down
12 changes: 6 additions & 6 deletions crates/iop-prover/src/basefold_zk_channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,12 @@ where
pub fn transcript(&self) -> &ProverTranscript<Challenger_> {
self.transcript
}

/// Consumes the channel, asserting all oracle specs have been consumed.
pub fn finish(self) {
let n_remaining = self.oracle_specs.len() - self.next_oracle_index;
assert!(n_remaining == 0, "finish called but {n_remaining} oracle specs remaining",);
}
}

impl<'a, F, P, NTT, MerkleScheme, MerkleProver_, Challenger_> IPProverChannel<F>
Expand Down Expand Up @@ -213,12 +219,6 @@ where
&mut self,
oracle_relations: impl IntoIterator<Item = (Self::Oracle, FieldBuffer<P>, P::Scalar)>,
) {
assert!(
self.remaining_oracle_specs().is_empty(),
"prove_oracle_relations called but {} oracle specs remaining",
self.remaining_oracle_specs().len()
);

for (oracle, transparent_poly, eval_claim) in oracle_relations {
let index = oracle.index;
assert!(
Expand Down
12 changes: 6 additions & 6 deletions crates/iop-prover/src/naive_channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,12 @@ where
pub fn transcript(&self) -> &ProverTranscript<Challenger_> {
self.transcript
}

/// Consumes the channel, asserting all oracle specs have been consumed.
pub fn finish(self) {
let n_remaining = self.oracle_specs.len() - self.next_oracle_index;
assert!(n_remaining == 0, "finish called but {n_remaining} oracle specs remaining",);
}
}

impl<F, P, Challenger_> IPProverChannel<F> for NaiveProverChannel<'_, F, P, Challenger_>
Expand Down Expand Up @@ -164,12 +170,6 @@ where
&mut self,
oracle_relations: impl IntoIterator<Item = (Self::Oracle, FieldBuffer<P>, P::Scalar)>,
) {
assert!(
self.remaining_oracle_specs().is_empty(),
"prove_oracle_relations called but {} oracle specs remaining",
self.remaining_oracle_specs().len()
);

// For the naive channel, we write the transparent polynomial to the transcript
// so the verifier can read it and verify the inner product directly.
for (oracle, transparent_poly, eval_claim) in oracle_relations {
Expand Down
16 changes: 8 additions & 8 deletions crates/iop/src/basefold_channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,12 @@ where
pub fn transcript(&self) -> &VerifierTranscript<Challenger_> {
self.transcript
}

/// Consumes the channel, asserting all oracle specs have been consumed.
pub fn finish(self) {
let n_remaining = self.oracle_specs.len() - self.next_oracle_index;
assert!(n_remaining == 0, "finish called but {n_remaining} oracle specs remaining",);
}
}

impl<F, MerkleScheme_, Challenger_> IPVerifierChannel<F>
Expand Down Expand Up @@ -183,16 +189,10 @@ where
Ok(BaseFoldOracle { index })
}

fn verify_oracle_relations(
fn verify_oracle_relations<'a>(
&mut self,
oracle_relations: impl IntoIterator<Item = OracleLinearRelation<Self::Oracle, Self::Elem>>,
oracle_relations: impl IntoIterator<Item = OracleLinearRelation<'a, Self::Oracle, Self::Elem>>,
) -> Result<(), Error> {
assert!(
self.remaining_oracle_specs().is_empty(),
"verify_oracle_relations called but {} oracle specs remaining",
self.remaining_oracle_specs().len()
);

// Process each oracle relation with its own BaseFold verification
for relation in oracle_relations {
let index = relation.oracle.index;
Expand Down
16 changes: 8 additions & 8 deletions crates/iop/src/basefold_zk_channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ where
pub fn transcript(&self) -> &VerifierTranscript<Challenger_> {
self.transcript
}

/// Consumes the channel, asserting all oracle specs have been consumed.
pub fn finish(self) {
let n_remaining = self.oracle_specs.len() - self.next_oracle_index;
assert!(n_remaining == 0, "finish called but {n_remaining} oracle specs remaining",);
}
}

impl<F, MerkleScheme_, Challenger_> IPVerifierChannel<F>
Expand Down Expand Up @@ -170,16 +176,10 @@ where
Ok(BaseFoldZKOracle { index })
}

fn verify_oracle_relations(
fn verify_oracle_relations<'a>(
&mut self,
oracle_relations: impl IntoIterator<Item = OracleLinearRelation<Self::Oracle, Self::Elem>>,
oracle_relations: impl IntoIterator<Item = OracleLinearRelation<'a, Self::Oracle, Self::Elem>>,
) -> Result<(), Error> {
assert!(
self.remaining_oracle_specs().is_empty(),
"verify_oracle_relations called but {} oracle specs remaining",
self.remaining_oracle_specs().len()
);

for relation in oracle_relations {
let index = relation.oracle.index;
assert!(
Expand Down
10 changes: 5 additions & 5 deletions crates/iop/src/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,22 +38,22 @@ pub struct OracleSpec {
}

/// A boxed closure that evaluates a transparent MLE at a given point.
pub type TransparentEvalFn<Elem> = Box<dyn Fn(&[Elem]) -> Elem>;
pub type TransparentEvalFn<'a, Elem> = Box<dyn Fn(&[Elem]) -> Elem + 'a>;

/// An oracle linear relation specifying an inner product claim between a committed oracle
/// polynomial and a transparent polynomial.
///
/// The claim asserts that `<oracle_poly, transparent_poly> = claim`, where `transparent_poly` is
/// the multilinear extension defined by the `transparent` closure evaluated at the challenge point
/// sampled during the protocol.
pub struct OracleLinearRelation<Oracle, Elem> {
pub struct OracleLinearRelation<'a, Oracle, Elem> {
/// The oracle handle for the committed polynomial.
pub oracle: Oracle,
/// A closure that evaluates the transparent MLE at a given point.
///
/// The closure receives the challenge point (sampled during `verify_oracle_relations`) and
/// returns the evaluation of the transparent polynomial's MLE at that point.
pub transparent: TransparentEvalFn<Elem>,
pub transparent: TransparentEvalFn<'a, Elem>,
/// The claimed inner product of the oracle polynomial and the transparent polynomial.
pub claim: Elem,
}
Expand Down Expand Up @@ -100,8 +100,8 @@ pub trait IOPVerifierChannel<F: Field>: IPVerifierChannel<F> {
/// * `remaining_oracle_specs()` must be empty (all oracles received).
/// * All oracle handles in `oracle_relations` must be valid handles returned by
/// `recv_oracle()`.
fn verify_oracle_relations(
fn verify_oracle_relations<'a>(
&mut self,
oracle_relations: impl IntoIterator<Item = OracleLinearRelation<Self::Oracle, Self::Elem>>,
oracle_relations: impl IntoIterator<Item = OracleLinearRelation<'a, Self::Oracle, Self::Elem>>,
) -> Result<(), Error>;
}
16 changes: 8 additions & 8 deletions crates/iop/src/naive_channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,12 @@ where
pub fn transcript(&self) -> &VerifierTranscript<Challenger_> {
self.transcript
}

/// Consumes the channel, asserting all oracle specs have been consumed.
pub fn finish(self) {
let n_remaining = self.oracle_specs.len() - self.next_oracle_index;
assert!(n_remaining == 0, "finish called but {n_remaining} oracle specs remaining",);
}
}

impl<F, Challenger_> IPVerifierChannel<F> for NaiveVerifierChannel<'_, F, Challenger_>
Expand Down Expand Up @@ -165,16 +171,10 @@ where
Ok(NaiveOracle { index })
}

fn verify_oracle_relations(
fn verify_oracle_relations<'a>(
&mut self,
oracle_relations: impl IntoIterator<Item = OracleLinearRelation<Self::Oracle, F>>,
oracle_relations: impl IntoIterator<Item = OracleLinearRelation<'a, Self::Oracle, F>>,
) -> Result<(), Error> {
assert!(
self.remaining_oracle_specs().is_empty(),
"verify_oracle_relations called but {} oracle specs remaining",
self.remaining_oracle_specs().len()
);

for relation in oracle_relations {
let index = relation.oracle.index;
assert!(index < self.stored_polynomials.len(), "oracle index {index} out of bounds");
Expand Down
4 changes: 2 additions & 2 deletions crates/iop/src/size_tracking_channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,9 +132,9 @@ impl<F: BinaryField, MerkleScheme_: MerkleTreeScheme<F>> IOPVerifierChannel<F>
Ok(())
}

fn verify_oracle_relations(
fn verify_oracle_relations<'a>(
&mut self,
_oracle_relations: impl IntoIterator<Item = OracleLinearRelation<Self::Oracle, Self::Elem>>,
_oracle_relations: impl IntoIterator<Item = OracleLinearRelation<'a, Self::Oracle, Self::Elem>>,
) -> Result<(), Error> {
// Add FRI proof sizes for all oracles. This accounts for the dominant component of
// BaseFold proofs (FRI decommitments) but is missing smaller elements (e.g. sumcheck
Expand Down
12 changes: 12 additions & 0 deletions crates/spartan-frontend/src/constraint_system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,18 @@ pub struct ConstraintWire {
pub(crate) id: u32,
}

impl ConstraintWire {
/// Creates a constraint wire referencing an inout wire by ID.
///
/// TODO: This is not ideal, and instead we should use some sort of allocator.
pub fn inout(id: u32) -> Self {
Self {
kind: WireKind::InOut,
id,
}
}
}

#[derive(Debug, Clone)]
pub struct Operand<W>(SmallVec<[W; 4]>);

Expand Down
5 changes: 2 additions & 3 deletions crates/spartan-verifier/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,6 @@ impl IOPVerifier {
where
F: BinaryField,
Channel: IOPVerifierChannel<F>,
Channel::Elem: 'static,
{
let _verify_guard =
tracing::info_span!("Verify", operation = "verify", perfetto_category = "operation")
Expand Down Expand Up @@ -339,10 +338,10 @@ where
}

/// Returns a closure that evaluates the mask transparent polynomial at a given point.
fn mask_transparent<E: FieldOps + 'static>(
fn mask_transparent<'a, E: FieldOps + 'a>(
cs: &ConstraintSystemPadded,
r_x: &[E],
) -> binius_iop::channel::TransparentEvalFn<E> {
) -> binius_iop::channel::TransparentEvalFn<'a, E> {
let (_m_n, m_d) = cs.mask_dims();
let n_vars = r_x.len();
let mask_degree = 2; // quadratic composition
Expand Down
4 changes: 2 additions & 2 deletions crates/spartan-verifier/src/wiring.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,13 @@ where
///
/// The returned closure computes the expected evaluation of the wiring MLE batched with the
/// public input equality check, given a challenge point from the BaseFold opening.
pub fn eval_transparent<F: FieldOps + 'static>(
pub fn eval_transparent<'a, F: FieldOps + 'a>(
constraint_system: &ConstraintSystemPadded,
r_public: &[F],
r_x: &[F],
lambda: F,
batch_coeff: F,
) -> binius_iop::channel::TransparentEvalFn<F> {
) -> binius_iop::channel::TransparentEvalFn<'a, F> {
let r_public = r_public.to_vec();
let r_x = r_x.to_vec();
let mul_constraints = constraint_system.mul_constraints().to_vec();
Expand Down
32 changes: 32 additions & 0 deletions crates/spartan-wrapper-prover/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
[package]
name = "binius-spartan-wrapper-prover"
version.workspace = true
edition.workspace = true
authors.workspace = true

[dependencies]
binius-field = { path = "../field" }
binius-iop = { path = "../iop" }
binius-ip = { path = "../ip" }
binius-iop-prover = { path = "../iop-prover" }
binius-ip-prover = { path = "../ip-prover" }
binius-math = { path = "../math" }
binius-spartan-frontend = { path = "../spartan-frontend" }
binius-spartan-prover = { path = "../spartan-prover" }
binius-spartan-verifier = { path = "../spartan-verifier" }
binius-spartan-wrapper = { path = "../spartan-wrapper" }
binius-transcript = { path = "../transcript" }
binius-utils = { path = "../utils" }
rand.workspace = true

[dev-dependencies]
binius-hash = { path = "../hash" }
binius-iop = { path = "../iop" }
binius-ip = { path = "../ip" }
binius-math = { path = "../math" }
binius-spartan-verifier = { path = "../spartan-verifier" }
binius-spartan-wrapper = { path = "../spartan-wrapper" }
binius-verifier = { path = "../verifier" }

[lints]
workspace = true
18 changes: 18 additions & 0 deletions crates/spartan-wrapper-prover/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright 2026 The Binius Developers

//! Spartan wrapper prover for ZK-wrapped IOP proving.
//!
//! This crate provides [`ZKWrappedProverChannel`], the prover-side counterpart to
//! [`ZKWrappedVerifierChannel`]. It wraps a [`BaseFoldZKProverChannel`] and records all channel
//! operations. After the inner proof is run through the channel, [`finish`] replays the
//! interaction through a [`ReplayChannel`] to fill the outer witness, then runs the outer IOP
//! prover.
//!
//! [`ZKWrappedVerifierChannel`]: binius_spartan_wrapper::ZKWrappedVerifierChannel
//! [`BaseFoldZKProverChannel`]: binius_iop_prover::basefold_zk_channel::BaseFoldZKProverChannel
//! [`ReplayChannel`]: binius_spartan_wrapper::ReplayChannel
//! [`finish`]: ZKWrappedProverChannel::finish

mod zk_wrapped_prover_channel;

pub use zk_wrapped_prover_channel::ZKWrappedProverChannel;
Loading
Loading