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