LogoLogo
  • WELCOME TO ALEPH ZERO
  • EXPLORE
    • About Aleph Zero
    • AlephBFT Consensus
    • The Economy of Aleph Zero
    • Where to Buy AZERO
    • Decentralized Governance on Aleph Zero
    • Ecosystem
    • Aleph Zero Foundation Treasury Management
    • Community
    • Glossary
    • Audit & Research Papers
  • USE
    • Wallets
    • Explorer
    • Ledger
    • Telegram Notifications
    • Aleph Zero Signer
      • General introduction
      • What does Signer do?
      • What are Sub-accounts and Sub-account paths?
      • Why is it critical to store your Secret Phrase in a safe place?
      • How to forget and restore accounts?
      • What are Networks?
      • What are Trusted apps?
    • Dashboard
      • Dashboard basics
      • Overview
    • Stake
      • Staking Basics
      • Staking Menu Overview
      • How to Start Staking with the Aleph Zero Dashboard
      • How to Start Staking With the Developer Wallet
      • How to start staking using Ledger hardware wallet
      • How to Change Nominations
      • How to Stop Staking
      • Staking Rewards
      • Validators
      • Commission and Foundation Nodes
      • Proxy Accounts
    • Validate
      • Validating Overview
      • Hardware requirements
      • Running an Aleph Node on Testnet
        • Downloading and running the node
        • Verifying your setup
        • Customizing your setup
        • Building and running from source [advanced]
          • Building from source
          • Set environment variables
          • Download DB snapshot
          • Running the binary
        • Appendix: Ports, addresses, validators, and archivists
      • Running an Aleph Node on Mainnet
        • Running the node
        • Building and running from source [advanced]
      • Setting your identity
      • Making the node validate
      • Securing your validator
      • Troubleshooting
      • Elections and Rewards Math
      • Testnet Validator Airdrop
      • Foundation Nomination Program
    • Using the EVM-layer
    • Governance
      • Token
      • Multisig Accounts
  • BUILD
    • Aleph Zero smart contracts basics
      • Setting up a Testnet account
      • Installing required tools
      • Creating your first contract
      • Deploying your contract to Aleph Zero Testnet
      • Extending your contract
    • Cross contract calls
      • Using references
      • Using dynamic calls
    • Migrating from Solidity
    • Writing e2e tests with ink-wrapper
    • Aleph Zero Signer integration
    • Front-end app: smart contract interaction
    • Security Course by Kudelski Security
      • ink! Developers Security Guideline
      • Lesson 1 - Getting started with ink!
      • Lesson 2 - Threat Assessment
      • Lesson 3 - Integer Overflow
      • Lesson 4 - Signed-integer
      • Lesson 5 - Role-Based Access Control
      • Lesson 6 - Address Validation
      • Lesson 7 - Smart Contract Control
    • Development on EVM-layer
  • 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
    • Common DEX
      • Common Whitepaper - Differences
      • Dutch Auctions
  • FAQ
  • Tutorials
    • Withdrawing coins from exchanges
      • How to withdraw your AZERO coins from KuCoin
      • How to withdraw your AZERO coins from MEXC Global
      • How to withdraw your AZERO coins from HTX
  • Setting up or restoring a wallet
    • How to set up or recover your AZERO account using Aleph Zero Signer
    • How to set up or recover your AZERO account using the official mainnet web wallet
    • How to set up or recover your AZERO account using Nova Wallet
    • How to set up or recover your AZERO account using SubWallet
    • How to set up or recover your AZERO account using Talisman
  • Staking
    • How to stake via a direct nomination using the Aleph Zero Dashboard
    • How to stake via a nomination pool using the Aleph Zero Dashboard
    • How to destroy a nomination pool via the Aleph Zero Dashboard
Powered by GitBook
On this page
  • Anonymity Revoker Key
  • User Transactions
  • Modification to Transactions
  • Revoking Anonymity
  • Step 1)
  • Step 2)
  • Complete Deanonymization
  • Simpler variant of Revoking

Was this helpful?

  1. PROTOCOL DETAILS
  2. Shielder

Anonymity Revokers

