Merge pull request #51 from tornadocash/upstream pass fixes size array arg in solidity poseidon implementation
Jordi Baylina jordi@baylina.cat
Thu, 26 Nov 2020 07:35:17 +0100
2 files changed,
63 insertions(+),
31 deletions(-)
M
src/poseidon_gencontract.js
→
src/poseidon_gencontract.js
@@ -4,6 +4,7 @@ //
const Contract = require("./evmasm"); const { unstringifyBigInts } = require("ffjavascript").utils; +const Web3Utils = require("web3-utils"); const { C:K, M } = unstringifyBigInts(require("./poseidon_constants.json"));@@ -99,8 +100,13 @@ C.push("0x0100000000000000000000000000000000000000000000000000000000");
C.push(0); C.calldataload(); C.div(); - C.push("0xc4420fb4"); // poseidon(uint256[]) + C.dup(0); + C.push(Web3Utils.keccak256(`poseidon(uint256[${nInputs}])`).slice(0, 10)); // poseidon(uint256[n]) + C.eq(); + C.swap(1); + C.push(Web3Utils.keccak256(`poseidon(bytes32[${nInputs}])`).slice(0, 10)); // poseidon(bytes32[n]) C.eq(); + C.or(); C.jmpi("start"); C.invalid();@@ -112,11 +118,10 @@ C.push("0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001"); // q
// Load t values from the call data. // The function has a single array param param - // [Selector (4)] [Pointer (32)][Length (32)] [data1 (32)] .... - // We ignore the pointer and the length and just load t values to the state - // (Stack positions 0-{t-1}) If the array is shorter, we just set zeros. + // [Selector (4)] [item1 (32)] [item2 (32)] .... + // Stack positions 0-nInputs. for (let i=0; i<t; i++) { - C.push(0x44+(0x20*(t-1-i))); + C.push(0x04+(0x20*(nInputs-i))); C.calldataload(); }@@ -155,28 +160,54 @@
return C.createTxData(); } -module.exports.abi = [ - { - "constant": true, - "inputs": [ - { - "name": "input", - "type": "uint256[]" - } - ], - "name": "poseidon", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "pure", - "type": "function" - } -]; +function generateABI(nInputs) { + return [ + { + "constant": true, + "inputs": [ + { + "internalType": `bytes32[${nInputs}]`, + "name": "input", + "type": `bytes32[${nInputs}]` + } + ], + "name": "poseidon", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + }, + { + "constant": true, + "inputs": [ + { + "internalType": `uint256[${nInputs}]`, + "name": "input", + "type": `uint256[${nInputs}]` + } + ], + "name": "poseidon", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "payable": false, + "stateMutability": "pure", + "type": "function" + } + ]; +} +module.exports.generateABI = generateABI; module.exports.createCode = createCode;
M
test/poseidoncontract.js
→
test/poseidoncontract.js
@@ -21,15 +21,16 @@ accounts = await web3.eth.getAccounts();
}); it("Should deploy the contract", async () => { - const C = new web3.eth.Contract(poseidonGenContract.abi); + const C6 = new web3.eth.Contract(poseidonGenContract.generateABI(5)); + const C3 = new web3.eth.Contract(poseidonGenContract.generateABI(2)); - poseidon6 = await C.deploy({ + poseidon6 = await C6.deploy({ data: poseidonGenContract.createCode(5) }).send({ gas: 5000000, from: accounts[0] }); - poseidon3 = await C.deploy({ + poseidon3 = await C3.deploy({ data: poseidonGenContract.createCode(2) }).send({ gas: 5000000,@@ -37,7 +38,7 @@ from: accounts[0]
}); }); - it("Shold calculate the poseidon correctly t=6", async () => { + it("Should calculate the poseidon correctly t=6", async () => { const res = await poseidon6.methods.poseidon([1,2, 0, 0, 0]).call();@@ -48,7 +49,7 @@ // console.log("Ref: " + bigInt(res2).toString(16));
assert.equal(res.toString(), res2.toString()); }); - it("Shold calculate the poseidon correctly t=3", async () => { + it("Should calculate the poseidon correctly t=3", async () => { const res = await poseidon3.methods.poseidon([1,2]).call();