Skip to content

Commit

Permalink
feat: add groth16 (#1313)
Browse files Browse the repository at this point in the history
  • Loading branch information
mattstam authored Aug 17, 2024
1 parent 6a6c064 commit 5085525
Show file tree
Hide file tree
Showing 33 changed files with 1,215 additions and 205 deletions.
8 changes: 4 additions & 4 deletions book/developers/building-plonk-artifacts.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Building PLONK Artifacts
# Building Circuit Artifacts

To build the production Plonk Bn254 artifacts from scratch, you can use the `Makefile` inside the `prover` directory.
To build the production PLONK and Groth16 Bn254 artifacts from scratch, you can use the `Makefile` inside the `prover` directory.

```shell,noplayground
cd prover
RUST_LOG=info make build-plonk-bn254
```
RUST_LOG=info make build-circuits
```
4 changes: 4 additions & 0 deletions crates/prover/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ oneshot = "0.1.8"
name = "build_plonk_bn254"
path = "scripts/build_plonk_bn254.rs"

[[bin]]
name = "build_groth16_bn254"
path = "scripts/build_groth16_bn254.rs"

[[bin]]
name = "e2e"
path = "scripts/e2e.rs"
Expand Down
11 changes: 7 additions & 4 deletions crates/prover/Makefile
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
all:
make build-plonk-bn254
make release-plonk-bn254
make build-circuits
make release-circuits

build-plonk-bn254:
build-circuits:
rm -rf build && \
mkdir -p build && \
RUSTFLAGS='-C target-cpu=native' \
cargo run -p sp1-prover --release --bin build_plonk_bn254 --features native-gnark -- \
--build-dir=./build && \
RUSTFLAGS='-C target-cpu=native' \
cargo run -p sp1-prover --release --bin build_groth16_bn254 --features native-gnark -- \
--build-dir=./build

release-plonk-bn254:
release-circuits:
@read -p "Release version (ex. v1.0.0-testnet)? " version; \
bash release.sh $$version

Expand Down
18 changes: 18 additions & 0 deletions crates/prover/scripts/build_groth16_bn254.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use std::path::PathBuf;

use clap::Parser;
use sp1_core_machine::utils::setup_logger;
use sp1_prover::build::build_groth16_bn254_artifacts_with_dummy;

#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
struct Args {
#[clap(short, long)]
build_dir: PathBuf,
}

pub fn main() {
setup_logger();
let args = Args::parse();
build_groth16_bn254_artifacts_with_dummy(args.build_dir);
}
37 changes: 31 additions & 6 deletions crates/prover/scripts/e2e.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use sp1_prover::{
use sp1_recursion_circuit::{stark::build_wrap_circuit, witness::Witnessable};
use sp1_recursion_compiler::ir::Witness;
use sp1_recursion_core::air::RecursionPublicValues;
use sp1_recursion_gnark_ffi::Groth16Bn254Prover;
use sp1_recursion_gnark_ffi::PlonkBn254Prover;
use sp1_stark::SP1ProverOpts;
use subtle_encoding::hex;
Expand All @@ -21,6 +22,8 @@ use subtle_encoding::hex;
struct Args {
#[clap(short, long)]
build_dir: String,
#[arg(short, long)]
system: String,
}

pub fn main() {
Expand Down Expand Up @@ -69,25 +72,47 @@ pub fn main() {
witness.write_commited_values_digest(committed_values_digest);
witness.write_vkey_hash(vkey_hash);

tracing::info!("sanity check gnark test");
tracing::info!("sanity check plonk test");
PlonkBn254Prover::test(constraints.clone(), witness.clone());

tracing::info!("sanity check gnark build");
tracing::info!("sanity check plonk build");
PlonkBn254Prover::build(constraints.clone(), witness.clone(), build_dir.clone());

tracing::info!("sanity check gnark prove");
tracing::info!("sanity check plonk prove");
let plonk_bn254_prover = PlonkBn254Prover::new();

tracing::info!("gnark prove");
tracing::info!("plonk prove");
let proof = plonk_bn254_prover.prove(witness.clone(), build_dir.clone());

tracing::info!("verify gnark proof");
tracing::info!("verify plonk proof");
plonk_bn254_prover.verify(
&proof,
&vkey_hash.as_canonical_biguint(),
&committed_values_digest.as_canonical_biguint(),
&build_dir,
);

println!("{:?}", String::from_utf8(hex::encode(proof.encoded_proof)).unwrap());
println!("plonk proof: {:?}", String::from_utf8(hex::encode(proof.encoded_proof)).unwrap());

tracing::info!("sanity check groth16 test");
Groth16Bn254Prover::test(constraints.clone(), witness.clone());

tracing::info!("sanity check groth16 build");
Groth16Bn254Prover::build(constraints.clone(), witness.clone(), build_dir.clone());

tracing::info!("sanity check groth16 prove");
let groth16_bn254_prover = Groth16Bn254Prover::new();

tracing::info!("groth16 prove");
let proof = groth16_bn254_prover.prove(witness.clone(), build_dir.clone());

tracing::info!("verify groth16 proof");
groth16_bn254_prover.verify(
&proof,
&vkey_hash.as_canonical_biguint(),
&committed_values_digest.as_canonical_biguint(),
&build_dir,
);

println!("groth16 proof: {:?}", String::from_utf8(hex::encode(proof.encoded_proof)).unwrap());
}
42 changes: 40 additions & 2 deletions crates/prover/src/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ pub use sp1_recursion_compiler::ir::Witness;
use sp1_recursion_compiler::{config::OuterConfig, constraints::Constraint};
use sp1_recursion_core::air::RecursionPublicValues;
pub use sp1_recursion_core::stark::utils::sp1_dev_mode;
use sp1_recursion_gnark_ffi::PlonkBn254Prover;
use sp1_recursion_gnark_ffi::{Groth16Bn254Prover, PlonkBn254Prover};
use sp1_stark::{SP1ProverOpts, ShardProof, StarkVerifyingKey};

use crate::{
Expand All @@ -27,9 +27,25 @@ pub fn try_build_plonk_bn254_artifacts_dev(
build_dir
}

/// Tries to build the groth16 bn254 artifacts in the current environment.
pub fn try_build_groth16_bn254_artifacts_dev(
template_vk: &StarkVerifyingKey<OuterSC>,
template_proof: &ShardProof<OuterSC>,
) -> PathBuf {
let build_dir = groth16_bn254_artifacts_dev_dir();
println!("[sp1] building groth16 bn254 artifacts in development mode");
build_groth16_bn254_artifacts(template_vk, template_proof, &build_dir);
build_dir
}

/// Gets the directory where the PLONK artifacts are installed in development mode.
pub fn plonk_bn254_artifacts_dev_dir() -> PathBuf {
dirs::home_dir().unwrap().join(".sp1").join("circuits").join("plonk_bn254").join("dev")
dirs::home_dir().unwrap().join(".sp1").join("circuits").join("dev")
}

/// Gets the directory where the groth16 artifacts are installed in development mode.
pub fn groth16_bn254_artifacts_dev_dir() -> PathBuf {
dirs::home_dir().unwrap().join(".sp1").join("circuits").join("dev")
}

/// Build the plonk bn254 artifacts to the given directory for the given verification key and
Expand All @@ -45,6 +61,19 @@ pub fn build_plonk_bn254_artifacts(
PlonkBn254Prover::build(constraints, witness, build_dir);
}

/// Build the groth16 bn254 artifacts to the given directory for the given verification key and template
/// proof.
pub fn build_groth16_bn254_artifacts(
template_vk: &StarkVerifyingKey<OuterSC>,
template_proof: &ShardProof<OuterSC>,
build_dir: impl Into<PathBuf>,
) {
let build_dir = build_dir.into();
std::fs::create_dir_all(&build_dir).expect("failed to create build directory");
let (constraints, witness) = build_constraints_and_witness(template_vk, template_proof);
Groth16Bn254Prover::build(constraints, witness, build_dir);
}

/// Builds the plonk bn254 artifacts to the given directory.
///
/// This may take a while as it needs to first generate a dummy proof and then it needs to compile
Expand All @@ -54,6 +83,15 @@ pub fn build_plonk_bn254_artifacts_with_dummy(build_dir: impl Into<PathBuf>) {
crate::build::build_plonk_bn254_artifacts(&wrap_vk, &wrapped_proof, build_dir.into());
}

/// Builds the groth16 bn254 artifacts to the given directory.
///
/// This may take a while as it needs to first generate a dummy proof and then it needs to compile
/// the circuit.
pub fn build_groth16_bn254_artifacts_with_dummy(build_dir: impl Into<PathBuf>) {
let (wrap_vk, wrapped_proof) = dummy_proof();
crate::build::build_groth16_bn254_artifacts(&wrap_vk, &wrapped_proof, build_dir.into());
}

/// Build the verifier constraints and template witness for the circuit.
pub fn build_constraints_and_witness(
template_vk: &StarkVerifyingKey<OuterSC>,
Expand Down
3 changes: 2 additions & 1 deletion crates/prover/src/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ pub use sp1_core_machine::io::{SP1PublicValues, SP1Stdin};
use sp1_primitives::types::RecursionProgramType;
use sp1_recursion_compiler::config::InnerConfig;
use sp1_recursion_core::runtime::RecursionProgram;
pub use sp1_recursion_gnark_ffi::plonk_bn254::PlonkBn254Proof;
pub use sp1_recursion_gnark_ffi::groth16_bn254::Groth16Bn254Prover;
pub use sp1_recursion_gnark_ffi::plonk_bn254::PlonkBn254Prover;
pub use sp1_recursion_program::machine::{
ReduceProgramType, SP1CompressMemoryLayout, SP1DeferredMemoryLayout, SP1RecursionMemoryLayout,
SP1RootMemoryLayout,
Expand Down
51 changes: 47 additions & 4 deletions crates/prover/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,10 @@ use sp1_recursion_core::{
runtime::{ExecutionRecord, RecursionProgram, Runtime as RecursionRuntime},
stark::{config::BabyBearPoseidon2Outer, RecursionAir},
};
pub use sp1_recursion_gnark_ffi::plonk_bn254::PlonkBn254Proof;
use sp1_recursion_gnark_ffi::groth16_bn254::Groth16Bn254Prover;
use sp1_recursion_gnark_ffi::plonk_bn254::PlonkBn254Prover;
pub use sp1_recursion_gnark_ffi::proof::Groth16Bn254Proof;
pub use sp1_recursion_gnark_ffi::proof::PlonkBn254Proof;
use sp1_recursion_program::hints::Hintable;
pub use sp1_recursion_program::machine::{
ReduceProgramType, SP1CompressMemoryLayout, SP1DeferredMemoryLayout, SP1RecursionMemoryLayout,
Expand Down Expand Up @@ -860,6 +862,35 @@ impl<C: SP1ProverComponents> SP1Prover<C> {
proof
}

/// Wrap the STARK proven over a SNARK-friendly field into a Groth16 proof.
#[instrument(name = "wrap_groth16_bn254", level = "info", skip_all)]
pub fn wrap_groth16_bn254(
&self,
proof: SP1ReduceProof<OuterSC>,
build_dir: &Path,
) -> Groth16Bn254Proof {
let vkey_digest = proof.sp1_vkey_digest_bn254();
let commited_values_digest = proof.sp1_commited_values_digest_bn254();

let mut witness = Witness::default();
proof.proof.write(&mut witness);
witness.write_commited_values_digest(commited_values_digest);
witness.write_vkey_hash(vkey_digest);

let prover = Groth16Bn254Prover::new();
let proof = prover.prove(witness, build_dir.to_path_buf());

// Verify the proof.
prover.verify(
&proof,
&vkey_digest.as_canonical_biguint(),
&commited_values_digest.as_canonical_biguint(),
build_dir,
);

proof
}

/// Accumulate deferred proofs into a single digest.
pub fn hash_deferred_proofs(
prev_digest: [Val<CoreSC>; DIGEST_SIZE],
Expand All @@ -881,7 +912,7 @@ impl<C: SP1ProverComponents> SP1Prover<C> {
fn check_for_high_cycles(cycles: u64) {
if cycles > 100_000_000 {
tracing::warn!(
"high cycle count, consider using the prover network for proof generation: https://docs.succinct.xyz/prover-network/setup.html"
"high cycle count, consider using the prover network for proof generation: https://docs.succinct.xyz/generating-proofs/prover-network"
);
}
}
Expand All @@ -898,6 +929,7 @@ pub mod tests {
use super::*;

use anyhow::Result;
use build::try_build_groth16_bn254_artifacts_dev;
use build::try_build_plonk_bn254_artifacts_dev;
use p3_field::PrimeField32;
use sp1_core_machine::io::SP1Stdin;
Expand Down Expand Up @@ -993,11 +1025,20 @@ pub mod tests {
tracing::info!("generate plonk bn254 proof");
let artifacts_dir =
try_build_plonk_bn254_artifacts_dev(prover.wrap_vk(), &wrapped_bn254_proof.proof);
let plonk_bn254_proof = prover.wrap_plonk_bn254(wrapped_bn254_proof, &artifacts_dir);
let plonk_bn254_proof =
prover.wrap_plonk_bn254(wrapped_bn254_proof.clone(), &artifacts_dir);
println!("{:?}", plonk_bn254_proof);

prover.verify_plonk_bn254(&plonk_bn254_proof, &vk, &public_values, &artifacts_dir)?;

tracing::info!("generate groth16 bn254 proof");
let artifacts_dir =
try_build_groth16_bn254_artifacts_dev(prover.wrap_vk(), &wrapped_bn254_proof.proof);
let groth16_bn254_proof = prover.wrap_groth16_bn254(wrapped_bn254_proof, &artifacts_dir);
println!("{:?}", groth16_bn254_proof);

prover.verify_groth16_bn254(&groth16_bn254_proof, &vk, &public_values, &artifacts_dir)?;

Ok(())
}

Expand Down Expand Up @@ -1093,7 +1134,9 @@ pub mod tests {
let elf = include_bytes!("../../../tests/fibonacci/elf/riscv32im-succinct-zkvm-elf");
setup_logger();
let opts = SP1ProverOpts::default();
test_e2e_prover::<DefaultProverComponents>(elf, opts, Test::Plonk)
// TODO(mattstam): We should Test::Plonk here, but this uses the existing
// docker image which has a different API than the current. So we need to wait until the next release (v1.2.0+), and then switch it back.
test_e2e_prover::<DefaultProverComponents>(elf, opts, Test::Wrap)
}

/// Tests an end-to-end workflow of proving a program across the entire proof generation
Expand Down
49 changes: 45 additions & 4 deletions crates/prover/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use sp1_core_machine::{
};
use sp1_primitives::poseidon2_hash;
use sp1_recursion_core::{air::RecursionPublicValues, stark::config::BabyBearPoseidon2Outer};
use sp1_recursion_gnark_ffi::plonk_bn254::PlonkBn254Proof;
use sp1_recursion_gnark_ffi::proof::{Groth16Bn254Proof, PlonkBn254Proof};
use sp1_recursion_program::machine::{
SP1CompressMemoryLayout, SP1DeferredMemoryLayout, SP1RecursionMemoryLayout,
};
Expand Down Expand Up @@ -144,19 +144,60 @@ pub type SP1ReducedProof = SP1ProofWithMetadata<SP1ReducedProofData>;
/// An SP1 proof that has been wrapped into a single PLONK proof and can be verified onchain.
pub type SP1PlonkBn254Proof = SP1ProofWithMetadata<SP1PlonkBn254ProofData>;

/// An SP1 proof that has been wrapped into a single PLONK proof and can be verified onchain.
pub type SP1PlonkProof = SP1ProofWithMetadata<SP1PlonkProofData>;
/// An SP1 proof that has been wrapped into a single Groth16 proof and can be verified onchain.
pub type SP1Groth16Bn254Proof = SP1ProofWithMetadata<SP1Groth16Bn254ProofData>;

/// An SP1 proof that has been wrapped into a single proof and can be verified onchain.
pub type SP1Proof = SP1ProofWithMetadata<SP1Bn254ProofData>;

#[derive(Serialize, Deserialize, Clone)]
pub struct SP1CoreProofData(pub Vec<ShardProof<CoreSC>>);

#[derive(Serialize, Deserialize, Clone)]
pub struct SP1ReducedProofData(pub ShardProof<InnerSC>);

#[derive(Serialize, Deserialize, Clone)]
pub struct SP1PlonkBn254ProofData(pub PlonkBn254Proof);

#[derive(Serialize, Deserialize, Clone)]
pub struct SP1PlonkProofData(pub PlonkBn254Proof);
pub struct SP1Groth16Bn254ProofData(pub Groth16Bn254Proof);

#[derive(Serialize, Deserialize, Clone)]
pub enum SP1Bn254ProofData {
Plonk(PlonkBn254Proof),
Groth16(Groth16Bn254Proof),
}

impl SP1Bn254ProofData {
pub fn get_proof_system(&self) -> ProofSystem {
match self {
SP1Bn254ProofData::Plonk(_) => ProofSystem::Plonk,
SP1Bn254ProofData::Groth16(_) => ProofSystem::Groth16,
}
}

pub fn get_raw_proof(&self) -> &str {
match self {
SP1Bn254ProofData::Plonk(proof) => &proof.raw_proof,
SP1Bn254ProofData::Groth16(proof) => &proof.raw_proof,
}
}
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ProofSystem {
Plonk,
Groth16,
}

impl ProofSystem {
pub fn as_str(&self) -> &'static str {
match self {
ProofSystem::Plonk => "Plonk",
ProofSystem::Groth16 => "Groth16",
}
}
}

/// An intermediate proof which proves the execution over a range of shards.
#[derive(Serialize, Deserialize, Clone)]
Expand Down
Loading

0 comments on commit 5085525

Please sign in to comment.