From 75419e5cff407f3cf12541f1c9eb1caf8842ce10 Mon Sep 17 00:00:00 2001 From: poma Date: Fri, 13 Aug 2021 18:43:47 +0300 Subject: [PATCH 1/6] refactor TreeUpdater.circom --- circuits/transaction.circom | 2 +- circuits/treeUpdater.circom | 31 +++++++++++++++++++------------ 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/circuits/transaction.circom b/circuits/transaction.circom index 29b9486..45b59c6 100644 --- a/circuits/transaction.circom +++ b/circuits/transaction.circom @@ -124,7 +124,7 @@ template Transaction(levels, nIns, nOuts, zeroLeaf) { sumIns + extAmount === sumOuts + fee; // Check merkle tree update with inserted transaction outputs - component treeUpdater = TreeUpdater(levels, zeroLeaf); + component treeUpdater = TreeUpdater(levels, 1 /* log2(nOuts) */, zeroLeaf); treeUpdater.oldRoot <== root; treeUpdater.newRoot <== newRoot; for (var i = 0; i < nOuts; i++) { diff --git a/circuits/treeUpdater.circom b/circuits/treeUpdater.circom index e09a0b2..c77ae7a 100644 --- a/circuits/treeUpdater.circom +++ b/circuits/treeUpdater.circom @@ -1,32 +1,39 @@ include "./merkleTree.circom"; -// inserts a pair of leaves into a tree -// checks that tree previously contained zeroes is same positions -// zeroLeaf is a second level leaf: `hash(0, 0)` -template TreeUpdater(n, zeroLeaf) { +// inserts a subtree into a merkle tree +// checks that tree previously contained zeroes is the same positions +// zeroSubtreeRoot is a root of a subtree that contains only zeroes +template TreeUpdater(levels, subtreeLevels, zeroSubtreeRoot) { + // currently it works only with 1-level subtrees + assert(subtreeLevels == 1); + var remainingLevels = levels - subtreeLevels; + signal input oldRoot; signal input newRoot; - signal input leaf[2]; + signal input leaf[1 << subtreeLevels]; signal input pathIndices; - signal private input pathElements[n - 1]; + signal private input pathElements[remainingLevels]; + // calculate subtree root + // todo: make it work with arbitrary subtree levels + // currently it works only with 1-level subtrees component leafPair = HashLeftRight(); leafPair.left <== leaf[0]; leafPair.right <== leaf[1]; - component treeBefore = MerkleTree(n - 1); - for(var i = 0; i < n - 1; i++) { + component treeBefore = MerkleTree(remainingLevels); + for(var i = 0; i < remainingLevels; i++) { treeBefore.pathElements[i] <== pathElements[i]; } treeBefore.pathIndices <== pathIndices; - treeBefore.leaf <== zeroLeaf; + treeBefore.leaf <== zeroSubtreeRoot; treeBefore.root === oldRoot; - component treeAfter = MerkleTree(n - 1); - for(var i = 0; i < n - 1; i++) { + component treeAfter = MerkleTree(remainingLevels); + for(var i = 0; i < remainingLevels; i++) { treeAfter.pathElements[i] <== pathElements[i]; } treeAfter.pathIndices <== pathIndices; treeAfter.leaf <== leafPair.hash; treeAfter.root === newRoot; -} \ No newline at end of file +} From 476668d250c8c421d6be14663b2f1126a01f1933 Mon Sep 17 00:00:00 2001 From: poma Date: Fri, 13 Aug 2021 18:56:56 +0300 Subject: [PATCH 2/6] cache currentCommitmentIndex --- contracts/TornadoPool.sol | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/contracts/TornadoPool.sol b/contracts/TornadoPool.sol index 84b1a56..1f9f164 100644 --- a/contracts/TornadoPool.sol +++ b/contracts/TornadoPool.sol @@ -79,10 +79,12 @@ contract TornadoPool { require(!isSpent(_args.inputNullifiers[i]), "Input is already spent"); } require(uint256(_args.extDataHash) == uint256(keccak256(abi.encode(_extData))) % FIELD_SIZE, "Incorrect external data hash"); - require(_args.outPathIndices == currentCommitmentIndex >> 1, "Invalid merkle tree insert position"); + uint256 cachedCommitmentIndex = currentCommitmentIndex; + require(_args.outPathIndices == cachedCommitmentIndex >> 1, "Invalid merkle tree insert position"); require(verifyProof(_args), "Invalid transaction proof"); currentRoot = _args.newRoot; + currentCommitmentIndex = cachedCommitmentIndex + 2; for (uint256 i = 0; i < _args.inputNullifiers.length; i++) { nullifierHashes[_args.inputNullifiers[i]] = true; } @@ -102,8 +104,8 @@ contract TornadoPool { _extData.relayer.transfer(_args.fee); } - emit NewCommitment(_args.outputCommitments[0], currentCommitmentIndex++, _extData.encryptedOutput1); - emit NewCommitment(_args.outputCommitments[1], currentCommitmentIndex++, _extData.encryptedOutput2); + emit NewCommitment(_args.outputCommitments[0], cachedCommitmentIndex, _extData.encryptedOutput1); + emit NewCommitment(_args.outputCommitments[1], cachedCommitmentIndex + 1, _extData.encryptedOutput2); for (uint256 i = 0; i < _args.inputNullifiers.length; i++) { emit NewNullifier(_args.inputNullifiers[i]); } From f99eb4bd1ed70f1bb40d7d16d0ca28db753b92e9 Mon Sep 17 00:00:00 2001 From: poma Date: Fri, 13 Aug 2021 20:07:53 +0300 Subject: [PATCH 3/6] refactor extAmount and fee into a single public input --- circuits/transaction.circom | 12 ++++-------- contracts/TornadoPool.sol | 25 +++++++++++++------------ src/index.js | 8 ++++---- src/utils.js | 8 ++++++-- 4 files changed, 27 insertions(+), 26 deletions(-) diff --git a/circuits/transaction.circom b/circuits/transaction.circom index 45b59c6..bbd47d0 100644 --- a/circuits/transaction.circom +++ b/circuits/transaction.circom @@ -18,10 +18,10 @@ nullifier = hash(commitment, privKey, merklePath) template Transaction(levels, nIns, nOuts, zeroLeaf) { signal input root; signal input newRoot; - // external amount used for deposits and withdrawals + // extAmount = external amount used for deposits and withdrawals // correct extAmount range is enforced on the smart contract - signal input extAmount; - signal input fee; + // publicAmount = fee - extAmount + signal input publicAmount; signal input extDataHash; // data for transaction inputs @@ -103,10 +103,6 @@ template Transaction(levels, nIns, nOuts, zeroLeaf) { sumOuts += outAmount[tx]; } - // Check that fee fits into 248 bits to prevent overflow - component feeCheck = Num2Bits(248); - feeCheck.in <== fee; - // check that there are no same nullifiers among all inputs component sameNullifiers[nIns * (nIns - 1) / 2]; var index = 0; @@ -121,7 +117,7 @@ template Transaction(levels, nIns, nOuts, zeroLeaf) { } // verify amount invariant - sumIns + extAmount === sumOuts + fee; + sumIns === sumOuts + publicAmount; // Check merkle tree update with inserted transaction outputs component treeUpdater = TreeUpdater(levels, 1 /* log2(nOuts) */, zeroLeaf); diff --git a/contracts/TornadoPool.sol b/contracts/TornadoPool.sol index 1f9f164..01f589c 100644 --- a/contracts/TornadoPool.sol +++ b/contracts/TornadoPool.sol @@ -14,9 +14,9 @@ pragma solidity ^0.7.0; pragma experimental ABIEncoderV2; interface IVerifier { - function verifyProof(bytes memory _proof, uint256[10] memory _input) external view returns (bool); + function verifyProof(bytes memory _proof, uint256[9] memory _input) external view returns (bool); - function verifyProof(bytes memory _proof, uint256[24] memory _input) external view returns (bool); + function verifyProof(bytes memory _proof, uint256[23] memory _input) external view returns (bool); } contract TornadoPool { @@ -31,7 +31,9 @@ contract TornadoPool { struct ExtData { address payable recipient; + uint256 extAmount; address payable relayer; + uint256 fee; bytes encryptedOutput1; bytes encryptedOutput2; } @@ -43,8 +45,7 @@ contract TornadoPool { bytes32[] inputNullifiers; bytes32[2] outputCommitments; uint256 outPathIndices; - uint256 extAmount; - uint256 fee; + uint256 publicAmount; bytes32 extDataHash; } @@ -81,6 +82,8 @@ contract TornadoPool { require(uint256(_args.extDataHash) == uint256(keccak256(abi.encode(_extData))) % FIELD_SIZE, "Incorrect external data hash"); uint256 cachedCommitmentIndex = currentCommitmentIndex; require(_args.outPathIndices == cachedCommitmentIndex >> 1, "Invalid merkle tree insert position"); + require(_extData.fee < 2**248, "Invalid fee"); + require((_args.publicAmount + _extData.extAmount) % FIELD_SIZE == _extData.fee % FIELD_SIZE, "Invalid public amount"); require(verifyProof(_args), "Invalid transaction proof"); currentRoot = _args.newRoot; @@ -89,9 +92,9 @@ contract TornadoPool { nullifierHashes[_args.inputNullifiers[i]] = true; } - int256 extAmount = calculateExternalAmount(_args.extAmount); + int256 extAmount = calculateExternalAmount(_extData.extAmount); if (extAmount > 0) { - require(msg.value == uint256(_args.extAmount), "Incorrect amount of ETH sent on deposit"); + require(msg.value == uint256(_extData.extAmount), "Incorrect amount of ETH sent on deposit"); } else if (extAmount < 0) { require(msg.value == 0, "Sent ETH amount should be 0 for withdrawal"); require(_extData.recipient != address(0), "Can't withdraw to zero address"); @@ -100,8 +103,8 @@ contract TornadoPool { require(msg.value == 0, "Sent ETH amount should be 0 for transaction"); } - if (_args.fee > 0) { - _extData.relayer.transfer(_args.fee); + if (_extData.fee > 0) { + _extData.relayer.transfer(_extData.fee); } emit NewCommitment(_args.outputCommitments[0], cachedCommitmentIndex, _extData.encryptedOutput1); @@ -136,8 +139,7 @@ contract TornadoPool { [ uint256(_args.root), uint256(_args.newRoot), - _args.extAmount, - _args.fee, + _args.publicAmount, uint256(_args.extDataHash), uint256(_args.inputNullifiers[0]), uint256(_args.inputNullifiers[1]), @@ -153,8 +155,7 @@ contract TornadoPool { [ uint256(_args.root), uint256(_args.newRoot), - _args.extAmount, - _args.fee, + _args.publicAmount, uint256(_args.extDataHash), uint256(_args.inputNullifiers[0]), uint256(_args.inputNullifiers[1]), diff --git a/src/index.js b/src/index.js index c1d12c3..24f592b 100644 --- a/src/index.js +++ b/src/index.js @@ -48,7 +48,9 @@ async function getProof({ inputs, outputs, tree, extAmount, fee, recipient, rela const extData = { recipient: toFixedHex(recipient, 20), + extAmount: toFixedHex(extAmount), relayer: toFixedHex(relayer, 20), + fee: toFixedHex(fee), encryptedOutput1: outputs[0].encrypt(), encryptedOutput2: outputs[1].encrypt(), } @@ -59,8 +61,7 @@ async function getProof({ inputs, outputs, tree, extAmount, fee, recipient, rela newRoot: tree.root(), inputNullifier: inputs.map((x) => x.getNullifier()), outputCommitment: outputs.map((x) => x.getCommitment()), - extAmount, - fee, + publicAmount: BigNumber.from(fee).sub(extAmount).add(FIELD_SIZE).mod(FIELD_SIZE).toString(), extDataHash, // data for 2 transaction inputs @@ -87,8 +88,7 @@ async function getProof({ inputs, outputs, tree, extAmount, fee, recipient, rela inputNullifiers: inputs.map((x) => toFixedHex(x.getNullifier())), outputCommitments: outputs.map((x) => toFixedHex(x.getCommitment())), outPathIndices: toFixedHex(outputIndex >> outputBatchBits), - extAmount: toFixedHex(extAmount), - fee: toFixedHex(fee), + publicAmount: toFixedHex(input.publicAmount), extDataHash: toFixedHex(extDataHash), } // console.log('Solidity args', args) diff --git a/src/utils.js b/src/utils.js index 45fb17e..f237031 100644 --- a/src/utils.js +++ b/src/utils.js @@ -13,15 +13,19 @@ const FIELD_SIZE = BigNumber.from( /** Generate random number of specified byte length */ const randomBN = (nbytes = 31) => BigNumber.from(crypto.randomBytes(nbytes)) -function getExtDataHash({ recipient, relayer, encryptedOutput1, encryptedOutput2 }) { +function getExtDataHash({ recipient, extAmount, relayer, fee, encryptedOutput1, encryptedOutput2 }) { const abi = new ethers.utils.AbiCoder() const encodedData = abi.encode( - ['tuple(address recipient,address relayer,bytes encryptedOutput1,bytes encryptedOutput2)'], + [ + 'tuple(address recipient,uint256 extAmount,address relayer,uint256 fee,bytes encryptedOutput1,bytes encryptedOutput2)', + ], [ { recipient: toFixedHex(recipient, 20), + extAmount: toFixedHex(extAmount), relayer: toFixedHex(relayer, 20), + fee: toFixedHex(fee), encryptedOutput1: encryptedOutput1, encryptedOutput2: encryptedOutput2, }, From 12c90882d1fa0b10f255106af6250d2852535ef9 Mon Sep 17 00:00:00 2001 From: Alexey Pertsev Date: Fri, 13 Aug 2021 21:28:44 +0300 Subject: [PATCH 4/6] readme update --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 035f2c1..5c87310 100644 --- a/README.md +++ b/README.md @@ -7,3 +7,6 @@ yarn yarn build yarn test ``` + +TODO +1. deposit from mainnet to the pool on optimism in one tx From 8ab4b33d915df0e6d54e0ea4bde9c9e1c39b6ed0 Mon Sep 17 00:00:00 2001 From: poma Date: Mon, 16 Aug 2021 19:53:18 +0300 Subject: [PATCH 5/6] refactor publicAmount --- README.md | 1 + contracts/TornadoPool.sol | 29 ++++++++++------------------- src/index.js | 5 +---- src/utils.js | 20 +++++++++++++------- 4 files changed, 25 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index 5c87310..5107c5d 100644 --- a/README.md +++ b/README.md @@ -9,4 +9,5 @@ yarn test ``` TODO + 1. deposit from mainnet to the pool on optimism in one tx diff --git a/contracts/TornadoPool.sol b/contracts/TornadoPool.sol index 01f589c..bd68b75 100644 --- a/contracts/TornadoPool.sol +++ b/contracts/TornadoPool.sol @@ -22,6 +22,7 @@ interface IVerifier { contract TornadoPool { uint256 public constant FIELD_SIZE = 21888242871839275222246405745257275088548364400416034343698204186575808495617; uint256 public constant MAX_EXT_AMOUNT = 2**248 - 1; + uint256 public constant MAX_FEE = 2**248; mapping(bytes32 => bool) public nullifierHashes; bytes32 public currentRoot; @@ -31,7 +32,7 @@ contract TornadoPool { struct ExtData { address payable recipient; - uint256 extAmount; + int256 extAmount; address payable relayer; uint256 fee; bytes encryptedOutput1; @@ -82,8 +83,11 @@ contract TornadoPool { require(uint256(_args.extDataHash) == uint256(keccak256(abi.encode(_extData))) % FIELD_SIZE, "Incorrect external data hash"); uint256 cachedCommitmentIndex = currentCommitmentIndex; require(_args.outPathIndices == cachedCommitmentIndex >> 1, "Invalid merkle tree insert position"); - require(_extData.fee < 2**248, "Invalid fee"); - require((_args.publicAmount + _extData.extAmount) % FIELD_SIZE == _extData.fee % FIELD_SIZE, "Invalid public amount"); + require(_extData.fee < MAX_FEE, "Invalid fee"); + require(_extData.extAmount < int256(MAX_EXT_AMOUNT) && _extData.extAmount > -int256(MAX_EXT_AMOUNT), "Invalid ext amount"); + int256 _publicAmount = int256(_extData.fee) - _extData.extAmount; + uint256 publicAmount = (_publicAmount >= 0) ? uint256(_publicAmount) : FIELD_SIZE + uint256(_publicAmount); + require(_args.publicAmount == publicAmount, "Invalid public amount"); require(verifyProof(_args), "Invalid transaction proof"); currentRoot = _args.newRoot; @@ -92,13 +96,12 @@ contract TornadoPool { nullifierHashes[_args.inputNullifiers[i]] = true; } - int256 extAmount = calculateExternalAmount(_extData.extAmount); - if (extAmount > 0) { + if (_extData.extAmount > 0) { require(msg.value == uint256(_extData.extAmount), "Incorrect amount of ETH sent on deposit"); - } else if (extAmount < 0) { + } else if (_extData.extAmount < 0) { require(msg.value == 0, "Sent ETH amount should be 0 for withdrawal"); require(_extData.recipient != address(0), "Can't withdraw to zero address"); - _extData.recipient.transfer(uint256(-extAmount)); + _extData.recipient.transfer(uint256(-_extData.extAmount)); } else { require(msg.value == 0, "Sent ETH amount should be 0 for transaction"); } @@ -114,18 +117,6 @@ contract TornadoPool { } } - function calculateExternalAmount(uint256 _extAmount) public pure returns (int256) { - // -MAX_EXT_AMOUNT < extAmount < MAX_EXT_AMOUNT - if (_extAmount < MAX_EXT_AMOUNT) { - return int256(_extAmount); - } else if (_extAmount > FIELD_SIZE - MAX_EXT_AMOUNT) { - // FIELD_SIZE - MAX_EXT_AMOUNT < _extAmount < FIELD_SIZE - return -(int256(FIELD_SIZE) - int256(_extAmount)); - } else { - revert("Invalid extAmount value"); - } - } - /** @dev whether a note is already spent */ function isSpent(bytes32 _nullifierHash) public view returns (bool) { return nullifierHashes[_nullifierHash]; diff --git a/src/index.js b/src/index.js index 24f592b..8f8231f 100644 --- a/src/index.js +++ b/src/index.js @@ -121,10 +121,7 @@ async function prepareTransaction({ .add(outputs.reduce((sum, x) => sum.add(x.amount), BigNumber.from(0))) .sub(inputs.reduce((sum, x) => sum.add(x.amount), BigNumber.from(0))) - const amount = extAmount > 0 ? extAmount : 0 // extAmount will be positive for a deposit, zero for a transact and negative for withdraw - if (extAmount < 0) { - extAmount = FIELD_SIZE.add(extAmount) - } + const amount = extAmount > 0 ? extAmount : 0 const { args, extData } = await getProof({ inputs, diff --git a/src/utils.js b/src/utils.js index f237031..87b9e5f 100644 --- a/src/utils.js +++ b/src/utils.js @@ -18,7 +18,7 @@ function getExtDataHash({ recipient, extAmount, relayer, fee, encryptedOutput1, const encodedData = abi.encode( [ - 'tuple(address recipient,uint256 extAmount,address relayer,uint256 fee,bytes encryptedOutput1,bytes encryptedOutput2)', + 'tuple(address recipient,int256 extAmount,address relayer,uint256 fee,bytes encryptedOutput1,bytes encryptedOutput2)', ], [ { @@ -36,12 +36,18 @@ function getExtDataHash({ recipient, extAmount, relayer, fee, encryptedOutput1, } /** BigNumber to hex string of specified length */ -const toFixedHex = (number, length = 32) => - '0x' + - (number instanceof Buffer - ? number.toString('hex') - : BigNumber.from(number).toHexString().slice(2) - ).padStart(length * 2, '0') +function toFixedHex(number, length = 32) { + let result = + '0x' + + (number instanceof Buffer + ? number.toString('hex') + : BigNumber.from(number).toHexString().replace('0x', '') + ).padStart(length * 2, '0') + if (result.indexOf('-') > -1) { + result = '-' + result.replace('-', '') + } + return result +} /** Convert value into buffer of specified byte length */ const toBuffer = (value, length) => From 042be187d10d331024ab9fa371b8284c449fa77e Mon Sep 17 00:00:00 2001 From: Alexey Date: Mon, 16 Aug 2021 22:17:07 +0300 Subject: [PATCH 6/6] calc public amount --- circuits/transaction.circom | 2 +- contracts/TornadoPool.sol | 15 +++++++++------ src/index.js | 2 +- test/full.test.js | 8 ++++++++ 4 files changed, 19 insertions(+), 8 deletions(-) diff --git a/circuits/transaction.circom b/circuits/transaction.circom index bbd47d0..2009590 100644 --- a/circuits/transaction.circom +++ b/circuits/transaction.circom @@ -117,7 +117,7 @@ template Transaction(levels, nIns, nOuts, zeroLeaf) { } // verify amount invariant - sumIns === sumOuts + publicAmount; + sumIns + publicAmount === sumOuts; // Check merkle tree update with inserted transaction outputs component treeUpdater = TreeUpdater(levels, 1 /* log2(nOuts) */, zeroLeaf); diff --git a/contracts/TornadoPool.sol b/contracts/TornadoPool.sol index bd68b75..9f7bf8c 100644 --- a/contracts/TornadoPool.sol +++ b/contracts/TornadoPool.sol @@ -21,7 +21,7 @@ interface IVerifier { contract TornadoPool { uint256 public constant FIELD_SIZE = 21888242871839275222246405745257275088548364400416034343698204186575808495617; - uint256 public constant MAX_EXT_AMOUNT = 2**248 - 1; + int256 public constant MAX_EXT_AMOUNT = 2**248; uint256 public constant MAX_FEE = 2**248; mapping(bytes32 => bool) public nullifierHashes; @@ -83,11 +83,7 @@ contract TornadoPool { require(uint256(_args.extDataHash) == uint256(keccak256(abi.encode(_extData))) % FIELD_SIZE, "Incorrect external data hash"); uint256 cachedCommitmentIndex = currentCommitmentIndex; require(_args.outPathIndices == cachedCommitmentIndex >> 1, "Invalid merkle tree insert position"); - require(_extData.fee < MAX_FEE, "Invalid fee"); - require(_extData.extAmount < int256(MAX_EXT_AMOUNT) && _extData.extAmount > -int256(MAX_EXT_AMOUNT), "Invalid ext amount"); - int256 _publicAmount = int256(_extData.fee) - _extData.extAmount; - uint256 publicAmount = (_publicAmount >= 0) ? uint256(_publicAmount) : FIELD_SIZE + uint256(_publicAmount); - require(_args.publicAmount == publicAmount, "Invalid public amount"); + require(_args.publicAmount == calculatePublicAmount(_extData.extAmount, _extData.fee), "Invalid public amount"); require(verifyProof(_args), "Invalid transaction proof"); currentRoot = _args.newRoot; @@ -117,6 +113,13 @@ contract TornadoPool { } } + function calculatePublicAmount(int256 _extAmount, uint256 _fee) public pure returns(uint256) { + require(_fee < MAX_FEE, "Invalid fee"); + require(_extAmount > -MAX_EXT_AMOUNT && _extAmount < MAX_EXT_AMOUNT, "Invalid ext amount"); + int256 publicAmount = _extAmount - int256(_fee); + return (publicAmount >= 0) ? uint256(publicAmount) : FIELD_SIZE - uint256(-publicAmount); + } + /** @dev whether a note is already spent */ function isSpent(bytes32 _nullifierHash) public view returns (bool) { return nullifierHashes[_nullifierHash]; diff --git a/src/index.js b/src/index.js index 8f8231f..80e461e 100644 --- a/src/index.js +++ b/src/index.js @@ -61,7 +61,7 @@ async function getProof({ inputs, outputs, tree, extAmount, fee, recipient, rela newRoot: tree.root(), inputNullifier: inputs.map((x) => x.getNullifier()), outputCommitment: outputs.map((x) => x.getCommitment()), - publicAmount: BigNumber.from(fee).sub(extAmount).add(FIELD_SIZE).mod(FIELD_SIZE).toString(), + publicAmount: BigNumber.from(extAmount).sub(fee).add(FIELD_SIZE).mod(FIELD_SIZE).toString(), extDataHash, // data for 2 transaction inputs diff --git a/test/full.test.js b/test/full.test.js index 99518d2..9512d8a 100644 --- a/test/full.test.js +++ b/test/full.test.js @@ -44,6 +44,14 @@ describe('TornadoPool', () => { expect(result).to.be.deep.equal(data) }) + it('constants check', async () => { + const maxFee = await tornadoPool.MAX_FEE() + const maxExtAmount = await tornadoPool.MAX_EXT_AMOUNT() + const fieldSize = await tornadoPool.FIELD_SIZE() + + expect(maxExtAmount.add(maxFee)).to.be.lt(fieldSize) + }) + it('should register and deposit', async function () { // Alice deposits into tornado pool const aliceDepositAmount = 1e7