Skip to content
Draft

Spark #208

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
9d00214
SPARK prover with 2 gpa combined
batmendbar Sep 15, 2025
03e2726
Adds RS and WS
batmendbar Sep 16, 2025
dd1dd42
wip: batch whir
batmendbar Sep 17, 2025
f5ca88d
Adds test
batmendbar Sep 17, 2025
eb30b9f
Creates variable for number of variables
batmendbar Sep 17, 2025
a9bd8f9
Adds batched WHIR to sumcheck+rowwise
batmendbar Sep 18, 2025
6a67ee0
Adds B and C matrices
batmendbar Sep 18, 2025
8585d52
Merge branch 'main' into spark-batched-whir
batmendbar Sep 22, 2025
204259e
Writes request to file
batmendbar Sep 22, 2025
1f7a0eb
Pads matrices
batmendbar Sep 23, 2025
37524f9
Added cli flag and removed debug log
batmendbar Sep 23, 2025
3659823
Buggy: update
batmendbar Sep 24, 2025
745faf4
Parse initial commitments
batmendbar Sep 24, 2025
dd4ebe9
Buggy: current progress
batmendbar Sep 25, 2025
d958f97
Buggy: Merkle parse fix
batmendbar Sep 25, 2025
0a690a9
Fixes 3 poly
batmendbar Sep 26, 2025
cdd2c10
Buggy: current
batmendbar Sep 26, 2025
cf2ccb1
Adds partial RS WS
batmendbar Sep 26, 2025
9be0398
Single matrix
batmendbar Sep 29, 2025
10cf5ae
Cleanup
batmendbar Sep 30, 2025
a189da6
Adds B and C matrices
batmendbar Sep 30, 2025
2f4717b
Complete
batmendbar Sep 30, 2025
c6218eb
Bugg: RLC optimization - val not properly committed
batmendbar Oct 2, 2025
0462090
Rust rlc prover/verifier prototype
batmendbar Oct 2, 2025
dedc0dc
working rlc
batmendbar Oct 3, 2025
c8135bb
Cleanup rust prover
batmendbar Oct 3, 2025
a0b8b8d
cleanup circuit
batmendbar Oct 3, 2025
96d53cb
Cleanup
batmendbar Oct 3, 2025
2c0e940
Merge branch 'main' into spark-rlc
batmendbar Oct 6, 2025
8660d5d
Rust format
batmendbar Oct 6, 2025
962c6ca
feat: refactor
shreyas-londhe Oct 9, 2025
b0960cf
fix: spark proving
shreyas-londhe Oct 10, 2025
12bd1e1
feat: e2e working
shreyas-londhe Oct 11, 2025
775b2ef
chore: remove spark-prover
shreyas-londhe Oct 11, 2025
1990e2e
Merge pull request #214 from worldfnd/sl/spark
batmendbar Oct 15, 2025
d58e5e8
Merge branch 'main' into spark-rlc
batmendbar Oct 21, 2025
65fb227
Modify end-to-end workflow
batmendbar Oct 22, 2025
7cb9210
Adds sparkConfig to server
batmendbar Oct 22, 2025
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
2 changes: 1 addition & 1 deletion .github/workflows/end-to-end.yml
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ jobs:
MONITOR_PID=$!

# Run the main process
./gnark-verifier --config "../noir-examples/noir-passport-examples/complete_age_check/params_for_recursive_verifier" --r1cs "../noir-examples/noir-passport-examples/complete_age_check/r1cs.json" --pk_url ${{ vars.AGE_CHECK_PK }} --vk_url ${{ vars.AGE_CHECK_VK }}
./gnark-verifier --evaluation spark --config "../../../noir-examples/noir-passport-examples/complete_age_check/params_for_recursive_verifier" --spark_config "../../../noir-examples/noir-passport-examples/complete_age_check/gnark_spark_proof.json" --r1cs "../../../noir-examples/noir-passport-examples/complete_age_check/r1cs.json" --pk_url ${{ vars.AGE_CHECK_PK }} --vk_url ${{ vars.AGE_CHECK_VK }}

