diff --git a/assembler/src/test_data_generator.rs b/assembler/src/test_data_generator.rs index c4ac64b6..84dc655d 100644 --- a/assembler/src/test_data_generator.rs +++ b/assembler/src/test_data_generator.rs @@ -196,6 +196,12 @@ mod tests { fn generate_ptr_call() { generate_from_file("ptr_call.json".to_string(), "ptr_call.json".to_string()); } + + #[test] + fn generate_global() { + generate_from_file("global.json".to_string(), "global.json".to_string()); + } + fn generate_from_file(input_file_name: String, output_file_name: String) { let _ = fs::create_dir_all("test_data/bin/sccall"); let input_path = format!("test_data/asm/{}", input_file_name); diff --git a/assembler/test_data/asm/global.json b/assembler/test_data/asm/global.json new file mode 100644 index 00000000..b7e01cc2 --- /dev/null +++ b/assembler/test_data/asm/global.json @@ -0,0 +1,57 @@ +{ + "program": "heap_malloc:\n.LBL14_0:\n add r9 r9 1\n mstore [r9,-1] r1\n mload r1 [r9,-1]\n mov r3 18446744060824649731\n mload r0 [r3]\n add r2 r0 r1\n mov r1 18446744060824649731\n mstore [r1] r2\n add r9 r9 -1\n ret\nvector_new:\n.LBL15_0:\n add r9 r9 1\n mstore [r9,-1] r1\n mload r1 [r9,-1]\n mov r4 18446744060824649731\n mload r0 [r4]\n add r2 r1 1\n add r3 r0 r2\n mov r2 18446744060824649731\n mstore [r2] r3\n mstore [r0] r1\n add r9 r9 -1\n ret\nmemcpy:\n.LBL16_0:\n add r9 r9 4\n mstore [r9,-4] r1\n mload r1 [r9,-4]\n mstore [r9,-3] r2\n mload r2 [r9,-3]\n mstore [r9,-2] r3\n mload r3 [r9,-2]\n mov r4 0\n mstore [r9,-1] r4\n jmp .LBL16_1\n.LBL16_1:\n mload r4 [r9,-1]\n gte r5 r3 r4\n neq r6 r4 r3\n and r5 r5 r6\n cjmp r5 .LBL16_2\n jmp .LBL16_3\n.LBL16_2:\n mload r6 [r1,r4]\n mstore [r2,r4] r6\n add r5 r4 1\n mstore [r9,-1] r5\n jmp .LBL16_1\n.LBL16_3:\n add r9 r9 -4\n ret\nmemcmp_eq:\n.LBL17_0:\n add r9 r9 5\n mstore [r9,-4] r1\n mload r1 [r9,-4]\n mstore [r9,-3] r2\n mload r2 [r9,-3]\n mstore [r9,-2] r3\n mload r3 [r9,-2]\n mov r4 0\n mstore [r9,-1] r4\n jmp .LBL17_1\n.LBL17_1:\n mload r4 [r9,-1]\n gte r5 r3 r4\n neq r6 r4 r3\n and r5 r5 r6\n cjmp r5 .LBL17_2\n mov r0 1\n jmp .LBL17_3\n.LBL17_2:\n mload r6 [r1,r4]\n mload r7 [r2,r4]\n mstore [r9,-5] r7\n add r5 r4 1\n mstore [r9,-1] r5\n mload r4 [r9,-5]\n eq r4 r6 r4\n cjmp r4 .LBL17_1\n mov r0 0\n jmp .LBL17_3\n.LBL17_3:\n add r9 r9 -5\n ret\nmemcmp_ugt:\n.LBL18_0:\n add r9 r9 5\n mstore [r9,-4] r1\n mload r1 [r9,-4]\n mstore [r9,-3] r2\n mload r2 [r9,-3]\n mstore [r9,-2] r3\n mload r3 [r9,-2]\n mov r4 0\n mstore [r9,-1] r4\n jmp .LBL18_1\n.LBL18_1:\n mload r4 [r9,-1]\n gte r5 r3 r4\n neq r6 r4 r3\n and r5 r5 r6\n cjmp r5 .LBL18_2\n mov r0 1\n jmp .LBL18_3\n.LBL18_2:\n mload r6 [r1,r4]\n mload r7 [r2,r4]\n mstore [r9,-5] r7\n add r5 r4 1\n mstore [r9,-1] r5\n mload r4 [r9,-5]\n gte r4 r6 r4\n mload r5 [r9,-5]\n neq r5 r6 r5\n and r4 r4 r5\n cjmp r4 .LBL18_1\n mov r0 0\n jmp .LBL18_3\n.LBL18_3:\n add r9 r9 -5\n ret\nmemcmp_uge:\n.LBL19_0:\n add r9 r9 5\n mstore [r9,-4] r1\n mload r1 [r9,-4]\n mstore [r9,-3] r2\n mload r2 [r9,-3]\n mstore [r9,-2] r3\n mload r3 [r9,-2]\n mov r4 0\n mstore [r9,-1] r4\n jmp .LBL19_1\n.LBL19_1:\n mload r4 [r9,-1]\n gte r5 r3 r4\n neq r6 r4 r3\n and r5 r5 r6\n cjmp r5 .LBL19_2\n mov r0 1\n jmp .LBL19_3\n.LBL19_2:\n mload r6 [r1,r4]\n mload r7 [r2,r4]\n mstore [r9,-5] r7\n add r5 r4 1\n mstore [r9,-1] r5\n mload r4 [r9,-5]\n gte r4 r6 r4\n cjmp r4 .LBL19_1\n mov r0 0\n jmp .LBL19_3\n.LBL19_3:\n add r9 r9 -5\n ret\nu32_div_mod:\n.LBL20_0:\n add r9 r9 9\n mstore [r9,-4] r1\n mload r1 [r9,-4]\n mstore [r9,-7] r1\n mstore [r9,-3] r2\n mload r1 [r9,-3]\n mstore [r9,-8] r1\n mstore [r9,-2] r3\n mload r3 [r9,-2]\n mstore [r9,-1] r4\n mload r4 [r9,-1]\n mload r1 [r9,-8]\n mov r2 r1\n mload r1 [r9,-7]\n.PROPHET20_0:\n mov r0 psp\n mload r0 [r0]\n mov r1 r0\n mstore [r9,-9] r1\n mload r1 [r9,-9]\n range r1\n mload r1 [r9,-9]\n add r5 r1 1\n not r7 r5\n add r7 r7 1\n mload r1 [r9,-8]\n add r6 r1 r7\n range r6\n mload r1 [r9,-8]\n mov r2 r1\n mload r1 [r9,-7]\n.PROPHET20_1:\n mov r0 psp\n mload r0 [r0]\n mov r1 r0\n range r3\n mload r2 [r9,-8]\n mul r2 r1 r2\n mstore [r9,-5] r2\n mload r2 [r9,-5]\n mload r5 [r9,-9]\n add r2 r2 r5\n mstore [r9,-6] r2\n mload r2 [r9,-6]\n mload r5 [r9,-7]\n eq r2 r2 r5\n assert r2\n mstore [r3] r1\n mload r1 [r9,-9]\n mstore [r4] r1\n add r9 r9 -9\n ret\nu32_power:\n.LBL21_0:\n add r9 r9 2\n mstore [r9,-2] r1\n mload r1 [r9,-2]\n mstore [r9,-1] r2\n mload r2 [r9,-1]\n mov r0 1\n mov r3 0\n jmp .LBL21_1\n.LBL21_1:\n add r5 r3 1\n mul r4 r0 r1\n gte r3 r2 r5\n cjmp r3 .LBL21_1\n mov r0 r4\n mov r3 r5\n jmp .LBL21_2\n.LBL21_2:\n range r0\n add r9 r9 -2\n ret\ntest:\n.LBL22_0:\n add r9 r9 2\n mstore [r9,-2] r9\n mov r1 3\n call vector_new\n mov r1 r0\n add r2 r1 1\n mov r3 1\n mstore [r2] r3\n mov r3 2\n mstore [r2,+1] r3\n mov r3 3\n mstore [r2,+2] r3\n mload r1 [r1]\n eq r1 r1 3\n assert r1\n add r9 r9 -2\n ret\nfunction_dispatch:\n.LBL23_0:\n add r9 r9 3\n mstore [r9,-2] r9\n mov r2 r3\n mstore [r9,-3] r2\n mload r2 [r9,-3]\n eq r8 r1 4171824493\n cjmp r8 .LBL23_2\n jmp .LBL23_1\n.LBL23_1:\n ret\n.LBL23_2:\n call test\n mov r1 1\n call heap_malloc\n mov r1 r0\n mov r2 0\n mstore [r1] r2\n tstore r1 1\n add r9 r9 -3\n ret\nmain:\n.LBL24_0:\n add r9 r9 8\n mstore [r9,-2] r9\n mov r1 13\n call heap_malloc\n mov r1 r0\n mov r2 1\n tload r1 r2 13\n mload r1 [r1]\n mstore [r9,-4] r1\n mov r1 14\n call heap_malloc\n mov r1 r0\n mov r2 1\n tload r1 r2 14\n mload r1 [r1]\n mstore [r9,-6] r1\n mload r1 [r9,-6]\n add r1 r1 14\n mstore [r9,-3] r1\n mload r1 [r9,-3]\n call heap_malloc\n mov r3 r0\n mov r1 1\n mload r2 [r9,-3]\n tload r3 r1 r2\n mload r2 [r9,-6]\n mload r1 [r9,-4]\n call function_dispatch\n add r9 r9 -8\n end\n", + "prophets": [ + { + "label": ".PROPHET20_0", + "code": "%{\n function mod(felt x, felt y) -> felt {\n return x % y;\n }\n entry() {\n cid.r = mod(cid.x, cid.y);\n }\n%}", + "inputs": [ + { + "name": "cid.x", + "length": 1, + "is_ref": false, + "is_input_output": false + }, + { + "name": "cid.y", + "length": 1, + "is_ref": false, + "is_input_output": false + } + ], + "outputs": [ + { + "name": "cid.r", + "length": 1, + "is_ref": false, + "is_input_output": false + } + ] + }, + { + "label": ".PROPHET20_1", + "code": "%{\n function div(felt x, felt y) -> felt {\n return x / y;\n }\n entry() {\n cid.q = div(cid.x, cid.y);\n }\n%}", + "inputs": [ + { + "name": "cid.x", + "length": 1, + "is_ref": false, + "is_input_output": false + }, + { + "name": "cid.y", + "length": 1, + "is_ref": false, + "is_input_output": false + } + ], + "outputs": [ + { + "name": "cid.q", + "length": 1, + "is_ref": false, + "is_input_output": false + } + ] + } + ] +} diff --git a/executor/src/lib.rs b/executor/src/lib.rs index 68118309..474e8f00 100644 --- a/executor/src/lib.rs +++ b/executor/src/lib.rs @@ -1843,6 +1843,7 @@ impl Process { if prophets.is_some() { prophets_insert = prophets.clone().unwrap(); } + // todo : why need clear? //self.storage_log.clear(); let mut end_step = None; @@ -1864,6 +1865,21 @@ impl Process { } program.trace.builtin_poseidon.extend(prog_hash_rows); + // init heap ptr + self.memory.write( + HP_START_ADDR, + 0, //write, clk is 0 + GoldilocksField::from_canonical_u64(0 as u64), + GoldilocksField::from_canonical_u64(MemoryType::ReadWrite as u64), + GoldilocksField::from_canonical_u64(MemoryOperation::Write as u64), + GoldilocksField::from_canonical_u64(FilterLockForMain::False as u64), + GoldilocksField::from_canonical_u64(0_u64), + GoldilocksField::from_canonical_u64(1_u64), + GoldilocksField(HP_START_ADDR + 1), + self.tx_idx, + self.env_idx, + ); + loop { self.register_selector = RegisterSelector::default(); let registers_status = self.registers; diff --git a/executor/src/tests.rs b/executor/src/tests.rs index 9162d933..708c6c6b 100644 --- a/executor/src/tests.rs +++ b/executor/src/tests.rs @@ -411,6 +411,22 @@ fn callee_ret_test() { ); } +#[test] +fn global_test() { + let call_data = [0, 4171824493]; + + let calldata = call_data + .iter() + .map(|e| GoldilocksField::from_canonical_u64(*e)) + .collect(); + executor_run_test_program( + "../assembler/test_data/bin/global.json", + "global_trace.txt", + false, + Some(calldata), + ); +} + #[test] fn gen_storage_table_test() { let mut program: Program = Program::default(); diff --git a/executor/src/trace.rs b/executor/src/trace.rs index 14c68274..746cea01 100644 --- a/executor/src/trace.rs +++ b/executor/src/trace.rs @@ -9,6 +9,8 @@ use core::vm::error::ProcessorError; use core::vm::memory::MEM_SPAN_SIZE; use log::debug; use plonky2::field::types::{Field, Field64, PrimeField64}; +use core::merkle_tree::log::WitnessStorageLog; +use core::vm::memory::HP_START_ADDR; use std::collections::HashMap; use std::fs::File; @@ -28,6 +30,7 @@ pub fn gen_memory_table( let mut first_row_flag = true; let mut first_heap_row_flag = true; + process.memory.trace.get_mut(&HP_START_ADDR).unwrap().remove(0); for (field_addr, cells) in process.memory.trace.iter() { let mut new_addr_flag = true; @@ -195,6 +198,79 @@ pub fn gen_memory_table( Ok(()) } +pub fn storage_hash_table_gen( + storage_logs: Vec, + storage_log_len: usize, + program: &mut Program, + account_tree: &mut AccountTree, +) -> Vec<[GoldilocksField; TREE_VALUE_LEN]> { + let mut pre_root = account_tree.root_hash(); + let (hash_traces, _) = account_tree.process_block(storage_logs.iter()); + let _ = account_tree.save(); + + let mut root_hashes = Vec::new(); + + for (chunk, log) in hash_traces.chunks(ROOT_TREE_DEPTH).enumerate().zip(storage_logs) { + let is_write = GoldilocksField::from_canonical_u64(log.storage_log.kind as u64); + let mut root_hash = [GoldilocksField::ZERO; TREE_VALUE_LEN]; + root_hash.clone_from_slice(&chunk.1.last().unwrap().0.output[0..4]); + root_hashes.push(root_hash); + let mut acc = GoldilocksField::ZERO; + let key = tree_key_to_u256(&log.storage_log.key); + let mut hash_type = GoldilocksField::ZERO; + let rows: Vec<_> = chunk + .1 + .iter() + .rev() + .enumerate() + .map(|item| { + let layer_bit = ((key >> (LEAF_LAYER - item.0)) & TreeKeyU256::one()).as_u64(); + let layer = (item.0 + 1) as u64; + + if item.0 == LEAF_LAYER { + hash_type = GoldilocksField::ONE; + } + + acc = acc * GoldilocksField::from_canonical_u64(2) + + GoldilocksField::from_canonical_u64(layer_bit); + + let mut hash = [GoldilocksField::ZERO; 4]; + hash.clone_from_slice(&item.1 .0.output[0..4]); + let row = StorageHashRow { + storage_access_idx: (chunk.0 + 1) as u64, + pre_root, + root: root_hash, + is_write, + hash_type, + pre_hash: item.1 .3, + hash, + layer, + layer_bit, + addr_acc: acc, + addr: log.storage_log.key, + pre_path: item.1 .4, + path: item.1 .1, + sibling: item.1 .2, + }; + if layer % 64 == 0 { + acc = GoldilocksField::ZERO; + } + program.trace.builtin_poseidon.push(item.1 .0); + program.trace.builtin_poseidon.push(item.1 .5); + row + }) + .collect(); + pre_root = root_hash; + program.trace.builtin_storage_hash.extend(rows); + } + program.trace.builtin_program_hash = program + .trace + .builtin_storage_hash + .drain(storage_log_len * ROOT_TREE_DEPTH..) + .collect(); + root_hashes +} + pub fn gen_storage_hash_table( process: &mut Process, program: &mut Program,