diff --git a/package-lock.json b/package-lock.json index e9611a5..f361b55 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6590,95 +6590,14 @@ } }, "circomlib": { - "version": "git+https://github.com/tornadocash/circomlib.git#c372f14d324d57339c88451834bf2824e73bbdbc", - "from": "git+https://github.com/tornadocash/circomlib.git#c372f14d324d57339c88451834bf2824e73bbdbc", + "version": "git+https://github.com/tornadocash/circomlib.git#3b492f9801573eebcfe1b6c584afe8a3beecf2b4", + "from": "git+https://github.com/tornadocash/circomlib.git#3b492f9801573eebcfe1b6c584afe8a3beecf2b4", "requires": { "blake-hash": "^1.1.0", "blake2b": "^2.1.3", - "snarkjs": "git+https://github.com/peppersec/snarkjs.git#869181cfaf7526fe8972073d31655493a04326d5", + "snarkjs": "git+https://github.com/tornadocash/snarkjs.git#869181cfaf7526fe8972073d31655493a04326d5", "typedarray-to-buffer": "^3.1.5", - "web3": "^1.0.0-beta.55" - }, - "dependencies": { - "eslint": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.16.0.tgz", - "integrity": "sha512-S3Rz11i7c8AA5JPv7xAH+dOyq/Cu/VXHiHXBPOU1k/JAM5dXqQPt3qcrhpHSorXmrpu2g0gkIBVXAqCpzfoZIg==", - "requires": { - "@babel/code-frame": "^7.0.0", - "ajv": "^6.9.1", - "chalk": "^2.1.0", - "cross-spawn": "^6.0.5", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "eslint-scope": "^4.0.3", - "eslint-utils": "^1.3.1", - "eslint-visitor-keys": "^1.0.0", - "espree": "^5.0.1", - "esquery": "^1.0.1", - "esutils": "^2.0.2", - "file-entry-cache": "^5.0.1", - "functional-red-black-tree": "^1.0.1", - "glob": "^7.1.2", - "globals": "^11.7.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "inquirer": "^6.2.2", - "js-yaml": "^3.13.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.3.0", - "lodash": "^4.17.11", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.1", - "natural-compare": "^1.4.0", - "optionator": "^0.8.2", - "path-is-inside": "^1.0.2", - "progress": "^2.0.0", - "regexpp": "^2.0.1", - "semver": "^5.5.1", - "strip-ansi": "^4.0.0", - "strip-json-comments": "^2.0.1", - "table": "^5.2.3", - "text-table": "^0.2.0" - } - }, - "keccak": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/keccak/-/keccak-2.1.0.tgz", - "integrity": "sha512-m1wbJRTo+gWbctZWay9i26v5fFnYkOn7D5PCxJ3fZUGUEb49dE1Pm4BREUYCt/aoO6di7jeoGmhvqN9Nzylm3Q==", - "requires": { - "bindings": "^1.5.0", - "inherits": "^2.0.4", - "nan": "^2.14.0", - "safe-buffer": "^5.2.0" - } - }, - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "requires": { - "minimist": "^1.2.5" - } - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - }, - "snarkjs": { - "version": "git+https://github.com/peppersec/snarkjs.git#869181cfaf7526fe8972073d31655493a04326d5", - "from": "git+https://github.com/peppersec/snarkjs.git#869181cfaf7526fe8972073d31655493a04326d5", - "requires": { - "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" - } - } + "web3": "^1.2.11" } }, "class-is": { @@ -7230,6 +7149,11 @@ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" }, + "decimal.js": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.2.1.tgz", + "integrity": "sha512-KaL7+6Fw6i5A2XSnsbhm/6B+NuEA7TZ4vqxnd5tXz9sbKtrN9Srj8ab4vKVdK8YAqZO9P1kg45Y6YLoduPf+kw==" + }, "decode-uri-component": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", @@ -8471,6 +8395,39 @@ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" }, + "eth-sig-util": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-1.4.2.tgz", + "integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=", + "requires": { + "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git", + "ethereumjs-util": "^5.1.1" + } + }, + "ethereumjs-abi": { + "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#1a27c59c15ab1e95ee8e5c4ed6ad814c49cc439e", + "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", + "requires": { + "bn.js": "^4.11.8", + "ethereumjs-util": "^6.0.0" + }, + "dependencies": { + "ethereumjs-util": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz", + "integrity": "sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==", + "requires": { + "@types/bn.js": "^4.11.3", + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "elliptic": "^6.5.2", + "ethereum-cryptography": "^0.1.3", + "ethjs-util": "0.1.6", + "rlp": "^2.2.3" + } + } + } + }, "ethereumjs-util": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.1.tgz", @@ -8527,12 +8484,14 @@ } }, "eth-sig-util": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-1.4.2.tgz", - "integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=", + "version": "2.5.4", + "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-2.5.4.tgz", + "integrity": "sha512-aCMBwp8q/4wrW4QLsF/HYBOSA7TpLKmkVwP3pYQNkEEseW2Rr8Z5Uxc9/h6HX+OG3tuHo+2bINVSihIeBfym6A==", "requires": { - "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git", - "ethereumjs-util": "^5.1.1" + "ethereumjs-abi": "0.6.8", + "ethereumjs-util": "^5.1.1", + "tweetnacl": "^1.0.3", + "tweetnacl-util": "^0.15.0" }, "dependencies": { "bn.js": { @@ -8540,30 +8499,6 @@ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" }, - "ethereumjs-abi": { - "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#1a27c59c15ab1e95ee8e5c4ed6ad814c49cc439e", - "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", - "requires": { - "bn.js": "^4.11.8", - "ethereumjs-util": "^6.0.0" - }, - "dependencies": { - "ethereumjs-util": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz", - "integrity": "sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==", - "requires": { - "@types/bn.js": "^4.11.3", - "bn.js": "^4.11.0", - "create-hash": "^1.1.2", - "elliptic": "^6.5.2", - "ethereum-cryptography": "^0.1.3", - "ethjs-util": "0.1.6", - "rlp": "^2.2.3" - } - } - } - }, "ethereumjs-util": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.1.tgz", @@ -8577,6 +8512,11 @@ "rlp": "^2.0.0", "safe-buffer": "^5.1.1" } + }, + "tweetnacl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==" } } }, @@ -17240,6 +17180,11 @@ "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" }, + "tweetnacl-util": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/tweetnacl-util/-/tweetnacl-util-0.15.1.tgz", + "integrity": "sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw==" + }, "type": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", diff --git a/package.json b/package.json index 79713a6..38ce27a 100644 --- a/package.json +++ b/package.json @@ -37,17 +37,18 @@ "chai": "^4.2.0", "chai-as-promised": "^7.1.1", "circom": "^0.0.35", - "circomlib": "git+https://github.com/tornadocash/circomlib.git#c372f14d324d57339c88451834bf2824e73bbdbc", + "circomlib": "git+https://github.com/tornadocash/circomlib.git#3b492f9801573eebcfe1b6c584afe8a3beecf2b4", "commander": "^4.1.1", + "decimal.js": "^10.2.0", "dotenv": "^8.2.0", "eslint": "^6.6.0", "eth-json-rpc-filters": "^4.1.1", + "eth-sig-util": "^2.5.3", "ganache-cli": "^6.7.0", "snarkjs": "git+https://github.com/tornadocash/snarkjs.git#869181cfaf7526fe8972073d31655493a04326d5", "truffle": "^5.0.44", "truffle-flattener": "^1.4.2", - "web3": "^1.2.2", - "web3-utils": "^1.2.2", + "web3": "^1.2.11", "websnark": "git+https://github.com/tornadocash/websnark.git#2041cfa5fa0b71cd5cca9022a4eeea4afe28c9f7" }, "devDependencies": { diff --git a/src/account.js b/src/account.js new file mode 100644 index 0000000..58ddbd0 --- /dev/null +++ b/src/account.js @@ -0,0 +1,39 @@ +const {toBN} = require('web3-utils') +const {encrypt, decrypt} = require('eth-sig-util') +const {randomBN, poseidonHash} = require('./utils') + +class Account { + constructor({amount, secret, nullifier} = {}) { + this.amount = amount ? toBN(amount) : toBN('0') + this.secret = secret ? toBN(secret) : randomBN(31) + this.nullifier = nullifier ? toBN(nullifier) : randomBN(31) + + this.commitment = poseidonHash([this.amount, this.secret, this.nullifier]) + this.nullifierHash = poseidonHash([this.nullifier]) + + if (this.amount.lt(toBN(0))) { + throw new Error('Cannot create an account with negative amount') + } + } + + encrypt(pubkey) { + const bytes = Buffer.concat([ + this.amount.toBuffer('be', 31), + this.secret.toBuffer('b', 31), + this.nullifier.toBuffer('be', 31), + ]) + return encrypt(pubkey, {data: bytes.toString('base64')}, 'x25519-xsalsa20-poly1305') + } + + static decrypt(privkey, data) { + const decryptedMessage = decrypt(data, privkey) + const buf = Buffer.from(decryptedMessage, 'base64') + return new Account({ + amount: toBN('0x' + buf.slice(0, 31).toString('hex')), + secret: toBN('0x' + buf.slice(31, 62).toString('hex')), + nullifier: toBN('0x' + buf.slice(62, 93).toString('hex')), + }) + } +} + +module.exports = Account diff --git a/src/utils.js b/src/utils.js new file mode 100644 index 0000000..be747e3 --- /dev/null +++ b/src/utils.js @@ -0,0 +1,165 @@ +const crypto = require('crypto') +const Decimal = require('decimal.js') +const {bigInt} = require('snarkjs') +const {toBN, soliditySha3} = require('web3-utils') +const Web3 = require('web3') +const web3 = new Web3() +const {babyJub, pedersenHash, mimcsponge, poseidon} = require('circomlib') + +const RewardExtData = { + RewardExtData: { + relayer: 'address', + encryptedAccount: 'bytes', + }, +} +const AccountUpdate = { + AccountUpdate: { + inputRoot: 'bytes32', + inputNullifierHash: 'bytes32', + outputRoot: 'bytes32', + outputPathIndices: 'uint256', + outputCommitment: 'bytes32', + }, +} +const RewardArgs = { + RewardArgs: { + rate: 'uint256', + fee: 'uint256', + instance: 'address', + rewardNullifier: 'bytes32', + extDataHash: 'bytes32', + depositRoot: 'bytes32', + withdrawalRoot: 'bytes32', + extData: RewardExtData.RewardExtData, + account: AccountUpdate.AccountUpdate, + }, +} + +const WithdrawExtData = { + WithdrawExtData: { + fee: 'uint256', + recipient: 'address', + relayer: 'address', + encryptedAccount: 'bytes', + }, +} + +const pedersenHashBuffer = (buffer) => toBN(babyJub.unpackPoint(pedersenHash.hash(buffer))[0].toString()) + +const mimcHash = (items) => toBN(mimcsponge.multiHash(items.map((item) => bigInt(item))).toString()) + +const poseidonHash = (items) => toBN(poseidon(items).toString()) + +const poseidonHash2 = (a, b) => poseidonHash([a, b]) + +/** Generate random number of specified byte length */ +const randomBN = (nbytes = 31) => toBN(bigInt.leBuff2int(crypto.randomBytes(nbytes)).toString()) + +/** BigNumber to hex string of specified length */ +const toFixedHex = (number, length = 32) => + '0x' + + (number instanceof Buffer ? number.toString('hex') : bigInt(number).toString(16)).padStart(length * 2, '0') + +function getExtRewardArgsHash({relayer, encryptedAccount}) { + const encodedData = web3.eth.abi.encodeParameters( + [RewardExtData], + [{relayer: toFixedHex(relayer, 20), encryptedAccount}], + ) + const hash = soliditySha3({t: 'bytes', v: encodedData}) + return '0x00' + hash.slice(4) // cut last byte to make it 31 byte long to fit the snark field +} + +function getExtWithdrawArgsHash({fee, recipient, relayer, encryptedAccount}) { + const encodedData = web3.eth.abi.encodeParameters( + [WithdrawExtData], + [ + { + fee: toFixedHex(fee, 32), + recipient: toFixedHex(recipient, 20), + relayer: toFixedHex(relayer, 20), + encryptedAccount, + }, + ], + ) + const hash = soliditySha3({t: 'bytes', v: encodedData}) + return '0x00' + hash.slice(4) // cut first byte to make it 31 byte long to fit the snark field +} + +function packEncryptedMessage(encryptedMessage) { + const nonceBuf = Buffer.from(encryptedMessage.nonce, 'base64') + const ephemPublicKeyBuf = Buffer.from(encryptedMessage.ephemPublicKey, 'base64') + const ciphertextBuf = Buffer.from(encryptedMessage.ciphertext, 'base64') + const messageBuff = Buffer.concat([ + Buffer.alloc(24 - nonceBuf.length), + nonceBuf, + Buffer.alloc(32 - ephemPublicKeyBuf.length), + ephemPublicKeyBuf, + ciphertextBuf, + ]) + return '0x' + messageBuff.toString('hex') +} + +function unpackEncryptedMessage(encryptedMessage) { + if (encryptedMessage.slice(0, 2) === '0x') { + encryptedMessage = encryptedMessage.slice(2) + } + const messageBuff = Buffer.from(encryptedMessage, 'hex') + const nonceBuf = messageBuff.slice(0, 24) + const ephemPublicKeyBuf = messageBuff.slice(24, 56) + const ciphertextBuf = messageBuff.slice(56) + return { + version: 'x25519-xsalsa20-poly1305', + nonce: nonceBuf.toString('base64'), + ephemPublicKey: ephemPublicKeyBuf.toString('base64'), + ciphertext: ciphertextBuf.toString('base64'), + } +} + +function bitsToNumber(bits) { + let result = 0 + for (const item of bits.slice().reverse()) { + result = (result << 1) + item + } + return result +} + +// a = floor(10**18 * e^(-0.0000000001 * amount)) +// yield = BalBefore - (BalBefore * a)/10**18 +function tornadoFormula({balance, amount, poolWeight = 1e10}) { + const decimals = new Decimal(10 ** 18) + balance = new Decimal(balance.toString()) + amount = new Decimal(amount.toString()) + poolWeight = new Decimal(poolWeight.toString()) + + const power = amount.div(poolWeight).negated() + const exponent = Decimal.exp(power).mul(decimals) + const newBalance = balance.mul(exponent).div(decimals) + return toBN(balance.sub(newBalance).toFixed(0)) +} + +function reverseTornadoFormula({balance, tokens, poolWeight = 1e10}) { + balance = new Decimal(balance.toString()) + tokens = new Decimal(tokens.toString()) + poolWeight = new Decimal(poolWeight.toString()) + + return toBN(poolWeight.times(Decimal.ln(balance.div(balance.sub(tokens)))).toFixed(0)) +} + +module.exports = { + randomBN, + pedersenHashBuffer, + bitsToNumber, + getExtRewardArgsHash, + getExtWithdrawArgsHash, + packEncryptedMessage, + unpackEncryptedMessage, + toFixedHex, + mimcHash, + poseidonHash, + poseidonHash2, + tornadoFormula, + reverseTornadoFormula, + RewardArgs, + RewardExtData, + AccountUpdate, +} diff --git a/test/ERC20Tornado.test.js b/test/ERC20Tornado.test.js index 81c4181..37db76e 100644 --- a/test/ERC20Tornado.test.js +++ b/test/ERC20Tornado.test.js @@ -5,7 +5,13 @@ require('chai') .should() const fs = require('fs') -const { toBN } = require('web3-utils') +const { getEncryptionPublicKey } = require('eth-sig-util') +const { hexToBytes, toBN } = require('web3-utils') +const { + packEncryptedMessage, + unpackEncryptedMessage, +} = require('../src/utils') +const Account = require('../src/account') const { takeSnapshot, revertSnapshot } = require('../lib/ganacheHelper') const Tornado = artifacts.require('./ERC20Tornado.sol') @@ -23,6 +29,7 @@ const bigInt = snarkjs.bigInt const crypto = require('crypto') const circomlib = require('circomlib') const MerkleTree = require('../lib/MerkleTree') +const {randomBN} = require('../src/utils') const rbigint = (nbytes) => snarkjs.bigInt.leBuff2int(crypto.randomBytes(nbytes)) const pedersenHash = (data) => circomlib.babyJub.unpackPoint(circomlib.pedersenHash.hash(data))[0] @@ -31,10 +38,10 @@ const getRandomRecipient = () => rbigint(20) function generateDeposit() { let deposit = { - secret: rbigint(31), - nullifier: rbigint(31), + secret: randomBN(31), + nullifier: randomBN(31), } - const preimage = Buffer.concat([deposit.nullifier.leInt2Buff(31), deposit.secret.leInt2Buff(31)]) + const preimage = Buffer.concat([deposit.nullifier.toBuffer('le', 31), deposit.secret.toBuffer('le', 31)]) deposit.commitment = pedersenHash(preimage) return deposit } @@ -60,6 +67,10 @@ contract('ERC20Tornado', accounts => { let circuit let proving_key + // Public / private key pair used for encrypting / decrypting the deposit note + const privateKey = web3.eth.accounts.create().privateKey.slice(2) + const publicKey = getEncryptionPublicKey(privateKey) + before(async () => { tree = new MerkleTree( levels, @@ -113,6 +124,12 @@ contract('ERC20Tornado', accounts => { describe('#withdraw', () => { it('should work', async () => { const deposit = generateDeposit() + const account = new Account({ + amount: tokenDenomination, + secret: deposit.secret, + nullifier: deposit.nullifier, + }) + const encryptedMessage = packEncryptedMessage(account.encrypt(publicKey)) const user = accounts[4] await tree.insert(deposit.commitment) await token.mint(user, tokenDenomination) @@ -122,7 +139,18 @@ contract('ERC20Tornado', accounts => { // Uncomment to measure gas usage // let gas = await tornado.deposit.estimateGas(toBN(deposit.commitment.toString()), { from: user, gasPrice: '0' }) // console.log('deposit gas:', gas) - await tornado.deposit(toFixedHex(deposit.commitment), [], { from: user, gasPrice: '0' }) + const {logs: depositLogs} = await tornado.deposit( + toFixedHex(deposit.commitment), + hexToBytes(encryptedMessage), + { from: user, gasPrice: '0' }, + ) + + const encryptedNoteLog = depositLogs[depositLogs.length - 1] + encryptedNoteLog.event.should.be.equal("EncryptedNote") + encryptedNoteLog.args.sender.should.be.equal(accounts[4]) + encryptedNoteLog.args.encryptedNote.should.be.equal(encryptedMessage) + const unpackedMessage = unpackEncryptedMessage(encryptedMessage) + const decryptedAccount = Account.decrypt(privateKey, unpackedMessage) const balanceUserAfter = await token.balanceOf(user) balanceUserAfter.should.be.eq.BN(toBN(balanceUserBefore).sub(toBN(tokenDenomination))) @@ -132,15 +160,15 @@ contract('ERC20Tornado', accounts => { const input = stringifyBigInts({ // public root, - nullifierHash: pedersenHash(deposit.nullifier.leInt2Buff(31)), + nullifierHash: pedersenHash(decryptedAccount.nullifier.toBuffer('le', 31)), relayer, recipient, fee, refund, // private - nullifier: deposit.nullifier, - secret: deposit.secret, + nullifier: decryptedAccount.nullifier, + secret: decryptedAccount.secret, pathElements: path_elements, pathIndices: path_index, }) @@ -224,7 +252,7 @@ contract('ERC20Tornado', accounts => { const input = stringifyBigInts({ // public root, - nullifierHash: pedersenHash(deposit.nullifier.leInt2Buff(31)), + nullifierHash: pedersenHash(deposit.nullifier.toBuffer('le', 31)), relayer, recipient, fee, @@ -339,7 +367,7 @@ contract('ERC20Tornado', accounts => { const input = stringifyBigInts({ // public root, - nullifierHash: pedersenHash(deposit.nullifier.leInt2Buff(31)), + nullifierHash: pedersenHash(deposit.nullifier.toBuffer('le', 31)), relayer, recipient, fee, @@ -413,7 +441,7 @@ contract('ERC20Tornado', accounts => { const input = stringifyBigInts({ // public root, - nullifierHash: pedersenHash(deposit.nullifier.leInt2Buff(31)), + nullifierHash: pedersenHash(deposit.nullifier.toBuffer('le', 31)), relayer, recipient, fee, @@ -480,7 +508,7 @@ contract('ERC20Tornado', accounts => { const input = stringifyBigInts({ // public root, - nullifierHash: pedersenHash(deposit.nullifier.leInt2Buff(31)), + nullifierHash: pedersenHash(deposit.nullifier.toBuffer('le', 31)), relayer: operator, recipient, fee, @@ -569,7 +597,7 @@ contract('ERC20Tornado', accounts => { const input = stringifyBigInts({ // public root, - nullifierHash: pedersenHash(deposit.nullifier.leInt2Buff(31)), + nullifierHash: pedersenHash(deposit.nullifier.toBuffer('le', 31)), relayer: operator, recipient, fee, diff --git a/test/encrypt.test.js b/test/encrypt.test.js new file mode 100644 index 0000000..3989c44 --- /dev/null +++ b/test/encrypt.test.js @@ -0,0 +1,28 @@ +const { getEncryptionPublicKey } = require('eth-sig-util') +const { toBN } = require('web3-utils') + +const Account = require('../src/account') +const { + packEncryptedMessage, + unpackEncryptedMessage, +} = require('../src/utils') + +describe('#encrypt', () => { + // EncryptedNote + const privateKey = web3.eth.accounts.create().privateKey.slice(2) + const publicKey = getEncryptionPublicKey(privateKey) + + it('should work', () => { + const account = new Account() + const encryptedAccount = account.encrypt(publicKey) + const encryptedMessage = packEncryptedMessage(encryptedAccount) + const unpackedMessage = unpackEncryptedMessage(encryptedMessage) + const account2 = Account.decrypt(privateKey, unpackedMessage) + + assert(account.amount.toString() === toBN(account2.amount).toString()) + assert(account.secret.toString() === toBN(account2.secret).toString()) + assert(account.nullifier.toString() === toBN(account2.nullifier).toString()) + assert(account.commitment.toString() === toBN(account2.commitment).toString()) + }) +}) +