# Stop monitoring
kill $MONITOR_PID
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ members = [
"provekit/r1cs-compiler",
"provekit/prover",
"provekit/verifier",
"provekit/spark",
"tooling/cli",
"tooling/provekit-bench",
"tooling/provekit-gnark",
"tooling/spark-cli",
"tooling/verifier-server",
"ntt",
]
Expand Down Expand Up @@ -86,6 +88,7 @@ provekit-prover = { path = "provekit/prover" }
provekit-r1cs-compiler = { path = "provekit/r1cs-compiler" }
provekit-verifier = { path = "provekit/verifier" }
provekit-verifier-server = { path = "tooling/verifier-server" }
provekit-spark = { path = "provekit/spark" }

# 3rd party
anyhow = "1.0.93"
Expand Down
1 change: 1 addition & 0 deletions provekit/common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ ark-crypto-primitives.workspace = true
ark-ff.workspace = true
ark-serialize.workspace = true
ark-std.workspace = true
ark-poly.workspace = true
spongefish.workspace = true
spongefish-pow.workspace = true
whir.workspace = true
Expand Down
76 changes: 76 additions & 0 deletions provekit/common/src/gnark.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
use {
crate::WhirConfig,
ark_poly::EvaluationDomain,
serde::{Deserialize, Serialize},
};

#[derive(Debug, Serialize, Deserialize)]

pub struct WHIRConfigGnark {
/// number of rounds
pub n_rounds: usize,
/// rate
pub rate: usize,
/// number of variables
pub n_vars: usize,
/// folding factor
pub folding_factor: Vec<usize>,
/// out of domain samples
pub ood_samples: Vec<usize>,
/// number of queries
pub num_queries: Vec<usize>,
/// proof of work bits
pub pow_bits: Vec<i32>,
/// final queries
pub final_queries: usize,
/// final proof of work bits
pub final_pow_bits: i32,
/// final folding proof of work bits
pub final_folding_pow_bits: i32,
/// domain generator string
pub domain_generator: String,
/// batch size
pub batch_size: usize,
}

impl WHIRConfigGnark {
pub fn new(whir_params: &WhirConfig) -> Self {
WHIRConfigGnark {
n_rounds: whir_params
.folding_factor
.compute_number_of_rounds(whir_params.mv_parameters.num_variables)
.0,
rate: whir_params.starting_log_inv_rate,
n_vars: whir_params.mv_parameters.num_variables,
folding_factor: (0..(whir_params
.folding_factor
.compute_number_of_rounds(whir_params.mv_parameters.num_variables)
.0))
.map(|round| whir_params.folding_factor.at_round(round))
.collect(),
ood_samples: whir_params
.round_parameters
.iter()
.map(|x| x.ood_samples)
.collect(),
num_queries: whir_params
.round_parameters
.iter()
.map(|x| x.num_queries)
.collect(),
pow_bits: whir_params
.round_parameters
.iter()
.map(|x| x.pow_bits as i32)
.collect(),
final_queries: whir_params.final_queries,
final_pow_bits: whir_params.final_pow_bits as i32,
final_folding_pow_bits: whir_params.final_folding_pow_bits as i32,
domain_generator: format!(
"{}",
whir_params.starting_domain.backing_domain.group_gen()
),
batch_size: whir_params.batch_size,
}
}
}
8 changes: 4 additions & 4 deletions provekit/common/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
pub mod file;
pub mod gnark;
mod interner;
mod noir_proof_scheme;
mod prover;
mod r1cs;
pub mod skyscraper;
pub mod spark;
mod sparse_matrix;
pub mod utils;
mod verifier;
mod whir_r1cs;
pub mod witness;

