-
Notifications
You must be signed in to change notification settings - Fork 5.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
zkERC20: Confidential Token Standard #1724
Comments
nice! Just a nit - there is a missing closing (or one too many opening) bracket in this:
|
Nice job! Could there be multiple crytographic engine to achieve "zk" ERC20? If so, I would not name it zkERC20 - as we have a |
Name suggestions?
…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. |
Thanks guys!
…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->
.
|
Why do I'm also curious if |
zkatERC20 |
ZERC20 |
re. starting events with Log - IIRC this was the advice previously to distinguish function calls from emitting events. Now that we have the Changing 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
Regarding the
Sounds good! For this and all other questions raised by @adamdossa, @zac-williamson will write a reply soon. |
It's a very minor point, but for the Obviously standards don't really include a Solidity version, so a bit of grey area. |
cc @maurelian ^ |
Ya, the “emit” keyword makes the Log prefix unnecessary, thanks for the ping @fubuloubu |
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)? |
Hi HarryR, 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. |
consider changing the name to something like |
is there anyone else besides aztec who would implement something that uses this standard? |
I think the |
@zac-williamson what is the status of this proposal? Is AZTEC following the above spec? |
There has been no activity on this issue for two months. It will be closed in a week if no further activity occurs. If you would like to move this EIP forward, please respond to any outstanding feedback or add a comment indicating that you have addressed all required feedback and are ready for a review. |
This issue was closed due to inactivity. If you are still pursuing it, feel free to reopen it and respond to any feedback or request a review in a comment. |
The thing that could change everything. |
That and solving meta transactions, or the 'approve infinite' problem and being gas poor. |
Simple Summary
This EIP defines the standard interface and behaviours of a confidential token contract, where ownership values and the values of transfers are encrypted.
Abstract
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
Motivation
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.
Specification
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
owner
field of a note is public for ease-of-use as we want traditional Ethereum private keys to be able to sign against zero-knowledge notes, and zero-knowledge spending proofs. One can use a Monero-style stealth address protocol to ensure that the Ethereum address of a note'sowner
contains no identifying information about the note's true owner.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:
bytes32 _noteHash
variable, akeccak256
hash of a note's encrypted dataaddress _owner
variable, anaddress
that defines a note's ownerbytes _notedata
variable, thenotedata
is a combination of the note's public key and the note metadata. When implemented using the AZTEC protocol,secp256k1
andbn128
group elements that allows a note owner to recover and decrypt the note.An example implementation of zkERC20 represents this as a mapping from
noteHash
toowner
:mapping(bytes32 => address) noteRegistry;
. Themetadata
is required for logging purposes only, thenoteHash
andowner
variables alone are enough to define a unique note.View Functions
cryptographyEngine
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.
publicToken
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
0
.supportsProof
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
uint16
variable is twofold:confidentialTotalSupply
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.
scalingFactor
This function returns the token
scalingFactor
. The range of integers that can be represented in a note is likely smaller than the native word size of the EVM (~30 bits vs 256 bits). As a result, a scaling factor is applied when converting between public tokens and confidential note form. An ERC20 token value of1
corresponds to an zkERC20 value ofscalingFactor
.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
confidentialApprove
method is required to delegate.confidentialApprove
This function allows a note owner to approve the address
approved
to "spend" a zero-knowledge note in aconfidentialTransferFrom
transaction.Confidential Transfers
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
validateProof(uint16 _proofId, bytes _proofData) public returns (bytes32[] _destroyedNotes, Note[] _createdNotes, address _publicOwner, int256 _publicValue)
function. This method will throw an error if the proof is invalid. If the proof is valid, the following data is returned:The structure of
Note
is the following:The above information can be used by the zkERC20 token to validate the legitimacy of a confidential transfer.
Direct Transactions
Basic "unilateral" transfers of zero-knowledge notes are enabled via a "join-split"-style transaction, accessed via the
confidentialTransfer
method.confidentialTransfer
This function is designed as an analogue to the ERC20
transfer
method.To enact a
confidentialTransfer
method call, the token contract must check and perform the following:cryptographyEngine.validateProof(1, proofData)
cryptographyEngine.validateProof
(createdNotes, destroyedNotes, publicOwner, publicValue)
and validate the following:Note
indestroyedNotes
exists in the token's note registryNote
increatedNotes
does not exist in the token's note registryIf the above conditions are satisfied, the following steps must be performed:
publicValue < 0
, callerc20Token.transferFrom(publicOwner, this, uint256(-publicValue))
. If this call fails, abort the transactionpublicValue > 0
, callerc20Token.transfer(publicOwner, uint256(publicValue))
Note
indestroyedNotes
, removeNote
from the token's note registry and emitDestroyConfidentialNote(Note.owner, Note.noteHash)
Note
increatedNotes
, addNote
to the token's note registry and emitCreateConfidentialNote(Note.owner, Note.metadata)
ConfidentialTransfer
event.Autonomous Transactions
For more exotic forms of transfers, mediated by smart contracts, the
confidentialTransferFrom
method is used.confidentialTransferFrom
This function enacts a confidential transfer of zero-knowledge notes. This function is designed as an analogue to the ERC20
transferFrom
method, to be called by smart contracts that enact confidential transfers.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
bilateral-swap
style proof in the Cryptography Engine standard).The
bytes _proofOutput
variable MUST conform to the specification of a 'proof output' from the Cryptography Engine standard. A valid_proofOutput
will contain the following data:bytes inputNotes
,bytes outputNotes
,address publicOwner
,int256 publicValue
To enact a
confidentialTransferFrom
method call, the token contract must check and perform the following:proofId
must correspond to a proof supported by the tokenbytes32 proofHash
, a keccak256 hash ofbytes _proofOutput
cryptographyEngine.validateProofByHash(proofId, proofHash, msg.sender)
validateProofByHash
returnsfalse
the transaction MUST throwvalidateProofByHash
returnstrue
, the following MUST be validatedNote
ininputNotes
exists in the token's note registryNote
inoutputNotes
does not exist in the token's note registryNote
inoutputNotes
,confidentialIsApproved(noteHash, owner)
returnstrue
If the above conditions are satisfied, the following steps must be performed:
publicValue < 0
, callerc20Token.transferFrom(publicOwner, address(this), uint256(-publicValue))
. If this call fails, abort the transactionpublicValue > 0
, callerc20Token.transfer(publicOwner, uint256(publicValue))
Note
indestroyedNotes
, removeNote
from the token's note registry and emitDestroyConfidentialNote(Note.owner, Note.noteHash)
Note
increatedNotes
, addNote
to the token's note registry and emitCreateConfidentialNote(Note.owner, Note.metadata)
ConfidentialTransfer
event.Events
CreateConfidentialNote
An event that logs the creation of a note against the note owner and the note metadata.
DestroyConfidentialNote
An event that logs the destruction of a note against the note owner and the note metadata.
Implementation
Head to the AZTEC monorepo for a work in progress implementation. Many thanks to @PaulRBerg, @thomas-waite, @ArnSch and the @AztecProtocol team for their contributions to this document.
Copyright
Work released under LGPL-3.0.
The text was updated successfully, but these errors were encountered: