1- use p3_field:: { Field , PrimeField64 } ;
1+ use p3_field:: { Field , PrimeCharacteristicRing , PrimeField64 } ;
22use p3_symmetric:: Permutation ;
33
44use crate :: {
@@ -7,10 +7,13 @@ use crate::{
77 operand:: MemOrFp ,
88 program:: Program ,
99 } ,
10- constant:: { DIMENSION , F } ,
10+ constant:: {
11+ CODE_SEGMENT , DIMENSION , F , POSEIDON_16_NULL_HASH_PTR , POSEIDON_24_NULL_HASH_PTR ,
12+ PUBLIC_INPUT_START , ZERO_VEC_PTR ,
13+ } ,
1114 context:: run_context:: RunContext ,
1215 errors:: { memory:: MemoryError , vm:: VirtualMachineError } ,
13- memory:: manager:: MemoryManager ,
16+ memory:: { address :: MemoryAddress , manager:: MemoryManager } ,
1417} ;
1518
1619#[ derive( Debug ) ]
@@ -22,7 +25,11 @@ pub struct VirtualMachine<Perm16, Perm24> {
2225 pub ( crate ) program : Program ,
2326}
2427
25- impl < Perm16 , Perm24 > VirtualMachine < Perm16 , Perm24 > {
28+ impl < Perm16 , Perm24 > VirtualMachine < Perm16 , Perm24 >
29+ where
30+ Perm16 : Permutation < [ F ; 2 * DIMENSION ] > ,
31+ Perm24 : Permutation < [ F ; 3 * DIMENSION ] > ,
32+ {
2633 pub fn new ( poseidon2_16 : Perm16 , poseidon2_24 : Perm24 ) -> Self {
2734 Self {
2835 run_context : RunContext :: default ( ) ,
@@ -33,6 +40,97 @@ impl<Perm16, Perm24> VirtualMachine<Perm16, Perm24> {
3340 }
3441 }
3542
43+ /// Initializes the virtual machine with a given program.
44+ ///
45+ /// This function performs all the necessary setup before execution:
46+ ///
47+ /// - Allocates the required memory segments
48+ /// - Loads public and private inputs into stack memory
49+ /// - Fills in convention-based memory slots (e.g., zero vector, null hashes)
50+ /// - Computes and aligns allocation pointers
51+ /// - Sets up the initial execution context (program counter, frame pointer, etc.)
52+ pub fn setup (
53+ & mut self ,
54+ program : Program ,
55+ no_vec_runtime_memory : usize ,
56+ ) -> Result < ( ) , VirtualMachineError > {
57+ // Save the program internally.
58+ self . program = program;
59+
60+ // Extract the public and private inputs from the program.
61+ let public_input = & self . program . public_input ;
62+ let private_input = & self . program . private_input ;
63+
64+ // Allocate required memory segments: PUBLIC, STACK, VEC, CODE.
65+ // We ensure all necessary segments are present.
66+ while self . memory_manager . num_segments ( ) <= CODE_SEGMENT {
67+ self . memory_manager . add ( ) ;
68+ }
69+
70+ // Convention-Based Memory Initialization
71+
72+ // Write [0; DIMENSION] to the vector memory at ZERO_VEC_PTR.
73+ self . memory_manager
74+ . load_data ( ZERO_VEC_PTR , & [ F :: ZERO ; DIMENSION ] ) ?;
75+
76+ // Write Poseidon2([0; 16]) to POSEIDON_16_NULL_HASH_PTR.
77+ let hash16 = self . poseidon2_16 . permute ( [ F :: ZERO ; DIMENSION * 2 ] ) ;
78+ self . memory_manager
79+ . load_data ( POSEIDON_16_NULL_HASH_PTR , & hash16) ?;
80+
81+ // Write the last 8 elements of Poseidon2([0; 24]) to POSEIDON_24_NULL_HASH_PTR.
82+ let hash24 = self . poseidon2_24 . permute ( [ F :: ZERO ; DIMENSION * 3 ] ) ;
83+ self . memory_manager
84+ . load_data ( POSEIDON_24_NULL_HASH_PTR , & hash24[ 16 ..] ) ?;
85+
86+ // Load Public Inputs
87+
88+ // Place public input values starting at PUBLIC_INPUT_START in the public data segment.
89+ self . memory_manager
90+ . load_data ( PUBLIC_INPUT_START , public_input) ?;
91+
92+ // Compute the initial `fp` (frame pointer) just after the public inputs.
93+ let mut fp = ( PUBLIC_INPUT_START + public_input. len ( ) ) ?;
94+ // Align the `fp` offset to the next power of two.
95+ fp. offset = fp. offset . next_power_of_two ( ) ;
96+
97+ // Load Private Inputs
98+
99+ // Write private inputs starting at the aligned `fp`.
100+ self . memory_manager . load_data ( fp, private_input) ?;
101+
102+ // Advance `fp` past the private inputs.
103+ fp. offset += private_input. len ( ) ;
104+ // Ensure `fp` is aligned to `DIMENSION` for vector operations.
105+ fp. offset = fp. offset . next_multiple_of ( DIMENSION ) ;
106+
107+ // Compute Allocation Pointers
108+
109+ // Compute the initial allocation pointer for stack memory.
110+ let initial_ap = ( fp + self . program . bytecode . starting_frame_memory ) ?;
111+
112+ // Compute the vectorized allocation pointer, skipping past the non-vector memory.
113+ let mut initial_ap_vec = ( initial_ap + no_vec_runtime_memory) ?;
114+ // Align the vector allocation to the next multiple of `DIMENSION`.
115+ initial_ap_vec. offset = initial_ap_vec. offset . next_multiple_of ( DIMENSION ) / DIMENSION ;
116+
117+ // Set Initial Registers
118+
119+ // Set the program counter to the start of the code segment.
120+ self . run_context . pc = MemoryAddress :: new ( CODE_SEGMENT , 0 ) ;
121+
122+ // Set the frame pointer to the aligned `fp`.
123+ self . run_context . fp = fp;
124+
125+ // Set the allocation pointer for non-vector memory.
126+ self . run_context . ap = initial_ap;
127+
128+ // Set the allocation pointer for vector memory (in vector units, not field elements).
129+ self . run_context . ap_vectorized = initial_ap_vec;
130+
131+ Ok ( ( ) )
132+ }
133+
36134 /// Advances the program counter (`pc`) to the next instruction.
37135 ///
38136 /// This function embodies the control flow logic of the zkVM. For most instructions,
@@ -147,11 +245,10 @@ impl<Perm16, Perm24> VirtualMachine<Perm16, Perm24> {
147245 /// 2. **Register Update:** If the execution phase completes successfully, this function then
148246 /// calls `update_registers` to advance the program counter (`pc`) and frame pointer (`fp`)
149247 /// to prepare for the next instruction.
150- pub fn run_instruction ( & mut self , instruction : & Instruction ) -> Result < ( ) , VirtualMachineError >
151- where
152- Perm16 : Permutation < [ F ; 2 * DIMENSION ] > ,
153- Perm24 : Permutation < [ F ; 3 * DIMENSION ] > ,
154- {
248+ pub fn run_instruction (
249+ & mut self ,
250+ instruction : & Instruction ,
251+ ) -> Result < ( ) , VirtualMachineError > {
155252 // Execute the instruction.
156253 instruction. execute (
157254 & self . run_context ,
0 commit comments