Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.Sign up
zkERC20: Confidential Token Standard #1724
This EIP defines the standard interface and behaviours of a confidential token contract, where ownership values and the values of transfers are encrypted.
This standard defines a way of interacting with a confidential token contract. Confidential tokens do not have traditional balances - value is represented by notes, which are composed of a public owner and an encrypted value. Value is transferred by splitting a note into multiple notes with different owners. Similarly notes can be combined into a larger note. Note splitting is analogous to the behaviour of Bitcoin UTXOs, which is a good mental model to follow.
These "join-split" transactions must satisfy a balancing relationship (the sum of the values of the old notes must be equal to the sum of the values of the new notes) - this can be proven via a zero-knowledge proof.
This EIP was modelled on the zero-knowledge proofs enabled by the AZTEC protocol. However this specification is not specific to AZTEC and alternative technologies can be used to implement this standard, such as Bulletproofs or a zk-SNARK-based implementation
The ability to transact in confidentiality is a requirement for many kinds of financial instruments. The motivation of this EIP is to establish a standard that defines how these confidential assets are constructed and traded. Similar to an ERC20 token, if confidential tokens conform to the same interface then this standard can be re-used by other on-chain applications, such as confidential decentralized exchanges or confidential escrow accounts.
The zkERC20 token interface is designed such that the economic beneficiary of any transaction is completely divorced from the transaction sender. This is to facilitate the use of one-time stealth addresses to "own" zero-knowledge notes. Such addresses will not easily be fundable with gas to pay for transactions (without leaking information). Creating a clear separation between the transaction sender and the economic beneficiary allows third party service layers to be tasked with the responsibility to sign transactions.
An example zkERC20 token contract
The token contract must implement the above interface to be compatible with the standard. The implementation must follow the specifications described below.
The fundamental unit of 'value' in a zk-ERC20: the zero-knowledge note
Unlike traditional balances, value is represented via an UXTO-style model represented by notes. A note has the following public information:
A note has the following private information:
Public notes, private values: rationale behind the note construct
In order to enable cross-asset interoperability, we can hide the notionals in a given transaction, however what is being transacted is public, as well as the Ethereum addresses of the transactors.
This is to enable a high degree of interoperability between zero-knowledge assets - it is difficult to design a zero-knowledge DApp if one cannot identify the asset class of any given note.
The zero-knowledge note registry
A token that conforms to the zkERC20 standard must have a method of storing the token's set of unspent zero-knowledge notes. The Cryptography Engine identifies notes with the following tuple:
An example implementation of zkERC20 represents this as a mapping from
This function returns the address of the smart contract that validates this token's zero-knowledge proofs. For the specification of the Cryptography Engine, please see this ERC.
This function returns the address of the public token that this confidential token is attached to. The public token should conform to the ERC20 token standard. This link enables a user to convert between an ERC20 token balance and confidential zkERC20 notes.
If the token has no public analogue (i.e. it is a purely confidential token) this method should return
This function returns whether this token supports a specific zero-knowledge proof ID. The Cryptography Engine can support a number of zero-knowledge proofs. The token creator may wish to only support a subset of these proofs.
The rationale behind using a
This function returns the total sum of tokens that are currently represented in zero-knowledge note form by the contract. This value must be equal to the sum of the values of all unspent notes, which is validated by the Cryptography Engine. Note that this function may leak privacy if there's only one user of the zkERC20 contract instance.
This function returns the token
Approving addresses to transact zero-knowledge notes
For confidential transactions to become truly useful, it must be possible for smart contracts to transact notes on behalf of their owners. For example a confidential decentralized exchange or a confidential investment fund. These transactions still require zero-knowledge proofs that must be constructed on-chain, but they can be constructed on behalf of note owners and validated against ECDSA signatures signed by note owners.
To this end, a
This function allows a note owner to approve the address
The action of sending confidential notes requires a zero-knowledge proof to be validated by the Cryptography Engine that a given zk-ERC20 contract listens to. The semantics of this proof will vary depending on the proof ID. For example, the zero-knowledge proof required to partially fill an order between two zero-knowledge assets and the zero-knowledge proof required for a unilateral "join-split" transaction are different proofs, with different validation logic. Every proof supported by the Cryptography Engine will share the following common feature:
To validate a zero-knowledge proof, the token smart contract must call the Cryptography Engine's
The structure of
The above information can be used by the zkERC20 token to validate the legitimacy of a confidential transfer.
Basic "unilateral" transfers of zero-knowledge notes are enabled via a "join-split"-style transaction, accessed via the
This function is designed as an analogue to the ERC20
To enact a
If the above conditions are satisfied, the following steps must be performed:
For more exotic forms of transfers, mediated by smart contracts, the
This function enacts a confidential transfer of zero-knowledge notes. This function is designed as an analogue to the ERC20
Instead of supplying a zero-knowledge proof to be validated, this method is supplied with a transfer instruction that was generated by the Cryptography Engine that this asset listens to. This is to aid in preventing redundant validation of zero-knowledge proofs - some types of proof produce multiple transfer instructions (e.g. a
To enact a
If the above conditions are satisfied, the following steps must be performed:
An event that logs the creation of a note against the note owner and the note metadata.
An event that logs the destruction of a note against the note owner and the note metadata.
Work released under LGPL-3.0.
nice! Just a nit - there is a missing closing (or one too many opening) bracket in this:
On Tue, Jan 29, 2019 at 7:07 AM David Phan ***@***.***> wrote: Nice job! Could there be multiple crytographic engine to achieve "zk" ERC20? If so, I would not name it zkERC20 - as we have a aztecCryptographyEngine interface. — You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub <#1724 (comment)>, or mute the thread <https://github.com/notifications/unsubscribe-auth/Ar1NZyJNVlKDsBkneJfGsH0ltBjYfuk6ks5vIEeqgaJpZM4aTgo-> .
Thanks for spotting that! Fixed.
On Tue, Jan 29, 2019 at 11:35 AM Zachary James Williamson < ***@***.***> wrote: nice! Just a nit - there is a missing closing (or one too many opening) bracket in this: This function returns the address of the smart contract that validates this token's zero-knowledge proofs. For the specification of the [AZTEC Cryptography Engine, please see this ERC. Thanks for spotting that! Fixed. — You are receiving this because you commented. Reply to this email directly, view it on GitHub <#1724 (comment)>, or mute the thread <https://github.com/notifications/unsubscribe-auth/Ar1NZ1zoocvR5_R1yjNr7orFXYEy3d72ks5vIIZUgaJpZM4aTgo-> .
re. starting events with Log - IIRC this was the advice previously to distinguish function calls from emitting events. Now that we have the
Some questions / thoughts:
Yes, there could be multiple methodologies (cryptography engines) validating the zero-knowledge-ness of the token standards, that is, zkSNARKs or Bulletproofs. This is why we'd keep
It's a very minor point, but for the
Obviously standards don't really include a Solidity version, so a bit of grey area.
referenced this issue
Jan 30, 2019
This is very 'AZTEC' specific, and doesn't account for any other protocols.
What are the options to support Bulletproofs, tokens like Miximus and zkDAI (which use zkSNARK proofs), mixers like Möbius etc.?
It's not really a standard if it enforces one specific algorithm and is unusable by any others... because of the semantics imposed by it being over-fitted for your project.
How can this be made more agnostic to the underlying mechanisms? To be implementation agnostic...
I see no reason why the ERC20 interfaces (or ERC-223, ERC-721 and subsequent improvements etc.) can't be used to implement the basic functionality of anonymity tokens. If anything, the ERC-721 interface is probably the more viable candidate to implement an anonymity token, but this proposed standard doesn't take that into account.
Can you please re-consider your proposal, and see how you can implement this using existing standards with a wide range of wallet and tooling support (e.g. ERC-20, ERC-721)?
You're right that the language of the EIP leans heavily on AZTEC - we used AZTEC's zero-knowledge proof system as the scaffolding around which to construct this EIP, but the proposal is actually quite general and can accomodate implementations that use a variety of zero-knowledge technologies. Any zk-proof system that can validate 'join-split' style transfers involving zero-knowledge notes can be used to build a Cryptography Engine and implement this standard. I have changed the language of the EIP to reflect this.
To answer your question about the unique interface - the goal was to create an interface that is very similar to the ERC20 interface but still distinct. This is because a digital asset can have both an ERC20 representation and a confidential representation that conforms to this EIP. The EIP adds 'backwards-compatible' confidentiality - zkERC20 representations of existing tokens can be created.
The goal of this EIP is to define a fungible confidential token - where the values being transacted are encrypted, but the addresses of the transactors are not neccesarily hidden (this can be added on-top of the standard through anonymous addresses or note mixing). An ERC-721-style interface does not suit this purpose due to the non-fungible nature of an ERC-721 token. Similarly, existing token interfaces are predicated on knowing the values within a transaction, making them incompatible with such a confidential token.