From 6f88cbae96e44ea41ebada60838076fcee496fd2 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Thu, 30 Jan 2025 10:15:22 +0100 Subject: [PATCH 1/3] Arrabbiata: implement absorb_state --- arrabbiata/src/main.rs | 4 ++-- arrabbiata/src/witness.rs | 30 +++++++++++++++++++++++++++++- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/arrabbiata/src/main.rs b/arrabbiata/src/main.rs index b2d8e2f4a4..5e2cbea153 100644 --- a/arrabbiata/src/main.rs +++ b/arrabbiata/src/main.rs @@ -107,8 +107,8 @@ pub fn main() { // verify and accumulate it at the next iteration. env.commit_state(); - // FIXME: - // Absorb all commitments in the sponge. + // Absorb the last program state. + env.absorb_state(); // FIXME: // Coin chalenges β and γ for the permutation argument diff --git a/arrabbiata/src/witness.rs b/arrabbiata/src/witness.rs index f1d47328e4..34ab1545c2 100644 --- a/arrabbiata/src/witness.rs +++ b/arrabbiata/src/witness.rs @@ -1,3 +1,4 @@ +use ark_ec::CurveConfig; use ark_ff::PrimeField; use ark_poly::Evaluations; use kimchi::circuits::{domains::EvaluationDomains, gate::CurrOrNext}; @@ -6,7 +7,7 @@ use mina_poseidon::constants::SpongeConstants; use num_bigint::{BigInt, BigUint}; use num_integer::Integer; use o1_utils::field_helpers::FieldHelpers; -use poly_commitment::{ipa::SRS, PolyComm, SRS as _}; +use poly_commitment::{commitment::CommitmentCurve, ipa::SRS, PolyComm, SRS as _}; use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; use std::time::Instant; @@ -782,6 +783,8 @@ impl< where E1::BaseField: PrimeField, E2::BaseField: PrimeField, + <::Params as CurveConfig>::BaseField: PrimeField, + <::Params as CurveConfig>::BaseField: PrimeField, { pub fn new( srs_log2_size: usize, @@ -985,6 +988,31 @@ where } } + /// Absorb the last committed program state in the correct sponge. + /// + /// For a description of the messages to be given to the sponge, including + /// the expected instantiation, refer to the section "Message Passing" in + /// [crate::interpreter]. + pub fn absorb_state(&mut self) { + if self.current_iteration % 2 == 0 { + let mut sponge = E1::create_new_sponge(); + let previous_state: E1::BaseField = + E1::BaseField::from_biguint(&self.last_digest.to_biguint().unwrap()).unwrap(); + E1::absorb_fq(&mut sponge, previous_state); + self.previous_committed_state_e1 + .iter() + .for_each(|comm| E1::absorb_curve_points(&mut sponge, &comm.chunks)) + } else { + let mut sponge = E2::create_new_sponge(); + let previous_state: E2::BaseField = + E2::BaseField::from_biguint(&self.last_digest.to_biguint().unwrap()).unwrap(); + E2::absorb_fq(&mut sponge, previous_state); + self.previous_committed_state_e2 + .iter() + .for_each(|comm| E2::absorb_curve_points(&mut sponge, &comm.chunks)) + }; + } + /// Compute the output of the application on the previous output // TODO: we should compute the hash of the previous commitments, only on // CPU? From 907ffc62c908684583f7622752c9783f698ee751 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Thu, 30 Jan 2025 15:56:05 +0100 Subject: [PATCH 2/3] Arrabbiata: introduce two kind of "last digest". The verifier will need to recompute the challenges, and for this, we need to keep track of the digest of the program state before we committed at the previous iteration. For the current iteration, we keep track also of the digest of the program state we have to start from. --- arrabbiata/src/witness.rs | 42 +++++++++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/arrabbiata/src/witness.rs b/arrabbiata/src/witness.rs index 34ab1545c2..db3ae17f4f 100644 --- a/arrabbiata/src/witness.rs +++ b/arrabbiata/src/witness.rs @@ -143,11 +143,20 @@ pub struct Env< /// The current iteration of the IVC pub current_iteration: u64, - /// The digest of the last program state, including the cross-terms - /// commitments. - /// The value is a 128 bits value, to be absorbed to initialize the sponge - /// state for both curves. - pub last_digest: BigInt, + /// The digest of the program state before executing the last iteration. + /// The value will be used to initialize the execution trace of the verifier + /// in the next iteration, in particular to verify that the challenges have + /// been generated correctly. + /// + /// The value is a 128bits value. + pub last_program_digest_before_execution: BigInt, + + /// The digest of the program state after executing the last iteration. + /// The value will be used to initialize the sponge before committing to the + /// next iteration. + /// + /// The value is a 128bits value. + pub last_program_digest_after_execution: BigInt, /// The coin folding combiner will be used to generate the combinaison of /// folding instances @@ -896,7 +905,10 @@ where sponge_e1, sponge_e2, current_iteration: 0, - last_digest: BigInt::from(0_u64), + // FIXME: set a correct value + last_program_digest_before_execution: BigInt::from(0_u64), + // FIXME: set a correct value + last_program_digest_after_execution: BigInt::from(0_u64), r: BigInt::from(0_usize), // Initialize the temporary accumulators with 0 temporary_accumulators: ( @@ -996,16 +1008,26 @@ where pub fn absorb_state(&mut self) { if self.current_iteration % 2 == 0 { let mut sponge = E1::create_new_sponge(); - let previous_state: E1::BaseField = - E1::BaseField::from_biguint(&self.last_digest.to_biguint().unwrap()).unwrap(); + let previous_state: E1::BaseField = E1::BaseField::from_biguint( + &self + .last_program_digest_after_execution + .to_biguint() + .unwrap(), + ) + .unwrap(); E1::absorb_fq(&mut sponge, previous_state); self.previous_committed_state_e1 .iter() .for_each(|comm| E1::absorb_curve_points(&mut sponge, &comm.chunks)) } else { let mut sponge = E2::create_new_sponge(); - let previous_state: E2::BaseField = - E2::BaseField::from_biguint(&self.last_digest.to_biguint().unwrap()).unwrap(); + let previous_state: E2::BaseField = E2::BaseField::from_biguint( + &self + .last_program_digest_after_execution + .to_biguint() + .unwrap(), + ) + .unwrap(); E2::absorb_fq(&mut sponge, previous_state); self.previous_committed_state_e2 .iter() From 3b47ed2b45397c97f4638e08a686ffe05b0f1160 Mon Sep 17 00:00:00 2001 From: Danny Willems Date: Thu, 30 Jan 2025 16:23:08 +0100 Subject: [PATCH 3/3] Arrabbiata: introduce the concept of verifier/prover sponge state This will replace `sponge_e1` and `sponge_e2`. --- arrabbiata/src/witness.rs | 42 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/arrabbiata/src/witness.rs b/arrabbiata/src/witness.rs index db3ae17f4f..88b45b993d 100644 --- a/arrabbiata/src/witness.rs +++ b/arrabbiata/src/witness.rs @@ -140,6 +140,21 @@ pub struct Env< pub sponge_e1: [BigInt; PlonkSpongeConstants::SPONGE_WIDTH], pub sponge_e2: [BigInt; PlonkSpongeConstants::SPONGE_WIDTH], + /// Sponge state used by the prover for the current iteration. + /// + /// This sponge is used at the current iteration to absorb commitments of + /// the program state and generate the challenges for the current iteration. + /// The outputs of the sponge will be verified by the verifier of the next + /// iteration. + pub prover_sponge_state: [BigInt; PlonkSpongeConstants::SPONGE_WIDTH], + + /// Sponge state used by the verifier for the current iteration. + /// + /// This sponge is used at the current iteration to build the verifier + /// circuit. The state will need to match with the previous prover sopnge + /// state. + pub verifier_sponge_state: [BigInt; PlonkSpongeConstants::SPONGE_WIDTH], + /// The current iteration of the IVC pub current_iteration: u64, @@ -876,6 +891,10 @@ where // FIXME: challenges let challenges: Vec = vec![]; + let prover_sponge_state: [BigInt; PlonkSpongeConstants::SPONGE_WIDTH] = + std::array::from_fn(|_| BigInt::from(0_u64)); + let verifier_sponge_state: [BigInt; PlonkSpongeConstants::SPONGE_WIDTH] = + std::array::from_fn(|_| BigInt::from(0_u64)); Self { // ------- // Setup @@ -904,6 +923,8 @@ where current_instruction: IVC_STARTING_INSTRUCTION, sponge_e1, sponge_e2, + prover_sponge_state, + verifier_sponge_state, current_iteration: 0, // FIXME: set a correct value last_program_digest_before_execution: BigInt::from(0_u64), @@ -1018,7 +1039,14 @@ where E1::absorb_fq(&mut sponge, previous_state); self.previous_committed_state_e1 .iter() - .for_each(|comm| E1::absorb_curve_points(&mut sponge, &comm.chunks)) + .for_each(|comm| E1::absorb_curve_points(&mut sponge, &comm.chunks)); + let state: Vec = sponge + .sponge + .state + .iter() + .map(|x| x.to_biguint().into()) + .collect(); + self.prover_sponge_state = state.try_into().unwrap() } else { let mut sponge = E2::create_new_sponge(); let previous_state: E2::BaseField = E2::BaseField::from_biguint( @@ -1031,8 +1059,16 @@ where E2::absorb_fq(&mut sponge, previous_state); self.previous_committed_state_e2 .iter() - .for_each(|comm| E2::absorb_curve_points(&mut sponge, &comm.chunks)) - }; + .for_each(|comm| E2::absorb_curve_points(&mut sponge, &comm.chunks)); + + let state: Vec = sponge + .sponge + .state + .iter() + .map(|x| x.to_biguint().into()) + .collect(); + self.prover_sponge_state = state.try_into().unwrap() + } } /// Compute the output of the application on the previous output