This commit is contained in:
poma 2021-02-02 14:27:58 +03:00
parent 71efcb28a7
commit 4d6a05a88b
No known key found for this signature in database
GPG Key ID: BA20CB01FE165657
10 changed files with 96 additions and 56 deletions

@ -1,8 +1,6 @@
.vscode .vscode
build artifacts
cache
circuits circuits
scripts scripts
contracts/verifiers/RewardVerifier.sol contracts/verifiers
contracts/verifiers/WithdrawVerifier.sol
contracts/verifiers/TreeUpdateVerifier.sol
contracts/utils/FloatMath.sol

@ -3,7 +3,6 @@ pragma solidity ^0.6.0;
import "hardhat/console.sol"; import "hardhat/console.sol";
contract Greeter { contract Greeter {
string greeting; string greeting;

@ -3,7 +3,6 @@
pragma solidity ^0.6.0; pragma solidity ^0.6.0;
contract Pack { contract Pack {
uint256 public constant CHUNK_TREE_HEIGHT = 7; uint256 public constant CHUNK_TREE_HEIGHT = 7;
uint256 public constant CHUNK_SIZE = 2**CHUNK_TREE_HEIGHT; uint256 public constant CHUNK_SIZE = 2**CHUNK_TREE_HEIGHT;
uint256 public constant ITEM_SIZE = 32 + 20 + 4; uint256 public constant ITEM_SIZE = 32 + 20 + 4;
@ -17,10 +16,14 @@ contract Pack {
event DepositData(address instance, bytes32 indexed hash, uint256 block, uint256 index); event DepositData(address instance, bytes32 indexed hash, uint256 block, uint256 index);
function pack2(bytes32[CHUNK_SIZE] memory hashes, address[CHUNK_SIZE] memory instances, uint32[CHUNK_SIZE] memory blocks) public { function pack2(
bytes32[CHUNK_SIZE] memory hashes,
address[CHUNK_SIZE] memory instances,
uint32[CHUNK_SIZE] memory blocks
) public {
uint256 gasBefore = gasleft(); uint256 gasBefore = gasleft();
bytes memory data = new bytes(BYTES_SIZE); bytes memory data = new bytes(BYTES_SIZE);
for(uint i = 0; i < CHUNK_SIZE; i++) { for (uint256 i = 0; i < CHUNK_SIZE; i++) {
(bytes32 hash, address instance, uint32 block) = (hashes[i], instances[i], blocks[i]); (bytes32 hash, address instance, uint32 block) = (hashes[i], instances[i], blocks[i]);
assembly { assembly {
mstore(add(add(data, mul(ITEM_SIZE, i)), 0x38), block) mstore(add(add(data, mul(ITEM_SIZE, i)), 0x38), block)
@ -31,7 +34,7 @@ contract Pack {
uint256 gasHash = gasleft(); uint256 gasHash = gasleft();
bytes32 hash1 = sha256(data); bytes32 hash1 = sha256(data);
uint256 gasEvents = gasleft(); uint256 gasEvents = gasleft();
for(uint i = 0; i < CHUNK_SIZE; i++) { for (uint256 i = 0; i < CHUNK_SIZE; i++) {
emit DepositData(instances[i], hashes[i], blocks[i], i); emit DepositData(instances[i], hashes[i], blocks[i], i);
} }
gas1 = gasEvents - gasleft(); gas1 = gasEvents - gasleft();
@ -41,10 +44,22 @@ contract Pack {
hash = hash1; hash = hash1;
} }
function pack3(bytes32[CHUNK_SIZE] memory hashes, address[CHUNK_SIZE] memory instances, uint32[CHUNK_SIZE] memory blocks) public view returns(uint256 gas1, uint256 gas2, bytes32 hash) { function pack3(
bytes32[CHUNK_SIZE] memory hashes,
address[CHUNK_SIZE] memory instances,
uint32[CHUNK_SIZE] memory blocks
)
public
view
returns (
uint256 gas1,
uint256 gas2,
bytes32 hash
)
{
uint256 gasBefore = gasleft(); uint256 gasBefore = gasleft();
bytes memory data = new bytes(BYTES_SIZE); bytes memory data = new bytes(BYTES_SIZE);
for(uint i = 0; i < CHUNK_SIZE; i++) { for (uint256 i = 0; i < CHUNK_SIZE; i++) {
(bytes32 hash, address instance, uint32 block) = (hashes[i], instances[i], blocks[i]); (bytes32 hash, address instance, uint32 block) = (hashes[i], instances[i], blocks[i]);
assembly { assembly {
mstore(add(add(data, mul(ITEM_SIZE, i)), 0x38), block) mstore(add(add(data, mul(ITEM_SIZE, i)), 0x38), block)

@ -1,14 +1,14 @@
require("@nomiclabs/hardhat-waffle"); require('@nomiclabs/hardhat-waffle')
// This is a sample Hardhat task. To learn how to create your own go to // This is a sample Hardhat task. To learn how to create your own go to
// https://hardhat.org/guides/create-task.html // https://hardhat.org/guides/create-task.html
task("accounts", "Prints the list of accounts", async () => { task('accounts', 'Prints the list of accounts', async () => {
const accounts = await ethers.getSigners(); const accounts = await ethers.getSigners()
for (const account of accounts) { for (const account of accounts) {
console.log(account.address); console.log(account.address)
} }
}); })
// You need to export an object to set up your config // You need to export an object to set up your config
// Go to https://hardhat.org/config/ to learn more // Go to https://hardhat.org/config/ to learn more
@ -17,6 +17,5 @@ task("accounts", "Prints the list of accounts", async () => {
* @type import('hardhat/config').HardhatUserConfig * @type import('hardhat/config').HardhatUserConfig
*/ */
module.exports = { module.exports = {
solidity: "0.6.12", solidity: '0.6.12',
}; }

@ -1,5 +1,20 @@
{ {
"name": "hardhat-project", "name": "hardhat-project",
"repository": "https://github.com/tornadocash/tornado-trees.git",
"author": "Tornadocash team <hello@tornado.cash>",
"license": "MIT",
"scripts": {
"compile": "npx hardhat compile",
"test": "npx hardhat test",
"eslint": "eslint --ext .js --ignore-path .gitignore .",
"prettier:check": "prettier --check . --config .prettierrc",
"prettier:fix": "prettier --write . --config .prettierrc",
"lint": "yarn eslint && yarn prettier:check",
"circuit:batchTreeUpdate": "scripts/buildCircuit.sh BatchTreeUpdate",
"circuit:batchTreeUpdateLarge": "scripts/buildCircuit.sh BatchTreeUpdate large",
"circuit:batchTreeUpdateWitness": "scripts/buildWitness.sh BatchTreeUpdate",
"circuit": "yarn circuit:batchTreeUpdate"
},
"devDependencies": { "devDependencies": {
"@nomiclabs/hardhat-ethers": "^2.0.1", "@nomiclabs/hardhat-ethers": "^2.0.1",
"@nomiclabs/hardhat-waffle": "^2.0.1", "@nomiclabs/hardhat-waffle": "^2.0.1",

@ -1,13 +1,7 @@
const ethers = require('ethers') const ethers = require('ethers')
const BigNumber = ethers.BigNumber const BigNumber = ethers.BigNumber
const { const { bitsToNumber, toFixedHex, toBuffer, poseidonHash, poseidonHash2 } = require('./utils')
bitsToNumber,
toFixedHex,
toBuffer,
poseidonHash,
poseidonHash2,
} = require('./utils')
const jsSHA = require('jssha') const jsSHA = require('jssha')
@ -29,12 +23,14 @@ function hashInputs(input) {
} }
const hash = '0x' + sha.getHash('HEX') const hash = '0x' + sha.getHash('HEX')
const result = BigNumber.from(hash).mod(BigNumber.from('21888242871839275222246405745257275088548364400416034343698204186575808495617')).toString() const result = BigNumber.from(hash)
.mod(BigNumber.from('21888242871839275222246405745257275088548364400416034343698204186575808495617'))
.toString()
return result return result
} }
function prove(input, keyBasePath) { function prove(input, keyBasePath) {
return tmp.dir().then(async dir => { return tmp.dir().then(async (dir) => {
dir = dir.path dir = dir.path
fs.writeFileSync(`${dir}/input.json`, JSON.stringify(input, null, 2)) fs.writeFileSync(`${dir}/input.json`, JSON.stringify(input, null, 2))
let out let out
@ -47,13 +43,15 @@ function prove(input, keyBasePath) {
out = await exec(`npx snarkjs wd ${keyBasePath}.wasm ${dir}/input.json ${dir}/witness.wtns`) out = await exec(`npx snarkjs wd ${keyBasePath}.wasm ${dir}/input.json ${dir}/witness.wtns`)
out = await exec(`npx snarkjs wej ${dir}/witness.wtns ${dir}/witness.json`) out = await exec(`npx snarkjs wej ${dir}/witness.wtns ${dir}/witness.json`)
} }
out = await exec(`zkutil prove -c ${keyBasePath}.r1cs -p ${keyBasePath}.params -w ${dir}/witness.json -r ${dir}/proof.json -o ${dir}/public.json`) out = await exec(
`zkutil prove -c ${keyBasePath}.r1cs -p ${keyBasePath}.params -w ${dir}/witness.json -r ${dir}/proof.json -o ${dir}/public.json`,
)
} catch (e) { } catch (e) {
console.log(out, e) console.log(out, e)
throw e throw e
} }
return '0x' + JSON.parse(fs.readFileSync(`${dir}/proof.json`)).proof return '0x' + JSON.parse(fs.readFileSync(`${dir}/proof.json`)).proof
}); })
} }
function batchTreeUpdate(tree, events) { function batchTreeUpdate(tree, events) {
@ -67,7 +65,7 @@ function batchTreeUpdate(tree, events) {
tree.bulkInsert(leaves) tree.bulkInsert(leaves)
const newRoot = tree.root().toString() const newRoot = tree.root().toString()
let { pathElements, pathIndices } = tree.path(tree.elements().length - 1) let { pathElements, pathIndices } = tree.path(tree.elements().length - 1)
pathElements = pathElements.slice(batchHeight).map(a => BigNumber.from(a).toString()) pathElements = pathElements.slice(batchHeight).map((a) => BigNumber.from(a).toString())
pathIndices = bitsToNumber(pathIndices.slice(batchHeight)).toString() pathIndices = bitsToNumber(pathIndices.slice(batchHeight)).toString()
const input = { const input = {

@ -13,9 +13,19 @@ const randomBN = (nbytes = 31) => BigNumber.from(crypto.randomBytes(nbytes))
/** BigNumber to hex string of specified length */ /** BigNumber to hex string of specified length */
const toFixedHex = (number, length = 32) => const toFixedHex = (number, length = 32) =>
'0x' + '0x' +
(number instanceof Buffer ? number.toString('hex') : BigNumber.from(number).toHexString().slice(2)).padStart(length * 2, '0') (number instanceof Buffer
? number.toString('hex')
: BigNumber.from(number).toHexString().slice(2)
).padStart(length * 2, '0')
const toBuffer = (value, length) => Buffer.from(BigNumber.from(value).toHexString().slice(2).padStart(length * 2, '0'), 'hex') const toBuffer = (value, length) =>
Buffer.from(
BigNumber.from(value)
.toHexString()
.slice(2)
.padStart(length * 2, '0'),
'hex',
)
function bitsToNumber(bits) { function bitsToNumber(bits) {
let result = 0 let result = 0

@ -1,5 +1,5 @@
/* global artifacts, web3, contract */ /* global artifacts, web3, contract */
const { expect } = require("chai") const { expect } = require('chai')
const MerkleTree = require('fixed-merkle-tree') const MerkleTree = require('fixed-merkle-tree')
const jsSHA = require('jssha') const jsSHA = require('jssha')
const { poseidonHash2 } = require('../src/utils') const { poseidonHash2 } = require('../src/utils')
@ -15,7 +15,7 @@ const instances = [
const hashes = [ const hashes = [
'0x6f44cd7458bf24f65851fa8097712e3a8d9a6f3e387c501b285338308a74b8f3', '0x6f44cd7458bf24f65851fa8097712e3a8d9a6f3e387c501b285338308a74b8f3',
'0xafd3103939b7b0cd7a0ad1ddac57dd13af7f2825a21b47ae995b5bb0f767a106', '0xafd3103939b7b0cd7a0ad1ddac57dd13af7f2825a21b47ae995b5bb0f767a106',
'0x57f7b90a3cb4ea6860e6dd5fa44ac4f53ebe6ae3948af577a01ef51738313246' '0x57f7b90a3cb4ea6860e6dd5fa44ac4f53ebe6ae3948af577a01ef51738313246',
] ]
const levels = 20 const levels = 20
@ -23,7 +23,7 @@ const CHUNK_TREE_HEIGHT = 7
describe.skip('Pack', () => { describe.skip('Pack', () => {
it('should work', async () => { it('should work', async () => {
const tree = new MerkleTree(levels, [], { hashFunction: poseidonHash2 }) const tree = new MerkleTree(levels, [], { hashFunction: poseidonHash2 })
const Pack = await ethers.getContractFactory("Pack") const Pack = await ethers.getContractFactory('Pack')
const pack = await Pack.deploy() const pack = await Pack.deploy()
const notes = [] const notes = []
@ -34,7 +34,11 @@ describe.skip('Pack', () => {
block: 1 + i, block: 1 + i,
} }
} }
const receipt = await pack.pack2(notes.map(a => a.hash), notes.map(a => a.instance), notes.map(a => a.block)) const receipt = await pack.pack2(
notes.map((a) => a.hash),
notes.map((a) => a.instance),
notes.map((a) => a.block),
)
const receipt2 = await receipt.wait() const receipt2 = await receipt.wait()
console.log(`total ${receipt2.gasUsed}`) console.log(`total ${receipt2.gasUsed}`)

@ -1,5 +1,5 @@
/* global artifacts, web3, contract */ /* global artifacts, web3, contract */
const { expect } = require("chai") const { expect } = require('chai')
const MerkleTree = require('fixed-merkle-tree') const MerkleTree = require('fixed-merkle-tree')
const { poseidonHash2, randomBN } = require('../src/utils') const { poseidonHash2, randomBN } = require('../src/utils')
const { batchTreeUpdate, prove } = require('../src/controller') const { batchTreeUpdate, prove } = require('../src/controller')

@ -1,16 +1,18 @@
const { expect } = require("chai") const { expect } = require('chai')
const { toFixedHex, poseidonHash2, randomBN } = require('../src/utils') const { toFixedHex, poseidonHash2, randomBN } = require('../src/utils')
const MerkleTree = require('fixed-merkle-tree') const MerkleTree = require('fixed-merkle-tree')
const controller = require('../src/controller') const controller = require('../src/controller')
async function register(note, tornadoTrees, from) { async function register(note, tornadoTrees, from) {
await tornadoTrees.connect(from).register( await tornadoTrees
note.instance, .connect(from)
toFixedHex(note.commitment), .register(
toFixedHex(note.nullifierHash), note.instance,
note.depositBlock, toFixedHex(note.commitment),
note.withdrawalBlock, toFixedHex(note.nullifierHash),
) note.depositBlock,
note.withdrawalBlock,
)
} }
const toEns = (addr) => toFixedHex(addr, 20).padEnd(66, '0') const toEns = (addr) => toFixedHex(addr, 20).padEnd(66, '0')
@ -27,7 +29,7 @@ const instances = [
const blocks = ['0xaaaaaaaa', '0xbbbbbbbb', '0xcccccccc', '0xdddddddd'] const blocks = ['0xaaaaaaaa', '0xbbbbbbbb', '0xcccccccc', '0xdddddddd']
describe("TornadoTrees", function() { describe('TornadoTrees', function () {
let tree let tree
let operator let operator
let tornadoProxy let tornadoProxy
@ -36,14 +38,14 @@ describe("TornadoTrees", function() {
let notes let notes
let events let events
beforeEach(async function() { beforeEach(async function () {
tree = new MerkleTree(levels, [], { hashFunction: poseidonHash2 }) tree = new MerkleTree(levels, [], { hashFunction: poseidonHash2 })
;[operator, tornadoProxy] = await ethers.getSigners() ;[operator, tornadoProxy] = await ethers.getSigners()
const BatchTreeUpdateVerifier = await ethers.getContractFactory("BatchTreeUpdateVerifier") const BatchTreeUpdateVerifier = await ethers.getContractFactory('BatchTreeUpdateVerifier')
verifier = await BatchTreeUpdateVerifier.deploy() verifier = await BatchTreeUpdateVerifier.deploy()
const TornadoTrees = await ethers.getContractFactory("TornadoTreesMock") const TornadoTrees = await ethers.getContractFactory('TornadoTreesMock')
tornadoTrees = await TornadoTrees.deploy( tornadoTrees = await TornadoTrees.deploy(
toEns(operator.address), toEns(operator.address),
toEns(tornadoProxy.address), toEns(tornadoProxy.address),
@ -71,7 +73,7 @@ describe("TornadoTrees", function() {
})) }))
}) })
it("Should calculate hash", async function() { it('Should calculate hash', async function () {
const data = await controller.batchTreeUpdate(tree, events) const data = await controller.batchTreeUpdate(tree, events)
const solHash = await tornadoTrees.updateDepositTreeMock( const solHash = await tornadoTrees.updateDepositTreeMock(
toFixedHex(data.oldRoot), toFixedHex(data.oldRoot),
@ -82,7 +84,7 @@ describe("TornadoTrees", function() {
expect(solHash).to.be.equal(data.argsHash) expect(solHash).to.be.equal(data.argsHash)
}) })
it("Should calculate hash", async function() { it('Should calculate hash', async function () {
const data = await controller.batchTreeUpdate(tree, events) const data = await controller.batchTreeUpdate(tree, events)
const proof = await controller.prove(data, './artifacts/circuits/BatchTreeUpdate') const proof = await controller.prove(data, './artifacts/circuits/BatchTreeUpdate')
await tornadoTrees.updateDepositTree( await tornadoTrees.updateDepositTree(