use crate::{
interner::{InternedFieldElement, Interner},
sparse_matrix::{HydratedSparseMatrix, SparseMatrix},
};
use crate::interner::{InternedFieldElement, Interner};
pub use {
acir::FieldElement as NoirElement,
noir_proof_scheme::{NoirProof, NoirProofScheme},
prover::Prover,
r1cs::R1CS,
sparse_matrix::{HydratedSparseMatrix, SparseMatrix},
verifier::Verifier,
whir::crypto::fields::Field256 as FieldElement,
whir_r1cs::{IOPattern, WhirConfig, WhirR1CSProof, WhirR1CSScheme},
Expand Down
2 changes: 2 additions & 0 deletions provekit/common/src/noir_proof_scheme.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use {
crate::{
spark::SparkStatement,
whir_r1cs::{WhirR1CSProof, WhirR1CSScheme},
witness::{LayeredWitnessBuilders, NoirWitnessGenerator},
NoirElement, R1CS,
Expand All @@ -21,6 +22,7 @@ pub struct NoirProofScheme {
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct NoirProof {
pub whir_r1cs_proof: WhirR1CSProof,
pub spark_statement: SparkStatement,
}

impl NoirProofScheme {
Expand Down
35 changes: 35 additions & 0 deletions provekit/common/src/spark.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
use {
crate::{utils::serde_ark, FieldElement},
ark_serialize::{CanonicalDeserialize, CanonicalSerialize},
serde::{Deserialize, Serialize},
};

#[derive(
Debug, Clone, PartialEq, Eq, CanonicalSerialize, Serialize, CanonicalDeserialize, Deserialize,
)]
pub struct Point {
#[serde(with = "serde_ark")]
pub row: Vec<FieldElement>,
#[serde(with = "serde_ark")]
pub col: Vec<FieldElement>,
}

#[derive(
Debug, Clone, PartialEq, Eq, CanonicalSerialize, Serialize, CanonicalDeserialize, Deserialize,
)]
pub struct ClaimedValues {
#[serde(with = "serde_ark")]
pub a: FieldElement,
#[serde(with = "serde_ark")]
pub b: FieldElement,
#[serde(with = "serde_ark")]
pub c: FieldElement,
}

#[derive(
Debug, Clone, PartialEq, Eq, CanonicalSerialize, Serialize, CanonicalDeserialize, Deserialize,
)]
pub struct SparkStatement {
pub point_to_evaluate: Point,
pub claimed_values: ClaimedValues,
}
1 change: 1 addition & 0 deletions provekit/prover/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ repository.workspace = true
# Workspace crates
provekit-common.workspace = true
skyscraper.workspace = true
serde_json.workspace = true

# Noir language
acir.workspace = true
Expand Down
9 changes: 6 additions & 3 deletions provekit/prover/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,14 +101,17 @@ impl Prove for Prover {
.context("While verifying R1CS instance")?;

// Prove R1CS instance
let whir_r1cs_proof = self
let (whir_r1cs_proof, spark_statement) = self
.whir_for_witness
.take()
.unwrap()
.prove(self.r1cs.take().unwrap(), witness)
.prove(&self.r1cs.take().unwrap(), witness)
.context("While proving R1CS instance")?;

Ok(NoirProof { whir_r1cs_proof })
Ok(NoirProof {
whir_r1cs_proof,
spark_statement,
})
}

