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

refactor: sdk improvements #580

Merged
merged 35 commits into from
Apr 27, 2024
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
d265626
small fixes to dependencies
ratankaliani Apr 18, 2024
9494a95
remove dependencies on sp1_sdk
ratankaliani Apr 18, 2024
a626cdb
wip
ratankaliani Apr 18, 2024
3f010a3
merge
ratankaliani Apr 18, 2024
da0cf08
wip
ratankaliani Apr 18, 2024
61b3ea6
Merge remote-tracking branch 'origin/ratan/prover-sdk-cleanup' into c…
ctian1 Apr 24, 2024
25bf0ea
wip
ctian1 Apr 24, 2024
8e442e5
feat: plonk e2e prover (#582)
jtguibas Apr 24, 2024
07cc531
feat(recursion): memory builder + fri-fold precompile (#581)
Sladuca Apr 24, 2024
ed51684
semi working
ctian1 Apr 24, 2024
b009149
Merge remote-tracking branch 'origin/main' into chris/sdk-improvements
ctian1 Apr 24, 2024
686f844
simple groth16 constraints
ctian1 Apr 24, 2024
1306e06
groth16 witness values
ctian1 Apr 25, 2024
806bb19
cleanup
ctian1 Apr 25, 2024
6e037fe
Merge remote-tracking branch 'origin/main' into chris/sdk-improvements
ctian1 Apr 25, 2024
6e3f872
verify
ctian1 Apr 25, 2024
bf634b3
rename
ctian1 Apr 25, 2024
451aeca
fix
ctian1 Apr 25, 2024
cc22d86
fix
ctian1 Apr 25, 2024
a27e3e3
cleanup
ctian1 Apr 25, 2024
024cba6
fix
ctian1 Apr 26, 2024
8247722
fix
ctian1 Apr 26, 2024
b6c7dfc
fix
ctian1 Apr 26, 2024
a94e59e
fix
ctian1 Apr 26, 2024
d0974a6
fix
ctian1 Apr 26, 2024
0837254
Merge remote-tracking branch 'origin/main' into chris/sdk-improvements-2
ctian1 Apr 26, 2024
7c4211d
Merge remote-tracking branch 'origin/main' into chris/sdk-improvements
ctian1 Apr 26, 2024
d7fea78
pk instead of elf
ctian1 Apr 27, 2024
6856f48
refactor: zkvm verify feature, fix examples
ctian1 Apr 27, 2024
83c9697
make
ctian1 Apr 27, 2024
9fa8608
cleanup
ctian1 Apr 27, 2024
912faf0
fix
ctian1 Apr 27, 2024
f9c2f6e
revert
ctian1 Apr 27, 2024
df3269e
fix
ctian1 Apr 27, 2024
cf4c0a3
clippy
ctian1 Apr 27, 2024
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
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion primitives/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1151,7 +1151,8 @@ lazy_static! {
> = poseidon2_hasher();
}

pub fn hash_deferred_proofs(
/// Append a single deferred proof to a hash chain of deferred proofs.
pub fn hash_deferred_proof(
prev_digest: &[BabyBear; 8],
vk_digest: &[BabyBear; 8],
pv_digest: &[BabyBear; 32],
Expand Down
1 change: 1 addition & 0 deletions prover/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ sp1-primitives = { path = "../primitives" }
p3-field = { workspace = true }
p3-challenger = { workspace = true }
p3-baby-bear = { workspace = true }
p3-bn254-fr = { workspace = true }
p3-commit = { workspace = true }
bincode = "1.3.3"
serde = { version = "1.0", features = ["derive", "rc"] }
Expand Down
3 changes: 1 addition & 2 deletions prover/scripts/e2e.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,12 @@ pub fn main() {
tracing::info!("prove core");
let stdin = SP1Stdin::new();
let core_proof = prover.prove_core(&pk, &stdin);
let core_challenger = prover.setup_core_challenger(&vk, &core_proof);

tracing::info!("reduce");
let reduced_proof = prover.reduce(&vk, core_proof, vec![]);

tracing::info!("wrap");
let wrapped_proof = prover.wrap_bn254(&vk, core_challenger, reduced_proof);
let wrapped_proof = prover.wrap_bn254(&vk, reduced_proof);

tracing::info!("building verifier constraints");
let constraints = tracing::info_span!("wrap circuit")
Expand Down
117 changes: 89 additions & 28 deletions prover/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,19 @@ mod types;
mod utils;
mod verify;

use std::path::PathBuf;

pub use sp1_recursion_gnark_ffi::plonk_bn254::PlonkBn254Proof;
use sp1_recursion_gnark_ffi::plonk_bn254::PlonkBn254Prover;
pub use sp1_recursion_gnark_ffi::Groth16Proof;
use sp1_recursion_program::commit;
pub use types::*;

use p3_baby_bear::BabyBear;
use p3_bn254_fr::Bn254Fr;
use p3_challenger::CanObserve;
use p3_field::AbstractField;
use p3_field::PrimeField32;
use rayon::iter::{IndexedParallelIterator, IntoParallelIterator, ParallelIterator};
use serde::de::DeserializeOwned;
use serde::Serialize;
Expand All @@ -36,8 +44,7 @@ use sp1_core::{
},
utils::{run_and_prove, BabyBearPoseidon2},
};
use sp1_primitives::hash_deferred_proofs;
use sp1_recursion_circuit::stark::build_wrap_circuit;
use sp1_primitives::hash_deferred_proof;
use sp1_recursion_circuit::witness::Witnessable;
use sp1_recursion_compiler::ir::Witness;
use sp1_recursion_core::runtime::RecursionProgram;
Expand Down Expand Up @@ -81,9 +88,7 @@ impl SP1Prover {
/// Initializes a new [SP1Prover].
pub fn new() -> Self {
let reduce_setup_program = ReduceProgram::setup();
// Load program from reduce.bin if it exists
let reduce_program = ReduceProgram::build();
println!("program size: {}", reduce_program.instructions.len());
let (_, reduce_vk_inner) = RecursionAir::machine(InnerSC::default()).setup(&reduce_program);
let (_, reduce_vk_outer) = RecursionAir::machine(OuterSC::default()).setup(&reduce_program);
let core_machine = RiscvAir::machine(CoreSC::default());
Expand All @@ -103,19 +108,44 @@ impl SP1Prover {
/// Creates a proving key and a verifying key for a given RISC-V ELF.
pub fn setup(&self, elf: &[u8]) -> (SP1ProvingKey, SP1VerifyingKey) {
let program = Program::from(elf);
let config = CoreSC::default();
let machine = RiscvAir::machine(config);
let (pk, vk) = machine.setup(&program);
let (pk, vk) = self.core_machine.setup(&program);
Copy link
Contributor

Choose a reason for hiding this comment

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

Are we including the ELF in the pk now? I feel like it should go in there

Copy link
Member Author

Choose a reason for hiding this comment

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

yea program is in SP1ProvingKey already actually

let pk = SP1ProvingKey { pk, program };
let vk = SP1VerifyingKey { vk };
(pk, vk)
}

/// Hash a verifying key, producing a single commitment that uniquely identifies the program
/// being proven.
pub fn hash_vkey(&self, vk: &StarkVerifyingKey<CoreSC>) -> [Val<CoreSC>; 8] {
self.core_machine.hash_vkey(vk)
}

/// Accumulate deferred proofs into a single digest.
pub fn hash_deferred_proofs(
prev_digest: [Val<CoreSC>; 8],
deferred_proofs: &[ShardProof<InnerSC>],
) -> [Val<CoreSC>; 8] {
let mut digest = prev_digest;
for proof in deferred_proofs.iter() {
let pv = RecursionPublicValues::from_vec(proof.public_values.clone());
let committed_values_digest = words_to_bytes(&pv.committed_value_digest);
digest = hash_deferred_proof(
&digest,
&pv.sp1_vk_digest,
&committed_values_digest.try_into().unwrap(),
);
}
digest
}

/// Generate a proof of an SP1 program with the specified inputs.
pub fn execute(elf: &[u8], stdin: &SP1Stdin) -> SP1PublicValues {
let program = Program::from(elf);
let mut runtime = Runtime::new(program);
runtime.write_vecs(&stdin.buffer);
for (proof, vkey) in stdin.proofs.iter() {
runtime.write_proof(proof.clone(), vkey.clone());
}
runtime.run();
SP1PublicValues::from(&runtime.state.public_values_stream)
}
Expand Down Expand Up @@ -288,15 +318,8 @@ impl SP1Prover {
.map(|chunk| {
let start_state = reduce_state.clone();
// Accumulate each deferred proof into the digest
for proof in chunk.iter() {
let pv = RecursionPublicValues::from_vec(proof.public_values.clone());
let committed_values_digest = words_to_bytes(&pv.committed_value_digest);
reduce_state.reconstruct_deferred_digest = hash_deferred_proofs(
&reduce_state.reconstruct_deferred_digest,
&pv.sp1_vk_digest,
&committed_values_digest.try_into().unwrap(),
);
}
reduce_state.reconstruct_deferred_digest =
Self::hash_deferred_proofs(reduce_state.reconstruct_deferred_digest, chunk);
start_state
})
.collect::<Vec<_>>();
Expand Down Expand Up @@ -458,9 +481,13 @@ impl SP1Prover {
pub fn wrap_bn254(
&self,
vk: &SP1VerifyingKey,
core_challenger: Challenger<CoreSC>,
reduced_proof: SP1ReduceProof<InnerSC>,
) -> ShardProof<OuterSC> {
// Get verify_start_challenger from the reduce proof's public values.
let pv = RecursionPublicValues::from_vec(reduced_proof.proof.public_values.clone());
Copy link
Contributor

Choose a reason for hiding this comment

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

So do we have to do this in verification as well? (Like similar initialization of the challenger)

Copy link
Member Author

Choose a reason for hiding this comment

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

no, it's checked in the program when is_complete=1 is committed, so we can just check that

let mut core_challenger = self.core_machine.config().challenger();
pv.verify_start_challenger
.set_challenger(&mut core_challenger);
// Since the proof passed in should be complete already, the start reconstruct_challenger
// should be in initial state with only vk observed.
let reconstruct_challenger = self.setup_initial_core_challenger(vk);
Expand All @@ -478,11 +505,49 @@ impl SP1Prover {
}

/// Wrap the STARK proven over a SNARK-friendly field into a Groth16 proof.
pub fn wrap_groth16(&self, proof: ShardProof<OuterSC>) {
pub fn wrap_groth16(&self, proof: ShardProof<OuterSC>, build_dir: PathBuf) -> Groth16Proof {
let pv = RecursionPublicValues::from_vec(proof.public_values.clone());

// Convert pv.vkey_digest to a bn254 field element
let mut vkey_hash = Bn254Fr::zero();
for (i, word) in pv.sp1_vk_digest.iter().enumerate() {
Copy link
Contributor

Choose a reason for hiding this comment

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

lol can we have more comments as to what is going on here and why (also maybe a link to the corresponding parts in the groth16 circuit code)

Copy link
Member Author

Choose a reason for hiding this comment

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

this is not stable yet, it's not constrained in circuit

if i == 0 {
// Truncate top 3 bits
vkey_hash = Bn254Fr::from_canonical_u32(word.as_canonical_u32() & 0x1fffffffu32);
} else {
vkey_hash *= Bn254Fr::from_canonical_u64(1 << 32);
vkey_hash += Bn254Fr::from_canonical_u32(word.as_canonical_u32());
}
}

// Convert pv.committed_value_digest to a bn254 field element
let mut committed_values_digest = Bn254Fr::zero();
for (i, word) in pv.committed_value_digest.iter().enumerate() {
for (j, byte) in word.0.iter().enumerate() {
if i == 0 && j == 0 {
// Truncate top 3 bits
committed_values_digest =
Bn254Fr::from_canonical_u32(byte.as_canonical_u32() & 0x1f);
} else {
committed_values_digest *= Bn254Fr::from_canonical_u32(256);
committed_values_digest += Bn254Fr::from_canonical_u32(byte.as_canonical_u32());
}
}
}

let mut witness = Witness::default();
proof.write(&mut witness);
let constraints = build_wrap_circuit(&self.reduce_vk_outer, proof);
Groth16Prover::test(constraints, witness);
witness.commited_values_digest = committed_values_digest;
witness.vkey_hash = vkey_hash;

// witness.commited_values_digest
Groth16Prover::prove(witness, build_dir)
}

pub fn wrap_plonk(&self, proof: ShardProof<OuterSC>, build_dir: PathBuf) -> PlonkBn254Proof {
let mut witness = Witness::default();
ctian1 marked this conversation as resolved.
Show resolved Hide resolved
proof.write(&mut witness);
PlonkBn254Prover::prove(witness, build_dir)
}

pub fn setup_initial_core_challenger(&self, vk: &SP1VerifyingKey) -> Challenger<CoreSC> {
Expand Down Expand Up @@ -539,17 +604,14 @@ mod tests {
tracing::info!("verify core");
core_proof.verify(&vk).unwrap();

// TODO: Get rid of this method by reading it from public values.
let core_challenger = prover.setup_core_challenger(&vk, &core_proof);

tracing::info!("reduce");
let reduced_proof = prover.reduce(&vk, core_proof, vec![]);

tracing::info!("wrap bn254");
let wrapped_bn254_proof = prover.wrap_bn254(&vk, core_challenger, reduced_proof);
let wrapped_bn254_proof = prover.wrap_bn254(&vk, reduced_proof);

tracing::info!("groth16");
prover.wrap_groth16(wrapped_bn254_proof);
prover.wrap_groth16(wrapped_bn254_proof, PathBuf::from("build"));
}

#[test]
Expand Down Expand Up @@ -661,10 +723,9 @@ mod tests {
println!("complete: {:?}", reduce_pv.is_complete);

println!("wrap");
let challenger = prover.setup_core_challenger(&verify_vk, &verify_proof);
let wrapped = prover.wrap_bn254(&verify_vk, challenger, verify_reduce);
let wrapped = prover.wrap_bn254(&verify_vk, verify_reduce);

tracing::info!("groth16");
prover.wrap_groth16(wrapped);
prover.wrap_groth16(wrapped, PathBuf::from("build"));
}
}
2 changes: 1 addition & 1 deletion prover/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ pub struct SP1ReduceProof<SC: StarkGenericConfig> {
pub proof: ShardProof<SC>,
}

/// A wrapper to abstract proofs representing a range of shards with multiple proving configs.
/// A proof that can be reduced along with other proofs into one proof.
#[derive(Serialize, Deserialize)]
pub enum SP1ReduceProofWrapper {
Core(SP1ReduceProof<CoreSC>),
Expand Down
18 changes: 9 additions & 9 deletions recursion/circuit/src/stark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -279,15 +279,15 @@ pub fn build_wrap_circuit(
);
challenger.observe_slice(&mut builder, pv_slice);

StarkVerifierCircuit::<OuterC, OuterSC>::verify_shard(
&mut builder,
vk,
&outer_machine,
&mut challenger.clone(),
&proof,
chips,
sorted_indices,
);
// StarkVerifierCircuit::<OuterC, OuterSC>::verify_shard(
// &mut builder,
// vk,
// &outer_machine,
// &mut challenger.clone(),
// &proof,
// chips,
// sorted_indices,
// );

let mut backend = ConstraintCompiler::<OuterConfig>::default();
backend.emit(builder.operations)
Expand Down
10 changes: 5 additions & 5 deletions recursion/gnark-ffi/src/groth16.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@ pub struct Groth16Prover;
/// A zero-knowledge proof generated by the Groth16 protocol.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Groth16Proof {
a: [String; 2],
b: [[String; 2]; 2],
c: [String; 2],
public_inputs: [String; 2],
pub a: [String; 2],
pub b: [[String; 2]; 2],
pub c: [String; 2],
pub public_inputs: [String; 2],
}

impl Groth16Prover {
/// Creates a nejw verifier.
/// Creates a new verifier.
pub fn new() -> Self {
Groth16Prover
}
Expand Down
Binary file modified recursion/gnark/gnark.pprof
Binary file not shown.
Loading