License: CC BY-NC-ND 4.0
arXiv:2307.00521v4 [cs.CR] 09 Mar 2024

zkFi: Privacy-Preserving and Regulation Compliant Transactions using Zero Knowledge Proofs
June 2023

Naveen Sahu nvnx@zkfi.tech Mitul Gajera mitul@zkfi.tech  and  Amit Chaudhary amit@zkfi.tech
Abstract.

We propose a middleware solution designed to facilitate seamless integration of privacy using zero-knowledge proofs within various multi-chain protocols, encompassing domains such as DeFi, gaming, social networks, DAOs, e-commerce, and the metaverse. Our design achieves two divergent goals. zkFi aims to preserve consumer privacy while achieving regulation compliance through zero-knowledge proofs. These ends are simultaneously achievable. zkFi protocol is designed to function as a plug-and-play solution, offering developers the flexibility to handle transactional assets while abstracting away the complexities associated with zero-knowledge proofs. Notably, specific expertise in zero-knowledge proofs (ZKP) is optional, attributed to zkFi’s modular approach and software development kit (SDK) availability.

copyright: none
[Uncaptioned image]

1. Introduction

Achieving privacy in blockchain applications presents unique challenges - often requiring trade-offs between user experience and privacy. The transparent nature of conventional blockchains reveals all of the transaction data, including addresses, assets involved, amount, smart-contract data, and timestamps, out to the public. It is analogous to using a regular bank account and revealing all private financial information, deterring the mass adoption of blockchain and digital asset technology.

As this space continues to evolve and more institutional and individual users engage in activities on these applications, privacy will become a paramount concern creating the biggest hurdle for achieving mainstream adoption. Individuals contemplating the adoption of blockchain-based payment systems may exhibit considerable hesitance if their salaries or other confidential financial details, such as payments for medical services and their online purchases, are accessible to the public. This demand for privacy will also be from social networking platforms, decentralized lending protocols, philanthropic platforms, e-commerce, gaming, and other protocols where users want to prioritize safeguarding the privacy of their information.

While there is a clear need for privacy solutions, regulatory scrutiny of privacy protocols necessitates action to develop practical and fair measures that deter bad actors from engaging in on-chain illicit activity. Selective De-anonymization, as mentioned in (a16z, ), lays out a method for allowing traceability. Particularly, an instantiation of involuntary de-anonymization as practically studied in (compliance-sol, ) can prove to be a flagship regulation-compliant technique that can be used when a malicious actor refuses to comply with the law.

In this paper, we propose a privacy-preserving solution with solid regulatory compliance using zero-knowledge proofs and threshold cryptography having the following features:

  • A general purpose multi-chain privacy solution spanning across multiple EVM chains.

  • Available with simple, composable and flexible plug-and-play middleware solution via an SDK.

  • Secure with built-in compliance solution with concrete AML practices.

  • Providing a seamless user-experience using account abstraction and wallet integrations (mm-snaps, ; ledger-apps, ).

2. Limitations in current architecture

At present most widely used programmable blockchains (e.g. EVM based chains such as Ethereum, Polygon, Optimism, Arbitrum) offer benefits such as permissionless nature, decentralization, and security, but these blockchains do not offer privacy. Alternative blockchain networks have been aiming to create solutions from scratch, to eliminate the pitfalls but fail to near the activity and value of mentioned public chains. This necessitates a solution to multiple problems on the public chain itself.

Lack of Privacy

A regular on-chain transaction exposes private data and transactions to the public. The data such as sender/receiver address, asset type, and quantity, smart-contract data, timestamps, etc. are conveniently available in an organized manner to the general public through block explorers such as Etherscan (etherscan, ). This information can be used to track funds for targeted attacks, identify users, and extract sensitive information and patterns about their activity. These pitfalls prevent the adoption of revolutionary blockchain applications by several serious users, especially users like institutional investors and businesses.

Weak Compliance

Privacy problem implicitly poses another severe issue of compliance. How to have robust compliance in place and prevent bad actors while maintaining user privacy? Enabling privacy on decentralized platforms has been very well known to attract malicious actors abusing the platform. These include using it for illicit activities like laundering stolen funds from hacks or preparing for one. Most of the time, these actors have succeeded because of the lack of firm AML (Anti-Money Laundering) practices to deter bad actors. Weak compliance deters institutional investors or businesses from entering the blockchain space for legitimate usage.

Lack of Infrastructure

Building private applications on the blockchain has been made possible by the advancements in Zero Knowledge (ZK). However, implementing ZK technology is complicated. Developers need specialized knowledge and resource investment in ZK development. This creates overhead and distraction from the divergence of resources from developing a core of their applications.

Poor User-Experience

These distractions and overheads due to the lack of middleware privacy solutions lead to a subpar developer and user experience. Even if the application develops its privacy layer, the UI/UX faces challenges for users. While UX is still an area to be improved in web3 generally - it is even worse in the ecosystem of privacy-preserving applications.

2.1. Previous Solutions

ZCash blockchain was among the first to tackle privacy by facilitating anonymous transactions. While innovations there have been impressive, they could not reach the intended adoption nor offered any programmability - restricting only to peer-to-peer transactions. Hence, missing out on the prominent application level use-case for, eg. DeFi. Monero, another private chain, more or less shares the same context.

Tornado protocol on Ethereum amassed a significant number of usage despite not-so-good UX. But it overlooked compliance and became go-to-place for money laundering (trm-labs, ). A portion of its volume has ties to large-scale hacks (Chainalysis, ), attracting serious implications from regulators. It, too, only offered peer-to-peer private transactions lacking any interoperability beyond that. Aztec came up with a novel solution with their L2 roll-up approach that had DeFi compatibility to some extent. However, it required users to bridge their assets back and forth and had significant waiting times - making it not-so-practical for all kinds of DeFi interaction, e.g. in swaps because of slippage.

Others also share the same problems, especially weak compliance guarantees and friction in user experiences.

3. zkFi: A Middleware Solution

Refer to caption
Figure 1. Middleware Solution

To tackle problems, as discussed above, zkFi offers a packaged solution that acts as a privacy middleware with built-in compliance. Privacy and compliance-related complexity are abstracted away by providing the developers with an SDK that facilitates a plug-and-play solution.

3.1. Privacy with Zero Knowledge Proofs (ZKPs)

zkFi uses ZKPs to facilitate privacy at its core by achieving the following goals:

  • Performing private transactions concealing sender, recipient, and amount of funds being transferred.

  • Ensuring transactions cannot be linked together, preventing tracking the flow of funds.

  • Preventing double-spending by proving the transaction is valid without revealing information about the transaction itself.

  • Selective de-anonymization by ensuring verifiable encryption of transaction data.

While there are multiple formulations of ZKP systems available and being researched, zkFi specifically utilizes a groth16 (groth16, ) zkSNARK system which is currently most suitable for on-chain privacy applications.

3.2. Stronger Compliance Guarantees

Compliance has been the conundrum for privacy protocols so far. zkFi aims to have an industry-standard compliance framework such as:

  • Selective De-Anonymization: For an industry-standard AML practice, a process for the de-anonymization of user-specific private transaction data needs to be followed. It could be a voluntary de-anonymization where the entity in question can share general or per-transaction viewing key to a regulatory authority. In other cases (for malicious actors), involuntary de-anonymization may be enforced in response to a regulatory emergency or court order. The latter is an accountable multi-party process to prevent abuse of power. It is thoroughly studied in (compliance-sol, ) as SeDe (short for Selective De-anonymization) framework for compliance and is a flagship among all compliance tools available.

  • Deposit Limits: We put a fiat limit on the asset being transacted and/or the volume flowing through the protocol in a time period. There can be a provision to relax this limit for specific entities like a compliant businesses.

  • Risk Management and Screening The protocol sets up compliance and risk management integrations to identify and prevent any kind of illegal financial activity. This could be achieved by services like TRM Labs111https://www.trmlabs.com/ products and Chainalysis222https://go.chainalysis.com/chainalysis-oracle-docs.html oracles perform screening and identifying inflow of illegal funds into the system.

3.3. Pluggable Privacy With SDK

By offering an SDK, a full set of compliant privacy features is instantly available to protocols and their developers. SDK facilitates a simple composable plug-and-play solution that abstracts away every bit of ZKPs or compliance-specific complexities. This renders immense benefits to protocols such as:

  • New protocols can focus on developing their core features without investing time and resources into ZK development.

  • Existing protocols do not have to modify their smart contracts for compatibility. It’s a simple plug-and-play through SDK.

  • Compliance issues often come as part of a privacy conundrum. But with zkFi, protocols will not have the burden of juggling privacy-related compliance practices.

In addition to the advantages mentioned above, the flexibility of interaction with the integrating protocol remains at the hands of a developer. Given private user assets and/or data as input, developers are free to write any custom logic to apply to the inputs.

See section 6.4 for implementation details.

3.4. Account Abstraction and UX

The advent of EIP-4337 (eip-4337, ) Account Abstraction proposal allowed for significant improvements in user experience across protocols. One such improvement or feature it brings is the ability for smart contracts to pay for gas fees of transactions. This allows for gas-sponsored transactions or payment of gas fees in ERC-20 tokens.

In privacy protocols, there exists a common problem referred to as gas dilemma or fee payment dilemma. A gas dilemma exists because if users need to pay the gas fees from their wallet to execute their transactions then this gas payment discloses the user’s public profile since their address as the sender of the transaction is now visible publicly.

zkFi uses account abstraction features from EIP-4337 so that the gas fee can be paid in ERC-20 tokens making transactions on zkFi a smooth experience. The flexibility of gas payment is left to the integrating protocol - allowing it to sponsor transaction fees or charge from their users in any desired way. In the case of peer-to-peer transactions, a user simply pays gas in transacting assets. This is facilitated through a custom EIP-4337 Paymaster contract that pays the gas on the user’s behalf in exchange for a small fee in any supported asset.

3.5. Wallet Integrations

By implementing a simple interface, provided within SDK, for the shielded account operations (e.g. signing private transactions), crypto wallet applications can support private transactions for their users. In that case, the shielded account keys share the same security space as the wallet’s private keys. Developers simply send defined requests to the shielded account for, say, authorizing transactions by signing it. This allows developers to directly use the shielded account in their application UIs without concern about securely handling sensitive keys.

Some examples of such wallet integrations are:

  • MetaMask: MetaMask is a browser extension as a crypto wallet. Through its Snaps API (mm-snaps, ) it allows developers to extend its functionality by publishing custom packages of logic called ”Snap”. One such Snap, the ”zkFi Snap” acts as an interface to the shielded accounts within MetaMask.

  • Ledger: Ledger is a hardware wallet that securely stores private keys for multiple cryptocurrencies. It allows Embedded Apps (ledger-apps, ) to be installed on the user’s device. A zkFi app is one such app tailored to securely store shielded account keys and authorize private transactions from the device.

4. Use Cases of zkFi

Pluggable Privacy for DeFi protocols

As mentioned, previously in section 3.3, the design of the infrastructure allows any existing DeFi protocol for seamless integration to enable anonymous transactions.

For instance, consider Aave333https://aave.com/ which is a lending/borrowing liquidity protocol. Aave users normally supply assets to one of Aave markets and get interest-bearing tokens a.k.a aToken444https://docs.aave.com/developers/tokens/atoken in return. For Aave to let its users supply assets anonymously, it’d just require a simple stateless proxy contract, let’s call it AaveProxy. The job of AaveProxy is just to take an asset and return the corresponding aToken asset by talking to APIs already written by Aave in their core contracts. The proxy is very loosely coupled, no ZK circuit programming is required at all nor any changes in Aave’s existing contracts.

The same kind of seamless integration is possible with other protocols for - earning interest anonymously on Compound, doing anonymous swaps on Uniswap, staking anonymously on Lido, and many more.

Private Payments via Stealth Address

While normal peer-to-peer private transactions are supported, one may opt to receive assets in the form of payment to their stealth address - which preserves anonymity one can share a random-looking address each time.

So, for instance, payment links can be generated by a receiver and can be shared with a sender such that the shared link has no traceability to any previous payment. This is similar to sharing payment links in Stripe555https://stripe.com/in/payments/payment-links but with anonymity.

Shielded Account for protocol UIs

Via its integration directly in existing crypto wallets, starting with MetaMask Snaps integration, any protocol may request spending of user’s private assets instead of public assets from a normal wallet. This frees protocols to define their own custom UIs on their own domains and request interaction with Shielded Wallet however it wants.

This adds up with a better user experience thanks to built-in account abstraction features like gasless transactions.

zkFi strives to offer a general solution, so it is future compatible with other use cases that may arise as the need for privacy is realized more and more.

5. Architecture

The diagram in figure 2 shows an architectural overview of the system with involved actors and their interaction with each other:

Refer to caption
Figure 2. Architecture Diagram
Wallet Provider

The host for shielded account. This includes crypto wallets (e.g. MetaMask and Ledger) which provide functionalities to deterministically derive keys of shielded account from ethereum account of user.

Consumer

The consumer of the SDK that communicates with the Shielded Account via a connection to the wallet provider. It can invoke private transaction approvals by requesting transaction signature. The SDK consumers can be an application user interface or command-line applications which can construct complex transactions by passing only simple transaction requests to SDK. The SDK parses the request and handles creation, signing and (ZK) proving of the transaction. Ultimately, SDK outputs a suitable transaction payload to be sent on-chain.

EIP-4337 Bundler

A bundler sends the transactions to the network through a EIP-4337 bundler node rather than directly from a wallet. This has two main benefits - the user avoids exposing their wallet address publicly and it can pay for the gas with shielded/private assets itself.

Gas Price Oracle

A decentralized oracle to consulted by SDK and paymaster to calculate the equivalent amount of gas price in ERC-20 tokens at the time of transaction. A decentralized exchange like Uniswap (uniswap-oracle, ) could be a suitable oracle.

EIP-4337 Paymaster

A custom EIP-4337 compatible paymaster that pays for the user operations in exchange for fees cut in the asset being transacted. The paymaster validates the operation after consulting Gas Price Oracle and making sure enough fee will be paid.

Core

The core of zkFi protocol encapsulates a multi-transactional multi-asset pool, an asset manager, a merkle tree of notes and an on-chain ZK proof verifier. See section 6.3.

Convertor

A smart contract that mediates the convert operation on behalf of core. It involves calling target protocol (e.g. DeFi) via its proxy for performing an operation (e.g. swap, stake, lend) and returning any resulting assets as a result of operation, back to core.

Protocol Proxy

Proxies are simple smart contracts that implement/extend a simple interface/base provided by SDK. Doing this allows it to plug nicely into the Core and be able to receive assets from it to perform any DeFi operation. See section 6.4.

Guardians

Guardians are multi-party entities that exist to perform the involuntary selective de-anonymization process upon a verifiable request from a revoker entity as per the (compliance-sol, ). See section 6.5.

6. Building Blocks

6.1. Shielded Account

A user holding a shielded account can sign valid transactions and decrypt balances and transaction data. Unlike normal Ethereum accounts which are controlled by a single private key, a shielded account contains two types of such keys.

We assume the existence of a cryptographically secure random number generator (RNG) function used to generate private keys:

(1) 𝚁𝙽𝙶:ϕ𝔹256;()ξ:𝚁𝙽𝙶formulae-sequenceitalic-ϕsuperscript𝔹256maps-to𝜉\mathtt{RNG}\colon\phi\to\mathbb{B}^{256};()\mapsto\xitypewriter_RNG : italic_ϕ → blackboard_B start_POSTSUPERSCRIPT 256 end_POSTSUPERSCRIPT ; ( ) ↦ italic_ξ

We cryptographically derive the keys of the shielded account using the 𝚙𝚘𝚜𝚎𝚒𝚍𝚘𝚗𝚙𝚘𝚜𝚎𝚒𝚍𝚘𝚗\mathtt{poseidon}typewriter_poseidon hash function (from 25) and group operations on the BabyJubJub curve (see Sec. 7.2).

6.1.1. Sign Key

The sign private key can sign valid transactions authorizing the spending of user funds in shielded accounts. A new private key is generated by first sampling an entropy element, ξ𝜉\xiitalic_ξ by invoking 𝚁𝙽𝙶𝚁𝙽𝙶\mathtt{RNG}typewriter_RNG and then hashing it with a fixed salt value ΔsignsubscriptΔ𝑠𝑖𝑔𝑛\Delta_{sign}roman_Δ start_POSTSUBSCRIPT italic_s italic_i italic_g italic_n end_POSTSUBSCRIPT.

(2) s=𝚙𝚘𝚜𝚎𝚒𝚍𝚘𝚗(ξ,Δsign)𝑠𝚙𝚘𝚜𝚎𝚒𝚍𝚘𝚗𝜉subscriptΔ𝑠𝑖𝑔𝑛s=\mathtt{poseidon}(\xi,\Delta_{sign})italic_s = typewriter_poseidon ( italic_ξ , roman_Δ start_POSTSUBSCRIPT italic_s italic_i italic_g italic_n end_POSTSUBSCRIPT )

The corresponding public key S𝑆Sitalic_S is simply a point on the curve as:

(3) S=sG𝑆𝑠𝐺S=s\cdot Gitalic_S = italic_s ⋅ italic_G

6.1.2. View Key

The view private key decrypts the user balances and transaction history. This private key is generated by hashing the entropy ξ𝜉\xiitalic_ξ with salt ΔviewsubscriptΔ𝑣𝑖𝑒𝑤\Delta_{view}roman_Δ start_POSTSUBSCRIPT italic_v italic_i italic_e italic_w end_POSTSUBSCRIPT:

(4) p=𝚙𝚘𝚜𝚎𝚒𝚍𝚘𝚗(ξ,Δview)𝑝𝚙𝚘𝚜𝚎𝚒𝚍𝚘𝚗𝜉subscriptΔ𝑣𝑖𝑒𝑤p=\mathtt{poseidon}(\xi,\Delta_{view})italic_p = typewriter_poseidon ( italic_ξ , roman_Δ start_POSTSUBSCRIPT italic_v italic_i italic_e italic_w end_POSTSUBSCRIPT )

and public key is P=pG𝑃𝑝𝐺P=p\cdot Gitalic_P = italic_p ⋅ italic_G.

During the construction of a transaction, p𝑝pitalic_p is used to symmetrically encrypt transaction data (e.g. amounts, owner) using ChaCha20-Poly1305 encryption scheme (chacha20, ). The resulting ciphertext is decrypted and later utilized for future transactions.

Having a distinct key for read-only access renders multiple advantages including revealing p𝑝pitalic_p for compliance purposes without giving up spending authority and allowing protocol websites for read-only access of data to display on their custom UIs.

This also allows to have a transaction-specific view key giving the ability to reveal only selected transactions or protocol-specific viewing keys so that protocol websites only get to read data relevant to it rather than the entire transaction history.

6.1.3. Shielded Address

The shielded address, A𝐴Aitalic_A of a shielded account is the public key of both key pairs:

(5) A(S,P)𝐴𝑆𝑃A\equiv(S,P)italic_A ≡ ( italic_S , italic_P )

A user may choose to post A𝐴Aitalic_A on a public address registry for others to look it up using public wallet addresses or ENS names and conveniently send funds to address A𝐴Aitalic_A. Although A𝐴Aitalic_A is not directly used as is while associating funds to it in a zkFi transaction, it allows the derivation of a random-looking ”stealth address”, x𝑥xitalic_x from A𝐴Aitalic_A. x𝑥xitalic_x is then used instead for the purpose.

For the sake of better user experience for crypto wallet users, the 𝚁𝙽𝙶𝚁𝙽𝙶\mathtt{RNG}typewriter_RNG at equation 1 should be facilitated by the wallet application, and the entropy ξ𝜉\xiitalic_ξ be seeded by the private key or seed phrase. This is possible with the wallet integrations (see Sec 3.5). In that case, the keys of the shielded account can be derived from the wallet account itself. This frees the user from handling additional keys.

6.2. Stealth Address

A stealth address is a one-time address that is randomly generated to receive funds to. This address is not linked to the receiver’s permanent address. Hence making it difficult to link or track a particular user’s transactions and protect their identity.

There are multiple different schemes available for deriving a stealth address from a user account. These schemes allow the receiver to detect funded stealth addresses meant for them and calculate the associated private key from auxiliary data, normally sent along with the transaction. The calculated private key can then be used to sign transactions authorizing the spending of funds at that stealth address. One example of such a scheme is defined in EIP-5564 (eip-5564, ).

In zkFi, we primarily use ZK proofs (but also signatures) for constructing valid transactions. This allows for a much simpler and more efficient way to generate and use stealth addresses in the protocol. A zkFi stealth address, x𝑥xitalic_x is derived from sign public key S𝑆Sitalic_S as:

(6) x=𝚙𝚘𝚜𝚎𝚒𝚍𝚘𝚗((S,δ))𝑥𝚙𝚘𝚜𝚎𝚒𝚍𝚘𝚗𝑆𝛿x=\mathtt{poseidon}((S,\delta))italic_x = typewriter_poseidon ( ( italic_S , italic_δ ) )

where δ𝛿\deltaitalic_δ is a random element also referred to as a blinding factor.

To relay any auxiliary data to be included in the transaction request, the sender generates an ephemeral public key, Q=rG𝑄𝑟𝐺Q=r\cdot Gitalic_Q = italic_r ⋅ italic_G where r𝔹248𝑟superscript𝔹248r\in\mathbb{B}^{248}italic_r ∈ blackboard_B start_POSTSUPERSCRIPT 248 end_POSTSUPERSCRIPT is another random element.

A sender then calculates a shared key K𝐾Kitalic_K from the view public key P𝑃Pitalic_P of the receiver as:

(7) K=rP𝐾𝑟𝑃K=r\cdot Pitalic_K = italic_r ⋅ italic_P

