Poof.cash
Search…
Overview
A rough explanation. Some details are overlooked.

Summary

Poof v2 enables users to have a hidden balance that only they can read and write. Everyone's hidden balance is hashed into a commitment and all the commitments form leaves that represent a Merkle tree. This Merkle tree is the source of truth for everyone's hidden balances.
Every user must keep track of which leaf stores their most up-to-date balance. Since all leaves are hashes and only balance owners know the preimage of their commitment, balances are intractable to read by anyone else.
In order to update your balance, you must prove that you know the preimage to the commitment representing your latest account balance and that this commitment exists in the latest Merkle tree. zkSNARKs make it possible to prove this without revealing which commitment you're referring to. This mechanism makes it so that only balance owners can update their balance.

Example

Let's say a new user wants to deposit 10 cUSD into Poof v2:
  1. 1.
    The client searches through a list of encrypted accounts in the Poof smart contract to see if the user's private key can decrypt any of the encrypted accounts. The user is new, so none of the accounts successfully decrypt.
  2. 2.
    The client creates a new account for the user. An account consists of a balance, debt, nullifier, and secret. balance and debt get initialized to 0 and nullfier and secret are random numbers that the user generates on the client side. We also generate a commitment which is a hash of these four values
    1. 1.
      1
      balance = 0
      2
      debt = 0
      3
      nullfier = randInt()
      4
      secret = randInt()
      5
      inputCommitment = hash(balance, debt, nullifier, secret)
      Copied!
  3. 3.
    The client creates an output account for the user. This account represents the user's account state after depositing 10 cUSD. We also generate an encryptedAccount which represents the account object but encrypted by the user's public key. The new account, commitment, and encryptedAccount looks like the following
    1. 1.
      1
      balance = 10
      2
      debt = 0
      3
      nullifier = randInt()
      4
      secret = randInt()
      5
      outputCommitment = hash(balance, debt, nullifier, secret)
      6
      encryptedAccount =
      7
      enrypt(Account(balance, debt, nullifier, secret), publicKey)
      Copied!
  4. 4.
    The client fetches all the commitments from the Poof v2 smart contract representing all the account updates. We create a Merkle tree out of these commitments and represent it using the Merkle tree root inputRoot
  5. 5.
    The client calculates a Merkle tree's next state after inserting outputCommitment and represent this tree using the Merkle root outputRoot
  6. 6.
    The client now computes a zkSNARK proof that takes all these inputs to assert that the user runs the following program:
    1. 1.
      Check that output_balance - input_balance = amount where amount = 10
    2. 2.
      Check that input_debt - output_debt = debt where debt = 0
    3. 3.
      Hash the input account into inputCommitment
    4. 4.
      Check if input_commitment exists in the inputRoot tree. Skip this check if input_balance == 0
    5. 5.
      Hash the output account into outputCommitment
    6. 6.
      Check if output_commitment exists in the outputRoot tree
  7. 7.
    The client finally submits the proof to the smart contract along with the public inputs: amount, debt, inputRoot, and outputRoot. It also includes the encryptedAccount
  8. 8.
    The smart contract verifies that the submitted proof is valid given the public inputs for amount, debt, inputRoot, outputRoot inputCommitment and outputCommitment.
  9. 9.
    The smart contract pulls amount cUSD from the calling user and custodies it
  10. 10.
    The smart contract emits an event for the encryptedAccount and the outputCommitment.
Last modified 2mo ago
Copy link