Rollup circuit
Circuit Description
The rollup circuit aggregates proofs from a defined set of ‘inner’ circuits.
Each inner circuit has 16 public inputs. The rollup circuit will execute several defined subroutines on the public inputs.
Notation
We use the following definitions in this spec:
-
NUM_BRIDGE_CALLS_PER_BLOCK -
NUM_ASSETS -
NUM_FIELDS(number of inner-circuit public inputs propagated by rollup circuit) - rollup size (i.e. number of transaction proofs in a single rollup)
Public Inputs: Detail
There are public inputs, in three sections:
- Rollup Proof Data: elements from that define the rollup block information (described below)
- Rolled-Up Transactions Data: Inner-circuit public inputs (a total of inputs; inputs per rolled up transaction)1
- Recursive Proof Data: elements from , represented as elements from , whose values are ; see here for explanation.
All are field elements. The first public inputs are the following:
rollup_idrollup_sizedata_start_indexold_data_rootnew_data_rootold_null_rootnew_null_rootold_data_roots_rootnew_data_roots_rootold_defi_root = 0new_defi_rootdefi_bridge_call_datas(size: )defi_bridge_deposits(size: )asset_ids(size: )total_tx_fees(size: )public_inputs_hash
The public_inputs_hash value is a SHA256 hash of the set of all join-split public inputs that will be broadcasted on-chain. These are:
proof_idoutput_note_commitment_1output_note_commitment_2nullifier_1nullifier_2public_valuepublic_ownerpublic_asset_id
Private Inputs: Detail
The following inputs are private to reduce proof size:
- The recursive proof output of each inner proof (4 elements represented as 16 elements, see above)
- The remaining public inputs of each inner-circuit proof (see footnote 1)
old_data_pathlinked_commitment_pathslinked_commitment_indicesnew_null_roots(except the latest one since that becomes a public input)old_null_pathsdata_roots_pathsdata_roots_indices
Index of Functions
ExtractExtraction Function extracts the public inputs from an inner proof, and validates the result matches the rollup’s inner public inputsAggregateProof Aggregation Function for ultimate batch verification outside the circuit, given a verification key and (optional, defined by 4th input parameter) a previous output of Aggregate. Returns a BN254 point pairNonMembershipUpdateNullifier Update Function checks a nullifier is not in a nullifier set given its root, then inserts the nullifier and validates the correctness of the associated merkle root updateBatchUpdateBatch Update Function inserts a set of compressed note commitments into the note tree and validates the corretness of the associated merkle root update Update - inserts a single leaf into the root tree and validates the corretness of the associated merkle root updateProcessDefiDepositProcesses Defi Deposit ensures that if a given inner proof is a defi deposit proof, it has a valid bridge call data that matches one of the input bridge call datas to the rollup. Further, it also adds thedefi_interaction_noncein the encrypted claim note of a defi deposit proof.ProcessClaimProcess Claims checks if the claim proof is using the correct defi root.
Circuit Logic (Pseudocode)
Let
Q_0 = [0, 0]Validate
num_inputs == NLet
previous_note_commitment_1 = 0; previous_note_commitment_2 = 0; previous_allow_chain = 0;For
i = 1, ..., num_inputsLet
pub_inputs = Extract(PI_i)Let
vk = vks[proof_id_i]Let
Q_i = Aggregate(PI_i, pub_inputs, vk, Q_{i-1}, (i > 1))Let =
output_note_commitment_1_iLet =
output_note_commitment_2_iValidate
NonMembershipUpdate(, ,nullifier_1_i)Validate
NonMembershipUpdate(,, nullifier_2_i)Validate
Membership(old_data_roots_root, data_roots_indices[i], data_roots_pths[i], data_tree_root_i)If
pub_inputs.PROOF_ID = DEFI_DEPOSITthenProcessDefiDeposit:- Check
pub_inputs.ASSET_IDmatches only one (saykth) bridge call data inbridge_call_datas - Update
defi_bridge_deposits[k] += pub_inputs.PUBLIC_OUTPUT - Update
encrypted_claim_note += (defi_interaction_nonce * rollup_id + k) * G_j,k ⋹ 0, 1, 2, 3
- Check
Validate
ProcessClaim(pub_inputs, new_defi_root)Let
chaining = propagated_input_index != 0Let
propagating_previous_output_1 = backward_link == previous_note_commitment_1Let
propagating_previous_output_2 = backward_link == previous_note_commitment_2Let
previous_tx_linked = propagating_previous_output_1 || propagating_previous_output_2Let
start_of_subchain = chaining && !previous_tx_linkedLet
middle_of_chain = chaining && previous_tx_linkedIf
start_of_subchainthen:- Validate
Membership(old_data_root, linked_commitment_indices[i], linked_commitment_paths[i], backward_link)
- Validate
Let
propagating_previous_output_index =
propagating_previous_output_1 ? 1 :
propagating_previous_output_2 ? 2 : 0- If
middle_of_chainthen:require(previous_allow_chain == propagating_previous_output_index, "not permitted to propagate this note")- Set the inner proof value corresponding to the commitment being propagated to
0. - Set the inner proof value corresponding to the nullifier of the commitment being propagated to
0.
Validate
[P1, P2] = Q_{num_inputs}Validate
BatchUpdate(old_data_root, new_data_root, data_start_index, leaf_1, ..., leaf_{2 * num_inputs})Validate
old_null_root = null_root_1Validate
new_null_root = null_root_{2 * num_inputs + 1}
- A transaction proof (i.e. inner proof) contains a total of 16 public inputs but the rollup circuit propagates only 8 of them as its public inputs. Those public inputs of the inner proof marked as ✅ are propagated:
✅
proof_id✅output_note_1_commitment✅output_note_2_commitment✅input_note_1_nullifier✅input_note_2_nullifier✅public_value✅public_owner✅public_asset_id❌merkle_root❌tx_fee❌asset_id❌bridge_call_data❌defi_deposit_value❌defi_root❌backward_link❌allow_chain↩