K𝐾Kitalic_K is used to encrypt any desired sensitive transaction data, e.g. δ𝛿\deltaitalic_δ, to get a ciphertext, C𝐶Citalic_C.

A view tag, t𝑡titalic_t for this stealth address or transaction is the most significant byte of the hash of K𝐾Kitalic_K:

(8) t=𝚔𝚎𝚌𝚌𝚊𝚔𝟸𝟻𝟼(K)[0:1]t=\mathtt{keccak256}(K)[0:1]italic_t = typewriter_keccak256 ( italic_K ) [ 0 : 1 ]

t𝑡titalic_t, x𝑥xitalic_x, Q𝑄Qitalic_Q and C𝐶Citalic_C are concatenated to form auxiliary data (txQC)conditional𝑡norm𝑥𝑄𝐶(t\|x\|Q\|C)( italic_t ∥ italic_x ∥ italic_Q ∥ italic_C ) to be broadcasted along with the transaction.

A user parses the auxiliary data of a transaction and tries to calculate a shared key Ksuperscript𝐾K^{\prime}italic_K start_POSTSUPERSCRIPT ′ end_POSTSUPERSCRIPT using its view private key psuperscript𝑝p^{\prime}italic_p start_POSTSUPERSCRIPT ′ end_POSTSUPERSCRIPT and Q𝑄Qitalic_Q as:

(9) K=pQsuperscript𝐾superscript𝑝𝑄K^{\prime}=p^{\prime}\cdot Qitalic_K start_POSTSUPERSCRIPT ′ end_POSTSUPERSCRIPT = italic_p start_POSTSUPERSCRIPT ′ end_POSTSUPERSCRIPT ⋅ italic_Q

And calculates a view tag vsuperscript𝑣v^{\prime}italic_v start_POSTSUPERSCRIPT ′ end_POSTSUPERSCRIPT from Ksuperscript𝐾K^{\prime}italic_K start_POSTSUPERSCRIPT ′ end_POSTSUPERSCRIPT using equation 8. If vvsuperscript𝑣𝑣v^{\prime}\neq vitalic_v start_POSTSUPERSCRIPT ′ end_POSTSUPERSCRIPT ≠ italic_v, the user is not the receiver. It stops.

Otherwise, the receiver continues and uses Ksuperscript𝐾K^{\prime}italic_K start_POSTSUPERSCRIPT ′ end_POSTSUPERSCRIPT to perform decryption of C𝐶Citalic_C to retrieve the plaintext data, e.g. δsuperscript𝛿\delta^{\prime}italic_δ start_POSTSUPERSCRIPT ′ end_POSTSUPERSCRIPT, that was encrypted before. The receiver uses δsuperscript𝛿\delta^{\prime}italic_δ start_POSTSUPERSCRIPT ′ end_POSTSUPERSCRIPT to calculate the stealth address xsuperscript𝑥x^{\prime}italic_x start_POSTSUPERSCRIPT ′ end_POSTSUPERSCRIPT (using equation 6). The user performs an additional check that x=xsuperscript𝑥𝑥x^{\prime}=xitalic_x start_POSTSUPERSCRIPT ′ end_POSTSUPERSCRIPT = italic_x (hence, δ=δsuperscript𝛿𝛿\delta^{\prime}=\deltaitalic_δ start_POSTSUPERSCRIPT ′ end_POSTSUPERSCRIPT = italic_δ) to be sure that it is indeed the receiver just in case the view tag match was a false positive.

To spend the asset the receiver is now able to prove a statement 𝒮xsubscript𝒮𝑥\mathcal{S}_{x}caligraphic_S start_POSTSUBSCRIPT italic_x end_POSTSUBSCRIPT defined as:

(10) 𝒮xKnowledge of (s,δ):x=𝚙𝚘𝚜𝚎𝚒𝚍𝚘𝚗(S,δ):subscript𝒮𝑥Knowledge of 𝑠𝛿𝑥𝚙𝚘𝚜𝚎𝚒𝚍𝚘𝚗𝑆𝛿\mathcal{S}_{x}\equiv\text{Knowledge of }(s,\delta)\colon x=\mathtt{poseidon}(% S,\delta)caligraphic_S start_POSTSUBSCRIPT italic_x end_POSTSUBSCRIPT ≡ Knowledge of ( italic_s , italic_δ ) : italic_x = typewriter_poseidon ( italic_S , italic_δ )

The proof of 𝒮xsubscript𝒮𝑥\mathcal{S}_{x}caligraphic_S start_POSTSUBSCRIPT italic_x end_POSTSUBSCRIPT is included in the ZK proof 𝝅𝝅\boldsymbol{\pi}bold_italic_π of the transaction to prove the ownership of x𝑥xitalic_x.

6.3. Core

Core smart contracts of the zkFi protocol. The core includes a multi-transactional multi-asset pool, meaning the pool supports multiple assets and can transact multiple assets in a single transaction. The on-chain ZK Verifier verifies the proof submitted during the transaction.

6.3.1. Setup

Let 𝒯𝒯\mathcal{T}caligraphic_T be the Merkle tree whose leaves are calculated using the poseidon hash function (equation 25). The tree leaf nodes are subsequently filled with note 𝐜𝐨𝐦𝐦𝐢𝐭𝐦𝐞𝐧𝐭𝐜𝐨𝐦𝐦𝐢𝐭𝐦𝐞𝐧𝐭\mathbf{commitment}bold_commitments in an append-only fashion.

A note is a tuple N𝑁Nitalic_N of multiple elements:

(11) N(e,x,v,δ)𝑁𝑒𝑥𝑣𝛿N\equiv(e,x,v,\delta)italic_N ≡ ( italic_e , italic_x , italic_v , italic_δ )

where, e𝔹24𝑒superscript𝔹24e\in\mathbb{B}^{24}italic_e ∈ blackboard_B start_POSTSUPERSCRIPT 24 end_POSTSUPERSCRIPT is the asset identifier and x𝔹248𝑥superscript𝔹248x\in\mathbb{B}^{248}italic_x ∈ blackboard_B start_POSTSUPERSCRIPT 248 end_POSTSUPERSCRIPT is the stealth address of the owner, v𝔹248𝑣superscript𝔹248v\in\mathbb{B}^{248}italic_v ∈ blackboard_B start_POSTSUPERSCRIPT 248 end_POSTSUPERSCRIPT is associated value of the note and δ𝛿\deltaitalic_δ is the blinding factor from which x𝑥xitalic_x was generated.

The 𝐜𝐨𝐦𝐦𝐢𝐭𝐦𝐞𝐧𝐭𝐜𝐨𝐦𝐦𝐢𝐭𝐦𝐞𝐧𝐭\mathbf{commitment}bold_commitment, c𝑐citalic_c of a note is:

(12) c=𝚙𝚘𝚜𝚎𝚒𝚍𝚘𝚗(e,x,v)𝑐𝚙𝚘𝚜𝚎𝚒𝚍𝚘𝚗𝑒𝑥𝑣c=\mathtt{poseidon}(e,x,v)italic_c = typewriter_poseidon ( italic_e , italic_x , italic_v )

Let σ𝜎\sigmaitalic_σ be the signature generated with sign key s𝑠sitalic_s that authenticates the ownership of N𝑁Nitalic_N as:

(13) σ=𝚂𝚌𝚑𝚗𝚘𝚛𝚛_𝚂𝚒𝚐𝚗(c,s)𝜎𝚂𝚌𝚑𝚗𝚘𝚛𝚛_𝚂𝚒𝚐𝚗𝑐𝑠\sigma=\mathtt{Schnorr\_Sign}(c,s)italic_σ = typewriter_Schnorr _ typewriter_Sign ( italic_c , italic_s )

where 𝚂𝚌𝚑𝚗𝚘𝚛𝚛_𝚂𝚒𝚐𝚗𝚂𝚌𝚑𝚗𝚘𝚛𝚛_𝚂𝚒𝚐𝚗\mathtt{Schnorr\_Sign}typewriter_Schnorr _ typewriter_Sign is as defined in 30.

Let η𝜂\etaitalic_η be the nullifier hash of note N𝑁Nitalic_N defined as:

(14) η=𝚙𝚘𝚜𝚎𝚒𝚍𝚘𝚗(l,c,δ)𝜂𝚙𝚘𝚜𝚎𝚒𝚍𝚘𝚗𝑙𝑐𝛿\eta=\mathtt{poseidon}(l,c,\delta)italic_η = typewriter_poseidon ( italic_l , italic_c , italic_δ )

where l𝑙litalic_l is index of note commitment c𝑐citalic_c as leaf node in 𝒯𝒯\mathcal{T}caligraphic_T.

Let’s define a set of public inputs, ρ𝜌\rhoitalic_ρ to the prover as:

ρ(R,𝐕,𝐄,𝜼in,𝐜out)𝜌𝑅𝐕𝐄superscript𝜼𝑖𝑛superscript𝐜𝑜𝑢𝑡\rho\equiv(R,\mathbf{V},\mathbf{E},\boldsymbol{\eta}^{in},\mathbf{c}^{out})italic_ρ ≡ ( italic_R , bold_V , bold_E , bold_italic_η start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT , bold_c start_POSTSUPERSCRIPT italic_o italic_u italic_t end_POSTSUPERSCRIPT )

where,

  • R𝑅Ritalic_R is root of 𝒯𝒯\mathcal{T}caligraphic_T.

  • 𝐕𝐕\mathbf{V}bold_V is a list of m𝑚mitalic_m public values for each output note. A value V𝑉Vitalic_V in list 𝐕𝐕\mathbf{V}bold_V is considered negative for any value leaving the pool, positive otherwise.

  • 𝐄insuperscript𝐄𝑖𝑛\mathbf{E}^{in}bold_E start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT is a list of public asset identifiers corresponding to public values.

  • 𝜼in=(η1,η2,,ηn)superscript𝜼𝑖𝑛subscript𝜂1subscript𝜂2subscript𝜂𝑛\boldsymbol{\eta}^{in}=(\eta_{1},\eta_{2},...,\eta_{n})bold_italic_η start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT = ( italic_η start_POSTSUBSCRIPT 1 end_POSTSUBSCRIPT , italic_η start_POSTSUBSCRIPT 2 end_POSTSUBSCRIPT , … , italic_η start_POSTSUBSCRIPT italic_n end_POSTSUBSCRIPT ) is list of nullifier hashes corresponding to n𝑛nitalic_n input notes 𝐍in=(N1in,N2in,Nnin)superscript𝐍𝑖𝑛subscriptsuperscript𝑁𝑖𝑛1subscriptsuperscript𝑁𝑖𝑛2subscriptsuperscript𝑁𝑖𝑛𝑛\mathbf{N}^{in}=(N^{in}_{1},N^{in}_{2},...N^{in}_{n})bold_N start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT = ( italic_N start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT start_POSTSUBSCRIPT 1 end_POSTSUBSCRIPT , italic_N start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT start_POSTSUBSCRIPT 2 end_POSTSUBSCRIPT , … italic_N start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT start_POSTSUBSCRIPT italic_n end_POSTSUBSCRIPT ).

  • 𝐜outsuperscript𝐜𝑜𝑢𝑡\mathbf{c}^{out}bold_c start_POSTSUPERSCRIPT italic_o italic_u italic_t end_POSTSUPERSCRIPT is list of commitments of m𝑚mitalic_m output notes 𝐍out=(N1out,N2out,,Nmout)superscript𝐍𝑜𝑢𝑡subscriptsuperscript𝑁𝑜𝑢𝑡1subscriptsuperscript𝑁𝑜𝑢𝑡2subscriptsuperscript𝑁𝑜𝑢𝑡𝑚\mathbf{N}^{out}=(N^{out}_{1},N^{out}_{2},...,N^{out}_{m})bold_N start_POSTSUPERSCRIPT italic_o italic_u italic_t end_POSTSUPERSCRIPT = ( italic_N start_POSTSUPERSCRIPT italic_o italic_u italic_t end_POSTSUPERSCRIPT start_POSTSUBSCRIPT 1 end_POSTSUBSCRIPT , italic_N start_POSTSUPERSCRIPT italic_o italic_u italic_t end_POSTSUPERSCRIPT start_POSTSUBSCRIPT 2 end_POSTSUBSCRIPT , … , italic_N start_POSTSUPERSCRIPT italic_o italic_u italic_t end_POSTSUPERSCRIPT start_POSTSUBSCRIPT italic_m end_POSTSUBSCRIPT ).

