Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add groth16 #1313

Merged
merged 16 commits into from
Aug 17, 2024
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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: circuit -> Circuit

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed


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
47 changes: 44 additions & 3 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
34 changes: 30 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,45 @@ 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<SP1ProofData>;

#[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 SP1ProofData {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: SP1Bn254ProofData

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SP1ProofData is a bit too general.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

Plonk(PlonkBn254Proof),
Groth16(Groth16Bn254Proof),
}

impl SP1ProofData {
pub fn get_proof_system(&self) -> &str {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: can you use an enum here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

match self {
SP1ProofData::Plonk(_) => "Plonk",
SP1ProofData::Groth16(_) => "Groth16",
}
}

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

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