diff --git a/Cargo.lock b/Cargo.lock index f6e2e8372b..c2fd41d67c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5308,7 +5308,6 @@ dependencies = [ "sp1-core-executor", "sp1-core-machine", "sp1-primitives", - "sp1-prover", "sp1-recursion-circuit", "sp1-recursion-compiler", "sp1-recursion-core-v2", diff --git a/crates/recursion/circuit-v2/Cargo.toml b/crates/recursion/circuit-v2/Cargo.toml index 49082342b2..8bb5495e39 100644 --- a/crates/recursion/circuit-v2/Cargo.toml +++ b/crates/recursion/circuit-v2/Cargo.toml @@ -37,7 +37,6 @@ sp1-recursion-compiler = { workspace = true } sp1-primitives = { workspace = true } sp1-recursion-gnark-ffi = { workspace = true } sp1-recursion-circuit = { workspace = true } -sp1-prover = { workspace = true } itertools = "0.13.0" serde = { version = "1.0.204", features = ["derive"] } diff --git a/crates/recursion/circuit-v2/src/build_wrap_v2.rs b/crates/recursion/circuit-v2/src/build_wrap_v2.rs index 009f18a61e..f5cc231baa 100644 --- a/crates/recursion/circuit-v2/src/build_wrap_v2.rs +++ b/crates/recursion/circuit-v2/src/build_wrap_v2.rs @@ -26,7 +26,8 @@ use sp1_stark::{ use crate::{ challenger::{CanObserveVariable, MultiField32ChallengerVariable}, stark::{ShardProofVariable, StarkVerifier}, - utils::{babybear_bytes_to_bn254, babybears_to_bn254, words_to_bytes}, + utils::{felt_bytes_to_bn254_var, felts_to_bn254_var, words_to_bytes}, + witness::Witnessable, BatchOpeningVariable, FriCommitPhaseProofStepVariable, FriProofVariable, FriQueryProofVariable, TwoAdicPcsProofVariable, VerifyingKeyVariable, }; @@ -56,9 +57,11 @@ where let pc_start = builder.eval(wrap_vk.pc_start); challenger.observe(&mut builder, pc_start); - // let mut witness = Witness::default(); + // let mut witness = OuterWitness::default(); // template_proof.write(&mut witness); - let proof = const_shard_proof(&mut builder, &template_proof); + + let proof = template_proof.read(&mut builder); + // let proof = const_shard_proof(&mut builder, &template_proof); let commited_values_digest = builder.constant(::N::zero()); builder.commit_commited_values_digest_circuit(commited_values_digest); @@ -81,7 +84,7 @@ where // builder.assert_felt_eq(pv.is_complete, one_felt); // Convert pv.sp1_vk_digest into Bn254 - let pv_vkey_hash = babybears_to_bn254(&mut builder, &pv.sp1_vk_digest); + let pv_vkey_hash = felts_to_bn254_var(&mut builder, &pv.sp1_vk_digest); // Vkey hash must match the witnessed commited_values_digest that we are committing to. builder.assert_var_eq(pv_vkey_hash, vkey_hash); @@ -89,7 +92,7 @@ where let pv_committed_values_digest_bytes: [Felt<_>; 32] = words_to_bytes(&pv.committed_value_digest).try_into().unwrap(); let pv_committed_values_digest: Var<_> = - babybear_bytes_to_bn254(&mut builder, &pv_committed_values_digest_bytes); + felt_bytes_to_bn254_var(&mut builder, &pv_committed_values_digest_bytes); // // Committed values digest must match the witnessed one that we are committing to. builder.assert_var_eq(pv_committed_values_digest, commited_values_digest); @@ -143,7 +146,7 @@ where /// A utility function to convert a `ShardProof` into a `ShardProofVariable`. Should be replaced by /// more refined witness generation. -fn const_shard_proof( +pub fn const_shard_proof( builder: &mut Builder, proof: &ShardProof, ) -> ShardProofVariable { @@ -265,7 +268,7 @@ fn const_fri_proof( } } -fn const_two_adic_pcs_proof( +pub fn const_two_adic_pcs_proof( builder: &mut Builder, proof: TwoAdicFriPcsProof, ) -> TwoAdicPcsProofVariable { @@ -310,7 +313,6 @@ pub mod tests { use p3_matrix::dense::RowMajorMatrix; use rand::{rngs::StdRng, SeedableRng}; use sp1_core_machine::utils::{log2_strict_usize, run_test_machine, setup_logger}; - use sp1_prover::build::{Witness, Witnessable}; use sp1_recursion_compiler::{ config::OuterConfig, constraints::ConstraintCompiler, @@ -330,8 +332,12 @@ pub mod tests { use sp1_stark::{BabyBearPoseidon2Inner, StarkMachine}; use crate::{ - challenger::CanObserveVariable, fri::verify_two_adic_pcs, hash::BN254_DIGEST_SIZE, Digest, - TwoAdicPcsMatsVariable, TwoAdicPcsRoundVariable, + challenger::CanObserveVariable, + fri::verify_two_adic_pcs, + hash::BN254_DIGEST_SIZE, + utils::{babybear_bytes_to_bn254, babybears_to_bn254, words_to_bytes}, + witness::{OuterWitness, Witnessable}, + Digest, TwoAdicPcsMatsVariable, TwoAdicPcsRoundVariable, }; use super::{build_wrap_circuit_v2, const_two_adic_pcs_proof}; @@ -368,14 +374,13 @@ pub mod tests { let pv: &RecursionPublicValues<_> = result.shard_proofs[0].public_values.as_slice().borrow(); - let vkey_hash = sp1_prover::utils::babybears_to_bn254(&pv.sp1_vk_digest); + let vkey_hash = babybears_to_bn254(&pv.sp1_vk_digest); let committed_values_digest_bytes: [BabyBear; 32] = - sp1_prover::utils::words_to_bytes(&pv.committed_value_digest).try_into().unwrap(); - let committed_values_digest = - sp1_prover::utils::babybear_bytes_to_bn254(&committed_values_digest_bytes); + words_to_bytes(&pv.committed_value_digest).try_into().unwrap(); + let committed_values_digest = babybear_bytes_to_bn254(&committed_values_digest_bytes); // Build the witness. - let mut witness = Witness::default(); + let mut witness = OuterWitness::default(); result.shard_proofs[0].write(&mut witness); witness.write_commited_values_digest(committed_values_digest); witness.write_vkey_hash(vkey_hash); @@ -506,7 +511,7 @@ pub mod tests { ); let mut backend = ConstraintCompiler::::default(); let constraints = backend.emit(builder.operations); - let witness = Witness::default(); + let witness = OuterWitness::default(); PlonkBn254Prover::test::(constraints, witness); } } diff --git a/crates/recursion/circuit-v2/src/challenger.rs b/crates/recursion/circuit-v2/src/challenger.rs index 12b2e77a2e..2ea066920d 100644 --- a/crates/recursion/circuit-v2/src/challenger.rs +++ b/crates/recursion/circuit-v2/src/challenger.rs @@ -446,7 +446,6 @@ pub(crate) mod tests { use p3_challenger::{CanObserve, CanSample, CanSampleBits, FieldChallenger}; use p3_field::AbstractField; use p3_symmetric::{CryptographicHasher, Hash, PseudoCompressionFunction}; - use sp1_prover::build::Witness; use sp1_recursion_compiler::{ asm::{AsmBuilder, AsmConfig}, config::OuterConfig, @@ -459,7 +458,10 @@ pub(crate) mod tests { use sp1_recursion_gnark_ffi::PlonkBn254Prover; use sp1_stark::{baby_bear_poseidon2::BabyBearPoseidon2, StarkGenericConfig}; - use crate::challenger::{DuplexChallengerVariable, FieldChallengerVariable}; + use crate::{ + challenger::{DuplexChallengerVariable, FieldChallengerVariable}, + witness::OuterWitness, + }; type SC = BabyBearPoseidon2; type C = OuterConfig; @@ -567,7 +569,7 @@ pub(crate) mod tests { let mut backend = ConstraintCompiler::::default(); let constraints = backend.emit(builder.operations); - let witness = Witness::default(); + let witness = OuterWitness::default(); PlonkBn254Prover::test::(constraints, witness); } @@ -588,7 +590,7 @@ pub(crate) mod tests { let mut backend = ConstraintCompiler::::default(); let constraints = backend.emit(builder.operations); - let witness = Witness::default(); + let witness = OuterWitness::default(); PlonkBn254Prover::test::(constraints, witness); } @@ -622,7 +624,7 @@ pub(crate) mod tests { let mut backend = ConstraintCompiler::::default(); let constraints = backend.emit(builder.operations); - PlonkBn254Prover::test::(constraints.clone(), Witness::default()); + PlonkBn254Prover::test::(constraints.clone(), OuterWitness::default()); } #[test] @@ -643,6 +645,6 @@ pub(crate) mod tests { let mut backend = ConstraintCompiler::::default(); let constraints = backend.emit(builder.operations); - PlonkBn254Prover::test::(constraints.clone(), Witness::default()); + PlonkBn254Prover::test::(constraints.clone(), OuterWitness::default()); } } diff --git a/crates/recursion/circuit-v2/src/lib.rs b/crates/recursion/circuit-v2/src/lib.rs index 98689b837b..c3aedb819f 100644 --- a/crates/recursion/circuit-v2/src/lib.rs +++ b/crates/recursion/circuit-v2/src/lib.rs @@ -102,6 +102,12 @@ pub trait BabyBearFriConfigVariable>: pub trait CircuitConfig: Config { type Bit: Clone + Variable; + fn read_bit(builder: &mut Builder) -> Self::Bit; + + fn read_felt(builder: &mut Builder) -> Felt; + + fn read_ext(builder: &mut Builder) -> Ext; + fn ext2felt( builder: &mut Builder, ext: Ext<::F, ::EF>, @@ -136,6 +142,18 @@ pub trait CircuitConfig: Config { impl CircuitConfig for InnerConfig { type Bit = Felt<::F>; + fn read_bit(builder: &mut Builder) -> Self::Bit { + builder.hint_felt_v2() + } + + fn read_felt(builder: &mut Builder) -> Felt { + builder.hint_felt_v2() + } + + fn read_ext(builder: &mut Builder) -> Ext { + builder.hint_ext_v2() + } + fn ext2felt( builder: &mut Builder, ext: Ext<::F, ::EF>, @@ -186,11 +204,25 @@ impl CircuitConfig for InnerConfig { impl CircuitConfig for OuterConfig { type Bit = Var<::N>; + fn read_bit(builder: &mut Builder) -> Self::Bit { + builder.witness_var() + } + + fn read_felt(builder: &mut Builder) -> Felt { + builder.witness_felt() + } + + fn read_ext(builder: &mut Builder) -> Ext { + builder.witness_ext() + } + fn ext2felt( builder: &mut Builder, ext: Ext<::F, ::EF>, ) -> [Felt<::F>; D] { - builder.ext2felt_v2(ext) + let felts = core::array::from_fn(|_| builder.uninit()); + builder.operations.push(DslIr::CircuitExt2Felt(felts, ext)); + felts } fn exp_reverse_bits( diff --git a/crates/recursion/circuit-v2/src/machine/witness.rs b/crates/recursion/circuit-v2/src/machine/witness.rs index 90d891e775..44f8ab54c7 100644 --- a/crates/recursion/circuit-v2/src/machine/witness.rs +++ b/crates/recursion/circuit-v2/src/machine/witness.rs @@ -5,7 +5,7 @@ use p3_challenger::DuplexChallenger; use p3_symmetric::Hash; use p3_field::AbstractField; -use sp1_recursion_compiler::ir::{Builder, Config}; +use sp1_recursion_compiler::ir::Builder; use sp1_stark::{ air::MachineAir, baby_bear_poseidon2::BabyBearPoseidon2, InnerChallenge, InnerPerm, InnerVal, StarkVerifyingKey, @@ -14,14 +14,16 @@ use sp1_stark::{ use sp1_recursion_compiler::ir::Felt; use crate::{ - challenger::DuplexChallengerVariable, witness::Witnessable, CircuitConfig, VerifyingKeyVariable, + challenger::DuplexChallengerVariable, + witness::{WitnessWriter, Witnessable}, + CircuitConfig, VerifyingKeyVariable, }; use super::{SP1RecursionMemoryLayout, SP1RecursionWitnessVariable}; impl Witnessable for DuplexChallenger where - C: Config, + C: CircuitConfig, { type WitnessVariable = DuplexChallengerVariable; @@ -32,19 +34,16 @@ where DuplexChallengerVariable { sponge_state, input_buffer, output_buffer } } - fn write(&self) -> Vec> { - [ - Witnessable::::write(&self.sponge_state), - Witnessable::::write(&self.input_buffer), - Witnessable::::write(&self.output_buffer), - ] - .concat() + fn write(&self, witness: &mut impl WitnessWriter) { + self.sponge_state.write(witness); + self.input_buffer.write(witness); + self.output_buffer.write(witness); } } impl Witnessable for Hash where - C: Config, + C: CircuitConfig, W: Witnessable, { type WitnessVariable = [W::WitnessVariable; DIGEST_ELEMENTS]; @@ -54,9 +53,9 @@ where array.read(builder) } - fn write(&self) -> Vec> { + fn write(&self, witness: &mut impl WitnessWriter) { let array: &[W; DIGEST_ELEMENTS] = self.borrow(); - array.write() + array.write(witness); } } @@ -74,8 +73,9 @@ where VerifyingKeyVariable { commitment, pc_start, chip_information, chip_ordering } } - fn write(&self) -> Vec> { - [Witnessable::::write(&self.commit), Witnessable::::write(&self.pc_start)].concat() + fn write(&self, witness: &mut impl WitnessWriter) { + self.commit.write(witness); + self.pc_start.write(witness); } } @@ -101,14 +101,11 @@ where } } - fn write(&self) -> Vec> { - [ - Witnessable::::write(&self.vk), - Witnessable::::write(&self.shard_proofs), - Witnessable::::write(&self.leaf_challenger), - Witnessable::::write(&self.initial_reconstruct_challenger), - Witnessable::::write(&InnerVal::from_bool(self.is_complete)), - ] - .concat() + fn write(&self, witness: &mut impl WitnessWriter) { + self.vk.write(witness); + self.shard_proofs.write(witness); + self.leaf_challenger.write(witness); + self.initial_reconstruct_challenger.write(witness); + self.is_complete.write(witness); } } diff --git a/crates/recursion/circuit-v2/src/stark.rs b/crates/recursion/circuit-v2/src/stark.rs index edfc159143..9f0a07b107 100644 --- a/crates/recursion/circuit-v2/src/stark.rs +++ b/crates/recursion/circuit-v2/src/stark.rs @@ -255,10 +255,10 @@ pub mod tests { use sp1_core_executor::{programs::tests::FIBONACCI_ELF, Program}; use sp1_core_machine::{ + io::SP1Stdin, riscv::RiscvAir, utils::{prove, setup_logger}, }; - use sp1_prover::{SP1Stdin, SP1VerifyingKey}; use sp1_recursion_compiler::{ config::{InnerConfig, OuterConfig}, ir::{Builder, DslIr, TracedVec}, @@ -279,7 +279,7 @@ pub mod tests { type A = RiscvAir; pub fn build_verify_shard_with_provers< - C: CircuitConfig, + C: CircuitConfig>, SC: BabyBearFriConfigVariable + Default + Sync + Send, CoreP: MachineProver, RecP: MachineProver>, @@ -288,7 +288,7 @@ pub mod tests { elf: &[u8], opts: SP1CoreOpts, num_shards_in_batch: Option, - ) -> (TracedVec>, VecDeque>) + ) -> (TracedVec>, Vec>) where SC::Challenger: Send, <::ValMmcs as Mmcs>::ProverData< @@ -314,12 +314,12 @@ pub mod tests { // Observe all the commitments. let mut builder = Builder::::default(); - let mut witness_stream = VecDeque::>::new(); + let mut witness_stream = Vec::>::new(); // Add a hash invocation, since the poseidon2 table expects that it's in the first row. let mut challenger = config.challenger_variable(&mut builder); // let vk = VerifyingKeyVariable::from_constant_key_babybear(&mut builder, &vk); - witness_stream.extend(Witnessable::::write(&vk)); + vk.write(&mut witness_stream); let vk: VerifyingKeyVariable<_, _> = vk.read(&mut builder); vk.observe_into(&mut builder, &mut challenger); @@ -327,7 +327,7 @@ pub mod tests { .shard_proofs .into_iter() .map(|proof| { - witness_stream.extend(Witnessable::::write(&proof)); + proof.write(&mut witness_stream); proof.read(&mut builder) }) .collect::>(); diff --git a/crates/recursion/circuit-v2/src/utils.rs b/crates/recursion/circuit-v2/src/utils.rs index 34fd4d3bde..71a630f2f7 100644 --- a/crates/recursion/circuit-v2/src/utils.rs +++ b/crates/recursion/circuit-v2/src/utils.rs @@ -1,6 +1,9 @@ use std::borrow::BorrowMut; +use p3_baby_bear::BabyBear; +use p3_bn254_fr::Bn254Fr; use p3_field::AbstractField; +use p3_field::PrimeField32; use sp1_recursion_compiler::{ circuit::CircuitV2Builder, @@ -33,7 +36,39 @@ pub fn commit_recursion_public_values( } } -pub fn babybears_to_bn254( +/// Convert 8 BabyBear words into a Bn254Fr field element by shifting by 31 bits each time. The last +/// word becomes the least significant bits. +#[allow(dead_code)] +pub fn babybears_to_bn254(digest: &[BabyBear; 8]) -> Bn254Fr { + let mut result = Bn254Fr::zero(); + for word in digest.iter() { + // Since BabyBear prime is less than 2^31, we can shift by 31 bits each time and still be + // within the Bn254Fr field, so we don't have to truncate the top 3 bits. + result *= Bn254Fr::from_canonical_u64(1 << 31); + result += Bn254Fr::from_canonical_u32(word.as_canonical_u32()); + } + result +} + +/// Convert 32 BabyBear bytes into a Bn254Fr field element. The first byte's most significant 3 bits +/// (which would become the 3 most significant bits) are truncated. +#[allow(dead_code)] +pub fn babybear_bytes_to_bn254(bytes: &[BabyBear; 32]) -> Bn254Fr { + let mut result = Bn254Fr::zero(); + for (i, byte) in bytes.iter().enumerate() { + debug_assert!(byte < &BabyBear::from_canonical_u32(256)); + if i == 0 { + // 32 bytes is more than Bn254 prime, so we need to truncate the top 3 bits. + result = Bn254Fr::from_canonical_u32(byte.as_canonical_u32() & 0x1f); + } else { + result *= Bn254Fr::from_canonical_u32(256); + result += Bn254Fr::from_canonical_u32(byte.as_canonical_u32()); + } + } + result +} + +pub fn felts_to_bn254_var( builder: &mut Builder, digest: &[Felt; DIGEST_SIZE], ) -> Var { @@ -51,7 +86,7 @@ pub fn babybears_to_bn254( result } -pub fn babybear_bytes_to_bn254( +pub fn felt_bytes_to_bn254_var( builder: &mut Builder, bytes: &[Felt; 32], ) -> Var { @@ -93,7 +128,7 @@ pub(crate) mod tests { baby_bear_poseidon2::BabyBearPoseidon2, CpuProver, InnerChallenge, InnerVal, MachineProver, }; - use crate::witness::Witness; + use crate::witness::WitnessBlock; type SC = BabyBearPoseidon2; type F = InnerVal; @@ -104,7 +139,7 @@ pub(crate) mod tests { /// of machines depending on the provided test_config. pub(crate) fn run_test_recursion_with_prover>>( operations: TracedVec>>, - witness_stream: impl IntoIterator>>, + witness_stream: impl IntoIterator>>, ) { setup_logger(); @@ -139,7 +174,7 @@ pub(crate) mod tests { #[allow(dead_code)] pub(crate) fn run_test_recursion( operations: TracedVec>>, - witness_stream: impl IntoIterator>>, + witness_stream: impl IntoIterator>>, ) { run_test_recursion_with_prover::>(operations, witness_stream) } diff --git a/crates/recursion/circuit-v2/src/witness.rs b/crates/recursion/circuit-v2/src/witness.rs deleted file mode 100644 index bfd1796899..0000000000 --- a/crates/recursion/circuit-v2/src/witness.rs +++ /dev/null @@ -1,328 +0,0 @@ -use std::borrow::Borrow; - -use p3_baby_bear::BabyBear; -use p3_field::AbstractExtensionField; -use p3_fri::{CommitPhaseProofStep, QueryProof}; - -use sp1_recursion_compiler::{ - circuit::CircuitV2Builder, - ir::{Builder, Config, Ext, Felt}, -}; -use sp1_recursion_core_v2::air::Block; -use sp1_stark::{ - baby_bear_poseidon2::BabyBearPoseidon2, AirOpenedValues, ChipOpenedValues, InnerBatchOpening, - InnerChallenge, InnerChallengeMmcs, InnerDigest, InnerFriProof, InnerPcsProof, InnerVal, - ShardCommitment, ShardOpenedValues, ShardProof, -}; - -use crate::{ - stark::ShardProofVariable, BatchOpeningVariable, CircuitConfig, - FriCommitPhaseProofStepVariable, FriProofVariable, FriQueryProofVariable, - TwoAdicPcsProofVariable, -}; - -pub type Witness = Block<::F>; - -/// TODO change the name. For now, the name is unique to prevent confusion. -pub trait Witnessable { - type WitnessVariable; - - fn read(&self, builder: &mut Builder) -> Self::WitnessVariable; - - fn write(&self) -> Vec>; -} - -impl<'a, C: Config, T: Witnessable> Witnessable for &'a T { - type WitnessVariable = T::WitnessVariable; - - fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { - (*self).read(builder) - } - - fn write(&self) -> Vec> { - (*self).write() - } -} - -// TODO Bn254Fr - -impl> Witnessable for InnerVal { - type WitnessVariable = Felt; - - fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { - builder.hint_felt_v2() - } - - fn write(&self) -> Vec> { - vec![Block::from(*self)] - } -} - -impl> Witnessable for InnerChallenge { - type WitnessVariable = Ext; - - fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { - builder.hint_ext_v2() - } - - fn write(&self) -> Vec> { - vec![Block::from(self.as_base_slice())] - } -} - -impl, const N: usize> Witnessable for [T; N] { - type WitnessVariable = [T::WitnessVariable; N]; - - fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { - self.iter().map(|x| x.read(builder)).collect::>().try_into().unwrap_or_else( - |x: Vec<_>| { - // Cannot just `.unwrap()` without requiring Debug bounds. - panic!("could not coerce vec of len {} into array of len {N}", x.len()) - }, - ) - } - - fn write(&self) -> Vec> { - self.iter().flat_map(|x| x.write()).collect() - } -} - -impl> Witnessable for Vec { - type WitnessVariable = Vec; - - fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { - self.iter().map(|x| x.read(builder)).collect() - } - - fn write(&self) -> Vec> { - self.iter().flat_map(|x| x.write()).collect() - } -} - -impl>> Witnessable - for ShardProof -{ - type WitnessVariable = ShardProofVariable; - - fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { - let commitment = self.commitment.read(builder); - let opened_values = self.opened_values.read(builder); - let opening_proof = self.opening_proof.read(builder); - let public_values = self.public_values.read(builder); - let chip_ordering = self.chip_ordering.clone(); - - ShardProofVariable { - commitment, - opened_values, - opening_proof, - public_values, - chip_ordering, - } - } - - fn write(&self) -> Vec> { - [ - Witnessable::::write(&self.commitment), - Witnessable::::write(&self.opened_values), - Witnessable::::write(&self.opening_proof), - Witnessable::::write(&self.public_values), - ] - .concat() - } -} - -impl> Witnessable for ShardCommitment { - type WitnessVariable = ShardCommitment; - - fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { - let main_commit = self.main_commit.read(builder); - let permutation_commit = self.permutation_commit.read(builder); - let quotient_commit = self.quotient_commit.read(builder); - Self::WitnessVariable { main_commit, permutation_commit, quotient_commit } - } - - fn write(&self) -> Vec> { - [ - Witnessable::::write(&self.main_commit), - Witnessable::::write(&self.permutation_commit), - Witnessable::::write(&self.quotient_commit), - ] - .concat() - } -} - -impl> Witnessable - for ShardOpenedValues -{ - type WitnessVariable = ShardOpenedValues>; - - fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { - let chips = self.chips.read(builder); - Self::WitnessVariable { chips } - } - - fn write(&self) -> Vec> { - Witnessable::::write(&self.chips) - } -} - -impl> Witnessable - for ChipOpenedValues -{ - type WitnessVariable = ChipOpenedValues>; - - fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { - let preprocessed = self.preprocessed.read(builder); - let main = self.main.read(builder); - let permutation = self.permutation.read(builder); - let quotient = self.quotient.read(builder); - let cumulative_sum = self.cumulative_sum.read(builder); - let log_degree = self.log_degree; - Self::WitnessVariable { - preprocessed, - main, - permutation, - quotient, - cumulative_sum, - log_degree, - } - } - - fn write(&self) -> Vec> { - [ - Witnessable::::write(&self.preprocessed), - Witnessable::::write(&self.main), - Witnessable::::write(&self.permutation), - Witnessable::::write(&self.quotient), - Witnessable::::write(&self.cumulative_sum), - ] - .concat() - } -} - -impl> Witnessable - for AirOpenedValues -{ - type WitnessVariable = AirOpenedValues>; - - fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { - let local = self.local.read(builder); - let next = self.next.read(builder); - Self::WitnessVariable { local, next } - } - - fn write(&self) -> Vec> { - let mut stream = Vec::new(); - stream.extend(Witnessable::::write(&self.local)); - stream.extend(Witnessable::::write(&self.next)); - stream - } -} - -impl>> Witnessable - for InnerPcsProof -{ - type WitnessVariable = TwoAdicPcsProofVariable; - - fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { - let fri_proof = self.fri_proof.read(builder); - let query_openings = self.query_openings.read(builder); - Self::WitnessVariable { fri_proof, query_openings } - } - - fn write(&self) -> Vec> { - [Witnessable::::write(&self.fri_proof), Witnessable::::write(&self.query_openings)] - .concat() - } -} - -impl>> Witnessable - for InnerBatchOpening -{ - type WitnessVariable = BatchOpeningVariable; - - fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { - let opened_values = self - .opened_values - .read(builder) - .into_iter() - .map(|a| a.into_iter().map(|b| vec![b]).collect()) - .collect(); - let opening_proof = self.opening_proof.read(builder); - Self::WitnessVariable { opened_values, opening_proof } - } - - fn write(&self) -> Vec> { - [Witnessable::::write(&self.opened_values), Witnessable::::write(&self.opening_proof)] - .concat() - } -} - -impl>> Witnessable - for InnerFriProof -{ - type WitnessVariable = FriProofVariable; - - fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { - let commit_phase_commits = self - .commit_phase_commits - .iter() - .map(|commit| { - let commit: &InnerDigest = commit.borrow(); - commit.read(builder) - }) - .collect(); - let query_proofs = self.query_proofs.read(builder); - let final_poly = self.final_poly.read(builder); - let pow_witness = self.pow_witness.read(builder); - Self::WitnessVariable { commit_phase_commits, query_proofs, final_poly, pow_witness } - } - - fn write(&self) -> Vec> { - [ - self.commit_phase_commits - .iter() - .flat_map(|commit| { - let commit = Borrow::::borrow(commit); - Witnessable::::write(commit) - }) - .collect(), - Witnessable::::write(&self.query_proofs), - Witnessable::::write(&self.final_poly), - Witnessable::::write(&self.pow_witness), - ] - .concat() - } -} - -impl>> Witnessable - for QueryProof -{ - type WitnessVariable = FriQueryProofVariable; - - fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { - let commit_phase_openings = self.commit_phase_openings.read(builder); - Self::WitnessVariable { commit_phase_openings } - } - - fn write(&self) -> Vec> { - Witnessable::::write(&self.commit_phase_openings) - } -} - -impl>> Witnessable - for CommitPhaseProofStep -{ - type WitnessVariable = FriCommitPhaseProofStepVariable; - - fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { - let sibling_value = self.sibling_value.read(builder); - let opening_proof = self.opening_proof.read(builder); - Self::WitnessVariable { sibling_value, opening_proof } - } - - fn write(&self) -> Vec> { - [Witnessable::::write(&self.sibling_value), Witnessable::::write(&self.opening_proof)] - .concat() - } -} diff --git a/crates/recursion/circuit-v2/src/witness/mod.rs b/crates/recursion/circuit-v2/src/witness/mod.rs new file mode 100644 index 0000000000..c8c90e7c20 --- /dev/null +++ b/crates/recursion/circuit-v2/src/witness/mod.rs @@ -0,0 +1,212 @@ +mod outer; +mod stark; + +use sp1_recursion_compiler::ir::{Builder, Ext, Felt}; + +pub use outer::*; +use sp1_stark::{ + ChipOpenedValues, Com, InnerChallenge, InnerVal, OpeningProof, ShardCommitment, + ShardOpenedValues, ShardProof, +}; +pub use stark::*; + +use crate::{ + hash::FieldHasherVariable, stark::ShardProofVariable, BabyBearFriConfigVariable, CircuitConfig, + TwoAdicPcsProofVariable, +}; + +pub trait WitnessWriter: Sized { + fn write_bit(&mut self, value: bool); + + fn write_var(&mut self, value: C::N); + + fn write_felt(&mut self, value: C::F); + + fn write_ext(&mut self, value: C::EF); +} + +/// TODO change the name. For now, the name is unique to prevent confusion. +pub trait Witnessable { + type WitnessVariable; + + fn read(&self, builder: &mut Builder) -> Self::WitnessVariable; + + fn write(&self, witness: &mut impl WitnessWriter); +} + +impl Witnessable for bool { + type WitnessVariable = C::Bit; + + fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { + C::read_bit(builder) + } + + fn write(&self, witness: &mut impl WitnessWriter) { + witness.write_bit(*self); + } +} + +impl<'a, C: CircuitConfig, T: Witnessable> Witnessable for &'a T { + type WitnessVariable = T::WitnessVariable; + + fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { + (*self).read(builder) + } + + fn write(&self, witness: &mut impl WitnessWriter) { + (*self).write(witness) + } +} + +impl> Witnessable for InnerVal { + type WitnessVariable = Felt; + + fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { + C::read_felt(builder) + } + + fn write(&self, witness: &mut impl WitnessWriter) { + witness.write_felt(*self); + } +} + +impl> Witnessable for InnerChallenge { + type WitnessVariable = Ext; + + fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { + C::read_ext(builder) + } + + fn write(&self, witness: &mut impl WitnessWriter) { + // vec![Block::from(self.as_base_slice())] + witness.write_ext(*self); + } +} + +impl, const N: usize> Witnessable for [T; N] { + type WitnessVariable = [T::WitnessVariable; N]; + + fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { + self.iter().map(|x| x.read(builder)).collect::>().try_into().unwrap_or_else( + |x: Vec<_>| { + // Cannot just `.unwrap()` without requiring Debug bounds. + panic!("could not coerce vec of len {} into array of len {N}", x.len()) + }, + ) + } + + fn write(&self, witness: &mut impl WitnessWriter) { + for x in self.iter() { + x.write(witness); + } + } +} + +impl> Witnessable for Vec { + type WitnessVariable = Vec; + + fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { + self.iter().map(|x| x.read(builder)).collect() + } + + fn write(&self, witness: &mut impl WitnessWriter) { + for x in self.iter() { + x.write(witness); + } + } +} + +impl, SC: BabyBearFriConfigVariable> + Witnessable for ShardProof +where + Com: Witnessable>::Digest>, + OpeningProof: Witnessable>, +{ + type WitnessVariable = ShardProofVariable; + + fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { + let commitment = self.commitment.read(builder); + let opened_values = self.opened_values.read(builder); + let opening_proof = self.opening_proof.read(builder); + let public_values = self.public_values.read(builder); + let chip_ordering = self.chip_ordering.clone(); + + ShardProofVariable { + commitment, + opened_values, + opening_proof, + public_values, + chip_ordering, + } + } + + fn write(&self, witness: &mut impl WitnessWriter) { + self.commitment.write(witness); + self.opened_values.write(witness); + self.opening_proof.write(witness); + self.public_values.write(witness); + } +} + +impl> Witnessable for ShardCommitment { + type WitnessVariable = ShardCommitment; + + fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { + let main_commit = self.main_commit.read(builder); + let permutation_commit = self.permutation_commit.read(builder); + let quotient_commit = self.quotient_commit.read(builder); + Self::WitnessVariable { main_commit, permutation_commit, quotient_commit } + } + + fn write(&self, witness: &mut impl WitnessWriter) { + self.main_commit.write(witness); + self.permutation_commit.write(witness); + self.quotient_commit.write(witness); + } +} + +impl> Witnessable + for ShardOpenedValues +{ + type WitnessVariable = ShardOpenedValues>; + + fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { + let chips = self.chips.read(builder); + Self::WitnessVariable { chips } + } + + fn write(&self, witness: &mut impl WitnessWriter) { + self.chips.write(witness); + } +} + +impl> Witnessable + for ChipOpenedValues +{ + type WitnessVariable = ChipOpenedValues>; + + fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { + let preprocessed = self.preprocessed.read(builder); + let main = self.main.read(builder); + let permutation = self.permutation.read(builder); + let quotient = self.quotient.read(builder); + let cumulative_sum = self.cumulative_sum.read(builder); + let log_degree = self.log_degree; + Self::WitnessVariable { + preprocessed, + main, + permutation, + quotient, + cumulative_sum, + log_degree, + } + } + + fn write(&self, witness: &mut impl WitnessWriter) { + self.preprocessed.write(witness); + self.main.write(witness); + self.permutation.write(witness); + self.quotient.write(witness); + self.cumulative_sum.write(witness); + } +} diff --git a/crates/recursion/circuit-v2/src/witness/outer.rs b/crates/recursion/circuit-v2/src/witness/outer.rs new file mode 100644 index 0000000000..a8fe1b84f7 --- /dev/null +++ b/crates/recursion/circuit-v2/src/witness/outer.rs @@ -0,0 +1,143 @@ +use std::borrow::Borrow; + +use p3_bn254_fr::Bn254Fr; +use p3_field::AbstractField; + +use p3_fri::{CommitPhaseProofStep, QueryProof}; +pub use sp1_recursion_compiler::ir::Witness as OuterWitness; +use sp1_recursion_compiler::{ + config::OuterConfig, + ir::{Builder, Var}, +}; +use sp1_recursion_core_v2::stark::config::{ + BabyBearPoseidon2Outer, OuterBatchOpening, OuterChallenge, OuterChallengeMmcs, OuterDigest, + OuterFriProof, OuterPcsProof, OuterVal, +}; + +use crate::{ + BatchOpeningVariable, FriCommitPhaseProofStepVariable, FriProofVariable, FriQueryProofVariable, + TwoAdicPcsProofVariable, +}; + +use super::{WitnessWriter, Witnessable}; + +impl WitnessWriter for OuterWitness { + fn write_bit(&mut self, value: bool) { + self.vars.push(Bn254Fr::from_bool(value)); + } + + fn write_var(&mut self, value: Bn254Fr) { + self.vars.push(value); + } + + fn write_felt(&mut self, value: OuterVal) { + self.felts.push(value); + } + + fn write_ext(&mut self, value: OuterChallenge) { + self.exts.push(value); + } +} + +impl Witnessable for Bn254Fr { + type WitnessVariable = Var; + + fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { + builder.witness_var() + } + fn write(&self, witness: &mut impl WitnessWriter) { + witness.write_var(*self) + } +} + +impl Witnessable for OuterBatchOpening { + type WitnessVariable = BatchOpeningVariable; + + fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { + let opened_values = self + .opened_values + .read(builder) + .into_iter() + .map(|a| a.into_iter().map(|b| vec![b]).collect()) + .collect(); + let opening_proof = self.opening_proof.read(builder); + Self::WitnessVariable { opened_values, opening_proof } + } + + fn write(&self, witness: &mut impl WitnessWriter) { + self.opened_values.write(witness); + self.opening_proof.write(witness); + } +} + +impl Witnessable for OuterPcsProof { + type WitnessVariable = TwoAdicPcsProofVariable; + + fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { + let fri_proof = self.fri_proof.read(builder); + let query_openings = self.query_openings.read(builder); + Self::WitnessVariable { fri_proof, query_openings } + } + + fn write(&self, witness: &mut impl WitnessWriter) { + self.fri_proof.write(witness); + self.query_openings.write(witness); + } +} + +impl Witnessable for OuterFriProof { + type WitnessVariable = FriProofVariable; + + fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { + let commit_phase_commits = self + .commit_phase_commits + .iter() + .map(|commit| { + let commit: &OuterDigest = commit.borrow(); + commit.read(builder) + }) + .collect(); + let query_proofs = self.query_proofs.read(builder); + let final_poly = self.final_poly.read(builder); + let pow_witness = self.pow_witness.read(builder); + Self::WitnessVariable { commit_phase_commits, query_proofs, final_poly, pow_witness } + } + + fn write(&self, witness: &mut impl WitnessWriter) { + self.commit_phase_commits.iter().for_each(|commit| { + let commit = Borrow::::borrow(commit); + commit.write(witness); + }); + self.query_proofs.write(witness); + self.final_poly.write(witness); + self.pow_witness.write(witness); + } +} + +impl Witnessable for CommitPhaseProofStep { + type WitnessVariable = FriCommitPhaseProofStepVariable; + + fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { + let sibling_value = self.sibling_value.read(builder); + let opening_proof = self.opening_proof.read(builder); + Self::WitnessVariable { sibling_value, opening_proof } + } + + fn write(&self, witness: &mut impl WitnessWriter) { + self.sibling_value.write(witness); + self.opening_proof.write(witness); + } +} + +impl Witnessable for QueryProof { + type WitnessVariable = FriQueryProofVariable; + + fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { + let commit_phase_openings = self.commit_phase_openings.read(builder); + Self::WitnessVariable { commit_phase_openings } + } + + fn write(&self, witness: &mut impl WitnessWriter) { + self.commit_phase_openings.write(witness); + } +} diff --git a/crates/recursion/circuit-v2/src/witness/stark.rs b/crates/recursion/circuit-v2/src/witness/stark.rs new file mode 100644 index 0000000000..0f2308c0e7 --- /dev/null +++ b/crates/recursion/circuit-v2/src/witness/stark.rs @@ -0,0 +1,161 @@ +use std::borrow::Borrow; + +use p3_baby_bear::BabyBear; +use p3_field::{AbstractExtensionField, AbstractField}; +use p3_fri::{CommitPhaseProofStep, QueryProof}; + +use sp1_recursion_compiler::ir::{Builder, Config, Ext, Felt}; +use sp1_recursion_core_v2::air::Block; +use sp1_stark::{ + baby_bear_poseidon2::BabyBearPoseidon2, AirOpenedValues, InnerBatchOpening, InnerChallenge, + InnerChallengeMmcs, InnerDigest, InnerFriProof, InnerPcsProof, InnerVal, +}; + +use crate::{ + BatchOpeningVariable, CircuitConfig, FriCommitPhaseProofStepVariable, FriProofVariable, + FriQueryProofVariable, TwoAdicPcsProofVariable, +}; + +use super::{WitnessWriter, Witnessable}; + +pub type WitnessBlock = Block<::F>; + +impl>> WitnessWriter + for Vec> +{ + fn write_bit(&mut self, value: bool) { + self.push(Block::from(C::F::from_bool(value))) + } + + fn write_var(&mut self, _value: ::N) { + unimplemented!("Cannot write Var in this configuration") + } + + fn write_felt(&mut self, value: ::F) { + self.push(Block::from(value)) + } + + fn write_ext(&mut self, value: ::EF) { + self.push(Block::from(value.as_base_slice())) + } +} + +impl> Witnessable + for AirOpenedValues +{ + type WitnessVariable = AirOpenedValues>; + + fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { + let local = self.local.read(builder); + let next = self.next.read(builder); + Self::WitnessVariable { local, next } + } + + fn write(&self, witness: &mut impl WitnessWriter) { + self.local.write(witness); + self.next.write(witness); + } +} + +impl>> Witnessable + for InnerPcsProof +{ + type WitnessVariable = TwoAdicPcsProofVariable; + + fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { + let fri_proof = self.fri_proof.read(builder); + let query_openings = self.query_openings.read(builder); + Self::WitnessVariable { fri_proof, query_openings } + } + + fn write(&self, witness: &mut impl WitnessWriter) { + self.fri_proof.write(witness); + self.query_openings.write(witness); + } +} + +impl Witnessable for InnerBatchOpening +where + C: CircuitConfig>, +{ + type WitnessVariable = BatchOpeningVariable; + + fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { + let opened_values = self + .opened_values + .read(builder) + .into_iter() + .map(|a| a.into_iter().map(|b| vec![b]).collect()) + .collect(); + let opening_proof = self.opening_proof.read(builder); + Self::WitnessVariable { opened_values, opening_proof } + } + + fn write(&self, witness: &mut impl WitnessWriter) { + self.opened_values.write(witness); + self.opening_proof.write(witness); + } +} + +impl>> Witnessable + for InnerFriProof +{ + type WitnessVariable = FriProofVariable; + + fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { + let commit_phase_commits = self + .commit_phase_commits + .iter() + .map(|commit| { + let commit: &InnerDigest = commit.borrow(); + commit.read(builder) + }) + .collect(); + let query_proofs = self.query_proofs.read(builder); + let final_poly = self.final_poly.read(builder); + let pow_witness = self.pow_witness.read(builder); + Self::WitnessVariable { commit_phase_commits, query_proofs, final_poly, pow_witness } + } + + fn write(&self, witness: &mut impl WitnessWriter) { + self.commit_phase_commits.iter().for_each(|commit| { + let commit = Borrow::::borrow(commit); + commit.write(witness); + }); + self.query_proofs.write(witness); + self.final_poly.write(witness); + self.pow_witness.write(witness); + } +} + +impl>> Witnessable + for QueryProof +{ + type WitnessVariable = FriQueryProofVariable; + + fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { + let commit_phase_openings = self.commit_phase_openings.read(builder); + Self::WitnessVariable { commit_phase_openings } + } + + fn write(&self, witness: &mut impl WitnessWriter) { + self.commit_phase_openings.write(witness); + } +} + +impl>> Witnessable + for CommitPhaseProofStep +{ + type WitnessVariable = FriCommitPhaseProofStepVariable; + + fn read(&self, builder: &mut Builder) -> Self::WitnessVariable { + let sibling_value = self.sibling_value.read(builder); + let opening_proof = self.opening_proof.read(builder); + Self::WitnessVariable { sibling_value, opening_proof } + } + + fn write(&self, witness: &mut impl WitnessWriter) { + self.sibling_value.write(witness); + self.opening_proof.write(witness); + } +}