Knowledge Base
  • Introduction
  • SHIELDING
    • Shielded pools
    • Key generation process
    • Privacy best practices
  • Fraud protection
  • Web App – User Guide
  • SMART YIELD
    • How does Smart Yield work?
    • Governance Model
    • Shielding
  • COMMON ECONOMY
    • The Economy of Common
    • CMN Token
    • CMN Tokenomics and Vesting Schedules
    • CMN Airdrops
    • Shared Fees and Reward Economics of Common
  • Wallet (Extension)
    • Introduction
    • Getting Started
    • Usage
    • Settings
  • DEX and Bridge (Aleph Zero WASM layer 1)
    • Account
      • How to Connect Your Wallet
      • Video Guide: How to Connect Your Wallet
      • How to Check Your Balance
      • Video Guide: How to Check Your Balance
    • Swap
      • How to Swap Tokens
      • Video Guide: How to Swap Tokens
    • Farm
      • How to Farm
      • Video Guide: How to Farm
    • Pool
      • Explaining Liquidity Pools
      • Video guide: Explaining Liquidity Pools
      • Managing Liquidity Pools with Custom Tokens
      • Video Guide: Managing Liquidity Pools with Custom Tokens
    • Bridge
      • How to Bridge With Most
        • Ethereum to Aleph Zero WASM
        • Aleph Zero WASM to Aleph Zero EVM
      • Video Guide: How to Bridge With MOST?
      • Bridging 10,000+ AZERO from Aleph Zero WASM to EVM
  • Protocol Details
    • Shielder
    • Overview
    • Design Against Bad Actors
    • Preliminaries: ZK Relations
    • Notes and Accounts
    • ZK-ID and Registrars
    • Anonymity Revokers
    • PoW Anonymity Revoking
    • Relayers
    • Deterministic Secret Management
    • SNARK-friendly Symmetric Encryption
    • SNARK-friendly Asymmetric Encryption
    • Cryptography
    • Token Shortlist
    • User Wallet
    • Versioning
    • PoC
    • Version 0.1.0
    • Version 0.2.0
Powered by GitBook
On this page
  • Id and secrets
  • Account
  • Recovery and account tracking
  • Relations

Was this helpful?

  1. Protocol Details

PoC

What will all this look like in the first version?

Description of initial PoC version that will be deployed to testnet only.

Id and secrets

In order to deposit any funds to the Shielder some on-chain transaction must be sent. Thus we assume that a user already has some native account with a corresponding private key (essentially, some 32 random bytes). For the sake of simplicity, we use this key as the user ID in the Shielder system. Note that there are no checks performed relating to the corresponding on-chain account - essentially, you can use arbitrary 32 bytes.

All other (operational) secrets, namely nullifiers and trapdoors, are generated as the Keccak256 hash of id || nonce || label, where:

  • id is the private key, as stated above

  • nonce is the counter of how many Shielder operations have been already done using id

  • label is a byte string, either b"nullifier" or b"trapdoor"

Account

In the PoC version, for the sake of simplicity, we only allow for shielding native AZERO tokens. Therefore, the only information (apart from operational secrets) kept in a note is the current shielded AZERO balance.

Recovery and account tracking

If you lose your shielded state (e.g., due to losing your device or accidentally deleting the state file), you can still recover your funds as long as you have your ID.

All Shielder transactions share a common property - every such action invalidates some nullifier. For deposits and withdrawals we just publish the hash of the nullifier of our current note. For the new-account action, we publish the hash of our ID, which can be seen as a special pre-nullifier. Shielder contract maintains a registry of all used (hashes of) nullifiers to prevent double spending or creating multiple accounts for the same ID. This is implemented as a mapping from a used nullifier hash to a block number when it was published.

Thanks to this design we can easily derive a recovery procedure as follows. Starting with a nonce 0, we repeatedly ask the contract whether a corresponding nullifier has already been spent, and if so, we can fetch the proper block, find our transaction and update the local state.

This also helps with account tracking. Since a user can interact with the Shielder from many different devices, we must always ensure, that the local state is up-to-date. Therefore, anytime our app is turned on, we check if the nullifier for the current note has been already spent. If so, then we just have to fetch latest transactions and update the state.

