const fs = require("fs");
|
|
const bigInt = require("big-integer");
|
|
const { groth } = require('snarkjs');
|
|
const { Fr } = require('ffjavascript').bn128;
|
|
const { stringifyBigInts, unstringifyBigInts } = require('ffjavascript').utils;
|
|
const WitnessCalculatorBuilder = require("circom_runtime").WitnessCalculatorBuilder;
|
|
const circomlib = require("circomlib");
|
|
const smt = require("circomlib").smt;
|
|
const Web3 = require("web3");
|
|
// const buildBn128 = require("wasmsnark").buildBn128;
|
|
|
|
|
|
const coinCode = "0"; // refearing to ETH
|
|
const ethAmount = '1';
|
|
const amount = Web3.utils.toWei(ethAmount, 'ether');
|
|
|
|
exports.randBigInt = () => {
|
|
return Fr.random();
|
|
};
|
|
|
|
exports.calcCommitment = (key, secret) => {
|
|
const poseidon = circomlib.poseidon.createHash(6, 8, 57);
|
|
const nullifier = poseidon([key, secret]).toString();
|
|
const commitment = poseidon([coinCode, amount, secret, nullifier]).toString();
|
|
return commitment;
|
|
};
|
|
|
|
exports.calcDepositWitness = async (wasm, nLevels, key, secret, commitments) => {
|
|
const poseidon = circomlib.poseidon.createHash(6, 8, 57);
|
|
const nullifier = poseidon([key, secret]).toString();
|
|
const commitment = poseidon([coinCode, amount, secret, nullifier]).toString();
|
|
|
|
console.log("Commitment", commitment.toString());
|
|
|
|
// rebuild the tree
|
|
let tree = await smt.newMemEmptyTrie();
|
|
await tree.insert(0, 0);
|
|
for (let i=0; i <commitments.length; i++) {
|
|
await tree.insert(i+1, commitments[i]);
|
|
}
|
|
|
|
let res = await tree.insert(key, commitment);
|
|
|
|
// new root
|
|
let siblings = res.siblings;
|
|
console.log(res);
|
|
// while (siblings.length < nLevels) {
|
|
// siblings.push("0");
|
|
// };
|
|
|
|
// calculate witness
|
|
const input = unstringifyBigInts({
|
|
"coinCode": coinCode,
|
|
"amount": amount,
|
|
"secret": secret,
|
|
"oldKey": res.isOld0 ? 0 : res.oldKey,
|
|
"oldValue": res.isOld0 ? 0 : res.oldValue,
|
|
"isOld0": res.isOld0 ? 1 : 0,
|
|
"siblings": siblings,
|
|
"rootOld": res.oldRoot,
|
|
"rootNew": res.newRoot,
|
|
"commitment": commitment,
|
|
"key": key
|
|
});
|
|
console.log("input", input);
|
|
// const options = {};
|
|
// const wc = await WitnessCalculatorBuilder(wasm, options);
|
|
|
|
const wc = await WitnessCalculatorBuilder(wasm);
|
|
|
|
const witness = await wc.calculateWitness(input, {sanityCheck: true});
|
|
|
|
const wBuff = Buffer.allocUnsafe(witness.length*32);
|
|
|
|
for (let i=0; i <witness.length; i++) {
|
|
for (let j=0; j <8; j++) {
|
|
const bi = witness[i];
|
|
const v = bigInt(bi).shiftRight(j*32).and(0xFFFFFFFF).toJSNumber();
|
|
// wBuff.writeUInt32LE(v, i*32 + j*4, 4)
|
|
wBuff.writeUInt32LE(v, i*32 + j*4)
|
|
}
|
|
}
|
|
|
|
|
|
// const witness = unstringifyBigInts(stringifyBigInts(w));
|
|
// return wBuff;
|
|
return {
|
|
witness: wBuff,
|
|
publicInputs: {
|
|
commitment:commitment,
|
|
root:res.newRoot
|
|
}
|
|
};
|
|
}
|
|
|
|
exports.calcWithdrawWitness = async (wasm, nLevels, key, secret, commitments, addr) => {
|
|
const poseidon = circomlib.poseidon.createHash(6, 8, 57);
|
|
const nullifier = poseidon([key, secret]).toString();
|
|
const commitment = poseidon([coinCode, amount, secret, nullifier]).toString();
|
|
|
|
// rebuild the tree
|
|
let tree = await smt.newMemEmptyTrie();
|
|
await tree.insert(0, 0);
|
|
for (let i=0; i <commitments.length; i++) {
|
|
await tree.insert(i+1, commitments[i]);
|
|
}
|
|
// await tree.insert(commitment, 0);
|
|
|
|
// root
|
|
const root = tree.root;
|
|
const res = await tree.find(key);
|
|
if (!res.found) {
|
|
console.error("leaf expect to exist but not exists, key:", key);
|
|
}
|
|
let siblings = res.siblings;
|
|
while (siblings.length < nLevels) {
|
|
siblings.push("0");
|
|
};
|
|
|
|
// calculate witness
|
|
const input = unstringifyBigInts({
|
|
"coinCode": coinCode,
|
|
"amount": amount,
|
|
"secret": secret,
|
|
"nullifier": nullifier,
|
|
"siblings": siblings,
|
|
"root": root,
|
|
"address": addr,
|
|
"key": key
|
|
});
|
|
console.log("input", input);
|
|
// const options = {};
|
|
// const wc = await WitnessCalculatorBuilder(wasm, options);
|
|
|
|
const wc = await WitnessCalculatorBuilder(wasm);
|
|
|
|
const witness = await wc.calculateWitness(input, {sanityCheck: true});
|
|
|
|
const wBuff = Buffer.allocUnsafe(witness.length*32);
|
|
|
|
for (let i=0; i <witness.length; i++) {
|
|
for (let j=0; j <8; j++) {
|
|
const bi = witness[i];
|
|
const v = bigInt(bi).shiftRight(j*32).and(0xFFFFFFFF).toJSNumber();
|
|
// wBuff.writeUInt32LE(v, i*32 + j*4, 4)
|
|
wBuff.writeUInt32LE(v, i*32 + j*4)
|
|
}
|
|
}
|
|
|
|
|
|
// const witness = unstringifyBigInts(stringifyBigInts(w));
|
|
return {
|
|
witness: wBuff,
|
|
publicInputs: {
|
|
address:addr,
|
|
nullifier:nullifier
|
|
}
|
|
};
|
|
}
|