Compare commits

..

No commits in common. "master" and "proposal_audit" have entirely different histories.

19 changed files with 301 additions and 360 deletions

1
.npmrc
View File

@ -1 +0,0 @@
@tornado:registry=https://git.tornado.ws/api/packages/tornado-packages/npm/

View File

@ -24,10 +24,14 @@ $ npx hardhat node --fork <https://eth-mainnet.alchemyapi.io/v2/API_KEY> --fork-
$ npx hardhat test $ npx hardhat test
``` ```
## Checklist for batch size changing
find and replace the `CHUNK_TREE_HEIGHT = ` in following files
1. `circuits/BatchTreeUpdate.circom`
2. `contracts/TornadoTrees.sol`
3. `tornadoTrees.test.js`
## build large circuits ## build large circuits
Make sure you have enough RAM 1. docker build . -t tornadocash/tornado-trees
```bash
docker build . -t tornadocash/tornado-trees
```

View File

@ -1,16 +1,14 @@
include "../node_modules/@tornado/circomlib/circuits/poseidon.circom"; include "../node_modules/circomlib/circuits/poseidon.circom";
include "../node_modules/@tornado/circomlib/circuits/bitify.circom"; include "../node_modules/circomlib/circuits/bitify.circom";
include "./MerkleTreeUpdater.circom"; include "./MerkleTreeUpdater.circom";
include "./TreeUpdateArgsHasher.circom"; include "./Utils.circom";
// Computes hashes of the next tree layer
template TreeLayer(height) { template TreeLayer(height) {
var nItems = 1 << height; signal input ins[1 << (height + 1)];
signal input ins[nItems * 2]; signal output outs[1 << height];
signal output outs[nItems];
component hash[nItems]; component hash[1 << height];
for(var i = 0; i < nItems; i++) { for(var i = 0; i < (1 << height); i++) {
hash[i] = HashLeftRight(); hash[i] = HashLeftRight();
hash[i].left <== ins[i * 2]; hash[i].left <== ins[i * 2];
hash[i].right <== ins[i * 2 + 1]; hash[i].right <== ins[i * 2 + 1];
@ -20,8 +18,6 @@ template TreeLayer(height) {
// Inserts a leaf batch into a tree // Inserts a leaf batch into a tree
// Checks that tree previously contained zero leaves in the same position // Checks that tree previously contained zero leaves in the same position
// Hashes leaves with Poseidon hash
// `batchLevels` should be less than `levels`
template BatchTreeUpdate(levels, batchLevels, zeroBatchLeaf) { template BatchTreeUpdate(levels, batchLevels, zeroBatchLeaf) {
var height = levels - batchLevels; var height = levels - batchLevels;
var nLeaves = 1 << batchLevels; var nLeaves = 1 << batchLevels;

View File

@ -1,5 +1,5 @@
include "../node_modules/@tornado/circomlib/circuits/poseidon.circom"; include "../node_modules/circomlib/circuits/poseidon.circom";
include "../node_modules/@tornado/circomlib/circuits/bitify.circom"; include "../node_modules/circomlib/circuits/bitify.circom";
// Computes Poseidon([left, right]) // Computes Poseidon([left, right])
template HashLeftRight() { template HashLeftRight() {

View File

@ -1,19 +1,17 @@
include "../node_modules/@tornado/circomlib/circuits/bitify.circom"; include "../node_modules/circomlib/circuits/bitify.circom";
include "../node_modules/@tornado/circomlib/circuits/sha256/sha256.circom"; include "../node_modules/circomlib/circuits/sha256/sha256.circom";
// Computes a SHA256 hash of all inputs packed into a byte array
// Field elements are padded to 256 bits with zeroes
template TreeUpdateArgsHasher(nLeaves) { template TreeUpdateArgsHasher(nLeaves) {
signal input oldRoot; signal private input oldRoot;
signal input newRoot; signal private input newRoot;
signal input pathIndices; signal private input pathIndices;
signal input instances[nLeaves]; signal private input instances[nLeaves];
signal input hashes[nLeaves]; signal private input hashes[nLeaves];
signal input blocks[nLeaves]; signal private input blocks[nLeaves];
signal output out; signal output out;
var header = 256 + 256 + 32; var header = 256 + 256 + 32;
var bitsPerLeaf = 256 + 160 + 32; var bitsPerLeaf = 160 + 256 + 32;
component hasher = Sha256(header + nLeaves * bitsPerLeaf); component hasher = Sha256(header + nLeaves * bitsPerLeaf);
// the range check on old root is optional, it's enforced by smart contract anyway // the range check on old root is optional, it's enforced by smart contract anyway
@ -28,20 +26,18 @@ template TreeUpdateArgsHasher(nLeaves) {
bitsNewRoot.in <== newRoot; bitsNewRoot.in <== newRoot;
bitsPathIndices.in <== pathIndices; bitsPathIndices.in <== pathIndices;
var index = 0; hasher.in[0] <== 0;
hasher.in[1] <== 0;
hasher.in[index++] <== 0;
hasher.in[index++] <== 0;
for(var i = 0; i < 254; i++) { for(var i = 0; i < 254; i++) {
hasher.in[index++] <== bitsOldRoot.out[253 - i]; hasher.in[i + 2] <== bitsOldRoot.out[253 - i];
} }
hasher.in[index++] <== 0; hasher.in[256] <== 0;
hasher.in[index++] <== 0; hasher.in[257] <== 0;
for(var i = 0; i < 254; i++) { for(var i = 0; i < 254; i++) {
hasher.in[index++] <== bitsNewRoot.out[253 - i]; hasher.in[i + 258] <== bitsNewRoot.out[253 - i];
} }
for(var i = 0; i < 32; i++) { for(var i = 0; i < 32; i++) {
hasher.in[index++] <== bitsPathIndices.out[31 - i]; hasher.in[i + 512] <== bitsPathIndices.out[31 - i];
} }
for(var leaf = 0; leaf < nLeaves; leaf++) { for(var leaf = 0; leaf < nLeaves; leaf++) {
// the range check on hash is optional, it's enforced by the smart contract anyway // the range check on hash is optional, it's enforced by the smart contract anyway
@ -51,16 +47,16 @@ template TreeUpdateArgsHasher(nLeaves) {
bitsHash[leaf].in <== hashes[leaf]; bitsHash[leaf].in <== hashes[leaf];
bitsInstance[leaf].in <== instances[leaf]; bitsInstance[leaf].in <== instances[leaf];
bitsBlock[leaf].in <== blocks[leaf]; bitsBlock[leaf].in <== blocks[leaf];
hasher.in[index++] <== 0; hasher.in[header + leaf * bitsPerLeaf + 0] <== 0;
hasher.in[index++] <== 0; hasher.in[header + leaf * bitsPerLeaf + 1] <== 0;
for(var i = 0; i < 254; i++) { for(var i = 0; i < 254; i++) {
hasher.in[index++] <== bitsHash[leaf].out[253 - i]; hasher.in[header + leaf * bitsPerLeaf + i + 2] <== bitsHash[leaf].out[253 - i];
} }
for(var i = 0; i < 160; i++) { for(var i = 0; i < 160; i++) {
hasher.in[index++] <== bitsInstance[leaf].out[159 - i]; hasher.in[header + leaf * bitsPerLeaf + i + 256] <== bitsInstance[leaf].out[159 - i];
} }
for(var i = 0; i < 32; i++) { for(var i = 0; i < 32; i++) {
hasher.in[index++] <== bitsBlock[leaf].out[31 - i]; hasher.in[header + leaf * bitsPerLeaf + i + 416] <== bitsBlock[leaf].out[31 - i];
} }
} }
component b2n = Bits2Num(256); component b2n = Bits2Num(256);

View File

@ -10,11 +10,7 @@ contract AdminUpgradeableProxy is TransparentUpgradeableProxy {
/** /**
* @dev Initializes an upgradeable proxy backed by the implementation at `_logic`. * @dev Initializes an upgradeable proxy backed by the implementation at `_logic`.
*/ */
constructor( constructor(address _logic, bytes memory _data) public payable TransparentUpgradeableProxy(_logic, msg.sender, _data) {}
address _logic,
address _admin,
bytes memory _data
) public payable TransparentUpgradeableProxy(_logic, _admin, _data) {}
/** /**
* @dev Override to allow admin access the fallback function. * @dev Override to allow admin access the fallback function.

View File

@ -7,7 +7,6 @@ import "./interfaces/ITornadoTreesV1.sol";
import "./interfaces/IBatchTreeUpdateVerifier.sol"; import "./interfaces/IBatchTreeUpdateVerifier.sol";
import "@openzeppelin/upgrades-core/contracts/Initializable.sol"; import "@openzeppelin/upgrades-core/contracts/Initializable.sol";
/// @dev This contract holds a merkle tree of all tornado cash deposit and withdrawal events
contract TornadoTrees is Initializable { contract TornadoTrees is Initializable {
address public immutable governance; address public immutable governance;
bytes32 public depositRoot; bytes32 public depositRoot;
@ -18,6 +17,7 @@ contract TornadoTrees is Initializable {
IBatchTreeUpdateVerifier public treeUpdateVerifier; IBatchTreeUpdateVerifier public treeUpdateVerifier;
ITornadoTreesV1 public immutable tornadoTreesV1; ITornadoTreesV1 public immutable tornadoTreesV1;
// make sure CHUNK_TREE_HEIGHT has the same value in BatchTreeUpdate.circom
uint256 public constant CHUNK_TREE_HEIGHT = 8; uint256 public constant CHUNK_TREE_HEIGHT = 8;
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;
@ -36,8 +36,6 @@ contract TornadoTrees is Initializable {
event DepositData(address instance, bytes32 indexed hash, uint256 block, uint256 index); event DepositData(address instance, bytes32 indexed hash, uint256 block, uint256 index);
event WithdrawalData(address instance, bytes32 indexed hash, uint256 block, uint256 index); event WithdrawalData(address instance, bytes32 indexed hash, uint256 block, uint256 index);
event VerifierUpdated(address newVerifier);
event ProxyUpdated(address newProxy);
struct TreeLeaf { struct TreeLeaf {
bytes32 hash; bytes32 hash;
@ -102,140 +100,18 @@ contract TornadoTrees is Initializable {
withdrawalsLength = withdrawalsV1Length; withdrawalsLength = withdrawalsV1Length;
} }
/// @dev Queue a new deposit data to be inserted into a merkle tree // todo make things internal
function registerDeposit(address _instance, bytes32 _commitment) public onlyTornadoProxy {
uint256 _depositsLength = depositsLength;
deposits[_depositsLength] = keccak256(abi.encode(_instance, _commitment, blockNumber()));
emit DepositData(_instance, _commitment, blockNumber(), _depositsLength);
depositsLength = _depositsLength + 1;
}
/// @dev Queue a new withdrawal data to be inserted into a merkle tree
function registerWithdrawal(address _instance, bytes32 _nullifierHash) public onlyTornadoProxy {
uint256 _withdrawalsLength = withdrawalsLength;
withdrawals[_withdrawalsLength] = keccak256(abi.encode(_instance, _nullifierHash, blockNumber()));
emit WithdrawalData(_instance, _nullifierHash, blockNumber(), _withdrawalsLength);
withdrawalsLength = _withdrawalsLength + 1;
}
/// @dev Insert a full batch of queued deposits into a merkle tree
/// @param _proof A snark proof that elements were inserted correctly
/// @param _argsHash A hash of snark inputs
/// @param _currentRoot Current merkle tree root
/// @param _newRoot Updated merkle tree root
/// @param _pathIndices Merkle path to inserted batch
/// @param _events A batch of inserted events (leaves)
function updateDepositTree(
bytes calldata _proof,
bytes32 _argsHash,
bytes32 _currentRoot,
bytes32 _newRoot,
uint32 _pathIndices,
TreeLeaf[CHUNK_SIZE] calldata _events
) public {
uint256 offset = lastProcessedDepositLeaf;
require(_currentRoot == depositRoot, "Proposed deposit root is invalid");
require(_pathIndices == offset >> CHUNK_TREE_HEIGHT, "Incorrect deposit insert index");
bytes memory data = new bytes(BYTES_SIZE);
assembly {
mstore(add(data, 0x44), _pathIndices)
mstore(add(data, 0x40), _newRoot)
mstore(add(data, 0x20), _currentRoot)
}
for (uint256 i = 0; i < CHUNK_SIZE; i++) {
(bytes32 hash, address instance, uint32 blockNumber) = (_events[i].hash, _events[i].instance, _events[i].block);
bytes32 leafHash = keccak256(abi.encode(instance, hash, blockNumber));
bytes32 deposit = offset + i >= depositsV1Length ? deposits[offset + i] : tornadoTreesV1.deposits(offset + i);
require(leafHash == deposit, "Incorrect deposit");
assembly {
let itemOffset := add(data, mul(ITEM_SIZE, i))
mstore(add(itemOffset, 0x7c), blockNumber)
mstore(add(itemOffset, 0x78), instance)
mstore(add(itemOffset, 0x64), hash)
}
if (offset + i >= depositsV1Length) {
delete deposits[offset + i];
} else {
emit DepositData(instance, hash, blockNumber, offset + i);
}
}
uint256 argsHash = uint256(sha256(data)) % SNARK_FIELD;
require(argsHash == uint256(_argsHash), "Invalid args hash");
require(treeUpdateVerifier.verifyProof(_proof, [argsHash]), "Invalid deposit tree update proof");
previousDepositRoot = _currentRoot;
depositRoot = _newRoot;
lastProcessedDepositLeaf = offset + CHUNK_SIZE;
}
/// @dev Insert a full batch of queued withdrawals into a merkle tree
/// @param _proof A snark proof that elements were inserted correctly
/// @param _argsHash A hash of snark inputs
/// @param _currentRoot Current merkle tree root
/// @param _newRoot Updated merkle tree root
/// @param _pathIndices Merkle path to inserted batch
/// @param _events A batch of inserted events (leaves)
function updateWithdrawalTree(
bytes calldata _proof,
bytes32 _argsHash,
bytes32 _currentRoot,
bytes32 _newRoot,
uint32 _pathIndices,
TreeLeaf[CHUNK_SIZE] calldata _events
) public {
uint256 offset = lastProcessedWithdrawalLeaf;
require(_currentRoot == withdrawalRoot, "Proposed withdrawal root is invalid");
require(_pathIndices == offset >> CHUNK_TREE_HEIGHT, "Incorrect withdrawal insert index");
bytes memory data = new bytes(BYTES_SIZE);
assembly {
mstore(add(data, 0x44), _pathIndices)
mstore(add(data, 0x40), _newRoot)
mstore(add(data, 0x20), _currentRoot)
}
for (uint256 i = 0; i < CHUNK_SIZE; i++) {
(bytes32 hash, address instance, uint32 blockNumber) = (_events[i].hash, _events[i].instance, _events[i].block);
bytes32 leafHash = keccak256(abi.encode(instance, hash, blockNumber));
bytes32 withdrawal = offset + i >= withdrawalsV1Length ? withdrawals[offset + i] : tornadoTreesV1.withdrawals(offset + i);
require(leafHash == withdrawal, "Incorrect withdrawal");
assembly {
let itemOffset := add(data, mul(ITEM_SIZE, i))
mstore(add(itemOffset, 0x7c), blockNumber)
mstore(add(itemOffset, 0x78), instance)
mstore(add(itemOffset, 0x64), hash)
}
if (offset + i >= withdrawalsV1Length) {
delete withdrawals[offset + i];
} else {
emit WithdrawalData(instance, hash, blockNumber, offset + i);
}
}
uint256 argsHash = uint256(sha256(data)) % SNARK_FIELD;
require(argsHash == uint256(_argsHash), "Invalid args hash");
require(treeUpdateVerifier.verifyProof(_proof, [argsHash]), "Invalid withdrawal tree update proof");
previousWithdrawalRoot = _currentRoot;
withdrawalRoot = _newRoot;
lastProcessedWithdrawalLeaf = offset + CHUNK_SIZE;
}
function validateRoots(bytes32 _depositRoot, bytes32 _withdrawalRoot) public view {
require(_depositRoot == depositRoot || _depositRoot == previousDepositRoot, "Incorrect deposit tree root");
require(_withdrawalRoot == withdrawalRoot || _withdrawalRoot == previousWithdrawalRoot, "Incorrect withdrawal tree root");
}
/// @dev There is no array length getter for deposit and withdrawal arrays /// @dev There is no array length getter for deposit and withdrawal arrays
/// in the previous contract, so we have to find them length manually. /// in previous contract, so we have to find them length manually
/// Used only during deployment
function findArrayLength( function findArrayLength(
ITornadoTreesV1 _tornadoTreesV1, ITornadoTreesV1 _tornadoTreesV1,
string memory _type, string memory _type,
uint256 _from, // most likely array length after the proposal has passed uint256 _from, // most likely array length after the proposal has passed
uint256 _step // optimal step size to find first match, approximately equals dispersion uint256 _step // optimal step size to find first match, approximately equals dispersion
) internal view virtual returns (uint256) { ) public view returns (uint256) {
if (_from == 0 && _step == 0) {
return 0; // for tests
}
// Find the segment with correct array length // Find the segment with correct array length
bool direction = elementExists(_tornadoTreesV1, _type, _from); bool direction = elementExists(_tornadoTreesV1, _type, _from);
do { do {
@ -266,14 +142,139 @@ contract TornadoTrees is Initializable {
(success, ) = address(_tornadoTreesV1).staticcall{ gas: 2500 }(abi.encodeWithSignature(_type, index)); (success, ) = address(_tornadoTreesV1).staticcall{ gas: 2500 }(abi.encodeWithSignature(_type, index));
} }
function registerDeposit(address _instance, bytes32 _commitment) public onlyTornadoProxy {
uint256 _depositsLength = depositsLength;
deposits[_depositsLength] = keccak256(abi.encode(_instance, _commitment, blockNumber()));
emit DepositData(_instance, _commitment, blockNumber(), _depositsLength);
depositsLength = _depositsLength + 1;
}
function registerWithdrawal(address _instance, bytes32 _nullifierHash) public onlyTornadoProxy {
uint256 _withdrawalsLength = withdrawalsLength;
withdrawals[_withdrawalsLength] = keccak256(abi.encode(_instance, _nullifierHash, blockNumber()));
emit WithdrawalData(_instance, _nullifierHash, blockNumber(), _withdrawalsLength);
withdrawalsLength = _withdrawalsLength + 1;
}
function updateDepositTree(
bytes calldata _proof,
bytes32 _argsHash,
bytes32 _currentRoot,
bytes32 _newRoot,
uint32 _pathIndices,
TreeLeaf[CHUNK_SIZE] calldata _events
) public {
uint256 offset = lastProcessedDepositLeaf;
require(_newRoot != previousDepositRoot, "Outdated deposit root");
require(_currentRoot == depositRoot, "Proposed deposit root is invalid");
require(_pathIndices == offset >> CHUNK_TREE_HEIGHT, "Incorrect insert index");
bytes memory data = new bytes(BYTES_SIZE);
assembly {
mstore(add(data, 0x44), _pathIndices)
mstore(add(data, 0x40), _newRoot)
mstore(add(data, 0x20), _currentRoot)
}
for (uint256 i = 0; i < CHUNK_SIZE; i++) {
(bytes32 hash, address instance, uint32 blockNumber) = (_events[i].hash, _events[i].instance, _events[i].block);
bytes32 leafHash = keccak256(abi.encode(instance, hash, blockNumber));
bytes32 deposit = offset + i >= depositsV1Length ? deposits[offset + i] : tornadoTreesV1.deposits(offset + i);
require(leafHash == deposit, "Incorrect deposit");
assembly {
mstore(add(add(data, mul(ITEM_SIZE, i)), 0x7c), blockNumber)
mstore(add(add(data, mul(ITEM_SIZE, i)), 0x78), instance)
mstore(add(add(data, mul(ITEM_SIZE, i)), 0x64), hash)
}
if (offset + i >= depositsV1Length) {
delete deposits[offset + i];
} else {
emit DepositData(instance, hash, blockNumber, offset + i);
}
}
uint256 argsHash = uint256(sha256(data)) % SNARK_FIELD;
require(argsHash == uint256(_argsHash), "Invalid args hash");
require(treeUpdateVerifier.verifyProof(_proof, [argsHash]), "Invalid deposit tree update proof");
previousDepositRoot = _currentRoot;
depositRoot = _newRoot;
lastProcessedDepositLeaf = offset + CHUNK_SIZE;
}
function updateWithdrawalTree(
bytes calldata _proof,
bytes32 _argsHash,
bytes32 _currentRoot,
bytes32 _newRoot,
uint256 _pathIndices,
TreeLeaf[CHUNK_SIZE] calldata _events
) public {
uint256 offset = lastProcessedWithdrawalLeaf;
require(_newRoot != previousWithdrawalRoot, "Outdated withdrawal root");
require(_currentRoot == withdrawalRoot, "Proposed withdrawal root is invalid");
require(_pathIndices == offset >> CHUNK_TREE_HEIGHT, "Incorrect insert index");
require(uint256(_newRoot) < SNARK_FIELD, "Proposed root is out of range");
bytes memory data = new bytes(BYTES_SIZE);
assembly {
mstore(add(data, 0x44), _pathIndices)
mstore(add(data, 0x40), _newRoot)
mstore(add(data, 0x20), _currentRoot)
}
for (uint256 i = 0; i < CHUNK_SIZE; i++) {
(bytes32 hash, address instance, uint32 blockNumber) = (_events[i].hash, _events[i].instance, _events[i].block);
bytes32 leafHash = keccak256(abi.encode(instance, hash, blockNumber));
bytes32 withdrawal = offset + i >= withdrawalsV1Length ? withdrawals[offset + i] : tornadoTreesV1.withdrawals(offset + i);
require(leafHash == withdrawal, "Incorrect withdrawal");
require(uint256(hash) < SNARK_FIELD, "Hash out of range");
assembly {
mstore(add(add(data, mul(ITEM_SIZE, i)), 0x7c), blockNumber)
mstore(add(add(data, mul(ITEM_SIZE, i)), 0x78), instance)
mstore(add(add(data, mul(ITEM_SIZE, i)), 0x64), hash)
}
if (offset + i >= withdrawalsV1Length) {
delete withdrawals[offset + i];
} else {
emit WithdrawalData(instance, hash, blockNumber, offset + i);
}
}
uint256 argsHash = uint256(sha256(data)) % SNARK_FIELD;
require(argsHash == uint256(_argsHash), "Invalid args hash");
require(treeUpdateVerifier.verifyProof(_proof, [argsHash]), "Invalid withdrawal tree update proof");
previousWithdrawalRoot = _currentRoot;
withdrawalRoot = _newRoot;
lastProcessedWithdrawalLeaf = offset + CHUNK_SIZE;
}
function validateRoots(bytes32 _depositRoot, bytes32 _withdrawalRoot) public view {
require(_depositRoot == depositRoot || _depositRoot == previousDepositRoot, "Incorrect deposit tree root");
require(_withdrawalRoot == withdrawalRoot || _withdrawalRoot == previousWithdrawalRoot, "Incorrect withdrawal tree root");
}
function getRegisteredDeposits() external view returns (bytes32[] memory _deposits) {
uint256 count = depositsLength - lastProcessedDepositLeaf;
_deposits = new bytes32[](count);
for (uint256 i = 0; i < count; i++) {
_deposits[i] = deposits[lastProcessedDepositLeaf + i];
}
}
function getRegisteredWithdrawals() external view returns (bytes32[] memory _withdrawals) {
uint256 count = withdrawalsLength - lastProcessedWithdrawalLeaf;
_withdrawals = new bytes32[](count);
for (uint256 i = 0; i < count; i++) {
_withdrawals[i] = withdrawals[lastProcessedWithdrawalLeaf + i];
}
}
function setTornadoProxyContract(address _tornadoProxy) external onlyGovernance { function setTornadoProxyContract(address _tornadoProxy) external onlyGovernance {
tornadoProxy = _tornadoProxy; tornadoProxy = _tornadoProxy;
emit ProxyUpdated(_tornadoProxy);
} }
function setVerifierContract(IBatchTreeUpdateVerifier _treeUpdateVerifier) external onlyGovernance { function setVerifierContract(IBatchTreeUpdateVerifier _treeUpdateVerifier) external onlyGovernance {
treeUpdateVerifier = _treeUpdateVerifier; treeUpdateVerifier = _treeUpdateVerifier;
emit VerifierUpdated(address(_treeUpdateVerifier));
} }
function blockNumber() public view virtual returns (uint256) { function blockNumber() public view virtual returns (uint256) {

View File

@ -24,11 +24,11 @@ contract Pack {
uint256 gasBefore = gasleft(); uint256 gasBefore = gasleft();
bytes memory data = new bytes(BYTES_SIZE); bytes memory data = new bytes(BYTES_SIZE);
for (uint256 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)
mstore(add(add(data, mul(ITEM_SIZE, i)), 0x34), _instance) mstore(add(add(data, mul(ITEM_SIZE, i)), 0x34), instance)
mstore(add(add(data, mul(ITEM_SIZE, i)), 0x20), _hash) mstore(add(add(data, mul(ITEM_SIZE, i)), 0x20), hash)
} }
} }
uint256 gasHash = gasleft(); uint256 gasHash = gasleft();
@ -52,23 +52,23 @@ contract Pack {
public public
view view
returns ( returns (
uint256, uint256 gas1,
uint256, uint256 gas2,
bytes32 bytes32 hash
) )
{ {
uint256 gasBefore = gasleft(); uint256 gasBefore = gasleft();
bytes memory data = new bytes(BYTES_SIZE); bytes memory data = new bytes(BYTES_SIZE);
for (uint256 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)
mstore(add(add(data, mul(ITEM_SIZE, i)), 0x34), _instance) mstore(add(add(data, mul(ITEM_SIZE, i)), 0x34), instance)
mstore(add(add(data, mul(ITEM_SIZE, i)), 0x20), _hash) mstore(add(add(data, mul(ITEM_SIZE, i)), 0x20), hash)
} }
} }
uint256 gasHash = gasleft(); uint256 gasHash = gasleft();
bytes32 hash1 = sha256(data); bytes32 hash = sha256(data);
return (gasleft() - gasHash, gasHash - gasBefore, hash1); return (gasleft() - gasHash, gasHash - gasBefore, hash);
} }
} }

View File

@ -24,15 +24,6 @@ contract TornadoTreesMock is TornadoTrees {
return currentBlock == 0 ? block.number : currentBlock; return currentBlock == 0 ? block.number : currentBlock;
} }
function findArrayLengthMock(
ITornadoTreesV1 _tornadoTreesV1,
string memory _type,
uint256 _from,
uint256 _step
) public view returns (uint256) {
return findArrayLength(_tornadoTreesV1, _type, _from, _step);
}
function register( function register(
address _instance, address _instance,
bytes32 _commitment, bytes32 _commitment,
@ -97,32 +88,4 @@ contract TornadoTreesMock is TornadoTrees {
} }
return data; return data;
} }
function getRegisteredDeposits() external view returns (bytes32[] memory _deposits) {
uint256 count = depositsLength - lastProcessedDepositLeaf;
_deposits = new bytes32[](count);
for (uint256 i = 0; i < count; i++) {
_deposits[i] = deposits[lastProcessedDepositLeaf + i];
}
}
function getRegisteredWithdrawals() external view returns (bytes32[] memory _withdrawals) {
uint256 count = withdrawalsLength - lastProcessedWithdrawalLeaf;
_withdrawals = new bytes32[](count);
for (uint256 i = 0; i < count; i++) {
_withdrawals[i] = withdrawals[lastProcessedWithdrawalLeaf + i];
}
}
function findArrayLength(
ITornadoTreesV1 _tornadoTreesV1,
string memory _type,
uint256 _from, // most likely array length after the proposal has passed
uint256 _step // optimal step size to find first match, approximately equals dispersion
) internal view override returns (uint256) {
if (_from == 0 && _step == 0) {
return 0;
}
return super.findArrayLength(_tornadoTreesV1, _type, _from, _step);
}
} }

View File

@ -41,7 +41,7 @@ RUN source $HOME/.cargo/env && cargo install zkutil
RUN npm install -g circom snarkjs RUN npm install -g circom snarkjs
WORKDIR /root/test WORKDIR /root/test
RUN npm init -y && npm install @tornado/circomlib RUN npm init -y && npm install circomlib
RUN apt-get update && apt-get install -y ne RUN apt-get update && apt-get install -y ne
RUN mkdir circuits RUN mkdir circuits
COPY sha/circuit.circom sha/input.js test.sh ./circuits/ COPY sha/circuit.circom sha/input.js test.sh ./circuits/

View File

@ -1,14 +1,13 @@
{ {
"name": "@tornado/trees", "name": "tornado-trees",
"version": "0.0.11", "version": "0.0.7",
"main": "src/index.js", "main": "src/index.js",
"repository": "https://git.tornado.ws/tornado-packages/tornado-trees.git", "repository": "https://github.com/tornadocash/tornado-trees.git",
"author": "Tornadocash team <hello@tornado.cash>", "author": "Tornadocash team <hello@tornado.cash>",
"license": "MIT", "license": "MIT",
"files": [ "files": [
"src/*", "src/*",
"contracts/*", "contracts/*"
"scripts/*"
], ],
"scripts": { "scripts": {
"compile": "npx hardhat compile", "compile": "npx hardhat compile",
@ -42,13 +41,12 @@
"dependencies": { "dependencies": {
"@openzeppelin/contracts": "^3.4.0", "@openzeppelin/contracts": "^3.4.0",
"@openzeppelin/upgrades-core": "^1.5.1", "@openzeppelin/upgrades-core": "^1.5.1",
"@tornado/circomlib": "^0.0.21", "circom": "^0.5.38",
"@tornado/fixed-merkle-tree": "^0.5.0",
"circom": "0.5.42",
"circom_runtime": "^0.1.12", "circom_runtime": "^0.1.12",
"circomlib": "git+https://github.com/tornadocash/circomlib.git#d20d53411d1bef61f38c99a8b36d5d0cc4836aa1",
"dotenv": "^8.2.0", "dotenv": "^8.2.0",
"ffiasm": "^0.1.1", "ffiasm": "^0.1.1",
"ffjavascript": "^0.2.35", "fixed-merkle-tree": "^0.5.0",
"jssha": "^3.2.0", "jssha": "^3.2.0",
"snarkjs": "^0.3.57", "snarkjs": "^0.3.57",
"tmp-promise": "^3.0.2" "tmp-promise": "^3.0.2"

View File

@ -5,7 +5,7 @@
// Runtime Environment's members available in the global scope. // Runtime Environment's members available in the global scope.
const hre = require('hardhat') const hre = require('hardhat')
const { toFixedHex, poseidonHash2 } = require('../src/utils') const { toFixedHex, poseidonHash2 } = require('../src/utils')
const MerkleTree = require('@tornado/fixed-merkle-tree') const MerkleTree = require('fixed-merkle-tree')
const abi = new hre.ethers.utils.AbiCoder() const abi = new hre.ethers.utils.AbiCoder()
const instances = [ const instances = [
'0x1111000000000000000000000000000000001111', '0x1111000000000000000000000000000000001111',

View File

@ -5,7 +5,7 @@
// Runtime Environment's members available in the global scope. // Runtime Environment's members available in the global scope.
const hre = require('hardhat') const hre = require('hardhat')
const { toFixedHex, poseidonHash2 } = require('../src/utils') const { toFixedHex, poseidonHash2 } = require('../src/utils')
const MerkleTree = require('@tornado/fixed-merkle-tree') const MerkleTree = require('fixed-merkle-tree')
const abi = new hre.ethers.utils.AbiCoder() const abi = new hre.ethers.utils.AbiCoder()
const instances = [ const instances = [
'0x1111000000000000000000000000000000001111', '0x1111000000000000000000000000000000001111',

View File

@ -1,7 +1,5 @@
const ethers = require('ethers') const ethers = require('ethers')
const BigNumber = ethers.BigNumber const BigNumber = ethers.BigNumber
const { wtns } = require('snarkjs')
const { utils } = require('ffjavascript')
const { bitsToNumber, toBuffer, toFixedHex, poseidonHash } = require('./utils') const { bitsToNumber, toBuffer, toFixedHex, poseidonHash } = require('./utils')
@ -34,24 +32,16 @@ function hashInputs(input) {
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))
let out let out
try { try {
if (fs.existsSync(`${keyBasePath}`)) { if (fs.existsSync(`${keyBasePath}`)) {
// native witness calc // native witness calc
fs.writeFileSync(`${dir}/input.json`, JSON.stringify(input, null, 2))
out = await exec(`${keyBasePath} ${dir}/input.json ${dir}/witness.json`) out = await exec(`${keyBasePath} ${dir}/input.json ${dir}/witness.json`)
} else { } else {
await wtns.debug( out = await exec(`npx snarkjs wd ${keyBasePath}.wasm ${dir}/input.json ${dir}/witness.wtns`)
utils.unstringifyBigInts(input), out = await exec(`npx snarkjs wej ${dir}/witness.wtns ${dir}/witness.json`)
`${keyBasePath}.wasm`,
`${dir}/witness.wtns`,
`${keyBasePath}.sym`,
{},
console,
)
const witness = utils.stringifyBigInts(await wtns.exportJson(`${dir}/witness.wtns`))
fs.writeFileSync(`${dir}/witness.json`, JSON.stringify(witness, null, 2))
} }
out = await exec( out = await exec(
`zkutil prove -c ${keyBasePath}.r1cs -p ${keyBasePath}.params -w ${dir}/witness.json -r ${dir}/proof.json -o ${dir}/public.json`, `zkutil prove -c ${keyBasePath}.r1cs -p ${keyBasePath}.params -w ${dir}/witness.json -r ${dir}/proof.json -o ${dir}/public.json`,
@ -64,14 +54,6 @@ function prove(input, keyBasePath) {
}) })
} }
/**
* Generates inputs for a snark and tornado trees smart contract.
* This function updates MerkleTree argument
*
* @param tree Merkle tree with current smart contract state. This object is mutated during function execution.
* @param events New batch of events to insert.
* @returns {{args: [string, string, string, string, *], input: {pathElements: *, instances: *, blocks: *, newRoot: *, hashes: *, oldRoot: *, pathIndices: string}}}
*/
function batchTreeUpdate(tree, events) { function batchTreeUpdate(tree, events) {
const batchHeight = Math.log2(events.length) const batchHeight = Math.log2(events.length)
if (!Number.isInteger(batchHeight)) { if (!Number.isInteger(batchHeight)) {

View File

@ -1,7 +1,7 @@
const crypto = require('crypto') const crypto = require('crypto')
const ethers = require('ethers') const ethers = require('ethers')
const BigNumber = ethers.BigNumber const BigNumber = ethers.BigNumber
const { poseidon } = require('@tornado/circomlib') const { poseidon } = require('circomlib')
const poseidonHash = (items) => BigNumber.from(poseidon(items).toString()) const poseidonHash = (items) => BigNumber.from(poseidon(items).toString())

View File

@ -28,70 +28,40 @@ describe('findArrayLength', () => {
}) })
it('should work for even array', async () => { it('should work for even array', async () => {
const depositsLength = await tornadoTrees.findArrayLengthMock( const depositsLength = await tornadoTrees.findArrayLength(publicArray.address, 'deposits(uint256)', 4, 2)
publicArray.address,
'deposits(uint256)',
4,
2,
)
expect(depositsLength).to.be.equal(depositsEven.length) expect(depositsLength).to.be.equal(depositsEven.length)
}) })
it('should work for empty array', async () => { it('should work for empty array', async () => {
publicArray = await PublicArray.deploy() publicArray = await PublicArray.deploy()
// will throw out of gas if you pass non zero params // will throw out of gas if you pass non zero params
const depositsLength = await tornadoTrees.findArrayLengthMock( const depositsLength = await tornadoTrees.findArrayLength(publicArray.address, 'deposits(uint256)', 0, 0)
publicArray.address,
'deposits(uint256)',
0,
0,
)
expect(depositsLength).to.be.equal(0) expect(depositsLength).to.be.equal(0)
}) })
it('should work for odd array', async () => { it('should work for odd array', async () => {
publicArray = await PublicArray.deploy() publicArray = await PublicArray.deploy()
await publicArray.setDeposits(depositsOdd) await publicArray.setDeposits(depositsOdd)
const depositsLength = await tornadoTrees.findArrayLengthMock( const depositsLength = await tornadoTrees.findArrayLength(publicArray.address, 'deposits(uint256)', 4, 2)
publicArray.address,
'deposits(uint256)',
4,
2,
)
expect(depositsLength).to.be.equal(depositsOdd.length) expect(depositsLength).to.be.equal(depositsOdd.length)
}) })
it('should work for even array and odd step', async () => { it('should work for even array and odd step', async () => {
const depositsLength = await tornadoTrees.findArrayLengthMock( const depositsLength = await tornadoTrees.findArrayLength(publicArray.address, 'deposits(uint256)', 4, 3)
publicArray.address,
'deposits(uint256)',
4,
3,
)
expect(depositsLength).to.be.equal(depositsEven.length) expect(depositsLength).to.be.equal(depositsEven.length)
}) })
it('should work for odd array and odd step', async () => { it('should work for odd array and odd step', async () => {
publicArray = await PublicArray.deploy() publicArray = await PublicArray.deploy()
await publicArray.setDeposits(depositsOdd) await publicArray.setDeposits(depositsOdd)
const depositsLength = await tornadoTrees.findArrayLengthMock( const depositsLength = await tornadoTrees.findArrayLength(publicArray.address, 'deposits(uint256)', 4, 3)
publicArray.address,
'deposits(uint256)',
4,
3,
)
expect(depositsLength).to.be.equal(depositsOdd.length) expect(depositsLength).to.be.equal(depositsOdd.length)
}) })
it('should work for odd array and step 1', async () => { it('should work for odd array and step 1', async () => {
publicArray = await PublicArray.deploy() publicArray = await PublicArray.deploy()
await publicArray.setDeposits(depositsOdd) await publicArray.setDeposits(depositsOdd)
const depositsLength = await tornadoTrees.findArrayLengthMock( const depositsLength = await tornadoTrees.findArrayLength(publicArray.address, 'deposits(uint256)', 4, 1)
publicArray.address,
'deposits(uint256)',
4,
1,
)
expect(depositsLength).to.be.equal(depositsOdd.length) expect(depositsLength).to.be.equal(depositsOdd.length)
}) })
@ -99,7 +69,7 @@ describe('findArrayLength', () => {
const deposits = Array.from(Array(100).keys()) const deposits = Array.from(Array(100).keys())
publicArray = await PublicArray.deploy() publicArray = await PublicArray.deploy()
await publicArray.setDeposits(deposits) await publicArray.setDeposits(deposits)
const depositsLength = await tornadoTrees.findArrayLengthMock( const depositsLength = await tornadoTrees.findArrayLength(
publicArray.address, publicArray.address,
'deposits(uint256)', 'deposits(uint256)',
67, 67,
@ -112,12 +82,7 @@ describe('findArrayLength', () => {
const deposits = Array.from(Array(30).keys()) const deposits = Array.from(Array(30).keys())
publicArray = await PublicArray.deploy() publicArray = await PublicArray.deploy()
await publicArray.setDeposits(deposits) await publicArray.setDeposits(deposits)
const depositsLength = await tornadoTrees.findArrayLengthMock( const depositsLength = await tornadoTrees.findArrayLength(publicArray.address, 'deposits(uint256)', 1, 50)
publicArray.address,
'deposits(uint256)',
1,
50,
)
expect(depositsLength).to.be.equal(deposits.length) expect(depositsLength).to.be.equal(deposits.length)
}) })
@ -135,7 +100,7 @@ describe('findArrayLength', () => {
const deposits = Array.from(Array(len).keys()) const deposits = Array.from(Array(len).keys())
publicArray = await PublicArray.deploy() publicArray = await PublicArray.deploy()
await publicArray.setDeposits(deposits) await publicArray.setDeposits(deposits)
const depositsLength = await tornadoTrees.findArrayLengthMock( const depositsLength = await tornadoTrees.findArrayLength(
publicArray.address, publicArray.address,
'deposits(uint256)', 'deposits(uint256)',
days * depositsPerDay, days * depositsPerDay,

View File

@ -1,5 +1,5 @@
const { expect } = require('chai') const { expect } = require('chai')
const MerkleTree = require('@tornado/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/index') const { batchTreeUpdate, prove } = require('../src/index')

View File

@ -1,7 +1,7 @@
/* global ethers */ /* global ethers */
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('@tornado/fixed-merkle-tree') const MerkleTree = require('fixed-merkle-tree')
const controller = require('../src/index') const controller = require('../src/index')
async function register(note, tornadoTrees, from) { async function register(note, tornadoTrees, from) {

137
yarn.lock
View File

@ -736,37 +736,6 @@
dependencies: dependencies:
defer-to-connect "^1.0.1" defer-to-connect "^1.0.1"
"@tornado/circomlib@0.0.21", "@tornado/circomlib@^0.0.21":
version "0.0.21"
resolved "https://git.tornado.ws/api/packages/tornado-packages/npm/%40tornado%2Fcircomlib/-/0.0.21/circomlib-0.0.21.tgz#fb7a502aa32bcb2b23205a05877d1cd030c41b19"
integrity sha512-CFaqfgoWZBdD9xZurVOEalWKEVn/NzsT63W/VLGFRbmAUTYJ1vING9LjC0ZXBvec8vzyYquIkvNRdx6axFdJ5g==
dependencies:
"@tornado/snarkjs" "0.1.20"
blake-hash "^1.1.0"
blake2b "^2.1.3"
typedarray-to-buffer "^3.1.5"
web3 "^1.2.11"
"@tornado/fixed-merkle-tree@^0.5.0":
version "0.5.1"
resolved "https://git.tornado.ws/api/packages/tornado-packages/npm/%40tornado%2Ffixed-merkle-tree/-/0.5.1/fixed-merkle-tree-0.5.1.tgz#bda51bc964a8ed86ce9735f49d1efe1f32595140"
integrity sha512-aMbCrnHLnvGWSr54/oT4IUg7106+F/55APn2uMhEeg0rQk5PXXRgzzqvHgBqyjRpMibKzOT7m7G8SMMVMpXFFg==
dependencies:
"@tornado/circomlib" "0.0.21"
"@tornado/snarkjs" "0.1.20"
"@tornado/snarkjs@0.1.20":
version "0.1.20"
resolved "https://git.tornado.ws/api/packages/tornado-packages/npm/%40tornado%2Fsnarkjs/-/0.1.20/snarkjs-0.1.20.tgz#d7610cd3c8dc10598da7dc3e40e5d7470c3aa8c7"
integrity sha512-mn+ePoQjqOHyDyK8AMy8SXYqNSxJWVswWVmMYvuc75/9bBtJ7SNtwrTByxmfWjrf4S3BM3IrGfHqBHEXY6gR4Q==
dependencies:
big-integer "^1.6.43"
chai "^4.2.0"
escape-string-regexp "^1.0.5"
eslint "^5.16.0"
keccak "^2.0.0"
yargs "^12.0.5"
"@types/bn.js@*": "@types/bn.js@*":
version "5.1.0" version "5.1.0"
resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-5.1.0.tgz#32c5d271503a12653c62cf4d2b45e6eab8cebc68" resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-5.1.0.tgz#32c5d271503a12653c62cf4d2b45e6eab8cebc68"
@ -2256,10 +2225,26 @@ cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3:
inherits "^2.0.1" inherits "^2.0.1"
safe-buffer "^5.0.1" safe-buffer "^5.0.1"
circom@0.5.42: circom@0.5.33:
version "0.5.42" version "0.5.33"
resolved "https://registry.yarnpkg.com/circom/-/circom-0.5.42.tgz#96a456f9538f4425654df091d15e3158e9da2acc" resolved "https://registry.yarnpkg.com/circom/-/circom-0.5.33.tgz#6943d5799adf5388989bfbb3ef8f502fb1b4f662"
integrity sha512-v6+f9g3z2ia17NQvQmyZjvh8cE8O3GtxRE36KfJfx/a+s58Y7aEDWsUG+GFRJhp1ajiQELdj3NehY9vHSf5Rkg== integrity sha512-UdL8fr6GckhQ4VoWjIvuYwCHneJe8z/AyJpDxgKLyuaX51ijd4gBP6jlwHDbQJsha2aU2GR9qgDsxd0jfari1Q==
dependencies:
chai "^4.2.0"
circom_runtime "0.1.8"
fastfile "0.0.18"
ffiasm "0.1.1"
ffjavascript "0.2.22"
ffwasm "0.0.7"
fnv-plus "^1.3.1"
r1csfile "0.0.16"
tmp-promise "^2.0.2"
wasmbuilder "0.0.10"
circom@^0.5.38:
version "0.5.38"
resolved "https://registry.yarnpkg.com/circom/-/circom-0.5.38.tgz#c099fb196085837575fb266f37b0516b1ec56eb5"
integrity sha512-PFlXto8gDysUlwk6z/GYbn1Mv5BtW9BI4769N9gSP0/7KDNSqLNyVmL4DgMLc67/EpG4qJLGch3SdgzQD+/cfw==
dependencies: dependencies:
chai "^4.2.0" chai "^4.2.0"
circom_runtime "0.1.12" circom_runtime "0.1.12"
@ -2288,6 +2273,33 @@ circom_runtime@0.1.12, circom_runtime@^0.1.12:
ffjavascript "0.2.34" ffjavascript "0.2.34"
fnv-plus "^1.3.1" fnv-plus "^1.3.1"
circom_runtime@0.1.8:
version "0.1.8"
resolved "https://registry.yarnpkg.com/circom_runtime/-/circom_runtime-0.1.8.tgz#d967a1618fe5290849f9c0bbffb6b97b95c0f1c8"
integrity sha512-5ZmzCyidkNPb1zZsJGRXTuWcJ6kW6+gRBtHgf2tFqTh5dUyWVVPH0Zg7AsU2ijPr1AmYZUlme0yORUZK5HrjOA==
dependencies:
ffjavascript "0.2.10"
fnv-plus "^1.3.1"
"circomlib@git+https://github.com/tornadocash/circomlib.git#5beb6aee94923052faeecea40135d45b6ce6172c":
version "0.0.20"
resolved "git+https://github.com/tornadocash/circomlib.git#5beb6aee94923052faeecea40135d45b6ce6172c"
dependencies:
blake-hash "^1.1.0"
blake2b "^2.1.3"
snarkjs "git+https://github.com/tornadocash/snarkjs.git#869181cfaf7526fe8972073d31655493a04326d5"
typedarray-to-buffer "^3.1.5"
web3 "^1.2.11"
"circomlib@git+https://github.com/tornadocash/circomlib.git#d20d53411d1bef61f38c99a8b36d5d0cc4836aa1":
version "0.4.1"
resolved "git+https://github.com/tornadocash/circomlib.git#d20d53411d1bef61f38c99a8b36d5d0cc4836aa1"
dependencies:
blake-hash "^1.1.0"
blake2b "^2.1.3"
circom "0.5.33"
ffjavascript "0.1.0"
class-is@^1.1.0: class-is@^1.1.0:
version "1.1.0" version "1.1.0"
resolved "https://registry.yarnpkg.com/class-is/-/class-is-1.1.0.tgz#9d3c0fba0440d211d843cec3dedfa48055005825" resolved "https://registry.yarnpkg.com/class-is/-/class-is-1.1.0.tgz#9d3c0fba0440d211d843cec3dedfa48055005825"
@ -3843,6 +3855,22 @@ ffiasm@0.1.1, ffiasm@^0.1.1:
ejs "^3.0.1" ejs "^3.0.1"
yargs "^15.3.1" yargs "^15.3.1"
ffjavascript@0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/ffjavascript/-/ffjavascript-0.1.0.tgz#456256c259654cc1ce864c6762b0e76ee1714100"
integrity sha512-dmKlUasSfvUcxBm8nCSKl2x7EFJsXA7OVP8XLFA03T2+6mAc3IiVLC2ambEVOcMOhyhl0vJfVZjM9f9d38D1rw==
dependencies:
big-integer "^1.6.48"
ffjavascript@0.2.10:
version "0.2.10"
resolved "https://registry.yarnpkg.com/ffjavascript/-/ffjavascript-0.2.10.tgz#b0bf88d69be0b51e0bd28e1966c4a6fb29a86682"
integrity sha512-GQI6gHYYG5/iD4Kt3VzezzK7fARJzP0zkc82V/+JAdjfeKBXhDSo5rpKFuK3cDcrdW0Fu2emuYNMEAuFqhEQvQ==
dependencies:
big-integer "^1.6.48"
wasmcurves "0.0.5"
worker-threads "^1.0.0"
ffjavascript@0.2.22: ffjavascript@0.2.22:
version "0.2.22" version "0.2.22"
resolved "https://registry.yarnpkg.com/ffjavascript/-/ffjavascript-0.2.22.tgz#101f33db330b0f6a0c10dec22ebf5725618a8a7d" resolved "https://registry.yarnpkg.com/ffjavascript/-/ffjavascript-0.2.22.tgz#101f33db330b0f6a0c10dec22ebf5725618a8a7d"
@ -3862,15 +3890,6 @@ ffjavascript@0.2.34, ffjavascript@^0.2.30:
wasmcurves "0.0.14" wasmcurves "0.0.14"
worker-threads "^1.0.0" worker-threads "^1.0.0"
ffjavascript@^0.2.35:
version "0.2.35"
resolved "https://registry.yarnpkg.com/ffjavascript/-/ffjavascript-0.2.35.tgz#9166d95173b1c0a743b455bb03a72b581922a42e"
integrity sha512-xnC51tWbi0ah4SH+02jEfJyO+P+NiZWnxQrLDLtBYY1Dv3QM5ydxzd+gxnLEfWdT8i1bMM5pIh5P25l6fNCaVQ==
dependencies:
big-integer "^1.6.48"
wasmcurves "0.0.14"
web-worker "^1.0.0"
ffwasm@0.0.7: ffwasm@0.0.7:
version "0.0.7" version "0.0.7"
resolved "https://registry.yarnpkg.com/ffwasm/-/ffwasm-0.0.7.tgz#23bb9a3537ecc87c0f24fcfb3a9ddd0e86855fff" resolved "https://registry.yarnpkg.com/ffwasm/-/ffwasm-0.0.7.tgz#23bb9a3537ecc87c0f24fcfb3a9ddd0e86855fff"
@ -3988,6 +4007,14 @@ find-yarn-workspace-root@^1.2.1:
fs-extra "^4.0.3" fs-extra "^4.0.3"
micromatch "^3.1.4" micromatch "^3.1.4"
fixed-merkle-tree@^0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/fixed-merkle-tree/-/fixed-merkle-tree-0.5.0.tgz#401cdcf3d670c1e18bc7d3a8e81322eb1b27c1d1"
integrity sha512-egOy12EzVATX3Ru2/SLtnWprVpy/sbPCt/MbeG3ANB28jykWLEYj7EjinFnOxtsgR3gTHU6xYXX53yMn/bZqyw==
dependencies:
circomlib "git+https://github.com/tornadocash/circomlib.git#5beb6aee94923052faeecea40135d45b6ce6172c"
snarkjs "git+https://github.com/tornadocash/snarkjs.git#869181cfaf7526fe8972073d31655493a04326d5"
flat-cache@^2.0.1: flat-cache@^2.0.1:
version "2.0.1" version "2.0.1"
resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0"
@ -7422,6 +7449,17 @@ snarkjs@^0.3.57:
logplease "^1.2.15" logplease "^1.2.15"
r1csfile "0.0.31" r1csfile "0.0.31"
"snarkjs@git+https://github.com/tornadocash/snarkjs.git#869181cfaf7526fe8972073d31655493a04326d5":
version "0.1.20"
resolved "git+https://github.com/tornadocash/snarkjs.git#869181cfaf7526fe8972073d31655493a04326d5"
dependencies:
big-integer "^1.6.43"
chai "^4.2.0"
escape-string-regexp "^1.0.5"
eslint "^5.16.0"
keccak "^2.0.0"
yargs "^12.0.5"
solc@0.7.3: solc@0.7.3:
version "0.7.3" version "0.7.3"
resolved "https://registry.yarnpkg.com/solc/-/solc-0.7.3.tgz#04646961bd867a744f63d2b4e3c0701ffdc7d78a" resolved "https://registry.yarnpkg.com/solc/-/solc-0.7.3.tgz#04646961bd867a744f63d2b4e3c0701ffdc7d78a"
@ -8306,10 +8344,13 @@ wasmcurves@0.0.14:
big-integer "^1.6.42" big-integer "^1.6.42"
blakejs "^1.1.0" blakejs "^1.1.0"
web-worker@^1.0.0: wasmcurves@0.0.5:
version "1.0.0" version "0.0.5"
resolved "https://registry.yarnpkg.com/web-worker/-/web-worker-1.0.0.tgz#c7ced4e1eb6227636ada35056a9e5a477414e4d0" resolved "https://registry.yarnpkg.com/wasmcurves/-/wasmcurves-0.0.5.tgz#d0b58e803c0b1c09c966b7dc0fad6dd405d18547"
integrity sha512-BzuMqeKVkKKwHV6tJuwePFcxYMxvC97D448mXTgh/CxXAB4sRtoV26gRPN+JDxsXRR7QZyioMV9O6NzQaASf7Q== integrity sha512-BmI4GXLjLawGg2YkvHa8zRsnWec+d1uwoxE+Iov8cqOpDL7GA5XO2pk2yuDbXHMzwIug2exnKot3baRZ86R0pA==
dependencies:
big-integer "^1.6.42"
blakejs "^1.1.0"
web3-bzz@1.2.11: web3-bzz@1.2.11:
version "1.2.11" version "1.2.11"