---
# System prepended metadata

title: Proof of staking circuit design

---

# Proof of staking circuit design

## Goals

Being able to do privacy-preserving claims about my own staking history that can be automatically checked.

### Why existing solutions don't allow you to do that?

The most basic way of proving to someone some fact about your history of staking is to show them Ethereum blockchain, point out deposit and withdrawal TXes, and prove that you own the account that made those transactions. Problem with this approach - it is not privacy preserving (you reveal everything about your Ethereum usage) and it is not tunable (you don't decide how much verifier will learn).

## Transcript problem

Ethereum does not enable easy creation of zksnark proofs about it's contents. One can attempt to prove a state of particular cell (32 bytes) of Ethereum state. Creating a merkle proof against hash of the state at particular block height is easy. Dealing with Solidity contract variable layout is also realistic. The real problem with such proof - you can't make it privacy preserving. One can create a circuit that will allow you to make claims, but unfortunately this circuit will be huge. Which means long proving times and big RAM requirements.

There is also a problem of data representation in Ethereum blockchain. To prove that funds hasn't moved between block n and n+k one would need to construct a proof for exact amount of funds for each of the blocks in that range - k+1 proves. While it is possible without blowing up circuit size even more (with help of recursive snarks), amount of computation needed is rediculous. 

Which means that to make this problem tracktable we need to write our own transcript and make claims against it.

## Protocol custody problem

### Approaches that do not work
* stake attributed to the owner. In such case owner can deposit through protocol, withdraw outside of protocol, deposit through protocol again. This fakes wei\*block score and destroys transcript usefulness for ALL PARTICIPANTS, not just cheater. 
* stake of all of owners is attributed to the protocol contract. This breaks more interesting staking protocols (all with non-linear rewards, all where stake is connected with some obligations and possible penalties - such as Ethereum PoS).

Solution: **create a vault contract per owner**, let vault stake on behalf of the owner.

## Design

Protocol participants opt-in before making stakes. Their deposits and withdrawals are marked in the transcript. Transcript is constracted in provably correct way (guaranteed by both Ethereum and zksnarks). Next participants can create zksnark proofs for claims such as:
* I've been staking not less that 100 ETH during March of 2023
* During 2023 my staking score was between 1200 and 2400 ETH*months

### Limitations

Negative claims (*I wasn't staking during march 2023* or *I was staking less than X during march 2023*) are not supported - one can always dodge the protocol by staking directly. 

## Transcript

Transcript is organized as a binary merkle tree of fixed depth with leaves representing staking and unstaking events.
Each leaf contains:
* address of the token
* address of the staker
* nonce
* current staked amount
* current score (unit: wei\*block)
* event block-height

Leafs are hashed using zksnark-friendly hash. Merkle tree nodes are hashed with the same hash.

Transcript is not stored on-chain. Only its current root. Apart from transcript, contract stores {token, staker, nonce} triplets.

Update with nonce n is organized in similar manner to Tornado Cash updates. **Update circuit** takes merkle proofs of leafs  {token, staker, n-1, ..}, {token, staker, n, ..}, checks correctness of computation of current staked amount, current score etc. Public inputs are: token, staker, n, delta of staked funds, event block height.

## Proofs

Proofs are circuits that make claims against some of the values of transcript root hash. Such circuits can be provided by the validator.

To check proof validity, validator will need to check correctness of its public inputs, such as transcript tree hash, dates, amounts (and possibly challenge string).

### Designated verifier

Proof can be bound to a particular verifier. This is done by making designing a circuit to proof one of two thing: `claim is correct` OR `prover has private key of the verifier`. This way we can prevent proof reuse outside of context intended by the prover.

### Nullifiers

If client protocol uses PRODUCT as a way to obtain sybil resistance, nullifier can be used to prevent prover from making multiple claims. Nullifier can be a function of prover's private key. TODO: consider using new type of nullifiers (demoed at Bogota) to achieve that.

### Domain separation

Nullifiers can be bound to particular domain/protocol. This way staker can create two identities in different contexts without linking them together. This problem arises mostly in context of nullifiers. Domain binding is done by making nullifier a function of private key and domain string.