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.

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