Skip to content

Commit e4da12f

Browse files
committed
rebase hint multi observe
1 parent 4a49ffe commit e4da12f

12 files changed

Lines changed: 326 additions & 126 deletions

File tree

extensions/native/circuit/cuda/src/poseidon2.cu

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -355,31 +355,52 @@ template <size_t SBOX_REGISTERS> struct Poseidon2Wrapper {
355355
if (specific[COL_INDEX(MultiObserveCols, is_first)] == Fp::one()) {
356356
uint32_t very_start_timestamp =
357357
row[COL_INDEX(Cols, very_first_timestamp)].asUInt32();
358-
for (uint32_t i = 0; i < 4; ++i) {
358+
// 3 register reads at timestamps +0, +1, +2
359+
for (uint32_t i = 0; i < 3; ++i) {
359360
mem_fill_base(
360361
mem_helper,
361362
very_start_timestamp + i,
362363
specific.slice_from(COL_INDEX(MultiObserveCols, read_data[i].base))
363364
);
364365
}
366+
// 1 context array read at timestamp +3
367+
mem_fill_base(
368+
mem_helper,
369+
very_start_timestamp + 3,
370+
specific.slice_from(COL_INDEX(MultiObserveCols, read_ctx.base))
371+
);
372+
// 1 hint_id register read at timestamp +4 (reuse spare read_data[3] on head row)
373+
mem_fill_base(
374+
mem_helper,
375+
very_start_timestamp + 4,
376+
specific.slice_from(COL_INDEX(MultiObserveCols, read_data[3].base))
377+
);
365378
} else {
366379
uint32_t start_timestamp = row[COL_INDEX(Cols, start_timestamp)].asUInt32();
367380
uint32_t chunk_start =
368381
specific[COL_INDEX(MultiObserveCols, start_idx)].asUInt32();
369382
uint32_t chunk_end =
370383
specific[COL_INDEX(MultiObserveCols, end_idx)].asUInt32();
384+
// is_hint = ctx[2]
385+
uint32_t is_hint =
386+
specific[COL_INDEX(MultiObserveCols, ctx[2])].asUInt32();
387+
uint32_t ts_per_element = 2 - is_hint;
371388
for (uint32_t j = chunk_start; j < chunk_end; ++j) {
389+
if (!is_hint) {
390+
// Non-hint mode: fill read_data aux
391+
mem_fill_base(
392+
mem_helper,
393+
start_timestamp,
394+
specific.slice_from(COL_INDEX(MultiObserveCols, read_data[j].base))
395+
);
396+
}
397+
// Write timestamp: start_timestamp + (1 - is_hint) for non-hint, start_timestamp for hint
372398
mem_fill_base(
373399
mem_helper,
374-
start_timestamp,
375-
specific.slice_from(COL_INDEX(MultiObserveCols, read_data[j].base))
376-
);
377-
mem_fill_base(
378-
mem_helper,
379-
start_timestamp + 1,
400+
start_timestamp + (1 - is_hint),
380401
specific.slice_from(COL_INDEX(MultiObserveCols, write_data[j].base))
381402
);
382-
start_timestamp += 2;
403+
start_timestamp += ts_per_element;
383404
}
384405
if (chunk_end >= CHUNK) {
385406
mem_fill_base(

extensions/native/circuit/src/extension/mod.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -366,11 +366,6 @@ where
366366
inventory.add_executor_chip(fri_reduced_opening);
367367

368368
inventory.next_air::<NativePoseidon2Air<Val<SC>, 1>>()?;
369-
let poseidon2 = NativePoseidon2Chip::<_, 1>::new(
370-
NativePoseidon2Filler::new(Poseidon2Config::default()),
371-
mem_helper.clone(),
372-
);
373-
inventory.add_executor_chip(poseidon2);
374369

375370
let hint_bus = inventory.airs().system().hint_bridge.hint_bus();
376371
let hint_space_provider = Arc::new(HintSpaceProviderChip::new(
@@ -379,6 +374,12 @@ where
379374
timestamp_max_bits,
380375
));
381376

377+
let poseidon2 = NativePoseidon2Chip::<_, 1>::new(
378+
NativePoseidon2Filler::new(Poseidon2Config::default(), hint_space_provider.clone()),
379+
mem_helper.clone(),
380+
);
381+
inventory.add_executor_chip(poseidon2);
382+
382383
inventory.next_air::<HintSpaceProviderAir>()?;
383384
inventory.add_periphery_chip(hint_space_provider.clone());
384385

extensions/native/circuit/src/poseidon2/air.rs

Lines changed: 93 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -713,10 +713,16 @@ impl<AB: InteractionBuilder, const SBOX_REGISTERS: usize> Air<AB>
713713
let &MultiObserveCols {
714714
pc,
715715
final_timestamp_increment,
716+
state_ptr_register,
717+
ctx_register,
718+
input_ptr_register,
719+
hint_id_register,
716720
state_ptr,
721+
ctx_ptr,
717722
input_ptr,
718-
init_pos,
719-
len,
723+
hint_id,
724+
ctx,
725+
read_ctx,
720726
is_first,
721727
is_last,
722728
curr_len,
@@ -731,35 +737,38 @@ impl<AB: InteractionBuilder, const SBOX_REGISTERS: usize> Air<AB>
731737
should_permute,
732738
write_sponge_state,
733739
write_final_idx,
734-
input_register_1,
735-
input_register_2,
736-
input_register_3,
737-
output_register,
738740
} = multi_observe_specific;
739741

742+
// Alias context values
743+
let init_pos = ctx[0];
744+
let len = ctx[1];
745+
let is_hint = ctx[2];
746+
740747
builder.when(multi_observe_row).assert_bool(is_first);
741748
builder.when(multi_observe_row).assert_bool(is_last);
742749
builder.when(multi_observe_row).assert_bool(should_permute);
750+
builder.when(multi_observe_row).assert_bool(is_hint);
743751

744752
self.execution_bridge
745753
.execute_and_increment_pc(
746754
AB::F::from_canonical_usize(MULTI_OBSERVE.global_opcode().as_usize()),
747755
[
748-
output_register.into(),
749-
input_register_1.into(),
750-
input_register_2.into(),
756+
state_ptr_register.into(),
757+
ctx_register.into(),
758+
input_ptr_register.into(),
751759
self.address_space.into(),
752760
self.address_space.into(),
753-
input_register_3.into(),
761+
hint_id_register.into(),
754762
],
755763
ExecutionState::new(pc, very_first_timestamp),
756764
final_timestamp_increment,
757765
)
758766
.eval(builder, multi_observe_row * is_first);
759767

768+
// Head row: 3 register reads + 1 context array read + 1 hint_id register read
760769
self.memory_bridge
761770
.read(
762-
MemoryAddress::new(self.address_space, output_register),
771+
MemoryAddress::new(self.address_space, state_ptr_register),
763772
[state_ptr],
764773
very_first_timestamp,
765774
&read_data[0],
@@ -768,50 +777,82 @@ impl<AB: InteractionBuilder, const SBOX_REGISTERS: usize> Air<AB>
768777

769778
self.memory_bridge
770779
.read(
771-
MemoryAddress::new(self.address_space, input_register_1),
772-
[init_pos],
780+
MemoryAddress::new(self.address_space, ctx_register),
781+
[ctx_ptr],
773782
very_first_timestamp + AB::F::ONE,
774783
&read_data[1],
775784
)
776785
.eval(builder, multi_observe_row * is_first);
777786

778787
self.memory_bridge
779788
.read(
780-
MemoryAddress::new(self.address_space, input_register_2),
789+
MemoryAddress::new(self.address_space, input_ptr_register),
781790
[input_ptr],
782791
very_first_timestamp + AB::F::TWO,
783792
&read_data[2],
784793
)
785794
.eval(builder, multi_observe_row * is_first);
786795

796+
// Read context array: [init_pos, len, is_hint, reserved] from ctx_ptr
787797
self.memory_bridge
788798
.read(
789-
MemoryAddress::new(self.address_space, input_register_3),
790-
[len],
799+
MemoryAddress::new(self.address_space, ctx_ptr),
800+
ctx,
791801
very_first_timestamp + AB::F::from_canonical_usize(3),
802+
&read_ctx,
803+
)
804+
.eval(builder, multi_observe_row * is_first);
805+
806+
// Read hint_id from register (reuse spare read_data[3] on head row)
807+
self.memory_bridge
808+
.read(
809+
MemoryAddress::new(self.address_space, hint_id_register),
810+
[hint_id],
811+
very_first_timestamp + AB::F::from_canonical_usize(4),
792812
&read_data[3],
793813
)
794814
.eval(builder, multi_observe_row * is_first);
795815

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();
796819
for i in 0..CHUNK {
797-
let i_var = AB::F::from_canonical_usize(i);
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();
824+
825+
// Non-hint mode: read from memory
798826
self.memory_bridge
799827
.read(
800828
MemoryAddress::new(
801829
self.address_space,
802-
input_ptr + curr_len + i_var - start_idx,
830+
input_ptr + curr_len + i_var.clone() - start_idx_expr.clone(),
803831
),
804832
[data[i]],
805-
start_timestamp + i_var * AB::F::TWO - start_idx * AB::F::TWO,
833+
element_start_ts.clone(),
806834
&read_data[i],
807835
)
808-
.eval(builder, multi_observe_row * aux_read_enabled[i]);
836+
.eval(
837+
builder,
838+
multi_observe_row * aux_read_enabled[i] * (AB::Expr::ONE - is_hint_expr.clone()),
839+
);
809840

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+
);
849+
850+
// Write to sponge state (always, for both modes)
810851
self.memory_bridge
811852
.write(
812853
MemoryAddress::new(self.address_space, state_ptr + i_var),
813854
[data[i]],
814-
start_timestamp + i_var * AB::F::TWO - start_idx * AB::F::TWO + AB::F::ONE,
855+
element_start_ts + (AB::Expr::ONE - is_hint_expr.clone()),
815856
&write_data[i],
816857
)
817858
.eval(builder, multi_observe_row * aux_read_enabled[i]);
@@ -885,7 +926,7 @@ impl<AB: InteractionBuilder, const SBOX_REGISTERS: usize> Air<AB>
885926
.write(
886927
MemoryAddress::new(self.address_space, state_ptr),
887928
full_sponge_output,
888-
start_timestamp + (end_idx - start_idx) * AB::F::TWO,
929+
start_timestamp + (end_idx - start_idx) * (AB::Expr::TWO - is_hint_expr.clone()),
889930
&write_sponge_state,
890931
)
891932
.eval(builder, multi_observe_row * should_permute);
@@ -909,11 +950,12 @@ impl<AB: InteractionBuilder, const SBOX_REGISTERS: usize> Air<AB>
909950
// final_idx = aux_read_enabled[CHUNK-1] * 0 + (1 - aux_read_enabled[CHUNK-1]) * end_idx
910951
let final_idx = aux_read_enabled[CHUNK - 1] * AB::Expr::ZERO
911952
+ (AB::Expr::ONE - aux_read_enabled[CHUNK - 1]) * end_idx;
953+
// Write final_idx back to ctx[0] (ctx_ptr address)
912954
self.memory_bridge
913955
.write(
914-
MemoryAddress::new(self.address_space, input_register_1),
956+
MemoryAddress::new(self.address_space, ctx_ptr),
915957
[final_idx],
916-
start_timestamp + (end_idx - start_idx) * AB::F::TWO + should_permute,
958+
start_timestamp + (end_idx - start_idx) * (AB::Expr::TWO - is_hint_expr) + should_permute,
917959
&write_final_idx,
918960
)
919961
.eval(builder, multi_observe_row * is_last);
@@ -962,41 +1004,59 @@ impl<AB: InteractionBuilder, const SBOX_REGISTERS: usize> Air<AB>
9621004
builder
9631005
.when(next.multi_observe_row)
9641006
.when(not(next_multi_observe_specific.is_first))
965-
.assert_eq(init_pos, next_multi_observe_specific.init_pos);
1007+
.assert_eq(init_pos, next_multi_observe_specific.ctx[0]);
9661008

9671009
builder
9681010
.when(next.multi_observe_row)
9691011
.when(not(next_multi_observe_specific.is_first))
970-
.assert_eq(len, next_multi_observe_specific.len);
1012+
.assert_eq(len, next_multi_observe_specific.ctx[1]);
1013+
1014+
builder
1015+
.when(next.multi_observe_row)
1016+
.when(not(next_multi_observe_specific.is_first))
1017+
.assert_eq(
1018+
state_ptr_register,
1019+
next_multi_observe_specific.state_ptr_register,
1020+
);
9711021

9721022
builder
9731023
.when(next.multi_observe_row)
9741024
.when(not(next_multi_observe_specific.is_first))
9751025
.assert_eq(
976-
input_register_1,
977-
next_multi_observe_specific.input_register_1,
1026+
ctx_register,
1027+
next_multi_observe_specific.ctx_register,
9781028
);
9791029

9801030
builder
9811031
.when(next.multi_observe_row)
9821032
.when(not(next_multi_observe_specific.is_first))
9831033
.assert_eq(
984-
input_register_2,
985-
next_multi_observe_specific.input_register_2,
1034+
input_ptr_register,
1035+
next_multi_observe_specific.input_ptr_register,
9861036
);
9871037

1038+
builder
1039+
.when(next.multi_observe_row)
1040+
.when(not(next_multi_observe_specific.is_first))
1041+
.assert_eq(ctx_ptr, next_multi_observe_specific.ctx_ptr);
1042+
1043+
builder
1044+
.when(next.multi_observe_row)
1045+
.when(not(next_multi_observe_specific.is_first))
1046+
.assert_eq(hint_id, next_multi_observe_specific.hint_id);
1047+
9881048
builder
9891049
.when(next.multi_observe_row)
9901050
.when(not(next_multi_observe_specific.is_first))
9911051
.assert_eq(
992-
input_register_3,
993-
next_multi_observe_specific.input_register_3,
1052+
hint_id_register,
1053+
next_multi_observe_specific.hint_id_register,
9941054
);
9951055

9961056
builder
9971057
.when(next.multi_observe_row)
9981058
.when(not(next_multi_observe_specific.is_first))
999-
.assert_eq(output_register, next_multi_observe_specific.output_register);
1059+
.assert_eq(is_hint, next_multi_observe_specific.ctx[2]);
10001060

10011061
// Timestamp constraints
10021062
builder

0 commit comments

Comments
 (0)