arnaucube
arnaucube/miksi-appPublic Self-hosted repository
miksi-app/index.js
index.jsRaw
  1var circuit = {};
  2var provingKey = {};
  3var witnessCalc = {};
  4const abi = JSON.parse(`[{"inputs":[{"internalType":"address","name":"_depositVerifierContractAddr","type":"address"},{"internalType":"address","name":"_withdrawVerifierContractAddr","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"_commitment","type":"uint256"},{"internalType":"uint256","name":"_root","type":"uint256"},{"internalType":"uint256[2]","name":"a","type":"uint256[2]"},{"internalType":"uint256[2][2]","name":"b","type":"uint256[2][2]"},{"internalType":"uint256[2]","name":"c","type":"uint256[2]"}],"name":"deposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"getCommitments","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address payable","name":"_address","type":"address"},{"internalType":"uint256","name":"nullifier","type":"uint256"},{"internalType":"uint256[2]","name":"a","type":"uint256[2]"},{"internalType":"uint256[2][2]","name":"b","type":"uint256[2][2]"},{"internalType":"uint256[2]","name":"c","type":"uint256[2]"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]`);
  5const miksiAddress = "0x29DB549Ea98d41e0F28A5aA50ED1D37d62BA8C4B";
  6
  7function loadCircuit(circuitname) {
  8  fetch("circuits-files/"+circuitname+"-proving_key.bin").then( (response) => {
  9    return response.arrayBuffer();
 10  }).then( (b) => {
 11    provingKey[circuitname] = b;
 12    console.log("proving_key loaded for", circuitname);
 13  });
 14
 15  fetch("circuits-files/"+circuitname+".wasm").then( (response) => {
 16    return response.arrayBuffer();
 17  }).then( (b) => {
 18    witnessCalc[circuitname] = b;
 19    console.log("w", b);
 20    console.log("witnessCalc loaded for", circuitname);
 21  });
 22}
 23
 24async function deposit(circuitname) {
 25  document.getElementById("depositRes").innerHTML = `
 26    Generating zkProof & making the deposit
 27  `;
 28  console.log("circuit:", circuitname);
 29
 30  // TODO
 31  const secret = miksi.randBigInt().toString();
 32  const nullifier = miksi.randBigInt().toString();
 33  // const secret = "1234567890";
 34  // const nullifier = "5678901234";
 35  let res = await miksiContract.methods.getCommitments().call();
 36  console.log("res", res);
 37  const commitments = res[0];
 38  console.log("commitments", commitments);
 39  // getCommitments from the tree
 40
 41  // calculate witness
 42  console.log(witnessCalc[circuitname]);
 43  const cw = await miksi.calcDepositWitness(witnessCalc[circuitname], secret, nullifier, commitments);
 44  const witness = cw.witness;
 45  const publicInputs = cw.publicInputs;
 46  console.log("w", witness);
 47  console.log("publicInputs", publicInputs);
 48
 49  // generate proof
 50  const start = new Date().getTime();
 51  console.log(provingKey[circuitname]);
 52  const proof = await window.groth16GenProof(witness.buffer, provingKey[circuitname]);
 53  const end = new Date().getTime();
 54  const time = end - start;
 55  console.log("circuit " + circuitname + " took " + time + "ms to compute");
 56  console.log(proof);
 57
 58
 59  // send tx
 60  const accounts = await web3.eth.getAccounts();
 61  const sender = accounts[0];
 62  console.log("SENDER", sender);
 63
 64  console.log("sc call data",
 65    publicInputs.commitment,
 66    publicInputs.root.toString(),
 67    [proof.pi_a[0], proof.pi_a[1]],
 68    [
 69      [proof.pi_b[0][1], proof.pi_b[0][0]],
 70      [proof.pi_b[1][1], proof.pi_b[1][0]]
 71    ],
 72    [proof.pi_c[0], proof.pi_c[1]],
 73  );
 74  miksiContract.methods.deposit(
 75    publicInputs.commitment,
 76    publicInputs.root.toString(),
 77    [proof.pi_a[0], proof.pi_a[1]],
 78    [
 79      [proof.pi_b[0][1], proof.pi_b[0][0]],
 80      [proof.pi_b[1][1], proof.pi_b[1][0]]
 81    ],
 82    [proof.pi_c[0], proof.pi_c[1]],
 83  ).send(
 84    {from: sender, value: 1000000000000000000},
 85    function(error, transactionHash){
 86      console.log("https://goerli.etherscan.io/tx/"+transactionHash);
 87      console.log(error);
 88    });
 89
 90  // print secret & nullifier
 91  let jw = {
 92    secret: secret,
 93    nullifier: nullifier
 94  };
 95  console.log("jw", JSON.stringify(jw));
 96  document.getElementById("depositRes").innerHTML = `
 97  <b>Please store the secret data in a safe place:</b><br>
 98    <input class="form-control" onClick="this.select();" readonly value='`+JSON.stringify(jw)+`'>
 99    </input>
100  `;
101}
102
103async function withdraw(circuitname) {
104  document.getElementById("withdrawRes").innerHTML = `
105    Generating zkProof & making the withdraw
106  `;
107  console.log("circuit:", circuitname);
108  const jw = JSON.parse(document.getElementById("jsonWithdraw").value);
109  const secret = jw.secret;
110  const nullifier = jw.nullifier;
111  console.log(secret, nullifier);
112  const commitment = miksi.calcCommitment(secret, nullifier);
113
114  // getCommitments from the tree
115  let res = await miksiContract.methods.getCommitments().call();
116  console.log("res", res);
117  const commitments = res[0];
118  console.log("commitments", commitments);
119
120  // calculate witness
121  console.log(witnessCalc[circuitname]);
122  const proverAccounts = await web3.eth.getAccounts();
123  const addr = proverAccounts[0];
124  const cw = await miksi.calcWithdrawWitness(witnessCalc[circuitname], secret, nullifier, commitments, addr);
125  const witness = cw.witness;
126  const publicInputs = cw.publicInputs;
127  console.log("w", witness);
128  console.log("publicInputs", publicInputs);
129
130  // generate proof
131  const start = new Date().getTime();
132  console.log(provingKey[circuitname]);
133  const proof = await window.groth16GenProof(witness.buffer, provingKey[circuitname]);
134  const end = new Date().getTime();
135  const time = end - start;
136  console.log("circuit " + circuitname + " took " + time + "ms to compute");
137  console.log(proof);
138
139
140  // send tx
141  const accounts = await web3.eth.getAccounts();
142  const sender = accounts[0];
143  console.log("SENDER", sender);
144
145  console.log("sc call data",
146    publicInputs.address,
147    publicInputs.nullifier,
148    [proof.pi_a[0], proof.pi_a[1]],
149    [
150      [proof.pi_b[0][1], proof.pi_b[0][0]],
151      [proof.pi_b[1][1], proof.pi_b[1][0]]
152    ],
153    [proof.pi_c[0], proof.pi_c[1]],
154  );
155  miksiContract.methods.withdraw(
156    publicInputs.address,
157    publicInputs.nullifier,
158    [proof.pi_a[0], proof.pi_a[1]],
159    [
160      [proof.pi_b[0][1], proof.pi_b[0][0]],
161      [proof.pi_b[1][1], proof.pi_b[1][0]]
162    ],
163    [proof.pi_c[0], proof.pi_c[1]],
164  ).send(
165    {from: sender},
166    function(error, transactionHash){
167      console.log("https://goerli.etherscan.io/tx/"+transactionHash);
168      console.log(error);
169    });
170
171  // print secret & nullifier
172  document.getElementById("depositRes").innerHTML = `
173  `;
174}
175
176loadCircuit("deposit");
177loadCircuit("withdraw");
178
179
180
181
182let miksiContract;
183
184async function connectMetamask() {
185  const ethEnabled = () => {
186    if (window.web3) {
187      window.web3 = new Web3(window.web3.currentProvider);
188      window.ethereum.enable();
189      return true;
190    }
191    return false;
192  }
193
194  if (!ethEnabled()) {
195    alert("Please install MetaMask to use miksi");
196  }
197
198  console.log("abi", abi);
199  miksiContract = new web3.eth.Contract(abi, miksiAddress);
200  console.log("miksiContract", miksiContract);
201
202  const acc = await web3.eth.getAccounts();
203  const addr = acc[0];
204  web3.eth.getBalance(addr, function(err, res){console.log("BAL", JSON.stringify(res));});
205
206}