@@ -94,6 +94,7 @@ impl<AB: InteractionBuilder, const SBOX_REGISTERS: usize> Air<AB>
9494 inside_row,
9595 simple,
9696 multi_observe_row,
97+ not_hint_multi_observe,
9798 end_inside_row,
9899 end_top_level,
99100 start_top_level,
@@ -723,6 +724,7 @@ impl<AB: InteractionBuilder, const SBOX_REGISTERS: usize> Air<AB>
723724 hint_id,
724725 ctx,
725726 read_ctx,
727+ chunk_ts_count,
726728 is_first,
727729 is_last,
728730 curr_len,
@@ -748,6 +750,16 @@ impl<AB: InteractionBuilder, const SBOX_REGISTERS: usize> Air<AB>
748750 builder. when ( multi_observe_row) . assert_bool ( is_last) ;
749751 builder. when ( multi_observe_row) . assert_bool ( should_permute) ;
750752 builder. when ( multi_observe_row) . assert_bool ( is_hint) ;
753+ builder. assert_eq (
754+ not_hint_multi_observe,
755+ multi_observe_row * ( AB :: Expr :: ONE - is_hint) ,
756+ ) ;
757+ let hint_multi_observe: AB :: Expr = multi_observe_row - not_hint_multi_observe;
758+ // chunk_ts_count = (end_idx - start_idx) * (2 - is_hint)
759+ builder. when ( multi_observe_row) . assert_eq (
760+ chunk_ts_count,
761+ ( end_idx - start_idx) * AB :: F :: TWO - ( end_idx - start_idx) * is_hint,
762+ ) ;
751763
752764 self . execution_bridge
753765 . execute_and_increment_pc (
@@ -813,49 +825,48 @@ impl<AB: InteractionBuilder, const SBOX_REGISTERS: usize> Air<AB>
813825 )
814826 . eval ( builder, multi_observe_row * is_first) ;
815827
816- // ts_per_element = 2 - is_hint (non-hint: read+write=2, hint: write-only=1)
817- let is_hint_expr: AB :: Expr = is_hint. into ( ) ;
818- let ts_per_element: AB :: Expr = AB :: Expr :: TWO - is_hint_expr. clone ( ) ;
828+ // Per-element constraints for chunk rows.
819829 for i in 0 ..CHUNK {
820- let i_var: AB :: Expr = AB :: F :: from_canonical_usize ( i) . into ( ) ;
821- let start_idx_expr: AB :: Expr = start_idx. into ( ) ;
822- let element_start_ts: AB :: Expr =
823- start_timestamp. into ( ) + ( i_var. clone ( ) - start_idx_expr. clone ( ) ) * ts_per_element. clone ( ) ;
830+ let i_var = AB :: F :: from_canonical_usize ( i) ;
831+
832+ // Hint mode: lookup from hint space.
833+ self . hint_bridge . lookup (
834+ builder,
835+ hint_id,
836+ curr_len + i_var - start_idx,
837+ data[ i] ,
838+ hint_multi_observe. clone ( ) * aux_read_enabled[ i] ,
839+ ) ;
824840
825- // Non-hint mode: read from memory
841+ // Non-hint mode: read from memory.
826842 self . memory_bridge
827843 . read (
828844 MemoryAddress :: new (
829845 self . address_space ,
830- input_ptr + curr_len + i_var. clone ( ) - start_idx_expr . clone ( ) ,
846+ input_ptr + curr_len + i_var - start_idx ,
831847 ) ,
832848 [ data[ i] ] ,
833- element_start_ts . clone ( ) ,
849+ start_timestamp + i_var * AB :: F :: TWO - start_idx * AB :: F :: TWO ,
834850 & read_data[ i] ,
835851 )
836- . eval (
837- builder,
838- multi_observe_row * aux_read_enabled[ i] * ( AB :: Expr :: ONE - is_hint_expr. clone ( ) ) ,
839- ) ;
840-
841- // Hint mode: lookup from hint space
842- self . hint_bridge . lookup (
843- builder,
844- hint_id,
845- curr_len + i_var. clone ( ) - start_idx_expr. clone ( ) ,
846- data[ i] ,
847- multi_observe_row * aux_read_enabled[ i] * is_hint_expr. clone ( ) ,
848- ) ;
852+ . eval ( builder, not_hint_multi_observe * aux_read_enabled[ i] ) ;
853+ self . memory_bridge
854+ . write (
855+ MemoryAddress :: new ( self . address_space , state_ptr + i_var) ,
856+ [ data[ i] ] ,
857+ start_timestamp + i_var * AB :: F :: TWO - start_idx * AB :: F :: TWO + AB :: F :: ONE ,
858+ & write_data[ i] ,
859+ )
860+ . eval ( builder, not_hint_multi_observe * aux_read_enabled[ i] ) ;
849861
850- // Write to sponge state (always, for both modes)
851862 self . memory_bridge
852863 . write (
853864 MemoryAddress :: new ( self . address_space , state_ptr + i_var) ,
854865 [ data[ i] ] ,
855- element_start_ts + ( AB :: Expr :: ONE - is_hint_expr . clone ( ) ) ,
866+ start_timestamp + i_var - start_idx ,
856867 & write_data[ i] ,
857868 )
858- . eval ( builder, multi_observe_row * aux_read_enabled[ i] ) ;
869+ . eval ( builder, hint_multi_observe . clone ( ) * aux_read_enabled[ i] ) ;
859870 }
860871
861872 for i in 0 ..( CHUNK - 1 ) {
@@ -926,7 +937,7 @@ impl<AB: InteractionBuilder, const SBOX_REGISTERS: usize> Air<AB>
926937 . write (
927938 MemoryAddress :: new ( self . address_space , state_ptr) ,
928939 full_sponge_output,
929- start_timestamp + ( end_idx - start_idx ) * ( AB :: Expr :: TWO - is_hint_expr . clone ( ) ) ,
940+ start_timestamp + chunk_ts_count ,
930941 & write_sponge_state,
931942 )
932943 . eval ( builder, multi_observe_row * should_permute) ;
@@ -955,7 +966,7 @@ impl<AB: InteractionBuilder, const SBOX_REGISTERS: usize> Air<AB>
955966 . write (
956967 MemoryAddress :: new ( self . address_space , ctx_ptr) ,
957968 [ final_idx] ,
958- start_timestamp + ( end_idx - start_idx ) * ( AB :: Expr :: TWO - is_hint_expr ) + should_permute,
969+ start_timestamp + chunk_ts_count + should_permute,
959970 & write_final_idx,
960971 )
961972 . eval ( builder, multi_observe_row * is_last) ;
0 commit comments