diff --git a/extensions/native/circuit/src/poseidon2/air.rs b/extensions/native/circuit/src/poseidon2/air.rs index 5f40d41d32..d68ddf15f3 100644 --- a/extensions/native/circuit/src/poseidon2/air.rs +++ b/extensions/native/circuit/src/poseidon2/air.rs @@ -721,6 +721,7 @@ impl Air end_idx, aux_after_start, aux_before_end, + aux_read_enabled, read_data, write_data, data, @@ -802,7 +803,7 @@ impl Air start_timestamp + i_var * AB::F::TWO - start_idx * AB::F::TWO, &read_data[i], ) - .eval(builder, aux_after_start[i] * aux_before_end[i]); + .eval(builder, multi_observe_row * aux_read_enabled[i]); self.memory_bridge .write( @@ -811,21 +812,29 @@ impl Air start_timestamp + i_var * AB::F::TWO - start_idx * AB::F::TWO + AB::F::ONE, &write_data[i], ) - .eval(builder, aux_after_start[i] * aux_before_end[i]); + .eval(builder, multi_observe_row * aux_read_enabled[i]); } for i in 0..(CHUNK - 1) { builder + .when(multi_observe_row) .when(aux_after_start[i]) .assert_one(aux_after_start[i + 1]); } for i in 1..CHUNK { builder + .when(multi_observe_row) .when(aux_before_end[i]) .assert_one(aux_before_end[i - 1]); } + for i in 0..CHUNK { + builder + .when(multi_observe_row) + .assert_eq(aux_after_start[i] * aux_before_end[i], aux_read_enabled[i]); + } + builder .when(multi_observe_row) .when(not(is_first)) diff --git a/extensions/native/circuit/src/poseidon2/chip.rs b/extensions/native/circuit/src/poseidon2/chip.rs index 05b73bd8c4..a5a1d0d7d4 100644 --- a/extensions/native/circuit/src/poseidon2/chip.rs +++ b/extensions/native/circuit/src/poseidon2/chip.rs @@ -781,6 +781,7 @@ where input_ptr_u32 + input_idx as u32, multi_observe_cols.read_data[j].as_mut(), ); + multi_observe_cols.aux_read_enabled[j] = F::ONE; tracing_write_native_inplace( state.memory, state_ptr_u32 + j as u32, diff --git a/extensions/native/circuit/src/poseidon2/columns.rs b/extensions/native/circuit/src/poseidon2/columns.rs index df2ad6eef3..f710efc370 100644 --- a/extensions/native/circuit/src/poseidon2/columns.rs +++ b/extensions/native/circuit/src/poseidon2/columns.rs @@ -229,6 +229,7 @@ pub struct MultiObserveCols { pub end_idx: T, pub aux_after_start: [T; CHUNK], pub aux_before_end: [T; CHUNK], + pub aux_read_enabled: [T; CHUNK], // Transcript observation pub read_data: [MemoryReadAuxCols; CHUNK], diff --git a/extensions/native/recursion/tests/recursion.rs b/extensions/native/recursion/tests/recursion.rs index a147d161f0..4e3bba92e7 100644 --- a/extensions/native/recursion/tests/recursion.rs +++ b/extensions/native/recursion/tests/recursion.rs @@ -16,7 +16,8 @@ use openvm_native_compiler::{ prelude::Usize, }; use openvm_native_recursion::{ - challenger::duplex::DuplexChallengerVariable, testing_utils::inner::run_recursive_test, + challenger::{duplex::DuplexChallengerVariable, CanObserveVariable}, + testing_utils::inner::run_recursive_test, }; use openvm_stark_backend::{ config::{Domain, StarkGenericConfig, Val}, @@ -218,7 +219,14 @@ fn build_test_program(builder: &mut Builder) { let sample_lens: Vec = vec![10, 2, 1, 3, 20]; let mut rng = create_seeded_rng(); - let challenger = DuplexChallengerVariable::new(builder); + let mut challenger = DuplexChallengerVariable::new(builder); + + // Observe a setup label + let label_f: Vec = vec![128, 3098, 192, 394, 1662, 928, 374, 281, 598, 182, 475, 729]; + for n in label_f { + let f: Felt = builder.constant(C::F::from_canonical_u64(n)); + challenger.observe(builder, f); + } for l in sample_lens { let sample_input: Array> = builder.dyn_array(l);