The circuit starts here. This function allocate PI inputs that call the inner function, where all the main logic is implemented. In the end, it forms the fsm output and compute PI commitment. The main purpose of this circuit is enforcing that memory queries are executed correctly.
Some field, like unsorted_queue_initial_state and current_unsorted_queue_state represents the same value. So we should decide whether we take a new queue from Input or continue working with current one from FSM Input. We use start_flag for such purpose.
let unsorted_queue_state =QueueState::conditionally_select( cs, start_flag,&observable_input.unsorted_queue_initial_state,&hidden_fsm_input.current_unsorted_queue_state,);let sorted_queue_state =QueueState::conditionally_select( cs, start_flag,&observable_input.sorted_queue_initial_state,&hidden_fsm_input.current_sorted_queue_state,);
Also, we generate challenges and accumulators for permutation argument. The detailed explanation can be found here.
If the queues are empty now, that means that this instance should be the last one.
let completed = unsorted_queue.length.is_zero(cs);
If so, we should check that permutation argument accumulators are equal and number of nondeterministic writes is correct.
for (lhs, rhs) in lhs.iter().zip(rhs.iter()) {Num::conditionally_enforce_equal(cs, completed, lhs, rhs);}let num_nondeterministic_writes_equal =UInt32::equals( cs,&num_nondeterministic_writes,&observable_input.non_deterministic_bootloader_memory_snapshot_length,);num_nondeterministic_writes_equal.conditionally_enforce_true(cs, completed);
Finally, we form the output part of PI and compute a commitment to PI and allocate it as witness variables.
let input_commitment =commit_variable_length_encodable_item(cs, &compact_form, round_function);for el in input_commitment.iter() {let gate =PublicInputGate::new(el.get_variable()); gate.add_to_cs(cs);}