For reference: the Noir verify_proof ``` fn verify_proof( _verification_key : [Field], _proof : [Field], _public_inputs : [Field], _key_hash : Field, _input_aggregation_object : [Field]) -> [Field] {} ``` Procedure to compute r from sub-hashes and valid paths to r for sub hashes ``` fn ( addr_sorted_0, time_sorted_0 ) { var r0 = 0; for (var i = 0..addr_sorted_0.len) { r0 = Hash(addr_sorted[i], r) } for (var i = 0..time_sorted_0.len) { r0 = Hash(time_sorted[i], r) } r0 } // recursive fn (r0, r1, ...) { verify_proof(..., r0, ) verify_proof(..., r1, ) ... compute_merkle_root_and_paths(sub_hashes_r) } ``` Procedure to compute sub permutation products ``` fn ( addr_sorted_0, time_sorted_0, r, paths0 ) { var addr_perm_0 = 0 var time_perm_0 = 0 var r0 = 0; for (var i = 0..addr_sorted_0.len) { addr_perm_0 = (addr_sorted_0[i] - r)*addr_perm_0 r0 = Hash(addr_sorted[i], r) } for (var i = 0..time_sorted_0.len) { time_perm_0 = (time_perm_0[i] - r)*addr_perm_0 r0 = Hash(time_sorted[i], r) } is_valid_path(r0, paths0, r) (addr_perm_0, time_perm_0) } //recursive fn(addr_perm_0,...addr_perm_n, time_perm_0,...,time_perm_n) { verify_proof(..., addr_perm_0, ) verify_proof(..., time_perm_0, ) ... var final_addr_perm = addr_perm_0 * ... * addr_perm_n var final_time_perm = time_perm_0 * ... * time_perm_n assert final_addr_perm = final_time_perm } ``` Procedure to verify begin and end sequences ``` fn (time_sorted_0, time_sorted_n_old, r) { //should be same length, we assume emulator reads out memory in order for (var i = 0 .. time_sorted_0.len) { assert time_sorted_0[i] = time_sorted_n_old[i] } compute_permutation_check(time_sorted_0, r) } //can recursively collect permutations and assertions if readout is too large ``` Procedure to verify opcodes ``` //selected subset of array which includes read opcodes, read args, and relavant reads/writes for each op fn (time_sorted_opcodes, r) { while (i < time_sorted_opcodes.len) { // check time_sorted_opcodes reads opcode // check the arg is correct to address mode // check computation of reads / writes //update i } compute_permutation_check(time_sorted_opcodes, r) } //recursively collect opcodes and compute final permutation check for full time_sorted_array fn ( ... , r) { verify(op1_0) verify(op1_1) ... verify(opN_N) compute_permutation_check(..., r) } ``` The final aggregate proof will bring all procedures together, can make assertions all the permutation checks across the aggregates match