VM Execution
VM execution takes a DPNFunctionCircuitDefinition and generates witness data for zero-knowledge proof construction.
SimpleDPNExecutor
The executor maintains type-specific storage arrays:
#![allow(unused)] fn main() { pub struct SimpleDPNExecutor<F: RichField> { pub targets: Vec<F>, // Field elements pub target_arrays: Vec<Vec<F>>, pub hashes: Vec<[F; 4]>, pub bools: Vec<bool>, pub bool_arrays: Vec<Vec<bool>>, pub u32s: Vec<u32>, pub u32_arrays: Vec<Vec<u32>>, pub user_id: F, pub contract_id: F, pub caller_contract_id: F, pub checkpoint_id: F, pub user_public_key: [F; 4], pub nonce: F, pub inputs: Vec<F>, } }
Input
- DPNFunctionCircuitDefinition: Compiled bytecode with operations and state commands
- Function Parameters: Concrete values for function inputs
- Blockchain Context: User ID, contract ID, block height, nonce
- External State: Storage values from blockchain state tree
Execution Process
- Initialize executor with function inputs and blockchain context
- Process each
DPNIndexedVarDefoperation in sequence - Resolve input references to concrete values from storage arrays
- Execute operation and store result in appropriate type array
- Generate complete witness for proof construction
Output
- Witness Arrays: Computed values in type-specific storage (targets, bools, u32s, etc.)
- State Command Witness: Results from blockchain state operations
- Execution Context: Final blockchain state after execution
- State Changes: Modified storage slots and new values
- Events: Emitted contract events with parameters
Key Functions
#![allow(unused)] fn main() { pub fn resolve_target(&self, id: u64) -> F { let (data_type, index) = decode_indexed_op_id(id); match data_type { DPNBuiltInDataType::Target => self.targets[index], DPNBuiltInDataType::Bool => if self.bools[index] { F::ONE } else { F::ZERO }, DPNBuiltInDataType::U32Target => F::from_canonical_u32(self.u32s[index]), _ => panic!("Invalid data type"), } } pub fn process_var_def(&mut self, op: &DPNIndexedVarDef) { match op.op_type { DPNOpType::Add => { let left = self.resolve_target(op.inputs[0]); let right = self.resolve_target(op.inputs[1]); self.targets.push(left + right); }, DPNOpType::Constant => { self.targets.push(F::from_canonical_u64(op.inputs[0])); }, // ... other operations } } }
Output
Execution produces witness data containing computed values in type-specific arrays, which are used for zero-knowledge proof generation.