Similarly, we define a tuple of private inputs as:

(15) ω(𝐞in,𝐞out,𝐯in,𝐯out,𝜹in,𝐒in,𝝈in,𝐱out,𝐥in,𝐨in)𝜔superscript𝐞𝑖𝑛superscript𝐞𝑜𝑢𝑡superscript𝐯𝑖𝑛superscript𝐯𝑜𝑢𝑡superscript𝜹𝑖𝑛superscript𝐒𝑖𝑛superscript𝝈𝑖𝑛superscript𝐱𝑜𝑢𝑡superscript𝐥𝑖𝑛superscript𝐨𝑖𝑛\omega\equiv(\mathbf{e}^{in},\mathbf{e}^{out},\mathbf{v}^{in},\mathbf{v}^{out}% ,\boldsymbol{\delta}^{in},\mathbf{S}^{in},\boldsymbol{\sigma}^{in},\mathbf{x}^% {out},\mathbf{l}^{in},\mathbf{o}^{in})italic_ω ≡ ( bold_e start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT , bold_e start_POSTSUPERSCRIPT italic_o italic_u italic_t end_POSTSUPERSCRIPT , bold_v start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT , bold_v start_POSTSUPERSCRIPT italic_o italic_u italic_t end_POSTSUPERSCRIPT , bold_italic_δ start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT , bold_S start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT , bold_italic_σ start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT , bold_x start_POSTSUPERSCRIPT italic_o italic_u italic_t end_POSTSUPERSCRIPT , bold_l start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT , bold_o start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT )

where

  • 𝐞insuperscript𝐞𝑖𝑛\mathbf{e}^{in}bold_e start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT and 𝐞outsuperscript𝐞𝑜𝑢𝑡\mathbf{e}^{out}bold_e start_POSTSUPERSCRIPT italic_o italic_u italic_t end_POSTSUPERSCRIPT are the lists of asset identifiers of input notes and output notes.

  • 𝐯in=(v1in,v2in,,vnin)superscript𝐯𝑖𝑛subscriptsuperscript𝑣𝑖𝑛1subscriptsuperscript𝑣𝑖𝑛2subscriptsuperscript𝑣𝑖𝑛𝑛\mathbf{v}^{in}=(v^{in}_{1},v^{in}_{2},...,v^{in}_{n})bold_v start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT = ( italic_v start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT start_POSTSUBSCRIPT 1 end_POSTSUBSCRIPT , italic_v start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT start_POSTSUBSCRIPT 2 end_POSTSUBSCRIPT , … , italic_v start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT start_POSTSUBSCRIPT italic_n end_POSTSUBSCRIPT ) and 𝐯out=(v1out,v2out,,vmout)superscript𝐯𝑜𝑢𝑡subscriptsuperscript𝑣𝑜𝑢𝑡1subscriptsuperscript𝑣𝑜𝑢𝑡2subscriptsuperscript𝑣𝑜𝑢𝑡𝑚\mathbf{v}^{out}=(v^{out}_{1},v^{out}_{2},...,v^{out}_{m})bold_v start_POSTSUPERSCRIPT italic_o italic_u italic_t end_POSTSUPERSCRIPT = ( italic_v start_POSTSUPERSCRIPT italic_o italic_u italic_t end_POSTSUPERSCRIPT start_POSTSUBSCRIPT 1 end_POSTSUBSCRIPT , italic_v start_POSTSUPERSCRIPT italic_o italic_u italic_t end_POSTSUPERSCRIPT start_POSTSUBSCRIPT 2 end_POSTSUBSCRIPT , … , italic_v start_POSTSUPERSCRIPT italic_o italic_u italic_t end_POSTSUPERSCRIPT start_POSTSUBSCRIPT italic_m end_POSTSUBSCRIPT ) are the values of input notes, 𝐍insuperscript𝐍𝑖𝑛\mathbf{N}^{in}bold_N start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT and output notes in 𝐍outsuperscript𝐍𝑜𝑢𝑡\mathbf{N}^{out}bold_N start_POSTSUPERSCRIPT italic_o italic_u italic_t end_POSTSUPERSCRIPT.

  • 𝜹insuperscript𝜹𝑖𝑛\boldsymbol{\delta}^{in}bold_italic_δ start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT is a list of blinding factors of stealth addresses attached to input notes, 𝐍insuperscript𝐍𝑖𝑛\mathbf{N}^{in}bold_N start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT.

  • 𝐒in=(S1in,S2in,,Snin)superscript𝐒𝑖𝑛subscriptsuperscript𝑆𝑖𝑛1subscriptsuperscript𝑆𝑖𝑛2subscriptsuperscript𝑆𝑖𝑛𝑛\textbf{S}^{in}=(S^{in}_{1},S^{in}_{2},...,S^{in}_{n})S start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT = ( italic_S start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT start_POSTSUBSCRIPT 1 end_POSTSUBSCRIPT , italic_S start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT start_POSTSUBSCRIPT 2 end_POSTSUBSCRIPT , … , italic_S start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT start_POSTSUBSCRIPT italic_n end_POSTSUBSCRIPT ) are public keys associated with n𝑛nitalic_n input notes 𝐍insuperscript𝐍𝑖𝑛\textbf{N}^{in}N start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT.

  • 𝝈insuperscript𝝈𝑖𝑛\boldsymbol{\sigma}^{in}bold_italic_σ start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT are the signatures produced by signing commitments of 𝐍insuperscript𝐍𝑖𝑛\textbf{N}^{in}N start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT with private keys 𝐬insuperscript𝐬𝑖𝑛\textbf{s}^{in}s start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT corresponding to public keys 𝐒insuperscript𝐒𝑖𝑛\textbf{S}^{in}S start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT.

  • 𝐱outsuperscript𝐱𝑜𝑢𝑡\mathbf{x}^{out}bold_x start_POSTSUPERSCRIPT italic_o italic_u italic_t end_POSTSUPERSCRIPT are stealth addresses associated with output notes 𝐍outsuperscript𝐍𝑜𝑢𝑡\mathbf{N}^{out}bold_N start_POSTSUPERSCRIPT italic_o italic_u italic_t end_POSTSUPERSCRIPT.

  • 𝐥insuperscript𝐥𝑖𝑛\mathbf{l}^{in}bold_l start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT are leaf indices of input note commitments, 𝐜insuperscript𝐜𝑖𝑛\mathbf{c}^{in}bold_c start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT.

  • 𝐨insuperscript𝐨𝑖𝑛\mathbf{o}^{in}bold_o start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT are openings in 𝒯𝒯\mathcal{T}caligraphic_T at indices 𝐥insuperscript𝐥𝑖𝑛\mathbf{l}^{in}bold_l start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT respectively.

Then, given ρ𝜌\rhoitalic_ρ and ω𝜔\omegaitalic_ω, let 𝒮𝒮\mathcal{S}caligraphic_S be the statement of knowledge defined as:

(16) 𝒮𝒮absent\displaystyle\mathcal{S}\equiv\ caligraphic_S ≡ Knowledge ofω::Knowledge of𝜔absent\displaystyle\text{Knowledge of}\ \omega\colonKnowledge of italic_ω :
i[1,n],xiin=𝚙𝚘𝚜𝚎𝚒𝚍𝚘𝚗(Siin,δiin)formulae-sequencefor-all𝑖1𝑛subscriptsuperscript𝑥𝑖𝑛𝑖𝚙𝚘𝚜𝚎𝚒𝚍𝚘𝚗subscriptsuperscript𝑆𝑖𝑛𝑖subscriptsuperscript𝛿𝑖𝑛𝑖\displaystyle\ \ \ \forall i\in[1,n],\ x^{in}_{i}=\mathtt{poseidon}(S^{in}_{i}% ,\delta^{in}_{i})∀ italic_i ∈ [ 1 , italic_n ] , italic_x start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT start_POSTSUBSCRIPT italic_i end_POSTSUBSCRIPT = typewriter_poseidon ( italic_S start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT start_POSTSUBSCRIPT italic_i end_POSTSUBSCRIPT , italic_δ start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT start_POSTSUBSCRIPT italic_i end_POSTSUBSCRIPT )
i[1,n],ciin=𝚙𝚘𝚜𝚎𝚒𝚍𝚘𝚗(eiin,xiin,viin)formulae-sequencefor-all𝑖1𝑛subscriptsuperscript𝑐𝑖𝑛𝑖𝚙𝚘𝚜𝚎𝚒𝚍𝚘𝚗subscriptsuperscript𝑒𝑖𝑛𝑖subscriptsuperscript𝑥𝑖𝑛𝑖subscriptsuperscript𝑣𝑖𝑛𝑖\displaystyle\wedge\forall i\in[1,n],\ c^{in}_{i}=\mathtt{poseidon}(e^{in}_{i}% ,x^{in}_{i},v^{in}_{i})∧ ∀ italic_i ∈ [ 1 , italic_n ] , italic_c start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT start_POSTSUBSCRIPT italic_i end_POSTSUBSCRIPT = typewriter_poseidon ( italic_e start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT start_POSTSUBSCRIPT italic_i end_POSTSUBSCRIPT , italic_x start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT start_POSTSUBSCRIPT italic_i end_POSTSUBSCRIPT , italic_v start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT start_POSTSUBSCRIPT italic_i end_POSTSUBSCRIPT )
i[1,n],ηiin=𝚙𝚘𝚜𝚎𝚒𝚍𝚘𝚗(liin,ciin,δiin)formulae-sequencefor-all𝑖1𝑛subscriptsuperscript𝜂𝑖𝑛𝑖𝚙𝚘𝚜𝚎𝚒𝚍𝚘𝚗subscriptsuperscript𝑙𝑖𝑛𝑖subscriptsuperscript𝑐𝑖𝑛𝑖subscriptsuperscript𝛿𝑖𝑛𝑖\displaystyle\wedge\forall i\in[1,n],\ \eta^{in}_{i}=\mathtt{poseidon}(l^{in}_% {i},c^{in}_{i},\delta^{in}_{i})∧ ∀ italic_i ∈ [ 1 , italic_n ] , italic_η start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT start_POSTSUBSCRIPT italic_i end_POSTSUBSCRIPT = typewriter_poseidon ( italic_l start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT start_POSTSUBSCRIPT italic_i end_POSTSUBSCRIPT , italic_c start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT start_POSTSUBSCRIPT italic_i end_POSTSUBSCRIPT , italic_δ start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT start_POSTSUBSCRIPT italic_i end_POSTSUBSCRIPT )
i[1,n],𝚂𝚌𝚑𝚗𝚘𝚛𝚛_𝚅𝚎𝚛𝚒𝚏𝚢(ciin,Siin,σiin)=1formulae-sequencefor-all𝑖1𝑛𝚂𝚌𝚑𝚗𝚘𝚛𝚛_𝚅𝚎𝚛𝚒𝚏𝚢subscriptsuperscript𝑐𝑖𝑛𝑖subscriptsuperscript𝑆𝑖𝑛𝑖subscriptsuperscript𝜎𝑖𝑛𝑖1\displaystyle\wedge\forall i\in[1,n],\ \mathtt{Schnorr\_Verify}(c^{in}_{i},S^{% in}_{i},\sigma^{in}_{i})=1∧ ∀ italic_i ∈ [ 1 , italic_n ] , typewriter_Schnorr _ typewriter_Verify ( italic_c start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT start_POSTSUBSCRIPT italic_i end_POSTSUBSCRIPT , italic_S start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT start_POSTSUBSCRIPT italic_i end_POSTSUBSCRIPT , italic_σ start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT start_POSTSUBSCRIPT italic_i end_POSTSUBSCRIPT ) = 1
i[1,n],oiinis the opening atliinin𝒯for-all𝑖1𝑛subscriptsuperscript𝑜𝑖𝑛𝑖is the opening atsubscriptsuperscript𝑙𝑖𝑛𝑖in𝒯\displaystyle\wedge\forall i\in[1,n],\ o^{in}_{i}\ \text{is the opening at}\ l% ^{in}_{i}\ \text{in}\ \mathcal{T}∧ ∀ italic_i ∈ [ 1 , italic_n ] , italic_o start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT start_POSTSUBSCRIPT italic_i end_POSTSUBSCRIPT is the opening at italic_l start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT start_POSTSUBSCRIPT italic_i end_POSTSUBSCRIPT in caligraphic_T
i[1,m],ciout=𝚙𝚘𝚜𝚎𝚒𝚍𝚘𝚗(eiout,xiout,viout)formulae-sequencefor-all𝑖1𝑚subscriptsuperscript𝑐𝑜𝑢𝑡𝑖𝚙𝚘𝚜𝚎𝚒𝚍𝚘𝚗subscriptsuperscript𝑒𝑜𝑢𝑡𝑖subscriptsuperscript𝑥𝑜𝑢𝑡𝑖subscriptsuperscript𝑣𝑜𝑢𝑡𝑖\displaystyle\wedge\forall i\in[1,m],\ {c}^{out}_{i}=\mathtt{poseidon}(e^{out}% _{i},x^{out}_{i},v^{out}_{i})∧ ∀ italic_i ∈ [ 1 , italic_m ] , italic_c start_POSTSUPERSCRIPT italic_o italic_u italic_t end_POSTSUPERSCRIPT start_POSTSUBSCRIPT italic_i end_POSTSUBSCRIPT = typewriter_poseidon ( italic_e start_POSTSUPERSCRIPT italic_o italic_u italic_t end_POSTSUPERSCRIPT start_POSTSUBSCRIPT italic_i end_POSTSUBSCRIPT , italic_x start_POSTSUPERSCRIPT italic_o italic_u italic_t end_POSTSUPERSCRIPT start_POSTSUBSCRIPT italic_i end_POSTSUBSCRIPT , italic_v start_POSTSUPERSCRIPT italic_o italic_u italic_t end_POSTSUPERSCRIPT start_POSTSUBSCRIPT italic_i end_POSTSUBSCRIPT )
eiin𝐞in,𝚜𝚎𝚕𝚟(𝐯in,eiin)+𝚜𝚎𝚕𝚟(𝐕,eiin)for-allsubscriptsuperscript𝑒𝑖𝑛𝑖superscript𝐞𝑖𝑛𝚜𝚎𝚕𝚟superscript𝐯𝑖𝑛subscriptsuperscript𝑒𝑖𝑛𝑖𝚜𝚎𝚕𝚟𝐕subscriptsuperscript𝑒𝑖𝑛𝑖\displaystyle\wedge\forall e^{in}_{i}\in\mathbf{e}^{in},\sum\mathtt{selv}(% \mathbf{v}^{in},e^{in}_{i})+\sum\mathtt{selv}(\mathbf{V},e^{in}_{i})∧ ∀ italic_e start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT start_POSTSUBSCRIPT italic_i end_POSTSUBSCRIPT ∈ bold_e start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT , ∑ typewriter_selv ( bold_v start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT , italic_e start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT start_POSTSUBSCRIPT italic_i end_POSTSUBSCRIPT ) + ∑ typewriter_selv ( bold_V , italic_e start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT start_POSTSUBSCRIPT italic_i end_POSTSUBSCRIPT )
=𝚜𝚎𝚕𝚟(𝐯out,eiin)absent𝚜𝚎𝚕𝚟superscript𝐯𝑜𝑢𝑡subscriptsuperscript𝑒𝑖𝑛𝑖\displaystyle\hskip 80.0pt=\sum\mathtt{selv}(\mathbf{v}^{out},e^{in}_{i})= ∑ typewriter_selv ( bold_v start_POSTSUPERSCRIPT italic_o italic_u italic_t end_POSTSUPERSCRIPT , italic_e start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT start_POSTSUBSCRIPT italic_i end_POSTSUBSCRIPT )
eiout𝚜𝚎𝚕𝚎(𝐄,𝐞out),𝚜𝚎𝚕𝚟(𝐯in,eiout)for-allsubscriptsuperscript𝑒𝑜𝑢𝑡𝑖𝚜𝚎𝚕𝚎𝐄superscript𝐞𝑜𝑢𝑡𝚜𝚎𝚕𝚟superscript𝐯𝑖𝑛subscriptsuperscript𝑒𝑜𝑢𝑡𝑖\displaystyle\wedge\forall\ e^{out}_{i}\in\mathtt{sele}(\mathbf{E},\mathbf{e}^% {out}),\sum\mathtt{selv}(\mathbf{v}^{in},e^{out}_{i})∧ ∀ italic_e start_POSTSUPERSCRIPT italic_o italic_u italic_t end_POSTSUPERSCRIPT start_POSTSUBSCRIPT italic_i end_POSTSUBSCRIPT ∈ typewriter_sele ( bold_E , bold_e start_POSTSUPERSCRIPT italic_o italic_u italic_t end_POSTSUPERSCRIPT ) , ∑ typewriter_selv ( bold_v start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT , italic_e start_POSTSUPERSCRIPT italic_o italic_u italic_t end_POSTSUPERSCRIPT start_POSTSUBSCRIPT italic_i end_POSTSUBSCRIPT )
+𝚜𝚎𝚕𝚟(𝐕,eiout)=𝚜𝚎𝚕𝚟(𝐯out,eiout)𝚜𝚎𝚕𝚟𝐕subscriptsuperscript𝑒𝑜𝑢𝑡𝑖𝚜𝚎𝚕𝚟superscript𝐯𝑜𝑢𝑡subscriptsuperscript𝑒𝑜𝑢𝑡𝑖\displaystyle\hskip 30.0pt+\sum\mathtt{selv}(\mathbf{V},e^{out}_{i})=\sum% \mathtt{selv}(\mathbf{v}^{out},e^{out}_{i})+ ∑ typewriter_selv ( bold_V , italic_e start_POSTSUPERSCRIPT italic_o italic_u italic_t end_POSTSUPERSCRIPT start_POSTSUBSCRIPT italic_i end_POSTSUBSCRIPT ) = ∑ typewriter_selv ( bold_v start_POSTSUPERSCRIPT italic_o italic_u italic_t end_POSTSUPERSCRIPT , italic_e start_POSTSUPERSCRIPT italic_o italic_u italic_t end_POSTSUPERSCRIPT start_POSTSUBSCRIPT italic_i end_POSTSUBSCRIPT )

where 𝚜𝚎𝚕𝚟𝚜𝚎𝚕𝚟\mathtt{selv}typewriter_selv is a function to filter select values from a list of values by a given asset identifier:

(17) 𝚜𝚎𝚕𝚟(𝐯,e)={v:v𝐯v is the value of asset e}𝚜𝚎𝚕𝚟𝐯𝑒conditional-set𝑣𝑣𝐯𝑣 is the value of asset 𝑒\mathtt{selv}(\mathbf{v},e)=\{v\colon v\in\mathbf{v}\ \land v\text{ is the % value of asset }e\}typewriter_selv ( bold_v , italic_e ) = { italic_v : italic_v ∈ bold_v ∧ italic_v is the value of asset italic_e }

and 𝚜𝚎𝚕𝚎𝚜𝚎𝚕𝚎\mathtt{sele}typewriter_sele is a function to select elements from the first list parameter if non-zero, otherwise selecting from the second list parameter:

(18) 𝚜𝚎𝚕𝚎(𝐄,𝐞)={e:e=Ei if Ei0, otherwise e=ei}𝚜𝚎𝚕𝚎𝐄𝐞conditional-set𝑒formulae-sequence𝑒subscript𝐸𝑖 if subscript𝐸𝑖0 otherwise 𝑒subscript𝑒𝑖\mathtt{sele}(\mathbf{E},\mathbf{e})=\{e\colon e=E_{i}\text{ if }E_{i}\neq 0,% \text{ otherwise }e=e_{i}\}typewriter_sele ( bold_E , bold_e ) = { italic_e : italic_e = italic_E start_POSTSUBSCRIPT italic_i end_POSTSUBSCRIPT if italic_E start_POSTSUBSCRIPT italic_i end_POSTSUBSCRIPT ≠ 0 , otherwise italic_e = italic_e start_POSTSUBSCRIPT italic_i end_POSTSUBSCRIPT }

𝚂𝚌𝚑𝚗𝚘𝚛𝚛_𝚅𝚎𝚛𝚒𝚏𝚢𝚂𝚌𝚑𝚗𝚘𝚛𝚛_𝚅𝚎𝚛𝚒𝚏𝚢\mathtt{Schnorr\_Verify}typewriter_Schnorr _ typewriter_Verify is defined in 31.

