ZK Circuits
The ASCV uses five zero knowledge circuits to verify protocol operations without revealing private inputs. The CRE generates proofs inside the TEE, and anyone can verify them on chain.
Circuit Overview
| Circuit | Proof System | Constraints | Verify Gas | Purpose |
|---|---|---|---|---|
| Transfer | Groth16 | ~25,000 | ~220K | Verify private balance transfer |
| Collateral Adequacy | Groth16 | ~30,000 | ~220K | Verify collateral meets tier requirement |
| Interest Calculation | Groth16 | ~20,000 | ~220K | Verify correct interest computation per tick |
| Liquidation | Groth16 | ~35,000 | ~220K | Verify health factor breach and collateral distribution |
| Rate Ordering | PLONK | Variable | ~300K | Verify correct rate sorting for matching |
Transfer Circuit
Proves that a balance transfer is valid without revealing amounts.
Public inputs:
nullifier: Unique identifier for the spent commitmentcommitmentNew_sender: New sender balance commitmentcommitmentNew_recipient: New recipient balance commitmentmerkleRoot: Current commitment tree root
Private inputs (witness):
amount: Transfer amountsender_balance_old: Sender's previous balancesender_blinding_old: Sender's previous blinding factorsender_blinding_new: Sender's new blinding factorrecipient_balance_old: Recipient's previous balancerecipient_blinding_new: Recipient's new blinding factormerklePath: Merkle proof for sender's commitment
Constraints verified:
sender_balance_old >= amount(no overdraft)commitmentNew_sender = Pedersen(sender_balance_old - amount, sender_blinding_new)commitmentNew_recipient = Pedersen(recipient_balance_old + amount, recipient_blinding_new)- Merkle path verifies sender's old commitment exists in the tree
- Nullifier is correctly derived (prevents double spending)
Collateral Adequacy Circuit
Proves that a borrower's collateral meets the required ratio for their credit tier.
Public inputs:
collateralCommitment: Commitment to collateral amountloanCommitment: Commitment to loan amounttierMultiplier: Required collateral multiplier (public, tier dependent)priceCommitment: Commitment to collateral price
Private inputs:
collateralAmount: Actual collateral amountloanAmount: Actual loan amountcollateralPrice: Current price of collateral asset- Blinding factors for all commitments
Constraints verified:
collateralAmount * collateralPrice >= loanAmount * tierMultiplier- All commitments are correctly formed
- Price is within a valid range (sanity check)
Interest Calculation Circuit
Proves that interest was computed correctly for each matched tick.
Public inputs:
totalOwedCommitment: Commitment to total amount owedtickCommitments[]: Commitments to each tick's principal and rate
Private inputs:
tickAmounts[]: Individual tick amountstickRates[]: Individual tick ratesduration: Loan duration in days- Blinding factors
Constraints verified:
- For each tick:
tickInterest = tickAmount * tickRate * duration / 365 totalOwed = sum(tickAmount + tickInterest)for all ticks- Commitment to total owed is correctly formed
Liquidation Circuit
Proves that a liquidation is justified and collateral distribution is correct.
Public inputs:
loanCommitment: Commitment to loan principalcollateralCommitment: Commitment to collateral amountpriceCommitment: Commitment to current pricedistributionCommitments[]: Commitments to each lender's share
Private inputs:
principal: Loan principalcollateralAmount: Collateral amountcurrentPrice: Current collateral priceliquidationThreshold: Health factor thresholdtickAmounts[]: Each lender's tick amount- Blinding factors
Constraints verified:
(collateralAmount * currentPrice) / principal < liquidationThreshold(health breach)- Protocol fee = 5% of collateral
- Each lender share =
(tickAmount / totalPrincipal) * 95% * collateral - Sum of distributions = collateral (conservation)
Rate Ordering Circuit
Proves that the CRE sorted rates correctly during matching. Uses PLONK because the number of ticks varies per match.
Public inputs:
sortedRateCommitments[]: Commitments to the sorted rate arraymatchResult: Hash of the matching outcome
Private inputs:
rates[]: Actual decrypted ratessortPermutation[]: The permutation that sorts rates ascending- Blinding factors
Constraints verified:
- Applying
sortPermutationtoratesproduces a sorted array - Each rate commitment matches the corresponding rate
- The matching outcome is consistent with the sorted order
Proof Systems
Groth16
Used for circuits with fixed structure (Transfer, Collateral, Interest, Liquidation):
| Property | Value |
|---|---|
| Proof size | 128 bytes (3 group elements) |
| Verification gas | ~220,000 |
| Setup | Trusted setup per circuit (powers of tau + circuit specific) |
| Prover time | ~2 seconds (BN254, server grade hardware) |
PLONK
Used for the Rate Ordering circuit which has variable tick counts:
| Property | Value |
|---|---|
| Proof size | ~500 bytes |
| Verification gas | ~300,000 |
| Setup | Universal setup (reusable across circuits) |
| Prover time | ~3 to 5 seconds |
CRE as Proof Engine
The CRE generates all ZK proofs inside the TEE:
- CRE decrypts rates and runs matching (same as current design)
- CRE computes witness values for the relevant circuits
- CRE generates Groth16/PLONK proofs using snarkjs (WASM compatible)
- CRE bundles proofs into a DON report
- DON signs the report (threshold signature)
- Report is submitted to GhostVault.onReport()
- Contract verifies all proofs before executing operations
This means the CRE is a "trusted but verified" prover. It generates proofs, but anyone can check them on chain.