Anonymity Revoker (AR in short) is a role that helps protecting the Shielder from bad actors. The main idea is that an AR would deanonymize all actions within the Shielder of a recognized bad actor. The typical scenario we have in mind here is as follows:

  1. Illicit funds are detected on chain that have been used to interact with the Shielder. For instance the funds come from a well known hack.

  2. A specific Shielder transaction, say a deposit, is determined to be using illicit funds.

  3. A governance process decides whether to deanonymize the user behind this deposit. And if it decides YES, then a request to deanonymize is sent to the AR.

  4. The AR reveals the transaction, and as a consequence (because of how the solution is built technically) this allows everyone to see the details of all other transactions performed by the illicit user, as if they were not using the Shielder at all.

Anonymity Revoker Key

The AR holds a private key AR_sk for asymmetric encryption and the corresponding public key AR_pk is a known parameter of the Shielder. The encryption scheme in use must be snark-friendly. Indeed, some transactions will need to include proofs of statements of the form:

Enc(AR_pk, m) = c

where m is some private input and c is public input. For a description of the concrete scheme that we use refer to SNARK-friendly Asymmetric Encryption.

User Transactions

For a ZK-ID id we define by key(id) a procedure key: Scalar -> Scalar that produces a symmetric encryption key out of the id. The key map should be one-way. The simplest example would be to use key(id) = hash(id) but there might be other constraints that might force us to use a different key derivation.

When making their first transaction, the user includes on chain (in the form of an event) an encrypted version of the key key(id) using the Anonymity Revoker's key AR_pk , thus Enc(AR_pk, key(id)) = e_key and importantly e_keymust be proved correct via a snark (so e_keymust enter as a public input in the circuit for creating new accounts). Note, since some accounts were created in Version 0.1.0 the migration transaction should expose e_keyinstead for these accounts.

Moreover, whenever the user makes a different kind of transaction (not their first), the following data is included

  • mac = (r, hash(r, key(id))) : (Scalar, Scalar) -- the HMAC "signature" of the user under a random nonce. This is to be able to identify the user's transactions among all other transactions knowing the key(id).

  • e_op = SymEnc(key(id), op_priv) -- this is an encryption of the private part of the operation op_priv: OpPriv the user is performing on its account, encrypted using a symmetric (snark-friendly) encryption scheme (see SNARK-friendly Symmetric Encryption) using key key(id). Note: op_privis empty in Version 0.1.0 hence this field can be also omitted.

Modification to Transactions

Note that adding the encryptions to the transaction requires some changes to what we introduced in Notes and Accounts and ZK-ID and Registrars -- for completeness we repeat the parts that change including the necessary modifications. The main idea though is simple: in the new_notetransaction we want to reveal our key(id)but only to the AR, and in the update_note transaction we need to put constraints checking the correctness of encryption and forming the mac.

Changes to new_note

We skip the part about registrar, because it's optional and it doesn't change

relation R_new_note

inputs:
    - h_note: Scalar,
    - nullifier_create: Scalar,
    - ar_pk: ASPkey,
    - e_key: ASCipherText,
    
witnesses:
    - note: Note,
    - trapdoor, nullifier: Scalar,
    - id: Scalar,

constraints:
    1. k = key(id)
    2. e_key = Enc(AR_pk, k)
    3. h_note = hash(note)
    4. note = Note { id, trapdoor, nullifier, h_acc }
    5. acc = Account::new(date)
    6. h_acc = Account::hash(acc) 
    7. nullifier_create = hash(id, NULL) // NULL is a special field element

In the above ASPkeyis the type holding public key of the asymmetric encryption primitive and ASCipherTextis the type of ciphertexts produced using the asymmetric encryption primitive.

Similarly we update the corresponding transaction

transaction new_note

inputs:
    - proof_new: ZkProof,
    - h_note: Scalar,
    - nullifier_create: Scalar,
    - e_key: ASCipherText,
    
execution:
    - v_new = ZK-Verifier(R_new_note) // initialize verifier for the relation R_new_note
    - // Below ar_pk should be the AR pub key held in the contract
    - assert: v_new.verify(proof_new; (h_note, nullifier_create, ar_pk, e_key))
    - assert: nullifier_create is not in shielder.nullifier_create_set
    - shielder.notes.add_leaf(h_note)
    - shielder.nullifier_create_set.add(nullifier_create)

Changes to update_note

relation R_update_note_op

inputs:
    - op_pub: OpPub // the public part of  the operation to be performed
    - h_note_new: Scalar,
    - merkle_root: Scalar,
    - h_nullifier_old: Scalar,
    - mac: (Scalar, Scalar),
    - e_op: Scalar^n
    
witnesses:
    - note_new, note_old: Note,
    - trapdoor_new, trapdor_old: Scalar
    - nullifier_new, nullifier_old: Scalar,
    - proof: MerkleProof
    - id: Scalar
        
constraints:
    1. h_note_new = hash(note_new)
    2. note_new = Note { id, trapdoor_new, nullifier_new, h_acc_new }
    3. h_note_old = hash(note_old)
    4. note_old = Note { id, trapdoor_old, nullifier_old, h_acc_old }
    5. h_nullifier_old = hash(nullifier_old)
    6. verify_merkle_proof(merkle_root, h_note_old, proof)
    7. op = combine(op_pub, op_priv)
    8. R_update_account_op(op, h_acc_old, h_acc_new)
    9. k = key(id)
    10. mac = (r, hash(r, k))
    11. e_op = SymEnc(k, op_priv)
transaction update_note_op

inputs:
    - op_pub: OpPub,
    - proof: ZkProof,
    - h_nullifier_old: Scalar,
    - merkle_root: Scalar,
    - h_note_new: Scalar,
    - mac: (Scalar, Scalar),
    - e_op: Scalar^n
    
execution:
    - shielder.public_exec(op_pub)
    - assert: merkle_root is the current or historical root of shielder.notes
    - assert: h_nullifier_old not in shielder.nullifier_set
    - v = ZK-Verifier(R_update_note_op) // initialize verifier for the relation R_update_note_op
    - assert: v.verify(proof; (op_pub, h_note_new, merkle_root, h_nullifier_old, mac, e_op))
    - shielder.notes.add_leaf(h_note_new)
    - shielder.nullifier_set.add(h_nullifier_old)

Revoking Anonymity

In case the anonymity revocation procedure is triggered on a transaction tx, the AR proceeds in two steps: 1) Find the key(id)of the user (account) who created this transaction.

2) Find all transactions created by the user with the key(id)found in step 1).

We now explain both steps in detail.

Step 1)

Each transaction has a mac=(r,c)attached to it, which is essentially a symmetric signature of a user, but to recognize the user we must know the associated key. To find out the valid key ksuch that

mac = (r, c) = (r, hash(r, k))

the AR can simply collect ALL the keys that have been registered by users in their new_notetransactions, and then find the unique key kthat satisfies hash(r, k) = c.

Note that (although this is not crucial) there exists exactly one such user idwhose key(id)satisfies the above — this is because we guarantee that there are no duplicates among id's (by using the nullifiers upon creating the account) and key(id) is a deterministic hash-based procedure to generate a key, hence the collision-free property of the hash function guarantees there are no collisions among key(id)s either.

Having found the key key(id)the AR can reveal the key publicly — this way each 3rd party observer will be able to perform step 2). Note that, importantly, given just key(id)the 3rd party observer can verify that the reveal is correct, because they can simply verify that the macis valid. In particular, they don't need access to the AR's key.

Step 2)

The AR, or any interested 3rd party observer, given key(id)can now find all transactions issued by used id. The method is very simple:

  • Loop over ALL transactions sent to the Shielder, and check which of the macs were generated using this particular key(id) — these are exactly the transactions we are looking for.

Complete Deanonymization

After performing the above steps 1) and 2) one can recover the complete history of this user's account and in particular recover the current state, and see all the new transactions (that they might send in the future) of the user in the plain.

Simpler variant of Revoking

We note that Shielder in Version 0.0.1 is released with a simpler AR scheme based on PoW. The details are presented in PoW Anonymity Revoking.

PreviousZK-ID and RegistrarsNextPoW Anonymity Revoking

Last updated 2 months ago

Was this helpful?