Let dpsubscript𝑑𝑝d_{p}italic_d start_POSTSUBSCRIPT italic_p end_POSTSUBSCRIPT and dvsubscript𝑑𝑣d_{v}italic_d start_POSTSUBSCRIPT italic_v end_POSTSUBSCRIPT be the proving and verifying keys created using a trusted setup ceremony. Let’s define the SNARK proof generator function as:

(19) 𝙿𝚛𝚘𝚟𝚎:𝔹*𝔹2048;(dp,ρ,ω)𝝅:𝙿𝚛𝚘𝚟𝚎formulae-sequencesuperscript𝔹superscript𝔹2048maps-tosubscript𝑑𝑝𝜌𝜔𝝅\mathtt{Prove}:\mathbb{B}^{*}\to\mathbb{B}^{2048};(d_{p},\rho,\omega)\mapsto% \boldsymbol{\pi}typewriter_Prove : blackboard_B start_POSTSUPERSCRIPT * end_POSTSUPERSCRIPT → blackboard_B start_POSTSUPERSCRIPT 2048 end_POSTSUPERSCRIPT ; ( italic_d start_POSTSUBSCRIPT italic_p end_POSTSUBSCRIPT , italic_ρ , italic_ω ) ↦ bold_italic_π

where 𝝅𝝅\boldsymbol{\pi}bold_italic_π is called the proof.

And proof verifier as:

(20) 𝚅𝚎𝚛𝚒𝚏𝚢:𝔹*{0,1};(dv,𝝅,ρ)y:𝚅𝚎𝚛𝚒𝚏𝚢formulae-sequencesuperscript𝔹01maps-tosubscript𝑑𝑣𝝅𝜌𝑦\mathtt{Verify}:\mathbb{B}^{*}\to\{0,1\};(d_{v},\boldsymbol{\pi},\rho)\mapsto ytypewriter_Verify : blackboard_B start_POSTSUPERSCRIPT * end_POSTSUPERSCRIPT → { 0 , 1 } ; ( italic_d start_POSTSUBSCRIPT italic_v end_POSTSUBSCRIPT , bold_italic_π , italic_ρ ) ↦ italic_y

where y𝑦yitalic_y is a single bit for representing boolean true𝑡𝑟𝑢𝑒trueitalic_t italic_r italic_u italic_e or false𝑓𝑎𝑙𝑠𝑒falseitalic_f italic_a italic_l italic_s italic_e as a result of proof verification.

6.3.2. Creating Transaction

A transaction request is constructed by following the steps below:

  1. (1)

    Identify the different assets 𝐞=(e1,e2,en)𝐞subscript𝑒1subscript𝑒2subscript𝑒𝑛\mathbf{e}=(e_{1},e_{2},...e_{n})bold_e = ( italic_e start_POSTSUBSCRIPT 1 end_POSTSUBSCRIPT , italic_e start_POSTSUBSCRIPT 2 end_POSTSUBSCRIPT , … italic_e start_POSTSUBSCRIPT italic_n end_POSTSUBSCRIPT ) needed for transaction.

  2. (2)

    Scan the network and fetch encrypted notes data. Decrypt it using the viewing key and filter for notes, Ni𝐍subscript𝑁𝑖𝐍N_{i}\in\mathbf{N}italic_N start_POSTSUBSCRIPT italic_i end_POSTSUBSCRIPT ∈ bold_N such that its asset id, e𝐞𝑒𝐞e\in\mathbf{e}italic_e ∈ bold_e.

  3. (3)

    Choose a number of notes 𝐍in𝐍superscript𝐍𝑖𝑛𝐍\mathbf{N}^{in}\subset\mathbf{N}bold_N start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT ⊂ bold_N, with commitment indices 𝐥insubscript𝐥𝑖𝑛\mathbf{l}_{in}bold_l start_POSTSUBSCRIPT italic_i italic_n end_POSTSUBSCRIPT in 𝒯𝒯\mathcal{T}caligraphic_T, to spend.

  4. (4)

    Compute nullifier hashes, ηinsuperscript𝜂𝑖𝑛\mathbf{\eta}^{in}italic_η start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT of notes 𝐍insuperscript𝐍𝑖𝑛\mathbf{N}^{in}bold_N start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT.

  5. (5)

    Select a recent root, R𝑅Ritalic_R of 𝒯𝒯\mathcal{T}caligraphic_T and calculate tree openings 𝐨insuperscript𝐨𝑖𝑛\mathbf{o}^{in}bold_o start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT at indices 𝐥insuperscript𝐥𝑖𝑛\mathbf{l}^{in}bold_l start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT.

  6. (6)

    Derive stealth addresses 𝐱outsuperscript𝐱𝑜𝑢𝑡\mathbf{x}^{out}bold_x start_POSTSUPERSCRIPT italic_o italic_u italic_t end_POSTSUPERSCRIPT of recipients and create output notes 𝐍outsuperscript𝐍𝑜𝑢𝑡\mathbf{N}^{out}bold_N start_POSTSUPERSCRIPT italic_o italic_u italic_t end_POSTSUPERSCRIPT associated with them. Also, calculate output commitments, 𝐜outsuperscript𝐜𝑜𝑢𝑡\mathbf{c}^{out}bold_c start_POSTSUPERSCRIPT italic_o italic_u italic_t end_POSTSUPERSCRIPT.

  7. (7)

    Set 𝐕𝐕\mathbf{V}bold_V and 𝐄𝐄\mathbf{E}bold_E to control any public asset value, if any, going into or coming out of contracts.

6.3.3. Signing Transaction

To authorize the transaction, signatures σ𝐢𝐧superscript𝜎𝐢𝐧\mathbf{\sigma^{in}}italic_σ start_POSTSUPERSCRIPT bold_in end_POSTSUPERSCRIPT from the shielded account are required. Each signature σiinσ𝐢𝐧subscriptsuperscript𝜎𝑖𝑛𝑖superscript𝜎𝐢𝐧\sigma^{in}_{i}\in\mathbf{\sigma^{in}}italic_σ start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT start_POSTSUBSCRIPT italic_i end_POSTSUBSCRIPT ∈ italic_σ start_POSTSUPERSCRIPT bold_in end_POSTSUPERSCRIPT is obtained by signing ciinsubscriptsuperscript𝑐𝑖𝑛𝑖c^{in}_{i}italic_c start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT start_POSTSUBSCRIPT italic_i end_POSTSUBSCRIPT of notes being spent (𝐍insuperscript𝐍𝑖𝑛\mathbf{N}^{in}bold_N start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT):

(21) σiin=𝚂𝚌𝚑𝚗𝚘𝚛𝚛_𝚂𝚒𝚐𝚗(ciin,s)subscriptsuperscript𝜎𝑖𝑛𝑖𝚂𝚌𝚑𝚗𝚘𝚛𝚛_𝚂𝚒𝚐𝚗subscriptsuperscript𝑐𝑖𝑛𝑖𝑠\sigma^{in}_{i}=\mathtt{Schnorr\_Sign}(c^{in}_{i},s)italic_σ start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT start_POSTSUBSCRIPT italic_i end_POSTSUBSCRIPT = typewriter_Schnorr _ typewriter_Sign ( italic_c start_POSTSUPERSCRIPT italic_i italic_n end_POSTSUPERSCRIPT start_POSTSUBSCRIPT italic_i end_POSTSUBSCRIPT , italic_s )

6.3.4. Proving Transaction

Together with signatures and parameters identified or calculated during creation, the public and private inputs i.e. ρ𝜌\rhoitalic_ρ and ω𝜔\omegaitalic_ω are put together. Then proof 𝝅𝝅\boldsymbol{\pi}bold_italic_π of the transaction generated:

(22) 𝝅=𝙿𝚛𝚘𝚟𝚎(dp,ρ,ω)𝝅𝙿𝚛𝚘𝚟𝚎subscript𝑑𝑝𝜌𝜔\boldsymbol{\pi}=\mathtt{Prove}(d_{p},\rho,\omega)bold_italic_π = typewriter_Prove ( italic_d start_POSTSUBSCRIPT italic_p end_POSTSUBSCRIPT , italic_ρ , italic_ω )

6.3.5. Sending Transaction

Except for the deposit transactions type (public value going into pool), the transaction is sent as an EIP-4337 user operation (eip-4337, ) by submitting it to a bundler node.

For deposits, it is sent directly from a wallet since it involves transferring value from the wallet to the pool smart contract.

If 𝝅𝝅\boldsymbol{\pi}bold_italic_π was calculated correctly and the statement was true, the on-chain 𝚅𝚎𝚛𝚒𝚏𝚢𝚅𝚎𝚛𝚒𝚏𝚢\mathtt{Verify}typewriter_Verify function outputs 1111, and flow proceeds with necessary funds. Otherwise, 00 representing bad or tampered 𝝅𝝅\boldsymbol{\pi}bold_italic_π.

6.4. Protocol Proxy

A Protocol Proxy is a state-less contract that lives on-chain to act as a proxy for a target (e.g. DeFi) protocol. This contract must implement a standard interface that exposes a ”convert” functionality or operation. This reflects the fact that, in general, any DeFi operation e.g. swapping, lending, staking, can be thought of as a process of converting from one asset called input asset to another asset called output asset. Here are a few examples:

  • When swapping ETH for USDC on Uniswap, ETH (input asset) is converted to USDC (output asset).

  • When supplying DAI on the Aave market to earn interest, DAI (input asset) is essentially being converted to aDAI (output asset) the interest-bearing tokens given back in return.

  • Staking ETH (input asset) on Lido results in conversion to stETH (output asset) holding which represents your stake plus rewards.

This allows Core the core to interact with protocols via a Convertor contract. In its convert operation, this proxy is supposed to perform necessary operations by calling the target it is the proxy for, eventually returning any output to the Core.

It is a specific kind of transaction where V𝑉Vitalic_V values are set to non-zero so that these values, 𝐯𝐯\mathbf{v}bold_v are sent as input asset (with ids 𝐞𝐞\mathbf{e}bold_e) if required. A fee asset of id efsubscript𝑒𝑓e_{f}italic_e start_POSTSUBSCRIPT italic_f end_POSTSUBSCRIPT and value vfsubscript𝑣𝑓v_{f}italic_v start_POSTSUBSCRIPT italic_f end_POSTSUBSCRIPT is also given specifying gas fee requirements. Fee must be paid by returning it as one of the output assets. The target protocol may chose to pay gas however it wants. Lastly, the input also includes an arbitrary payload, d𝑑ditalic_d necessary for operation by the proxy. After processing the input, (𝐞,𝐯,ef,vf,d)𝐞𝐯subscript𝑒𝑓subscript𝑣𝑓𝑑(\mathbf{e},\mathbf{v},e_{f},v_{f},d)( bold_e , bold_v , italic_e start_POSTSUBSCRIPT italic_f end_POSTSUBSCRIPT , italic_v start_POSTSUBSCRIPT italic_f end_POSTSUBSCRIPT , italic_d ) with its specific target protocol, the proxy is expected to return output asset (𝐞,𝐯)superscript𝐞superscript𝐯(\mathbf{e}^{\prime},\mathbf{v}^{\prime})( bold_e start_POSTSUPERSCRIPT ′ end_POSTSUPERSCRIPT , bold_v start_POSTSUPERSCRIPT ′ end_POSTSUPERSCRIPT ).

