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: integration constraints #1455

Merged
merged 24 commits into from
Aug 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions crates/core/machine/src/riscv/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ use sp1_stark::{
use strum_macros::{EnumDiscriminants, EnumIter};
use tracing::instrument;

pub const MAX_LOG_NUMBER_OF_SHARDS: usize = 16;
pub const MAX_NUMBER_OF_SHARDS: usize = 1 << MAX_LOG_NUMBER_OF_SHARDS;

/// A module for importing all the different RISC-V chips.
pub(crate) mod riscv_chips {
pub use crate::{
Expand Down
4 changes: 2 additions & 2 deletions crates/prover/src/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::{borrow::Borrow, path::PathBuf};
use p3_baby_bear::BabyBear;
use sp1_core_executor::SP1Context;
use sp1_core_machine::io::SP1Stdin;
use sp1_recursion_circuit_v2::machine::{SP1CompressVerifier, SP1CompressWitnessValues};
use sp1_recursion_circuit_v2::machine::{SP1CompressRootVerifier, SP1CompressWitnessValues};
use sp1_recursion_compiler::{
config::OuterConfig,
constraints::{Constraint, ConstraintCompiler},
Expand Down Expand Up @@ -175,7 +175,7 @@ fn build_outer_circuit(template_input: &SP1CompressWitnessValues<OuterSC>) -> Ve
let wrap_span = tracing::debug_span!("build wrap circuit").entered();
let mut builder = Builder::<OuterConfig>::default();
let input = template_input.read(&mut builder);
SP1CompressVerifier::verify(&mut builder, &wrap_machine, input);
SP1CompressRootVerifier::verify(&mut builder, &wrap_machine, input);

let mut backend = ConstraintCompiler::<OuterConfig>::default();
let operations = backend.emit(builder.into_operations());
Expand Down
35 changes: 28 additions & 7 deletions crates/prover/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,10 @@ use sp1_recursion_core_v2::{
use sp1_recursion_circuit_v2::{
hash::FieldHasher,
machine::{
SP1CompressShape, SP1CompressVerifier, SP1CompressWithVKeyVerifier,
SP1CompressWithVKeyWitnessValues, SP1CompressWitnessValues, SP1DeferredVerifier,
SP1DeferredWitnessValues, SP1MerkleProofWitnessValues, SP1RecursionShape,
SP1RecursionWitnessValues, SP1RecursiveVerifier,
SP1CompressRootVerifier, SP1CompressRootVerifierWithVKey, SP1CompressShape,
SP1CompressWithVKeyVerifier, SP1CompressWithVKeyWitnessValues, SP1CompressWitnessValues,
SP1DeferredVerifier, SP1DeferredWitnessValues, SP1MerkleProofWitnessValues,
SP1RecursionShape, SP1RecursionWitnessValues, SP1RecursiveVerifier,
},
merkle_tree::MerkleTree,
witness::Witnessable,
Expand Down Expand Up @@ -326,7 +326,24 @@ impl<C: SP1ProverComponents> SP1Prover<C> {
&self,
input: &SP1CompressWithVKeyWitnessValues<InnerSC>,
) -> Arc<RecursionProgram<BabyBear>> {
self.compress_program(input)
// Get the operations.
let builder_span = tracing::debug_span!("build shrink program").entered();
let mut builder = Builder::<InnerConfig>::default();
let input = input.read(&mut builder);
SP1CompressRootVerifierWithVKey::verify(
&mut builder,
self.compress_prover.machine(),
input,
);
let operations = builder.into_operations();
builder_span.exit();

// Compile the program.
let compiler_span = tracing::debug_span!("compile shrink program").entered();
let mut compiler = AsmCompiler::<InnerConfig>::default();
let program = Arc::new(compiler.compile(operations));
compiler_span.exit();
program
}

pub fn wrap_program(
Expand All @@ -336,8 +353,11 @@ impl<C: SP1ProverComponents> SP1Prover<C> {
// Get the operations.
let builder_span = tracing::debug_span!("build compress program").entered();
let mut builder = Builder::<InnerConfig>::default();

let input = input.read(&mut builder);
SP1CompressVerifier::verify(&mut builder, self.shrink_prover.machine(), input);
// Verify the proof.
SP1CompressRootVerifier::verify(&mut builder, self.shrink_prover.machine(), input);

let operations = builder.into_operations();
builder_span.exit();

Expand Down Expand Up @@ -388,7 +408,7 @@ impl<C: SP1ProverComponents> SP1Prover<C> {
vk.observe_into(&mut reconstruct_challenger);

// Prepare the inputs for the recursion programs.
for batch in shard_proofs.chunks(batch_size) {
for (batch_idx, batch) in shard_proofs.chunks(batch_size).enumerate() {
let proofs = batch.to_vec();

core_inputs.push(SP1RecursionWitnessValues {
Expand All @@ -397,6 +417,7 @@ impl<C: SP1ProverComponents> SP1Prover<C> {
leaf_challenger: leaf_challenger.clone(),
initial_reconstruct_challenger: reconstruct_challenger.clone(),
is_complete,
is_first_shard: batch_idx == 0,
});
assert_eq!(reconstruct_challenger.input_buffer.len(), 0);
assert_eq!(reconstruct_challenger.sponge_state.len(), 16);
Expand Down
27 changes: 27 additions & 0 deletions crates/recursion/circuit-v2/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,10 @@ pub trait CircuitConfig: Config {

fn read_ext(builder: &mut Builder<Self>) -> Ext<Self::F, Self::EF>;

fn assert_bit_zero(builder: &mut Builder<Self>, bit: Self::Bit);

fn assert_bit_one(builder: &mut Builder<Self>, bit: Self::Bit);

fn ext2felt(
builder: &mut Builder<Self>,
ext: Ext<<Self as Config>::F, <Self as Config>::EF>,
Expand Down Expand Up @@ -162,11 +166,26 @@ pub trait CircuitConfig: Config {
first: impl IntoIterator<Item = Ext<<Self as Config>::F, <Self as Config>::EF>> + Clone,
second: impl IntoIterator<Item = Ext<<Self as Config>::F, <Self as Config>::EF>> + Clone,
) -> Vec<Ext<<Self as Config>::F, <Self as Config>::EF>>;

fn range_check_felt(builder: &mut Builder<Self>, value: Felt<Self::F>, num_bits: usize) {
let bits = Self::num2bits(builder, value, 32);
for bit in bits.into_iter().skip(num_bits) {
Self::assert_bit_zero(builder, bit);
}
}
}

impl CircuitConfig for InnerConfig {
type Bit = Felt<<Self as Config>::F>;

fn assert_bit_zero(builder: &mut Builder<Self>, bit: Self::Bit) {
builder.assert_felt_eq(bit, Self::F::zero());
}

fn assert_bit_one(builder: &mut Builder<Self>, bit: Self::Bit) {
builder.assert_felt_eq(bit, Self::F::one());
}

fn read_bit(builder: &mut Builder<Self>) -> Self::Bit {
builder.hint_felt_v2()
}
Expand Down Expand Up @@ -257,6 +276,14 @@ impl CircuitConfig for InnerConfig {
impl CircuitConfig for OuterConfig {
type Bit = Var<<Self as Config>::N>;

fn assert_bit_zero(builder: &mut Builder<Self>, bit: Self::Bit) {
builder.assert_var_eq(bit, Self::N::zero());
}

fn assert_bit_one(builder: &mut Builder<Self>, bit: Self::Bit) {
builder.assert_var_eq(bit, Self::N::one());
}

fn read_bit(builder: &mut Builder<Self>) -> Self::Bit {
builder.witness_var()
}
Expand Down
72 changes: 72 additions & 0 deletions crates/recursion/circuit-v2/src/machine/complete.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
use itertools::Itertools;
use p3_field::AbstractField;

use sp1_recursion_compiler::ir::{Builder, Config, Felt};
use sp1_recursion_core_v2::air::RecursionPublicValues;

/// Assertions on recursion public values which represent a complete proof.
///
/// The assertions consist of checking all the expected boundary conditions from a compress proof
/// that represents the end of the recursion tower.
pub(crate) fn assert_complete<C: Config>(
builder: &mut Builder<C>,
public_values: &RecursionPublicValues<Felt<C::F>>,
is_complete: Felt<C::F>,
) {
let RecursionPublicValues {
deferred_proofs_digest,
next_pc,
start_shard,
next_shard,
start_execution_shard,
cumulative_sum,
start_reconstruct_deferred_digest,
end_reconstruct_deferred_digest,
leaf_challenger,
end_reconstruct_challenger,
..
} = public_values;

// Assert that the `is_complete` flag is boolean.
builder.assert_felt_eq(is_complete * (is_complete - C::F::one()), C::F::zero());

// Assert that `next_pc` is equal to zero (so program execution has completed)
builder.assert_felt_eq(is_complete * *next_pc, C::F::zero());

// Assert that start shard is equal to 1.
builder.assert_felt_eq(is_complete * (*start_shard - C::F::one()), C::F::zero());

// Assert that the next shard is not equal to one. This guarantees that there is at least one
// shard that contains CPU.
//
// TODO: figure out if this is needed.
builder.assert_felt_ne(is_complete * *next_shard, C::F::one());

// Assert that the start execution shard is equal to 1.
builder.assert_felt_eq(is_complete * (*start_execution_shard - C::F::one()), C::F::zero());

// Assert that the end reconstruct challenger is equal to the leaf challenger.
for (end_challenger_d, leaf_challenger_d) in
end_reconstruct_challenger.into_iter().zip(*leaf_challenger)
{
builder.assert_felt_eq(is_complete * (end_challenger_d - leaf_challenger_d), C::F::zero());
}

// The start reconstruct deffered digest should be zero.
for start_digest_word in start_reconstruct_deferred_digest {
builder.assert_felt_eq(is_complete * *start_digest_word, C::F::zero());
}

// The end reconstruct deffered digest should be equal to the deferred proofs digest.
for (end_digest_word, deferred_digest_word) in
end_reconstruct_deferred_digest.iter().zip_eq(deferred_proofs_digest.iter())
{
builder
.assert_felt_eq(is_complete * (*end_digest_word - *deferred_digest_word), C::F::zero());
}

// Assert that the cumulative sum is zero.
for b in cumulative_sum.iter() {
builder.assert_felt_eq(is_complete * *b, C::F::zero());
}
}
Loading
Loading