-
Notifications
You must be signed in to change notification settings - Fork 401
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
Changes from 14 commits
d265626
9494a95
a626cdb
3f010a3
da0cf08
61b3ea6
25bf0ea
8e442e5
07cc531
ed51684
b009149
686f844
1306e06
806bb19
6e037fe
6e3f872
bf634b3
451aeca
cc22d86
a27e3e3
024cba6
8247722
b6c7dfc
a94e59e
d0974a6
0837254
7c4211d
d7fea78
6856f48
83c9697
9fa8608
912faf0
f9c2f6e
df3269e
cf4c0a3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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; | ||
|
@@ -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; | ||
|
@@ -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()); | ||
|
@@ -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); | ||
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) | ||
} | ||
|
@@ -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<_>>(); | ||
|
@@ -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()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no, it's checked in the program when |
||
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); | ||
|
@@ -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() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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) There was a problem hiding this comment. Choose a reason for hiding this commentThe 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> { | ||
|
@@ -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] | ||
|
@@ -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")); | ||
} | ||
} |
There was a problem hiding this comment.
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 thereThere was a problem hiding this comment.
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