Relations

Preliminaries / Recap

Scalar is a type for some fixed finite field elements.

hash function is a hashing function from a sequence of Scalar elements into a single Scalar value.

AMOUNT_BOUND is some limit on the amounts handled by the Shielder, so that arithmetic operations do not overflow in the field. E.g. 2^128

MERKLE_HEIGHT is the height of the Merkle tree kept in the contract.

MERKLE_ARITY is the arity of the Merkle tree kept in the contract.

New Account

relation PoC::NewAccount

inputs:
    - h_note:          Scalar
    - h_id:            Scalar
    - initial_deposit: Scalar

witnesses:
    - id:        Scalar
    - nullifier: Scalar
    - trapdoor:  Scalar

assumptions:
    - initial_deposit <= AMOUNT_BOUND

constraints:
    // id is correctly exposed as a public input
    - h_id = hash(id)
    // note is well-formed
    - h_note = hash(id, nullifier, trapdoor, hash(initial_deposit))
    
suggestions:
    - nullifier = hash(id, 0, 0)
    - trapdoor  = hash(id, 0, 1)

Deposit

relation PoC::Deposit

inputs:
    - merkle_root:     Scalar
    - h_nullifier_old: Scalar
    - h_note_new:      Scalar
    - value:           Scalar

witnesses:
    - id:                  Scalar
    - nullifier_old:       Scalar
    - trapdoor_old:        Scalar
    - account_balance_old: Scalar
    - merkle_path:         [[Scalar; MERKLE_ARITY]; MERKLE_HEIGHT]
    - nullifier_new:       Scalar
    - trapdoor_new:        Scalar

assumptions:
    - value <= AMOUNT_BOUND
    - account_balance_old <= AMOUNT_BOUND

constraints:
    // new value satisfies the bound
    - account_balance_old + value <= AMOUNT_BOUND
    // old nullifier is correctly exposed as a public input
    - h_nullifier_old = hash(nullifier_old)
    // new note is well-formed
    - h_note_new = hash(id, nullifier_new, trapdoor_new, hash(account_balance_old + value))
    // membership proof is valid
    - merkle_path is a valid path to merkle_root
    // membership proof relates to the old note
    - hash(id, nullifier_old, trapdoor_old, account_balance_old) is belongs to the first layer of merkle_path
    

suggestions:
    - nullifier_old = hash(id, n, 0)
    - nullifier_new = hash(id, n+1, 0)
    - trapdoor_old = hash(id, n, 1)
    - trapdoor_new = hash(id, n+1, 1)

Withdraw

relation PoC::Withdraw

inputs:
    - merkle_root:        Scalar
    - h_nullifier_old:    Scalar
    - h_note_new:         Scalar
    - value:              Scalar
    - relayer:            Scalar
    - fee:                Scalar
    - withdrawal_address: Scalar

witnesses:
    - id:                  Scalar
    - nullifier_old:       Scalar
    - trapdoor_old:        Scalar
    - account_balance_old: Scalar
    - merkle_path:         [[Scalar; MERKLE_ARITY]; MERKLE_HEIGHT]
    - nullifier_new:       Scalar
    - trapdoor_new:        Scalar

assumptions:
    - value <= AMOUNT_BOUND
    - fee <= AMOUNT_BOUND
    - account_balance_old <= AMOUNT_BOUND

constraints:
    // new value satisfies the bound
    - account_balance_old >= value + fee
    // old nullifier is correctly exposed as a public input
    - h_nullifier_old = hash(nullifier_old)
    // new note is well-formed
    - h_note_new = hash(id, nullifier_new, trapdoor_new, hash(account_balance_old - value - fee))
    // membership proof is valid
    - merkle_path is a valid path to merkle_root
    // membership proof relates to the old note
    - hash(id, nullifier_old, trapdoor_old, account_balance_old) is belongs to the first layer of merkle_path
    

suggestions:
    - nullifier_old = hash(id, n, 0)
    - nullifier_new = hash(id, n+1, 0)
    - trapdoor_old = hash(id, n, 1)
    - trapdoor_new = hash(id, n+1, 1)

PreviousVersioningNextVersion 0.1.0

Last updated 5 days ago

Was this helpful?