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