On the 29th of November, we announced proof of concept Zero Knowledge circuit built on top of Ethereum, and deployed to Mainnet. This contract was meant as an appendix to our cryptography paper.

On Sunday 2nd of December, we discovered that the contract allowed a withdrawal of $30 of DAI, through a transaction exploiting both a sub-routine of the code which was left commented in the rush to share our work with the community, and by us not fully accounting for the behaviour of ecrecover (detailed below).

These two problems are from a bug in the demo implementation of the protocol — the cryptography underpinning the protocol is formally sound. At present, and until we conduct a full audit of the byte code with an external auditor, and detail the production trusted setup process, our contracts remain use-at-own-risk.

While this case was found by our local testing suite, deployment was allowed to proceed without all the tests executing, in part due to our haste to share our PoC with the community.

The $30 were placed there by the AZTEC team, and no third party was impacted.

We have released updated versions of our AZTEC smart contracts, with the relevant subroutines un-commented and the note owner validation subroutine fixed.

Our next steps are as follows:

Update our deployment scripts to diminish the risks of similar human errors in future, by adding more test cases, minimal test coverage assertions and manual approval checkpoints

Release our bug bounty program, which is detailed at the bottom of this medium post

Full exploit description

On Saturday, we noticed a transaction to our zero-knowledge DAI smart contract which drained the smart contract’s DAI balance (30.6 DAI).

Naturally this should not have been possible, we noticed two problems in our deployed proof of concept smart contract that have now been addressed.

Our smart contract validator, AZTEC.sol, validates AZTEC zero-knowledge proofs by performing a series of elliptic curve arithmetic operations. There is a subroutine, validateCommitments , that checks that every input elliptic curve point is well formatted. It also checks that the integers used as inputs in the verification algorithm are well formed.

Unfortunately, this validation function was not being called for every input because the function call was commented out. Despite a test case failing because of this commented piece of code existing on our local development environment, in our haste to deploy our smart contracts before the weekend we allowed for deployment to proceed without the full battery of tests being run.

The second bug was present in our token smart contract, that created a confidential AZTEC note representation of DAI.

The method confidentialTransfer takes a set of ‘input’ AZTEC notes and ‘output’ AZTEC notes, as well as an AZTEC zero-knowledge proof that the values of these two note sets are equal.

As part of this method call, the validateInputNote subroutine is called on every input note. This subroutine checks that, for every input note, a valid ECDSA signature has been provided (the message of this signature is the AZTEC zero-knowledge proof, and it must be signed by the note owner).

AZTEC notes are stored in the noteRegistry mapping, which maps note hashes to ethereum addresses (owners). Mappings on ethereum will by default return 0 if given a key which was not initialised. This means that given an invalid note as a key, the noteRegistry mapping will return address(0x0).

Before being able to spend a note, the smart contract validates that the hash of said note in the noteRegistry maps to the address of the signer of the ECDSA signature provided in the transaction.

The address of the signer of this ECDSA signature was recovered via the ecrecover solidity helper method.

The bug in question was caused by us not fully accounting for the situation where the sender purposefully sends the ECDSA parameters which result in the ecrecover method to return 0.

This results in the smart contract allowing the spending of any invalid note, since the hash of this invalid note will map to 0 in the noteRegistry mapping, which is the address recovered from the ECDSA signature.

We have deployed fixed version of our proof of concept smart contracts to addresses 0xA43F8675850ac3f60A4D4cec954F1A1B0e1dbB07 (aztec.sol), 0xcf65A4e884373Ad12cd91c8C868F1DE9DA48501F (aztecToken.sol), which have addressed these problems. Please do not use the previous smart contracts as it is possible for an attacker to withdraw all of the DAI from these contracts.

Pre-audit bug bounty program

We have a planned audit with the ConsenSys Diligence team, before which AZTEC will remain in an alpha use-at-own-risk stage.

Please note that any rewards will ultimately be awarded at the discretion of Spilsbury Holdings Limited, the UK registered company trading as AZTEC Protocol.

Instructions for disclosure

Please e-mail all submissions to hello@aztecprotocol.com, with the subject “BUG BOUNTY”. Please include steps to replicate the bug you discovered. To give the team time to fix the vulnerability, please do not discuss your findings publicly. We will respond with our expected timelines after we receive a submission.