(23) 𝙲𝚘𝚗𝚟𝚎𝚛𝚝:(𝔹24n,𝔹256n,𝔹24,𝔹256,𝔹*)(𝔹24m,𝔹256m);(𝐞,𝐯,ef,vf,d)(𝐞,𝐯):𝙲𝚘𝚗𝚟𝚎𝚛𝚝formulae-sequencesuperscriptsuperscript𝔹24𝑛superscriptsuperscript𝔹256𝑛superscript𝔹24superscript𝔹256superscript𝔹superscriptsuperscript𝔹24𝑚superscriptsuperscript𝔹256𝑚maps-to𝐞𝐯subscript𝑒𝑓subscript𝑣𝑓𝑑superscript𝐞superscript𝐯\begin{split}\mathtt{Convert}\colon&({\mathbb{B}^{24}}^{n},{\mathbb{B}^{256}}^% {n},\mathbb{B}^{24},\mathbb{B}^{256},\mathbb{B}^{*})\to({\mathbb{B}^{24}}^{m},% {\mathbb{B}^{256}}^{m})\\ &;(\mathbf{e},\mathbf{v},e_{f},v_{f},d)\mapsto(\mathbf{e}^{\prime},\mathbf{v}^% {\prime})\end{split}start_ROW start_CELL typewriter_Convert : end_CELL start_CELL ( blackboard_B start_POSTSUPERSCRIPT 24 end_POSTSUPERSCRIPT start_POSTSUPERSCRIPT italic_n end_POSTSUPERSCRIPT , blackboard_B start_POSTSUPERSCRIPT 256 end_POSTSUPERSCRIPT start_POSTSUPERSCRIPT italic_n end_POSTSUPERSCRIPT , blackboard_B start_POSTSUPERSCRIPT 24 end_POSTSUPERSCRIPT , blackboard_B start_POSTSUPERSCRIPT 256 end_POSTSUPERSCRIPT , blackboard_B start_POSTSUPERSCRIPT * end_POSTSUPERSCRIPT ) → ( blackboard_B start_POSTSUPERSCRIPT 24 end_POSTSUPERSCRIPT start_POSTSUPERSCRIPT italic_m end_POSTSUPERSCRIPT , blackboard_B start_POSTSUPERSCRIPT 256 end_POSTSUPERSCRIPT start_POSTSUPERSCRIPT italic_m end_POSTSUPERSCRIPT ) end_CELL end_ROW start_ROW start_CELL end_CELL start_CELL ; ( bold_e , bold_v , italic_e start_POSTSUBSCRIPT italic_f end_POSTSUBSCRIPT , italic_v start_POSTSUBSCRIPT italic_f end_POSTSUBSCRIPT , italic_d ) ↦ ( bold_e start_POSTSUPERSCRIPT ′ end_POSTSUPERSCRIPT , bold_v start_POSTSUPERSCRIPT ′ end_POSTSUPERSCRIPT ) end_CELL end_ROW

Later, a note commitment is calculated with (e,v)superscript𝑒superscript𝑣(e^{\prime},v^{\prime})( italic_e start_POSTSUPERSCRIPT ′ end_POSTSUPERSCRIPT , italic_v start_POSTSUPERSCRIPT ′ end_POSTSUPERSCRIPT ) for each of m𝑚mitalic_m outputs and a given stealth address as a transaction parameter and inserted into 𝒯𝒯\mathcal{T}caligraphic_T.

The flexibility comes from the fact that the implementation of 𝙲𝚘𝚗𝚟𝚎𝚛𝚝𝙲𝚘𝚗𝚟𝚎𝚛𝚝\mathtt{Convert}typewriter_Convert is left to the developer trying to integrate the target protocol.

6.5. Involuntary Selective De-anonymization

zkFi adopts a framework for involuntary de-anonymization of illicit transaction subgraphs using a threshold multi-party procedure while keeping such parties accountable.

The process involves an independent set of parties called guardians. Each of the n𝑛nitalic_n guardians holds a share of the secret key which decrypts encrypted transaction data such that guardians must reach a quorum of minimum size t𝑡titalic_t (tn𝑡𝑛t\leq nitalic_t ≤ italic_n) for the de-anonymization of any transaction to occur. However, even after de-anonymization is granted by guardians, they still do not learn any information about the user because another decryption still needs to be performed by an individual party called the revoker.

Accountability comes from the fact that the revoker is bound to send a publicly verifiable request of de-anonymization to the guardians who must agree first for the revoker to extract any information at all. A more detailed study can be found in (compliance-sol, ).

7. Cryptographic Primitives

7.1. Hash Function

A hash function is a mathematical function, hhitalic_h that takes arbitrary length input, m𝔹*𝑚superscript𝔹m\in\mathbb{B}^{*}italic_m ∈ blackboard_B start_POSTSUPERSCRIPT * end_POSTSUPERSCRIPT, and outputs fixed-length output x𝔹n𝑥superscript𝔹𝑛x\in\mathbb{B}^{n}italic_x ∈ blackboard_B start_POSTSUPERSCRIPT italic_n end_POSTSUPERSCRIPT often called hash, hash value or digest.

(24) h:𝔹*𝔹n;mx:formulae-sequencesuperscript𝔹superscript𝔹𝑛maps-to𝑚𝑥h\colon\mathbb{B}^{*}\to\mathbb{B}^{n};m\mapsto xitalic_h : blackboard_B start_POSTSUPERSCRIPT * end_POSTSUPERSCRIPT → blackboard_B start_POSTSUPERSCRIPT italic_n end_POSTSUPERSCRIPT ; italic_m ↦ italic_x

A cryptographically secure hash function has the following properties:

  • Pre-image resistance Given a hash value, it must be difficult to find the input that produced it.

  • Second pre-image resistance Given an input and its hash value it must be difficult to find another input that produces the same hash.

  • Collision resistance It must be difficult to find two inputs that map to the same hash value.

Specifically for its ZK-related operations, zkFi extensively uses a hash function called Poseidon (poseidon, ) denoted as 𝚙𝚘𝚜𝚎𝚒𝚍𝚘𝚗𝚙𝚘𝚜𝚎𝚒𝚍𝚘𝚗\mathtt{poseidon}typewriter_poseidon:

(25) 𝚙𝚘𝚜𝚎𝚒𝚍𝚘𝚗:𝔹*𝔹254:𝚙𝚘𝚜𝚎𝚒𝚍𝚘𝚗superscript𝔹superscript𝔹254\mathtt{poseidon}\colon\mathbb{B}^{*}\to\mathbb{B}^{254}typewriter_poseidon : blackboard_B start_POSTSUPERSCRIPT * end_POSTSUPERSCRIPT → blackboard_B start_POSTSUPERSCRIPT 254 end_POSTSUPERSCRIPT

A common in the Ethereum ecosystem is the Keccak256 (keccak256, ). It is used within zkFi where it does not require proving via ZK proof. It is defined as:

(26) 𝚔𝚎𝚌𝚌𝚊𝚔𝟸𝟻𝟼:𝔹*𝔹256:𝚔𝚎𝚌𝚌𝚊𝚔𝟸𝟻𝟼superscript𝔹superscript𝔹256\mathtt{keccak256}\colon\mathbb{B}^{*}\to\mathbb{B}^{256}typewriter_keccak256 : blackboard_B start_POSTSUPERSCRIPT * end_POSTSUPERSCRIPT → blackboard_B start_POSTSUPERSCRIPT 256 end_POSTSUPERSCRIPT

7.2. Elliptic Curve

Elliptic curves are mathematical structures that are defined over some finite field that have interesting properties that make them very useful in cryptography. The security of ECC relies on the computational infeasibility of solving the elliptic curve discrete logarithm problem (DLP) (dlp, ).

Let E𝐸Eitalic_E be an elliptic curve defined over a finite field 𝔽qsubscript𝔽𝑞\mathbb{F}_{q}blackboard_F start_POSTSUBSCRIPT italic_q end_POSTSUBSCRIPT where q𝑞qitalic_q is a large prime number, and let P𝑃Pitalic_P, Q𝑄Qitalic_Q and R𝑅Ritalic_R be points on E𝐸Eitalic_E. The elliptic curve group operation on E𝐸Eitalic_E is typically denoted as P+Q𝑃𝑄P+Qitalic_P + italic_Q, where P+Q+R𝑃𝑄𝑅P+Q+Ritalic_P + italic_Q + italic_R satisfies the group law:

(27) P+Q+R=𝒪𝑃𝑄𝑅𝒪P+Q+R=\mathcal{O}italic_P + italic_Q + italic_R = caligraphic_O

where 𝒪𝒪\mathcal{O}caligraphic_O represents the point at infinity.

The elliptic curve DLP is defined as finding an integer k𝑘kitalic_k such that S=kP𝑆𝑘𝑃S=k\cdot Pitalic_S = italic_k ⋅ italic_P, where kP=P+P+.+Pformulae-sequence𝑘𝑃𝑃𝑃𝑃k\cdot P=P+P+....+Pitalic_k ⋅ italic_P = italic_P + italic_P + … . + italic_P (k𝑘kitalic_k times) is referred to as scaler multiplication of point P𝑃Pitalic_P.

A cyclic subgroup is a subset of an elliptic curve group that is generated by a single point called generator, denoted by G𝐺Gitalic_G. Elements of the subgroup are obtained when G𝐺Gitalic_G is scalar multiplied by integers i.e. kG𝑘𝐺k\cdot Gitalic_k ⋅ italic_G where k𝑘k\in\mathbb{Z}italic_k ∈ blackboard_Z.

zkFi protocol uses a specific elliptic curve called Baby JubJub as defined in (eip-2494, ). It is particularly well-suited for cryptography operations in zero-knowledge (ZK) applications.

7.3. Digital Signature

A digital signature σ𝜎\sigmaitalic_σ is a verifiable piece of data produced by signing a message m𝑚mitalic_m with a private key s𝑠sitalic_s through some chosen signature scheme or function.

(28) 𝚂𝚒𝚐𝚗:(𝔹*,𝔹k)𝔹n;(m,s)σ:𝚂𝚒𝚐𝚗formulae-sequencesuperscript𝔹superscript𝔹𝑘superscript𝔹𝑛maps-to𝑚𝑠𝜎\mathtt{Sign}\colon(\mathbb{B}^{*},\mathbb{B}^{k})\to\mathbb{B}^{n};(m,s)\mapsto\sigmatypewriter_Sign : ( blackboard_B start_POSTSUPERSCRIPT * end_POSTSUPERSCRIPT , blackboard_B start_POSTSUPERSCRIPT italic_k end_POSTSUPERSCRIPT ) → blackboard_B start_POSTSUPERSCRIPT italic_n end_POSTSUPERSCRIPT ; ( italic_m , italic_s ) ↦ italic_σ

The signature scheme can later verify that the signature σ𝜎\sigmaitalic_σ was produced by an entity who knows the m𝑚mitalic_m as well as private key s𝑠sitalic_s:

(29) 𝚅𝚎𝚛𝚒𝚏𝚢:(𝔹n,𝔹j){0,1};(σ,P)y:𝚅𝚎𝚛𝚒𝚏𝚢formulae-sequencesuperscript𝔹𝑛superscript𝔹𝑗01maps-to𝜎𝑃𝑦\mathtt{Verify}\colon(\mathbb{B}^{n},\mathbb{B}^{j})\to\{0,1\};(\sigma,P)\mapsto ytypewriter_Verify : ( blackboard_B start_POSTSUPERSCRIPT italic_n end_POSTSUPERSCRIPT , blackboard_B start_POSTSUPERSCRIPT italic_j end_POSTSUPERSCRIPT ) → { 0 , 1 } ; ( italic_σ , italic_P ) ↦ italic_y

where P𝑃Pitalic_P is public key corresponding to s𝑠sitalic_s and y𝑦yitalic_y is a single bit representing result of verification - true𝑡𝑟𝑢𝑒trueitalic_t italic_r italic_u italic_e or false𝑓𝑎𝑙𝑠𝑒falseitalic_f italic_a italic_l italic_s italic_e.

A cryptographically secure signature scheme must have the following properties:

  • Authenticity A valid signature implies that the message was deliberately signed by the signer only.

  • Unforgeability Only the signer can produce a valid signature for the associated message.

  • Non-reusability The signature of a message cannot be used on another message.

  • Non-repudiation The signer of the message cannot deny having signed the message with a valid signature.

  • Integrity Ensures that the contents of the message are not altered.

zkFi utilizes Schnorr (schnorr, ) signature scheme for signing private transactions and verifying those signatures. The signing function is defined as:

(30) 𝚂𝚌𝚑𝚗𝚘𝚛𝚛_𝚂𝚒𝚐𝚗:(𝔹256,𝔹512)𝔹768;(m,s)σ:𝚂𝚌𝚑𝚗𝚘𝚛𝚛_𝚂𝚒𝚐𝚗formulae-sequencesuperscript𝔹256superscript𝔹512superscript𝔹768maps-to𝑚𝑠𝜎\mathtt{Schnorr\_Sign}\colon(\mathbb{B}^{256},\mathbb{B}^{512})\to\mathbb{B}^{% 768};(m,s)\mapsto\sigmatypewriter_Schnorr _ typewriter_Sign : ( blackboard_B start_POSTSUPERSCRIPT 256 end_POSTSUPERSCRIPT , blackboard_B start_POSTSUPERSCRIPT 512 end_POSTSUPERSCRIPT ) → blackboard_B start_POSTSUPERSCRIPT 768 end_POSTSUPERSCRIPT ; ( italic_m , italic_s ) ↦ italic_σ

and verification as:

(31) 𝚂𝚌𝚑𝚗𝚘𝚛𝚛_𝚅𝚎𝚛𝚒𝚏𝚢:(𝔹256,𝔹512,𝔹512){0,1};(m,S,σ)b:𝚂𝚌𝚑𝚗𝚘𝚛𝚛_𝚅𝚎𝚛𝚒𝚏𝚢formulae-sequencesuperscript𝔹256superscript𝔹512superscript𝔹51201maps-to𝑚𝑆𝜎𝑏\mathtt{Schnorr\_Verify}\colon(\mathbb{B}^{256},\mathbb{B}^{512},\mathbb{B}^{5% 12})\to\{0,1\};(m,S,\sigma)\mapsto btypewriter_Schnorr _ typewriter_Verify : ( blackboard_B start_POSTSUPERSCRIPT 256 end_POSTSUPERSCRIPT , blackboard_B start_POSTSUPERSCRIPT 512 end_POSTSUPERSCRIPT , blackboard_B start_POSTSUPERSCRIPT 512 end_POSTSUPERSCRIPT ) → { 0 , 1 } ; ( italic_m , italic_S , italic_σ ) ↦ italic_b

where b𝑏bitalic_b is a single bit representing result of verification true𝑡𝑟𝑢𝑒trueitalic_t italic_r italic_u italic_e or false𝑓𝑎𝑙𝑠𝑒falseitalic_f italic_a italic_l italic_s italic_e.

7.4. Zero Knowledge Proofs

Zero-knowledge proof (ZKP) is a cryptographic technique that allows a party, a prover to prove to another party, a verifier that it knows a secret without actually revealing a secret by following a set of complex mathematical operations.

Although the origins of ZKPs can be traced back to the early 1980s, when a group of researchers, including Shafi Goldwasser, Silvio Micali, and Charles Rackoff, published a paper (zkp, ) that introduced the primitive concept to the world, it lacked practicality at the time. However, later developments addressed the problems leading to usable implementations in various systems, especially with the advent of blockchains.

In order to be ZKP, it must satisfy three properties:

  • Completeness: If the statement is true, both the prover and verifier are following the protocol, then the verifier will accept the proof.

  • Soundness: If the statement is false, no prover can convince the verifier that it is true with any significant probability.

  • Zero Knowledge: If a statement is true, the verifier learns nothing other than the fact that the statement is true.

One particularly efficient type of ZKP is zkSNARK. A SNARK (Succinct Non-Interactive Argument of Knowledge) defines a practical proof system where the proof is succinct that can be verified in a short time and is of small size. The system is non-interactive so that the prover and verifier do not have to interact over multiple rounds. Knowledge refers to the fact that the statement is true and the prover knows a secret, also called “witness” that establishes that fact. If a SNARK proof allows for proof verification without revealing a witness it becomes a zkSNARK.

Generating a zkSNARK proof is a multi-step process that involves breaking down logic to primitive operations like addition and multiplication, creating an Arithmetic Circuit consisting of gates and wires. This circuit is then converted to a R1CS (Rank-1 Constraint System) which constrains the circuit to verify, for instance, that values are being calculated correctly with gates. The next step converts these constraints in the circuit to a Quadratic Arithmetic Program (QAP). QAP represents these constraints with polynomials rather than numbers. Afterward, together with Elliptic Curve Cryptographic (ECC) and QAP, a zkSNARK proof is formed.

7.4.1. Trusted Setup Ceremony

A trusted setup ceremony is a cryptographic procedure that involves contributions of one or more secret values, sisubscript𝑠𝑖s_{i}italic_s start_POSTSUBSCRIPT italic_i end_POSTSUBSCRIPT from one or more parties into the trusted setup system to eventually generate some piece of data that can be used to run cryptographic protocols. Once this data is generated, the secrets, sisubscript𝑠𝑖s_{i}italic_s start_POSTSUBSCRIPT italic_i end_POSTSUBSCRIPT are considered toxic waste and must be destroyed because possession of these makes it possible to rig the system. In the context of ZK, for example, it can be used to generate proofs that are false positives.

There are multiple kinds of trusted setup procedures. The original ZCash ceremony in 2016 (zcash-ceremony, ) was one earliest trusted setups being used in a major protocol. One trusted setup of particular interest is powers-of-tau setup which is multi-participant and is commonly used in protocols. To get an idea of how multi-step setups work consider the image below where, secrets, s1,s2,,snsubscript𝑠1subscript𝑠2subscript𝑠𝑛s_{1},s_{2},...,s_{n}italic_s start_POSTSUBSCRIPT 1 end_POSTSUBSCRIPT , italic_s start_POSTSUBSCRIPT 2 end_POSTSUBSCRIPT , … , italic_s start_POSTSUBSCRIPT italic_n end_POSTSUBSCRIPT

Refer to caption
Figure 3. Trusted Setup Ceremony

To be a bit precise, the secrets are used in Elliptic Curve operations for security. An input sisubscript𝑠𝑖s_{i}italic_s start_POSTSUBSCRIPT italic_i end_POSTSUBSCRIPT is used to generate successive points on the curve given the generator G𝐺Gitalic_G by operation G*si𝐺subscript𝑠𝑖G*s_{i}italic_G * italic_s start_POSTSUBSCRIPT italic_i end_POSTSUBSCRIPT. The result of the contribution, G*si𝐺subscript𝑠𝑖G*s_{i}italic_G * italic_s start_POSTSUBSCRIPT italic_i end_POSTSUBSCRIPT is fed to the next step. The next participant cannot determine the previous contributor’s secret because it is a discrete log.

A more detailed discussion can be found at (trusted-setup, ).

7.4.2. Groth16

Groth16 is a SNARK proving system proposed by Jens Groth (groth16, ) in 2016. It is a non-interactive proof system that is commonly used in privacy protocols and is fast with small proofs. The prover complexity is O(nc)𝑂subscript𝑛𝑐O(n_{c})italic_O ( italic_n start_POSTSUBSCRIPT italic_c end_POSTSUBSCRIPT ) where ncsubscript𝑛𝑐n_{c}italic_n start_POSTSUBSCRIPT italic_c end_POSTSUBSCRIPT is the number of rank-1 constraints.

Groth16 requires a trusted setup to generate proving keys and verifying keys. The setup is required to make the proofs succinct and non-interactive.

7.5. Merkle Tree

Merkle Tree is a data structure that is used to store and verify the integrity of data. It is a binary tree where each node has two children. The leaves of the tree are the data blocks that are stored and the internal nodes of the tree are the hashes of children below them. Consequently, the root of the tree is the culmination of all data blocks in the tree. This means that if any data blocks at the leaf nodes are changed or corrupted it will propagate to the root which will change too.

Refer to caption
Figure 4. Merkle tree

The root hash of the Merkle tree can be compared to a reference to verify the integrity of the data. This makes the Merkle trees very efficient.

A merkle tree is maintained in zkFi to record user assets. User-deposited assets are represented in the form of a hash called commitment that gets stored in a Merkle tree structure. During withdrawal, the same user submits a proof a.k.a Merkle Proof (among others) of inclusion of the same commitment hash in the tree and proof of knowledge of the hash’s pre-image, without revealing any traceable information like an index of commitment in tree or constituents of pre-image.

8. Conclusion

For web3 to reach mass adoption, privacy is an unquestionable facet. While zero-knowledge technology has solved the privacy problem, earlier solutions have clearly indicated that strong compliance to prevent illicit use cannot be ignored at all. Furthermore, to encourage protocols and developers to build privacy into their products, infrastructure solutions must be present that are easy to integrate and build on top of.

In this paper, we demonstrated that an infrastructure-based privacy solution with built-in compliance is possible. We proposed a middleware solution through an SDK package that is easy to integrate and abstracts away solutions to privacy and compliance without sacrificing developer experience. Consequently, rendering the protocols and developers the freedom to innovate and focus on solving their core problem instead of worrying about user privacy or compliance.

References