Merge pull request #2 from tornadocash/poseidon-fixed-array

pass fixes size array arg in solidity poseidon implementation
This commit is contained in:
Alexey Pertsev 2020-10-26 16:32:04 +03:00 committed by GitHub
commit 47f33f2275
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 23 additions and 15 deletions

@ -4,6 +4,7 @@
const Contract = require("./evmasm"); const Contract = require("./evmasm");
const { unstringifyBigInts } = require("snarkjs"); const { unstringifyBigInts } = require("snarkjs");
const Web3Utils = require("web3-utils");
const { C:K, M } = unstringifyBigInts(require("./poseidon_constants.json")); const { C:K, M } = unstringifyBigInts(require("./poseidon_constants.json"));
@ -99,7 +100,7 @@ function createCode(nInputs) {
C.push(0); C.push(0);
C.calldataload(); C.calldataload();
C.div(); C.div();
C.push("0xc4420fb4"); // poseidon(uint256[]) C.push(Web3Utils.keccak256(`poseidon(uint256[${nInputs}])`).slice(0, 10)); // poseidon(uint256[])
C.eq(); C.eq();
C.jmpi("start"); C.jmpi("start");
C.invalid(); C.invalid();
@ -112,11 +113,10 @@ function createCode(nInputs) {
// Load t values from the call data. // Load t values from the call data.
// The function has a single array param param // The function has a single array param param
// [Selector (4)] [Pointer (32)][Length (32)] [data1 (32)] .... // [Selector (4)] [item1 (32)] [item2 (32)] ....
// We ignore the pointer and the length and just load t values to the state // Stack positions 0-nInputs.
// (Stack positions 0-{t-1}) If the array is shorter, we just set zeros.
for (let i=0; i<t; i++) { for (let i=0; i<t; i++) {
C.push(0x44+(0x20*(t-1-i))); C.push(0x04+(0x20*(nInputs-i)));
C.calldataload(); C.calldataload();
} }
@ -155,18 +155,21 @@ function createCode(nInputs) {
return C.createTxData(); return C.createTxData();
} }
module.exports.abi = [ function generateABI(nInputs) {
return [
{ {
"constant": true, "constant": true,
"inputs": [ "inputs": [
{ {
"internalType": `uint256[${nInputs}]`,
"name": "input", "name": "input",
"type": "uint256[]" "type": `uint256[${nInputs}]`
} }
], ],
"name": "poseidon", "name": "poseidon",
"outputs": [ "outputs": [
{ {
"internalType": "uint256",
"name": "", "name": "",
"type": "uint256" "type": "uint256"
} }
@ -175,8 +178,10 @@ module.exports.abi = [
"stateMutability": "pure", "stateMutability": "pure",
"type": "function" "type": "function"
} }
]; ]
};
module.exports.generateABI = generateABI;
module.exports.createCode = createCode; module.exports.createCode = createCode;

@ -14,6 +14,8 @@ describe("Poseidon Smart contract test", function () {
let poseidon4; let poseidon4;
let accounts; let accounts;
this.timeout(100000); this.timeout(100000);
let C2
let C4
before(async () => { before(async () => {
web3 = new Web3(ganache.provider(), null, { transactionConfirmationBlocks: 1 }); web3 = new Web3(ganache.provider(), null, { transactionConfirmationBlocks: 1 });
@ -21,15 +23,17 @@ describe("Poseidon Smart contract test", function () {
}); });
it("Should deploy the contract", async () => { it("Should deploy the contract", async () => {
const C = new web3.eth.Contract(poseidonGenContract.abi);
C2 = new web3.eth.Contract(poseidonGenContract.generateABI(2));
poseidon2 = await C.deploy({ poseidon2 = await C2.deploy({
data: poseidonGenContract.createCode(2) data: poseidonGenContract.createCode(2)
}).send({ }).send({
gas: 5000000, gas: 5000000,
from: accounts[0] from: accounts[0]
}); });
poseidon4 = await C.deploy({
C4 = new web3.eth.Contract(poseidonGenContract.generateABI(4));
poseidon4 = await C4.deploy({
data: poseidonGenContract.createCode(4) data: poseidonGenContract.createCode(4)
}).send({ }).send({
gas: 5000000, gas: 5000000,
@ -37,8 +41,7 @@ describe("Poseidon Smart contract test", function () {
}); });
}); });
it("Shold calculate the poseidon correctly for 2 inputs", async () => { it("Should calculate the poseidon correctly for 2 inputs", async () => {
const res = await poseidon2.methods.poseidon([1, 2]).call(); const res = await poseidon2.methods.poseidon([1, 2]).call();
// console.log("Cir: " + bigInt(res.toString(16)).toString(16)); // console.log("Cir: " + bigInt(res.toString(16)).toString(16));
@ -48,7 +51,7 @@ describe("Poseidon Smart contract test", function () {
assert.equal(res.toString(), res2.toString()); assert.equal(res.toString(), res2.toString());
}); });
it("Shold calculate the poseidon correctly for 4 inputs", async () => { it("Should calculate the poseidon correctly for 4 inputs", async () => {
const res = await poseidon4.methods.poseidon([1, 2, 3, 4]).call(); const res = await poseidon4.methods.poseidon([1, 2, 3, 4]).call();