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}