fn create_witness_io_pattern(&self) -> IOPattern {
Expand Down
137 changes: 137 additions & 0 deletions provekit/prover/src/noir_proof_scheme.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
use {
crate::{
r1cs::R1CSSolver,
whir_r1cs::WhirR1CSProver,
witness::{fill_witness, witness_io_pattern::WitnessIOPattern},
},
acir::native_types::WitnessMap,
anyhow::{Context, Result},
bn254_blackbox_solver::Bn254BlackBoxSolver,
nargo::foreign_calls::DefaultForeignCallBuilder,
noirc_abi::InputMap,
provekit_common::{
skyscraper::SkyscraperSponge, utils::noir_to_native, witness::WitnessBuilder, FieldElement,
IOPattern, NoirElement, NoirProof, NoirProofScheme,
},
spongefish::{codecs::arkworks_algebra::FieldToUnitSerialize, ProverState},
tracing::instrument,
};

pub trait NoirProofSchemeProver {
fn generate_witness(&self, input_map: &InputMap) -> Result<WitnessMap<NoirElement>>;

fn prove(&self, input_map: &InputMap) -> Result<NoirProof>;

fn create_witness_io_pattern(&self) -> IOPattern;

fn seed_witness_merlin(
&self,
merlin: &mut ProverState<SkyscraperSponge, FieldElement>,
witness: &WitnessMap<NoirElement>,
) -> Result<()>;
}

impl NoirProofSchemeProver for NoirProofScheme {
#[instrument(skip_all)]
fn generate_witness(&self, input_map: &InputMap) -> Result<WitnessMap<NoirElement>> {
let solver = Bn254BlackBoxSolver::default();
let mut output_buffer = Vec::new();
let mut foreign_call_executor = DefaultForeignCallBuilder {
output: &mut output_buffer,
enable_mocks: false,
resolver_url: None,
root_path: None,
package_name: None,
}
.build();

let initial_witness = self.witness_generator.abi().encode(input_map, None)?;

let mut witness_stack = nargo::ops::execute_program(
&self.program,
initial_witness,
&solver,
&mut foreign_call_executor,
)?;

Ok(witness_stack
.pop()
.context("Missing witness results")?
.witness)
}

#[instrument(skip_all)]
fn prove(&self, input_map: &InputMap) -> Result<NoirProof> {
let acir_witness_idx_to_value_map = self.generate_witness(input_map)?;

// Solve R1CS instance
let witness_io = self.create_witness_io_pattern();
let mut witness_merlin = witness_io.to_prover_state();
self.seed_witness_merlin(&mut witness_merlin, &acir_witness_idx_to_value_map)?;

let partial_witness = self.r1cs.solve_witness_vec(
&self.witness_builders,
&acir_witness_idx_to_value_map,
&mut witness_merlin,
);
let witness = fill_witness(partial_witness).context("while filling witness")?;

// Verify witness (redudant with solve)
#[cfg(test)]
self.r1cs
.test_witness_satisfaction(&witness)
.context("While verifying R1CS instance")?;

// Prove R1CS instance
let (whir_r1cs_proof, spark_statement) = self
.whir_for_witness
.prove(&self.r1cs, witness)
.context("While proving R1CS instance")?;

Ok(NoirProof {
whir_r1cs_proof,
spark_statement,
})
}

fn create_witness_io_pattern(&self) -> IOPattern {
let circuit = &self.program.functions[0];
let public_idxs = circuit.public_inputs().indices();
let num_challenges = self
.witness_builders
.iter()
.filter(|b| matches!(b, WitnessBuilder::Challenge(_)))
.count();

// Create witness IO pattern
IOPattern::new("📜")
.add_shape()
.add_public_inputs(public_idxs.len())
.add_logup_challenges(num_challenges)
}

fn seed_witness_merlin(
&self,
merlin: &mut ProverState<SkyscraperSponge, FieldElement>,
witness: &WitnessMap<NoirElement>,
) -> Result<()> {
// Absorb circuit shape
let _ = merlin.add_scalars(&[
FieldElement::from(self.r1cs.num_constraints() as u64),
FieldElement::from(self.r1cs.num_witnesses() as u64),
]);

// Absorb public inputs (values) in canonical order
let circuit = &self.program.functions[0];
let public_idxs = circuit.public_inputs().indices();
if !public_idxs.is_empty() {
let pub_vals: Vec<FieldElement> = public_idxs
.iter()
.map(|&i| noir_to_native(*witness.get_index(i).expect("missing public input")))
.collect();
let _ = merlin.add_scalars(&pub_vals);
}

Ok(())
}
}
Loading
Loading