You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

222 lines
7.6 KiB

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