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}