Local Proving
An overview of how local proving (aka. User Proving Sessions/UPS) works on Psy
Psy Network: Local User Proving Session (UPS) Deep Dive
The User Proving Session (UPS) is a cornerstone of Psy's architecture, enabling users to process their transactions locally, maintain privacy, and contribute to the network's overall scalability. This document provides a detailed exploration of the UPS, its constituent circuits, and the cryptographic guarantees it provides. Developers building client applications, wallets, or tools that interact with Psy at a low level will find this information essential.
Overview of the User Proving Session
A UPS is a sequence of operations performed locally by a user (or their delegate, such as client software) to:
- Establish a Baseline: Anchor the session to a globally finalized state of the Psy blockchain.
- Execute Transactions: Run the logic of smart contract functions (Contract Function Circuits - CFCs) for each desired transaction.
- Prove Correctness: Generate Zero-Knowledge Proofs (ZKPs) for each CFC execution.
- Maintain State Consistency: Prove that the user's local state (their
UCON
tree root, debt trees, etc.) is updated correctly based on the outcomes of the executed CFCs. - Recursive Verification: Chain these proofs together recursively, so each step verifies the previous one.
- Authorize: Cryptographically sign the entire session's outcome using the user's ZK-powered signature circuit (SDKey).
- Produce a Summary: Output a single, compact "End Cap" proof that attests to the validity of all transactions within the session.
This End Cap proof, along with the net state deltas (changes to the user's CSTATE
leaves), is then submitted to a Realm node for inclusion in the next block.
Key Circuits and Gadgets in a UPS
The UPS relies on a suite of specialized ZK circuits and gadgets. "Gadgets" are reusable ZK circuit components.
1. UPSStartSessionCircuit
- Initiating the Session
- Purpose: To securely initialize the UPS, ensuring it starts from a consistent and globally validated state for the user.
- Core Gadget:
UPSStartStepGadget
- Inputs/Witnesses (provided by user's client):
UPSStartStepInput
:header_witness
: A targetUserProvingSessionHeaderGadget
that the circuit will populate and constrain. Key fields within itssession_start_context
:checkpoint_tree_root
: The hash of theCHKP
root of the last globally finalized block the user is basing this session on.checkpoint_leaf_hash
: The hash of thePsyCheckpointLeaf
corresponding tocheckpoint_tree_root
.checkpoint_id
: The block height/index of this checkpoint.start_session_user_leaf
: The user'sPsyUserLeaf
data as it existed at this checkpoint.
checkpoint_leaf_gadget_witness
: The actualPsyCheckpointLeafCompactWithStateRoots
data.state_roots_gadget_witness
: ThePsyGlobalStateRoots
contained within thecheckpoint_leaf_gadget_witness
.checkpoint_tree_proof_witness
: A Merkle proof showing thatcheckpoint_leaf_hash
is a valid leaf in the tree rooted atcheckpoint_tree_root
atcheckpoint_id
.user_tree_proof_witness
: A Merkle proof showing that the hash ofstart_session_user_leaf
is a valid leaf in theGUSR
(Global User Tree) rooted atstate_roots_gadget_witness.user_tree_root
, at the user'suser_id
.
- What it Proves:
- Checkpoint Validity: The provided
checkpoint_leaf_hash
is indeed part of the claimedcheckpoint_tree_root
at the specifiedcheckpoint_id
(verified usingcheckpoint_tree_proof_witness
). - Global Context Consistency: The hash of
checkpoint_leaf_gadget_witness
matchescheckpoint_leaf_hash
. The hash ofstate_roots_gadget_witness
matches theglobal_chain_root
withincheckpoint_leaf_gadget_witness
. - User State Validity: The user's
start_session_user_leaf
(hashed) is a valid leaf in theGUSR
(rooted atstate_roots_gadget_witness.user_tree_root
) at the correctuser_id
(verified usinguser_tree_proof_witness
). - Header Initialization:
- The
session_start_context
in the outputUserProvingSessionHeader
is correctly populated from the verified inputs. - The
current_state
within the header is initialized:user_leaf
is set tostart_session_user_leaf
, but withlast_checkpoint_id
updated to the current session'scheckpoint_id
.deferred_tx_debt_tree_root
andinline_tx_debt_tree_root
are set toEMPTY_TREE_ROOT
.tx_count
is set to 0.tx_hash_stack
(a running hash of transactions) is set toZERO_HASH
.ups_step_circuit_whitelist_root
is set to a known constant for subsequent UPS step circuits.
- The
- Checkpoint Validity: The provided
- Output: A ZK proof for this start step, and the initialized
UserProvingSessionHeader
. - Significance: This step is crucial for preventing users from starting sessions based on invalid or outdated personal states. It anchors the entire UPS to a verifiable global consensus point.
2. DapenContractFunctionCircuit
(CFC) - Executing Smart Contract Logic
- Purpose: To execute the logic of a specific smart contract function chosen by the user and generate a ZK proof of this local execution. This circuit is defined by the smart contract developer using the Dapen toolchain.
- Core Gadget (Framework):
PsyContractFunctionBuilderGadget
(used by Dapen compiler). - Inputs/Witnesses (provided by user's client for each call):
DapenContractFunctionCircuitInput
:tx_input_ctx
(Transaction Input Context):transaction_call_start_ctx
: Contains the assumed starting state for this specific contract interaction:start_contract_state_tree_root
: The root of the user'sCSTATE
tree for this contract before this function call (derived from the user'sUCON
in the previous UPS step).start_user_balance
,start_user_event_index
.start_deferred_tx_debt_tree_root
,start_inline_tx_debt_tree_root
(from previous UPS step).
call_data_hash
,call_data_length
: Hash and length of the function arguments.contract_id
,method_id
.
circuit_inputs
: The actual arguments for the smart contract function.session_proof_tree_root
: The root of the user's recursive proof tree built so far within this UPS. This is used for "tree-aware" proofing, ensuring this CFC proof is part of the larger session's proof structure.
- What it Proves:
- Faithful Execution: The sequence of internal operations performed by the circuit exactly matches the compiled
DPNFunctionCircuitDefinition
(the smart contract's code for that function). - State Transformation: Given the
transaction_call_start_ctx
andcircuit_inputs
, the execution correctly produces theend_contract_state_tree_root
(new root of the user'sCSTATE
for this contract) andend_deferred_tx_debt_tree_root
recorded in the outputtransaction_end_ctx
. - Output Consistency: The computed
outputs_hash
andoutputs_length
(from the function's return values) match those recorded intransaction_end_ctx
. - Assertions: All assertions defined within the smart contract function's code hold true during this execution.
- Public Input Hashing: The circuit's main public input (a hash combining
session_proof_tree_root
and the hash oftx_input_ctx
) is correctly computed.
- Faithful Execution: The sequence of internal operations performed by the circuit exactly matches the compiled
- Output: A ZK proof for this specific CFC execution instance (CFC Proof).
- Significance: This is where the actual smart contract logic runs. Its ZK proof guarantees that the user's local execution was correct according to the contract code, without revealing the intermediate states or inputs if the contract is designed for privacy.
3. UPSCFCStandardTransactionCircuit
- Integrating a CFC Execution
- Purpose: To take a verified CFC proof (from step 2) and integrate its effects into the main UPS proof chain. It verifies the CFC's validity and proves that the overall UPS state (user's
UCON
root, debt trees, transaction counters) is correctly updated. It also recursively verifies the proof from the previous UPS step. - Core Gadgets:
VerifyPreviousUPSStepProofInProofTreeGadget
: Verifies the ZK proof of the immediately preceding UPS step.UPSVerifyCFCProofExistsAndValidGadget
: Verifies the CFC proof (from step 2), its inclusion in the session's proof tree, and that the function called is globally registered in the contract'sCFT
.UPSCFCStandardStateDeltaGadget
: Calculates and proves the changes to theUserProvingSessionHeader
.
- Inputs/Witnesses (provided by user's client):
UPSVerifyCFCStandardStepInput
:- The ZK proof of the previous UPS step.
- The
UserProvingSessionHeaderGadget
output by the previous UPS step. - The CFC Proof (from step 2) and its
transaction_end_ctx
. PsyContractFunctionInclusionProof
: A Merkle proof showing the CFC's fingerprint is in the contract'sCFT
(rooted inGCON
, which is anchored to the session'scheckpoint_leaf_hash
).user_contract_tree_update_proof
: ADeltaMerkleProofCore
proving the update to the user'sUCON
tree. This shows the leaf atcontract_id
changing from thestart_contract_state_tree_root
(from CFC'sstart_ctx
) toend_contract_state_tree_root
(from CFC'send_ctx
).deferred_tx_debt_pivot_proof
,inline_tx_debt_pivot_proof
:MerkleProofCore
s showing the debt tree roots transition correctly from their state in the previous UPS header to their state in the CFC'send_ctx
.
current_proof_tree_root
: The root of the UPS proof tree after including the current CFC proof and this step's proof.
- What it Proves:
- Previous Step Validity: The previous UPS step's proof is valid, was generated by a whitelisted UPS circuit, and its public inputs match the hash of the previous
UserProvingSessionHeader
. - CFC Validity & Legitimacy:
- The CFC proof is valid and is part of the
current_proof_tree_root
. - The function executed by the CFC is legitimate (its fingerprint is in the contract's
CFT
, which is part of the global state referenced byprevious_step_header.session_start_context.checkpoint_leaf_hash
). - The
cfc_inner_public_inputs_hash
(derived from the CFC'stx_input_ctx
) from the verified CFC proof matches the one used byUPSCFCStandardStateDeltaGadget
. This is a critical link ensuring the state delta calculation is based on the actual verified computation.
- The CFC proof is valid and is part of the
- State Delta Correctness (via
UPSCFCStandardStateDeltaGadget
):UCON
Update: Theuser_contract_tree_update_proof
correctly updates theUCON
root fromprevious_step_header.current_state.user_leaf.user_state_tree_root
to a new root reflecting the change forcontract_id
fromstart_contract_state_tree_root
toend_contract_state_tree_root
.- Debt Tree Consistency: The
deferred/inline_tx_debt_pivot_proofs
show that the debt tree roots in the CFC'send_ctx
are valid successors to the debt tree roots in theprevious_step_header
(orCorrectUPSHeaderHashesGadget
if overridden). - Counter & Stack:
tx_count
in the new header is incremented.tx_hash_stack
is updated by hashing the previous stack with aTransactionLogStackItemGadget
(containing CFC call details). - The
current_state.user_leaf
in the new header is updated (e.g.,user_state_tree_root
now reflects the newUCON
root).
- Previous Step Validity: The previous UPS step's proof is valid, was generated by a whitelisted UPS circuit, and its public inputs match the hash of the previous
- Output: A ZK proof for this transaction step, and the new
UserProvingSessionHeaderGadget
. - Significance: This is the workhorse circuit of the UPS, meticulously linking individual contract executions to the user's overall session state in a verifiable, recursive manner.
(Steps 2 and 3 are repeated for every transaction the user wishes to include in their session.)
4. UPSStandardEndCapCircuit
- Finalizing the Session
- Purpose: To securely conclude the UPS, producing the single End Cap proof. It verifies the entire chain of local proofs, validates the user's ZK signature authorizing the session, and ensures the session terminates in a defined, clean state.
- Core Gadgets:
UPSEndCapFromProofTreeGadget
: Orchestrates the final verifications.- Internally uses
VerifyPreviousUPSStepProofInProofTreeGadget
(often thePartialFromCurrent
variant) to verify the last transaction step's proof. - Uses
AttestProofInTreeGadget
to verify the user's ZK Signature Proof and its inclusion in the session proof tree.
- Internally uses
UPSEndCapCoreGadget
: Enforces final session constraints.
- Inputs/Witnesses (provided by user's client):
UPSEndCapFromProofTreeInput
:- Witnesses for verifying the last UPS transaction step's proof (attestation, previous state, whitelist proof).
- Witnesses for verifying the ZK Signature Proof (attestation, public key parameters of the signature circuit).
user_public_key_param
: The user-defined parameter part of their SDKey.nonce
: The new nonce value for the user.slots_modified
: A count of state slots modified (for stats).
- The ZK Signature Proof itself. This proof is generated by the user's chosen signature circuit. The signature circuit's public input is a sighash derived from
PsyUserProvingSessionSignatureDataCompactGadget
. PsyUserProvingSessionSignatureDataCompactGadget
(witness): Containsstart_user_leaf_hash
,end_user_leaf_hash
(from the finalUserProvingSessionHeader
),checkpoint_leaf_hash
(from session start),tx_stack_hash
, andtx_count
(from final header).
- What it Proves (via
UPSEndCapCoreGadget
and its constituents):- Last Step Validity: The proof of the last transaction step in the UPS is valid and used a whitelisted UPS circuit.
- Signature Proof Validity: The provided ZK Signature Proof is valid and is part of the same session proof tree as the last transaction step.
- Authorization:
- The fingerprint of the signature circuit (from
sig_proof_verifier_data
) combined withuser_public_key_param
correctly reconstructs the user's registered public key (which is present in thestart_user_leaf
andend_user_leaf
within the finalUserProvingSessionHeader
). - The public input of the ZK Signature Proof matches the sighash computed from the
PsyUserProvingSessionSignatureDataCompactGadget
witness, which in turn is derived from the final state of theUserProvingSessionHeader
. This confirms the signature authorizes this specific session's outcome.
- The fingerprint of the signature circuit (from
- Nonce Progression: The
nonce
witness is greater thanlast_header_gadget.current_state.user_leaf.nonce
(from the start of the session), and theend_user_leaf.nonce
is updated to this newnonce
. - Checkpoint Progression:
last_header_gadget.current_state.user_leaf.last_checkpoint_id
is updated tolast_header_gadget.session_start_context.checkpoint_id
(and this must be greater than the originallast_checkpoint_id
). - Clean State: The
deferred_tx_debt_tree_root
andinline_tx_debt_tree_root
in thelast_header_gadget.current_state
areEMPTY_TREE_ROOT
. - Output Generation:
UPSEndCapResultCompactGadget
is correctly formed usingstart_user_leaf_hash
,end_user_leaf_hash
,checkpoint_tree_root_hash
(from session start context), anduser_id
. Its hash is a public output.GUTAStatsGadget
is correctly formed (fees, transaction counts, slots modified). Its hash is a public output.
- Output: The End Cap ZK Proof. Its public inputs are the
end_cap_result_hash
andguta_stats_hash
. - Significance: This is the culmination of the user's local efforts. The End Cap proof is a compact, verifiable assertion of all the user's actions in the block, ready for efficient processing by the Psy network.
The UPS Proof Tree
Throughout the UPS, a local Merkle tree of proofs is implicitly constructed.
- The leaves of this tree are the ZK proofs for individual CFC executions and the ZK Signature Proof.
- Intermediate nodes are the ZK proofs from
UPSCFCStandardTransactionCircuit
(or variants) andUPSStartSessionCircuit
. - The root of this tree is referenced by
current_proof_tree_root
in various gadgets and is implicitly verified by the chain of recursive verifications. TheUPSEndCapCircuit
can optionally include an explicit proof of this tree's aggregation if needed for certain advanced scenarios or cross-UPS interactions, though typically the recursive verification suffices.
By offloading transaction execution and initial proof generation to users, the UPS dramatically reduces the computational load on the main Psy network, enabling it to focus on aggregation and maintaining global consensus. This local-first approach is fundamental to Psy's privacy, scalability, and user-centric design.