@lfdecentralizedtrust/zeto-contracts 0.2.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (155) hide show
  1. package/README.md +70 -162
  2. package/contracts/factory.sol +30 -34
  3. package/contracts/factory_upgradeable.sol +160 -0
  4. package/contracts/lib/common/util.sol +40 -0
  5. package/contracts/lib/interfaces/ILockableCapability.sol +318 -0
  6. package/contracts/lib/interfaces/{izeto.sol → IZeto.sol} +13 -1
  7. package/contracts/lib/interfaces/{izeto_initializable.sol → IZetoInitializable.sol} +14 -12
  8. package/contracts/lib/interfaces/{izeto_kyc.sol → IZetoKyc.sol} +3 -3
  9. package/contracts/lib/interfaces/IZetoLockableCapability.sol +237 -0
  10. package/contracts/lib/interfaces/IZetoStorage.sol +106 -0
  11. package/contracts/lib/interfaces/{izeto_lockable.sol → IZetoVerifier.sol} +8 -21
  12. package/contracts/lib/registry.sol +77 -27
  13. package/contracts/lib/storage/base.sol +210 -0
  14. package/contracts/lib/storage/nullifier.sol +166 -0
  15. package/contracts/lib/zeto_common.sol +277 -28
  16. package/contracts/lib/zeto_fungible.sol +451 -33
  17. package/contracts/lib/zeto_fungible_base.sol +69 -0
  18. package/contracts/lib/zeto_fungible_burn.sol +83 -53
  19. package/contracts/lib/zeto_fungible_burn_nullifier.sol +115 -72
  20. package/contracts/lib/zeto_fungible_nullifier.sol +167 -0
  21. package/contracts/lib/zeto_lockable.sol +613 -0
  22. package/contracts/lib/zeto_non_fungible.sol +236 -0
  23. package/contracts/lib/zeto_non_fungible_base.sol +61 -0
  24. package/contracts/lib/zeto_non_fungible_nullifier.sol +61 -0
  25. package/contracts/test/escrow1.sol +90 -34
  26. package/contracts/test/escrow2.sol +64 -29
  27. package/contracts/test/qurrency.sol +10 -2
  28. package/contracts/test/smt.sol +8 -3
  29. package/contracts/test/tendecimals.sol +14 -12
  30. package/contracts/verifiers/impl/anon.sol +189 -0
  31. package/contracts/verifiers/impl/anon_batch.sol +301 -0
  32. package/contracts/verifiers/impl/anon_enc.sol +266 -0
  33. package/contracts/verifiers/impl/anon_enc_batch.sol +602 -0
  34. package/contracts/verifiers/impl/anon_enc_nullifier.sol +287 -0
  35. package/contracts/verifiers/impl/anon_enc_nullifier_batch.sol +679 -0
  36. package/contracts/verifiers/impl/anon_enc_nullifier_kyc.sol +294 -0
  37. package/contracts/verifiers/impl/anon_enc_nullifier_kyc_batch.sol +686 -0
  38. package/contracts/verifiers/impl/anon_enc_nullifier_non_repudiation.sol +413 -0
  39. package/contracts/verifiers/impl/anon_enc_nullifier_non_repudiation_batch.sol +1141 -0
  40. package/contracts/verifiers/impl/anon_nullifier_kyc_transfer.sol +217 -0
  41. package/contracts/verifiers/impl/anon_nullifier_kyc_transferLocked.sol +196 -0
  42. package/contracts/verifiers/impl/anon_nullifier_kyc_transferLocked_batch.sol +308 -0
  43. package/contracts/verifiers/impl/anon_nullifier_kyc_transfer_batch.sol +385 -0
  44. package/contracts/verifiers/impl/anon_nullifier_qurrency_transfer.sol +497 -0
  45. package/contracts/verifiers/impl/anon_nullifier_qurrency_transfer_batch.sol +1001 -0
  46. package/contracts/verifiers/{verifier_anon_nullifier_transferLocked.sol → impl/anon_nullifier_transfer.sol} +12 -19
  47. package/contracts/verifiers/{verifier_anon_nullifier_transferLocked_batch.sol → impl/anon_nullifier_transfer_batch.sol} +44 -51
  48. package/contracts/verifiers/impl/burn.sol +182 -0
  49. package/contracts/verifiers/impl/burn_batch.sol +238 -0
  50. package/contracts/verifiers/impl/burn_nullifier.sol +203 -0
  51. package/contracts/verifiers/impl/burn_nullifier_batch.sol +315 -0
  52. package/contracts/verifiers/impl/deposit.sol +182 -0
  53. package/contracts/verifiers/impl/deposit_kyc.sol +189 -0
  54. package/contracts/verifiers/impl/nf_anon.sol +175 -0
  55. package/contracts/verifiers/{verifier_nf_anon_nullifier_transferLocked.sol → impl/nf_anon_nullifier_transfer.sol} +6 -13
  56. package/contracts/verifiers/impl/withdraw.sol +189 -0
  57. package/contracts/verifiers/impl/withdraw_batch.sol +245 -0
  58. package/contracts/verifiers/impl/withdraw_nullifier.sol +210 -0
  59. package/contracts/verifiers/impl/withdraw_nullifier_batch.sol +322 -0
  60. package/contracts/verifiers/verifier_anon.sol +31 -186
  61. package/contracts/verifiers/verifier_anon_batch.sol +31 -298
  62. package/contracts/verifiers/verifier_anon_enc.sol +31 -263
  63. package/contracts/verifiers/verifier_anon_enc_batch.sol +31 -599
  64. package/contracts/verifiers/verifier_anon_enc_nullifier.sol +31 -284
  65. package/contracts/verifiers/verifier_anon_enc_nullifier_batch.sol +33 -676
  66. package/contracts/verifiers/verifier_anon_enc_nullifier_kyc.sol +31 -291
  67. package/contracts/verifiers/verifier_anon_enc_nullifier_kyc_batch.sol +33 -683
  68. package/contracts/verifiers/verifier_anon_enc_nullifier_non_repudiation.sol +33 -410
  69. package/contracts/verifiers/verifier_anon_enc_nullifier_non_repudiation_batch.sol +33 -1138
  70. package/contracts/verifiers/verifier_anon_nullifier_kyc_transfer.sol +33 -214
  71. package/contracts/verifiers/verifier_anon_nullifier_kyc_transferLocked.sol +33 -221
  72. package/contracts/verifiers/verifier_anon_nullifier_kyc_transferLocked_batch.sol +33 -389
  73. package/contracts/verifiers/verifier_anon_nullifier_kyc_transfer_batch.sol +33 -382
  74. package/contracts/verifiers/verifier_anon_nullifier_qurrency_transfer.sol +33 -221
  75. package/contracts/verifiers/verifier_anon_nullifier_qurrency_transfer_batch.sol +33 -389
  76. package/contracts/verifiers/verifier_anon_nullifier_transfer.sol +33 -207
  77. package/contracts/verifiers/verifier_anon_nullifier_transfer_batch.sol +33 -375
  78. package/contracts/verifiers/verifier_burn.sol +31 -179
  79. package/contracts/verifiers/verifier_burn_batch.sol +31 -235
  80. package/contracts/verifiers/verifier_burn_nullifier.sol +31 -200
  81. package/contracts/verifiers/verifier_burn_nullifier_batch.sol +31 -312
  82. package/contracts/verifiers/verifier_deposit.sol +31 -179
  83. package/contracts/verifiers/verifier_deposit_kyc.sol +34 -0
  84. package/contracts/verifiers/verifier_nf_anon.sol +31 -172
  85. package/contracts/verifiers/verifier_nf_anon_nullifier_transfer.sol +33 -179
  86. package/contracts/verifiers/verifier_withdraw.sol +31 -186
  87. package/contracts/verifiers/verifier_withdraw_batch.sol +31 -242
  88. package/contracts/verifiers/verifier_withdraw_nullifier.sol +31 -207
  89. package/contracts/verifiers/verifier_withdraw_nullifier_batch.sol +33 -319
  90. package/contracts/zeto_anon.sol +77 -231
  91. package/contracts/zeto_anon_burnable.sol +56 -12
  92. package/contracts/zeto_anon_enc.sol +93 -190
  93. package/contracts/zeto_anon_enc_nullifier.sol +249 -195
  94. package/contracts/zeto_anon_enc_nullifier_kyc.sol +51 -232
  95. package/contracts/zeto_anon_enc_nullifier_non_repudiation.sol +231 -238
  96. package/contracts/zeto_anon_nullifier.sol +164 -298
  97. package/contracts/zeto_anon_nullifier_burnable.sol +68 -18
  98. package/contracts/zeto_anon_nullifier_kyc.sol +40 -345
  99. package/contracts/zeto_anon_nullifier_qurrency.sol +218 -360
  100. package/contracts/zeto_nf_anon.sol +55 -130
  101. package/contracts/zeto_nf_anon_nullifier.sol +90 -152
  102. package/hardhat.config.ts +9 -3
  103. package/ignition/modules/lib/deps.ts +9 -6
  104. package/ignition/modules/zeto_anon_burnable.ts +8 -7
  105. package/ignition/modules/zeto_anon_enc_nullifier.ts +33 -1
  106. package/ignition/modules/zeto_anon_enc_nullifier_kyc.ts +2 -2
  107. package/ignition/modules/zeto_anon_enc_nullifier_non_repudiation.ts +2 -1
  108. package/ignition/modules/zeto_anon_nullifier.ts +30 -5
  109. package/ignition/modules/zeto_anon_nullifier_burnable.ts +52 -17
  110. package/ignition/modules/zeto_anon_nullifier_kyc.ts +27 -12
  111. package/ignition/modules/zeto_anon_nullifier_qurrency.ts +2 -1
  112. package/ignition/modules/zeto_nf_anon_nullifier.ts +16 -12
  113. package/package.json +4 -2
  114. package/scripts/deploy_cloneable.ts +19 -10
  115. package/scripts/deploy_upgradeable.ts +9 -5
  116. package/scripts/tokens/Zeto_Anon.ts +3 -3
  117. package/scripts/tokens/Zeto_AnonBurnable.ts +1 -1
  118. package/scripts/tokens/Zeto_AnonEnc.ts +12 -3
  119. package/scripts/tokens/Zeto_AnonEncNullifier.ts +7 -3
  120. package/scripts/tokens/Zeto_AnonEncNullifierKyc.ts +1 -1
  121. package/scripts/tokens/Zeto_AnonEncNullifierNonRepudiation.ts +3 -1
  122. package/scripts/tokens/Zeto_AnonNullifier.ts +3 -1
  123. package/scripts/tokens/Zeto_AnonNullifierBurnable.ts +3 -1
  124. package/scripts/tokens/Zeto_AnonNullifierKyc.ts +1 -1
  125. package/scripts/tokens/Zeto_AnonNullifierQurrency.ts +3 -1
  126. package/scripts/tokens/Zeto_NfAnon.ts +2 -2
  127. package/scripts/tokens/Zeto_NfAnonNullifier.ts +3 -2
  128. package/test/factory.ts +46 -73
  129. package/test/factory_upgradeable.ts +311 -0
  130. package/test/lib/anon_nullifier_helpers.ts +89 -0
  131. package/test/lib/anon_zeto_helpers.ts +76 -0
  132. package/test/lib/deploy.ts +3 -2
  133. package/test/lib/utils.ts +74 -35
  134. package/test/test/escrow1.ts +185 -58
  135. package/test/test/escrow2.ts +200 -107
  136. package/test/test/qurrency.ts +13 -33
  137. package/test/usdc-shielding.ts +39 -26
  138. package/test/utils.ts +144 -21
  139. package/test/zeto_anon.ts +956 -465
  140. package/test/zeto_anon_enc.ts +881 -142
  141. package/test/zeto_anon_enc_nullifier.ts +847 -38
  142. package/test/zeto_anon_enc_nullifier_kyc.ts +120 -181
  143. package/test/zeto_anon_enc_nullifier_non_repudiation.ts +77 -46
  144. package/test/zeto_anon_nullifier.ts +1212 -953
  145. package/test/zeto_anon_nullifier_kyc.ts +674 -655
  146. package/test/zeto_anon_nullifier_qurrency.ts +452 -306
  147. package/test/zeto_nf_anon.ts +737 -137
  148. package/test/zeto_nf_anon_nullifier.ts +876 -246
  149. package/contracts/lib/zeto_base.sol +0 -293
  150. package/contracts/lib/zeto_fungible_withdraw.sol +0 -132
  151. package/contracts/lib/zeto_fungible_withdraw_nullifier.sol +0 -144
  152. package/contracts/lib/zeto_nullifier.sol +0 -334
  153. package/contracts/zkDvP.sol_ +0 -273
  154. package/test/zkDvP.ts_ +0 -455
  155. /package/contracts/lib/{common.sol → common/common.sol} +0 -0
@@ -15,14 +15,26 @@
15
15
  // limitations under the License.
16
16
 
17
17
  import { ethers, network } from "hardhat";
18
- import { ContractTransactionReceipt, Signer, BigNumberish, lock } from "ethers";
18
+ import {
19
+ ContractTransactionReceipt,
20
+ Signer,
21
+ BigNumberish,
22
+ AbiCoder,
23
+ } from "ethers";
24
+ import crypto from "crypto";
19
25
  import { expect } from "chai";
26
+ import { MlKem512 } from "mlkem";
20
27
  import {
21
28
  loadCircuit,
22
29
  Poseidon,
23
30
  encodeProof,
24
- getKyberCipherText,
31
+ bytesToBits,
32
+ newEncryptionNonce,
33
+ poseidonDecrypt,
34
+ publicKeyFromSeed,
35
+ recoverMlKemCiphertextBytes,
25
36
  } from "zeto-js";
37
+ import testKeyPair from "zeto-js/lib/testKeypair.js";
26
38
  import { groth16 } from "snarkjs";
27
39
  import { Merkletree, InMemoryDB, str2Bytes } from "@iden3/js-merkletree";
28
40
  import {
@@ -39,7 +51,8 @@ import {
39
51
  loadProvingKeys,
40
52
  prepareDepositProof,
41
53
  prepareNullifierWithdrawProof,
42
- randomBytesAsDigitArray,
54
+ encodeToBytesForDeposit,
55
+ encodeToBytesForWithdraw,
43
56
  } from "./utils";
44
57
  import { deployZeto } from "./lib/deploy";
45
58
 
@@ -95,277 +108,326 @@ describe("Zeto based fungible token with anonymity using nullifiers with Kyber e
95
108
  ));
96
109
  });
97
110
 
98
- it("onchain SMT root should be equal to the offchain SMT root", async function () {
99
- const root = await smtAlice.root();
100
- const onchainRoot = await zeto.getRoot();
101
- expect(onchainRoot).to.equal(0n);
102
- expect(root.string()).to.equal(onchainRoot.toString());
103
- });
104
-
105
- it("(batch) mint to Alice and batch transfer 10 UTXOs honestly to Bob & Charlie then withdraw should succeed", async function () {
106
- this.timeout(600000);
107
-
108
- // first mint the tokens for batch testing
109
- const inputUtxos = [];
110
- const nullifiers = [];
111
- for (let i = 0; i < 10; i++) {
112
- // mint 10 utxos
113
- const _utxo = newUTXO(1, Alice);
114
- nullifiers.push(newNullifier(_utxo, Alice));
115
- inputUtxos.push(_utxo);
116
- }
117
- const mintResult = await doMint(zeto, deployer, inputUtxos);
118
-
119
- const mintEvents = parseUTXOEvents(zeto, mintResult);
120
- const mintedHashes = mintEvents[0].outputs;
121
- for (let i = 0; i < mintedHashes.length; i++) {
122
- if (mintedHashes[i] !== 0) {
123
- await smtAlice.add(mintedHashes[i], mintedHashes[i]);
124
- await smtBob.add(mintedHashes[i], mintedHashes[i]);
111
+ describe("batch transfer", function () {
112
+ it("onchain SMT root should be equal to the offchain SMT root", async function () {
113
+ const root = await smtAlice.root();
114
+ const onchainRoot = await zeto.getRoot();
115
+ expect(onchainRoot).to.equal(0n);
116
+ expect(root.string()).to.equal(onchainRoot.toString());
117
+ });
118
+
119
+ it("(batch) mint to Alice and batch transfer 10 UTXOs honestly to Bob & Charlie then withdraw should succeed", async function () {
120
+ this.timeout(600000);
121
+
122
+ // first mint the tokens for batch testing
123
+ const inputUtxos = [];
124
+ const nullifiers = [];
125
+ for (let i = 0; i < 10; i++) {
126
+ // mint 10 utxos
127
+ const _utxo = newUTXO(1, Alice);
128
+ nullifiers.push(newNullifier(_utxo, Alice));
129
+ inputUtxos.push(_utxo);
125
130
  }
126
- }
127
- // Alice generates inclusion proofs for the UTXOs to be spent
128
- let root = await smtAlice.root();
129
- const mtps = [];
130
- for (let i = 0; i < inputUtxos.length; i++) {
131
- const p = await smtAlice.generateCircomVerifierProof(
132
- inputUtxos[i].hash,
133
- root,
131
+ const mintResult = await doMint(zeto, deployer, inputUtxos);
132
+
133
+ const mintEvents = parseUTXOEvents(zeto, mintResult);
134
+ const mintedHashes = mintEvents[0].outputs;
135
+ for (let i = 0; i < mintedHashes.length; i++) {
136
+ if (mintedHashes[i] !== 0) {
137
+ await smtAlice.add(mintedHashes[i], mintedHashes[i]);
138
+ await smtBob.add(mintedHashes[i], mintedHashes[i]);
139
+ }
140
+ }
141
+ // Alice generates inclusion proofs for the UTXOs to be spent
142
+ let root = await smtAlice.root();
143
+ const mtps = [];
144
+ for (let i = 0; i < inputUtxos.length; i++) {
145
+ const p = await smtAlice.generateCircomVerifierProof(
146
+ inputUtxos[i].hash,
147
+ root,
148
+ );
149
+ mtps.push(p.siblings.map((s) => s.bigInt()));
150
+ }
151
+ const aliceUTXOsToBeWithdrawn = [
152
+ newUTXO(1, Alice),
153
+ newUTXO(1, Alice),
154
+ newUTXO(1, Alice),
155
+ ];
156
+ // Alice proposes the output UTXOs, 1 utxo to bob, 1 utxo to charlie and 3 utxos to alice
157
+ const _bOut1 = newUTXO(6, Bob);
158
+ const _bOut2 = newUTXO(1, Charlie);
159
+
160
+ const outputUtxos = [_bOut1, _bOut2, ...aliceUTXOsToBeWithdrawn];
161
+ const outputOwners = [Bob, Charlie, Alice, Alice, Alice];
162
+ const inflatedOutputUtxos = [...outputUtxos];
163
+ const inflatedOutputOwners = [...outputOwners];
164
+ for (let i = 0; i < 10 - outputUtxos.length; i++) {
165
+ inflatedOutputUtxos.push(ZERO_UTXO);
166
+ inflatedOutputOwners.push(Bob);
167
+ }
168
+ // Alice transfers her UTXOs to Bob
169
+ const result = await doTransfer(
170
+ Alice,
171
+ inputUtxos,
172
+ nullifiers,
173
+ inflatedOutputUtxos,
174
+ root.bigInt(),
175
+ mtps,
176
+ inflatedOutputOwners,
134
177
  );
135
- mtps.push(p.siblings.map((s) => s.bigInt()));
136
- }
137
- const aliceUTXOsToBeWithdrawn = [
138
- newUTXO(1, Alice),
139
- newUTXO(1, Alice),
140
- newUTXO(1, Alice),
141
- ];
142
- // Alice proposes the output UTXOs, 1 utxo to bob, 1 utxo to charlie and 3 utxos to alice
143
- const _bOut1 = newUTXO(6, Bob);
144
- const _bOut2 = newUTXO(1, Charlie);
145
-
146
- const outputUtxos = [_bOut1, _bOut2, ...aliceUTXOsToBeWithdrawn];
147
- const outputOwners = [Bob, Charlie, Alice, Alice, Alice];
148
- const inflatedOutputUtxos = [...outputUtxos];
149
- const inflatedOutputOwners = [...outputOwners];
150
- for (let i = 0; i < 10 - outputUtxos.length; i++) {
151
- inflatedOutputUtxos.push(ZERO_UTXO);
152
- inflatedOutputOwners.push(Bob);
153
- }
154
- // Alice transfers her UTXOs to Bob
155
- const result = await doTransfer(
156
- Alice,
157
- inputUtxos,
158
- nullifiers,
159
- inflatedOutputUtxos,
160
- root.bigInt(),
161
- mtps,
162
- inflatedOutputOwners,
163
- );
164
178
 
165
- const signerAddress = await Alice.signer.getAddress();
166
- const events = parseUTXOEvents(zeto, result.txResult!);
167
- expect(events[0].submitter).to.equal(signerAddress);
168
- expect(events[0].inputs).to.deep.equal(nullifiers.map((n) => n.hash));
179
+ const signerAddress = await Alice.signer.getAddress();
180
+ const events = parseUTXOEvents(zeto, result.txResult!);
181
+ const event = events[0];
182
+ expect(event.submitter).to.equal(signerAddress);
183
+ expect(event.inputs).to.deep.equal(nullifiers.map((n) => n.hash));
184
+
185
+ const incomingUTXOs: any = event.outputs;
186
+ // check the non-empty output hashes are correct
187
+ for (let i = 0; i < outputUtxos.length; i++) {
188
+ // Bob uses the information received from Alice to reconstruct the UTXO sent to him
189
+ const receivedValue = outputUtxos[i].value;
190
+ const receivedSalt = outputUtxos[i].salt;
191
+ const hash = Poseidon.poseidon4([
192
+ BigInt(receivedValue),
193
+ receivedSalt,
194
+ outputOwners[i].babyJubPublicKey[0],
195
+ outputOwners[i].babyJubPublicKey[1],
196
+ ]);
197
+ expect(incomingUTXOs[i]).to.equal(hash);
198
+ await smtAlice.add(incomingUTXOs[i], incomingUTXOs[i]);
199
+ await smtBob.add(incomingUTXOs[i], incomingUTXOs[i]);
200
+ }
169
201
 
170
- const incomingUTXOs: any = events[0].outputs;
171
- // check the non-empty output hashes are correct
172
- for (let i = 0; i < outputUtxos.length; i++) {
173
- // Bob uses the information received from Alice to reconstruct the UTXO sent to him
174
- const receivedValue = outputUtxos[i].value;
175
- const receivedSalt = outputUtxos[i].salt;
176
- const hash = Poseidon.poseidon4([
177
- BigInt(receivedValue),
178
- receivedSalt,
179
- outputOwners[i].babyJubPublicKey[0],
180
- outputOwners[i].babyJubPublicKey[1],
181
- ]);
182
- expect(incomingUTXOs[i]).to.equal(hash);
183
- await smtAlice.add(incomingUTXOs[i], incomingUTXOs[i]);
184
- await smtBob.add(incomingUTXOs[i], incomingUTXOs[i]);
185
- }
202
+ // mint sufficient balance in Zeto contract address for Alice to withdraw
203
+ const mintTx = await erc20.connect(deployer).mint(zeto, 3);
204
+ await mintTx.wait();
205
+ const startingBalance = await erc20.balanceOf(Alice.ethAddress);
206
+
207
+ // Alice generates the nullifiers for the UTXOs to be spent
208
+ root = await smtAlice.root();
209
+ const inflatedWithdrawNullifiers = [];
210
+ const inflatedWithdrawInputs = [];
211
+ const inflatedWithdrawMTPs = [];
212
+ for (let i = 0; i < aliceUTXOsToBeWithdrawn.length; i++) {
213
+ inflatedWithdrawInputs.push(aliceUTXOsToBeWithdrawn[i]);
214
+ inflatedWithdrawNullifiers.push(
215
+ newNullifier(aliceUTXOsToBeWithdrawn[i], Alice),
216
+ );
217
+ const _withdrawUTXOProof = await smtAlice.generateCircomVerifierProof(
218
+ aliceUTXOsToBeWithdrawn[i].hash,
219
+ root,
220
+ );
221
+ inflatedWithdrawMTPs.push(
222
+ _withdrawUTXOProof.siblings.map((s) => s.bigInt()),
223
+ );
224
+ }
225
+ // Alice generates inclusion proofs for the UTXOs to be spent
186
226
 
187
- // check empty hashes are empty
188
- for (let i = outputUtxos.length; i < 10; i++) {
189
- expect(incomingUTXOs[i]).to.equal(0);
190
- }
227
+ for (let i = aliceUTXOsToBeWithdrawn.length; i < 10; i++) {
228
+ inflatedWithdrawInputs.push(ZERO_UTXO);
229
+ inflatedWithdrawNullifiers.push(ZERO_UTXO);
230
+ const _zeroProof = await smtAlice.generateCircomVerifierProof(0n, root);
231
+ inflatedWithdrawMTPs.push(_zeroProof.siblings.map((s) => s.bigInt()));
232
+ }
191
233
 
192
- // mint sufficient balance in Zeto contract address for Alice to withdraw
193
- const mintTx = await erc20.connect(deployer).mint(zeto, 3);
194
- await mintTx.wait();
195
- const startingBalance = await erc20.balanceOf(Alice.ethAddress);
196
-
197
- // Alice generates the nullifiers for the UTXOs to be spent
198
- root = await smtAlice.root();
199
- const inflatedWithdrawNullifiers = [];
200
- const inflatedWithdrawInputs = [];
201
- const inflatedWithdrawMTPs = [];
202
- for (let i = 0; i < aliceUTXOsToBeWithdrawn.length; i++) {
203
- inflatedWithdrawInputs.push(aliceUTXOsToBeWithdrawn[i]);
204
- inflatedWithdrawNullifiers.push(
205
- newNullifier(aliceUTXOsToBeWithdrawn[i], Alice),
234
+ const {
235
+ nullifiers: _withdrawNullifiers,
236
+ outputCommitments: withdrawCommitments,
237
+ encodedProof: withdrawEncodedProof,
238
+ } = await prepareNullifierWithdrawProof(
239
+ Alice,
240
+ inflatedWithdrawInputs,
241
+ inflatedWithdrawNullifiers,
242
+ ZERO_UTXO,
243
+ root.bigInt(),
244
+ inflatedWithdrawMTPs,
206
245
  );
207
- const _withdrawUTXOProof = await smtAlice.generateCircomVerifierProof(
208
- aliceUTXOsToBeWithdrawn[i].hash,
246
+
247
+ // Alice withdraws her UTXOs to ERC20 tokens
248
+ const tx = await zeto
249
+ .connect(Alice.signer)
250
+ .withdraw(
251
+ 3,
252
+ _withdrawNullifiers,
253
+ withdrawCommitments[0],
254
+ encodeToBytesForWithdraw(root.bigInt(), withdrawEncodedProof),
255
+ "0x",
256
+ );
257
+ await tx.wait();
258
+
259
+ // Alice checks her ERC20 balance
260
+ const endingBalance = await erc20.balanceOf(Alice.ethAddress);
261
+ expect(endingBalance - startingBalance).to.be.equal(3);
262
+ }).timeout(60000);
263
+ });
264
+
265
+ describe("transfer with verifications by the receiver and the audit authority", function () {
266
+ let event: any;
267
+ let outputUTXOs: UTXO[];
268
+ let outputOwners: User[];
269
+
270
+ it("mint ERC20 tokens to Alice to deposit to Zeto should succeed", async function () {
271
+ const startingBalance = await erc20.balanceOf(Alice.ethAddress);
272
+ const tx = await erc20.connect(deployer).mint(Alice.ethAddress, 100);
273
+ await tx.wait();
274
+ const endingBalance = await erc20.balanceOf(Alice.ethAddress);
275
+ expect(endingBalance - startingBalance).to.be.equal(100);
276
+
277
+ const tx1 = await erc20.connect(Alice.signer).approve(zeto.target, 100);
278
+ await tx1.wait();
279
+
280
+ utxo100 = newUTXO(100, Alice);
281
+ const utxo0 = newUTXO(0, Alice);
282
+ const { outputCommitments, encodedProof } = await prepareDepositProof(
283
+ Alice,
284
+ [utxo0, utxo100],
285
+ );
286
+ const tx2 = await zeto
287
+ .connect(Alice.signer)
288
+ .deposit(
289
+ 100,
290
+ outputCommitments,
291
+ encodeToBytesForDeposit(encodedProof),
292
+ "0x",
293
+ );
294
+ await tx2.wait();
295
+
296
+ await smtAlice.add(utxo100.hash, utxo100.hash);
297
+ await smtAlice.add(utxo0.hash, utxo0.hash);
298
+ await smtBob.add(utxo100.hash, utxo100.hash);
299
+ await smtBob.add(utxo0.hash, utxo0.hash);
300
+ });
301
+
302
+ it("mint to Alice and transfer UTXOs honestly to Bob should succeed", async function () {
303
+ const startingBalance = await erc20.balanceOf(Alice.ethAddress);
304
+ // The authority mints a new UTXO and assigns it to Alice
305
+ utxo1 = newUTXO(10, Alice);
306
+ utxo2 = newUTXO(20, Alice);
307
+ const result1 = await doMint(zeto, deployer, [utxo1, utxo2]);
308
+
309
+ // check the private mint activity is not exposed in the ERC20 contract
310
+ const afterMintBalance = await erc20.balanceOf(Alice.ethAddress);
311
+ expect(afterMintBalance).to.equal(startingBalance);
312
+
313
+ // Alice locally tracks the UTXOs inside the Sparse Merkle Tree
314
+ // hardhat doesn't have a good way to subscribe to events so we have to parse the Tx result object
315
+ const mintEvents = parseUTXOEvents(zeto, result1);
316
+ const [_utxo1, _utxo2] = mintEvents[0].outputs;
317
+ await smtAlice.add(_utxo1, _utxo1);
318
+ await smtAlice.add(_utxo2, _utxo2);
319
+ let root = await smtAlice.root();
320
+ let onchainRoot = await zeto.getRoot();
321
+ expect(root.string()).to.equal(onchainRoot.toString());
322
+ // Bob also locally tracks the UTXOs inside the Sparse Merkle Tree
323
+ await smtBob.add(_utxo1, _utxo1);
324
+ await smtBob.add(_utxo2, _utxo2);
325
+
326
+ // Alice proposes the output UTXOs for the transfer to Bob
327
+ const _utxo3 = newUTXO(25, Bob);
328
+ utxo4 = newUTXO(5, Alice);
329
+
330
+ // Alice generates the nullifiers for the UTXOs to be spent
331
+ const nullifier1 = newNullifier(utxo1, Alice);
332
+ const nullifier2 = newNullifier(utxo2, Alice);
333
+
334
+ // Alice generates inclusion proofs for the UTXOs to be spent
335
+ const proof1 = await smtAlice.generateCircomVerifierProof(
336
+ utxo1.hash,
209
337
  root,
210
338
  );
211
- inflatedWithdrawMTPs.push(
212
- _withdrawUTXOProof.siblings.map((s) => s.bigInt()),
339
+ const proof2 = await smtAlice.generateCircomVerifierProof(
340
+ utxo2.hash,
341
+ root,
213
342
  );
214
- }
215
- // Alice generates inclusion proofs for the UTXOs to be spent
216
-
217
- for (let i = aliceUTXOsToBeWithdrawn.length; i < 10; i++) {
218
- inflatedWithdrawInputs.push(ZERO_UTXO);
219
- inflatedWithdrawNullifiers.push(ZERO_UTXO);
220
- const _zeroProof = await smtAlice.generateCircomVerifierProof(0n, root);
221
- inflatedWithdrawMTPs.push(_zeroProof.siblings.map((s) => s.bigInt()));
222
- }
223
-
224
- const {
225
- nullifiers: _withdrawNullifiers,
226
- outputCommitments: withdrawCommitments,
227
- encodedProof: withdrawEncodedProof,
228
- } = await prepareNullifierWithdrawProof(
229
- Alice,
230
- inflatedWithdrawInputs,
231
- inflatedWithdrawNullifiers,
232
- ZERO_UTXO,
233
- root.bigInt(),
234
- inflatedWithdrawMTPs,
235
- );
236
-
237
- // Alice withdraws her UTXOs to ERC20 tokens
238
- const tx = await zeto
239
- .connect(Alice.signer)
240
- .withdraw(
241
- 3,
242
- _withdrawNullifiers,
243
- withdrawCommitments[0],
343
+ const merkleProofs = [
344
+ proof1.siblings.map((s) => s.bigInt()),
345
+ proof2.siblings.map((s) => s.bigInt()),
346
+ ];
347
+
348
+ // Alice transfers her UTXOs to Bob
349
+ outputUTXOs = [_utxo3, utxo4];
350
+ outputOwners = [Bob, Alice];
351
+ const result2 = await doTransfer(
352
+ Alice,
353
+ [utxo1, utxo2],
354
+ [nullifier1, nullifier2],
355
+ outputUTXOs,
244
356
  root.bigInt(),
245
- withdrawEncodedProof,
246
- "0x",
357
+ merkleProofs,
358
+ outputOwners,
247
359
  );
248
- await tx.wait();
249
-
250
- // Alice checks her ERC20 balance
251
- const endingBalance = await erc20.balanceOf(Alice.ethAddress);
252
- expect(endingBalance - startingBalance).to.be.equal(3);
253
- }).timeout(60000);
254
-
255
- it("mint ERC20 tokens to Alice to deposit to Zeto should succeed", async function () {
256
- const startingBalance = await erc20.balanceOf(Alice.ethAddress);
257
- const tx = await erc20.connect(deployer).mint(Alice.ethAddress, 100);
258
- await tx.wait();
259
- const endingBalance = await erc20.balanceOf(Alice.ethAddress);
260
- expect(endingBalance - startingBalance).to.be.equal(100);
261
-
262
- const tx1 = await erc20.connect(Alice.signer).approve(zeto.target, 100);
263
- await tx1.wait();
264
-
265
- utxo100 = newUTXO(100, Alice);
266
- const utxo0 = newUTXO(0, Alice);
267
- const { outputCommitments, encodedProof } = await prepareDepositProof(
268
- Alice,
269
- [utxo0, utxo100],
270
- );
271
- const tx2 = await zeto
272
- .connect(Alice.signer)
273
- .deposit(100, outputCommitments, encodedProof, "0x");
274
- await tx2.wait();
275
-
276
- await smtAlice.add(utxo100.hash, utxo100.hash);
277
- await smtAlice.add(utxo0.hash, utxo0.hash);
278
- await smtBob.add(utxo100.hash, utxo100.hash);
279
- await smtBob.add(utxo0.hash, utxo0.hash);
280
- });
281
360
 
282
- it("mint to Alice and transfer UTXOs honestly to Bob should succeed", async function () {
283
- const startingBalance = await erc20.balanceOf(Alice.ethAddress);
284
- // The authority mints a new UTXO and assigns it to Alice
285
- utxo1 = newUTXO(10, Alice);
286
- utxo2 = newUTXO(20, Alice);
287
- const result1 = await doMint(zeto, deployer, [utxo1, utxo2]);
288
-
289
- // check the private mint activity is not exposed in the ERC20 contract
290
- const afterMintBalance = await erc20.balanceOf(Alice.ethAddress);
291
- expect(afterMintBalance).to.equal(startingBalance);
292
-
293
- // Alice locally tracks the UTXOs inside the Sparse Merkle Tree
294
- // hardhat doesn't have a good way to subscribe to events so we have to parse the Tx result object
295
- const mintEvents = parseUTXOEvents(zeto, result1);
296
- const [_utxo1, _utxo2] = mintEvents[0].outputs;
297
- await smtAlice.add(_utxo1, _utxo1);
298
- await smtAlice.add(_utxo2, _utxo2);
299
- let root = await smtAlice.root();
300
- let onchainRoot = await zeto.getRoot();
301
- expect(root.string()).to.equal(onchainRoot.toString());
302
- // Bob also locally tracks the UTXOs inside the Sparse Merkle Tree
303
- await smtBob.add(_utxo1, _utxo1);
304
- await smtBob.add(_utxo2, _utxo2);
305
-
306
- // Alice proposes the output UTXOs for the transfer to Bob
307
- const _utxo3 = newUTXO(25, Bob);
308
- utxo4 = newUTXO(5, Alice);
309
-
310
- // Alice generates the nullifiers for the UTXOs to be spent
311
- const nullifier1 = newNullifier(utxo1, Alice);
312
- const nullifier2 = newNullifier(utxo2, Alice);
313
-
314
- // Alice generates inclusion proofs for the UTXOs to be spent
315
- const proof1 = await smtAlice.generateCircomVerifierProof(utxo1.hash, root);
316
- const proof2 = await smtAlice.generateCircomVerifierProof(utxo2.hash, root);
317
- const merkleProofs = [
318
- proof1.siblings.map((s) => s.bigInt()),
319
- proof2.siblings.map((s) => s.bigInt()),
320
- ];
321
-
322
- // Alice transfers her UTXOs to Bob
323
- const result2 = await doTransfer(
324
- Alice,
325
- [utxo1, utxo2],
326
- [nullifier1, nullifier2],
327
- [_utxo3, utxo4],
328
- root.bigInt(),
329
- merkleProofs,
330
- [Bob, Alice],
331
- );
361
+ // check the private transfer activity is not exposed in the ERC20 contract
362
+ const afterTransferBalance = await erc20.balanceOf(Alice.ethAddress);
363
+ expect(afterTransferBalance).to.equal(startingBalance);
364
+
365
+ // Alice locally tracks the UTXOs inside the Sparse Merkle Tree
366
+ await smtAlice.add(_utxo3.hash, _utxo3.hash);
367
+ await smtAlice.add(utxo4.hash, utxo4.hash);
368
+ root = await smtAlice.root();
369
+ onchainRoot = await zeto.getRoot();
370
+ expect(root.string()).to.equal(onchainRoot.toString());
371
+
372
+ // Bob locally tracks the UTXOs inside the Sparse Merkle Tree
373
+ // Bob parses the UTXOs from the onchain event
374
+ const signerAddress = await Alice.signer.getAddress();
375
+ const events = parseUTXOEvents(zeto, result2.txResult!);
376
+ event = events[0];
377
+ expect(event.submitter).to.equal(signerAddress);
378
+ expect(event.inputs).to.deep.equal([nullifier1.hash, nullifier2.hash]);
379
+ expect(event.outputs).to.deep.equal([_utxo3.hash, utxo4.hash]);
380
+ await smtBob.add(event.outputs[0], event.outputs[0]);
381
+ await smtBob.add(event.outputs[1], event.outputs[1]);
332
382
 
333
- // check the private transfer activity is not exposed in the ERC20 contract
334
- const afterTransferBalance = await erc20.balanceOf(Alice.ethAddress);
335
- expect(afterTransferBalance).to.equal(startingBalance);
336
-
337
- // Alice locally tracks the UTXOs inside the Sparse Merkle Tree
338
- await smtAlice.add(_utxo3.hash, _utxo3.hash);
339
- await smtAlice.add(utxo4.hash, utxo4.hash);
340
- root = await smtAlice.root();
341
- onchainRoot = await zeto.getRoot();
342
- expect(root.string()).to.equal(onchainRoot.toString());
343
-
344
- // Bob locally tracks the UTXOs inside the Sparse Merkle Tree
345
- // Bob parses the UTXOs from the onchain event
346
- const signerAddress = await Alice.signer.getAddress();
347
- const events = parseUTXOEvents(zeto, result2.txResult!);
348
- expect(events[0].submitter).to.equal(signerAddress);
349
- expect(events[0].inputs).to.deep.equal([nullifier1.hash, nullifier2.hash]);
350
- expect(events[0].outputs).to.deep.equal([_utxo3.hash, utxo4.hash]);
351
- await smtBob.add(events[0].outputs[0], events[0].outputs[0]);
352
- await smtBob.add(events[0].outputs[1], events[0].outputs[1]);
353
-
354
- // Bob uses the information received from Alice to reconstruct the UTXO sent to him
355
- const receivedValue = _utxo3.value!;
356
- const receivedSalt = _utxo3.salt;
357
- const incomingUTXOs: any = events[0].outputs;
358
- const hash = Poseidon.poseidon4([
359
- BigInt(receivedValue),
360
- receivedSalt,
361
- Bob.babyJubPublicKey[0],
362
- Bob.babyJubPublicKey[1],
363
- ]);
364
- expect(incomingUTXOs[0]).to.equal(hash);
365
-
366
- // Bob uses the decrypted values to construct the UTXO received from the transaction
367
- utxo3 = newUTXO(receivedValue, Bob, receivedSalt);
368
- }).timeout(600000);
383
+ // Bob uses the information received from Alice to reconstruct the UTXO sent to him
384
+ const receivedValue = _utxo3.value!;
385
+ const receivedSalt = _utxo3.salt;
386
+ const incomingUTXOs: any = event.outputs;
387
+ const hash = Poseidon.poseidon4([
388
+ BigInt(receivedValue),
389
+ receivedSalt,
390
+ Bob.babyJubPublicKey[0],
391
+ Bob.babyJubPublicKey[1],
392
+ ]);
393
+ expect(incomingUTXOs[0]).to.equal(hash);
394
+
395
+ // Bob uses the decrypted values to construct the UTXO received from the transaction
396
+ utxo3 = newUTXO(receivedValue, Bob, receivedSalt);
397
+ }).timeout(600000);
398
+
399
+ it("The audit authority can decrypt the encrypted values in the transfer event", async function () {
400
+ // The audit authority can decrypt the encrypted values in the transfer event
401
+ const encapsulatedSharedSecret = event.encapsulatedSharedSecret;
402
+ const cBytes = recoverMlKemCiphertextBytes(encapsulatedSharedSecret);
403
+ // the receiver can decap the ciphertext, and recover the shared secret
404
+ // using the mlkem ciphertext and the receiver's private key
405
+ const receiver = new MlKem512();
406
+ const ssReceiver = await receiver.decap(
407
+ new Uint8Array(cBytes),
408
+ new Uint8Array(testKeyPair.sk),
409
+ );
410
+ // corresponding to the logic in the circuit "pubkey.circom", we derive the symmetric key
411
+ // from the shared secret
412
+ expect(ssReceiver.length).to.equal(32);
413
+ const recoveredKey = publicKeyFromSeed(ssReceiver);
414
+
415
+ const encryptedValues = event.encryptedValues;
416
+ const encryptionNonce = event.encryptionNonce;
417
+ expect(encryptedValues.length).to.equal(16);
418
+
419
+ let plainText = poseidonDecrypt(
420
+ encryptedValues,
421
+ recoveredKey,
422
+ encryptionNonce,
423
+ 14,
424
+ );
425
+ expect(plainText[0]).to.equal(Alice.babyJubPublicKey[0]);
426
+ expect(plainText[1]).to.equal(Alice.babyJubPublicKey[1]);
427
+ expect(plainText[2]).to.equal(BigInt(utxo1.value!));
428
+ expect(plainText[3]).to.equal(utxo1.salt!);
429
+ });
430
+ });
369
431
 
370
432
  // describe("lock() tests", function () {
371
433
  // let lockedUtxo1: UTXO;
@@ -539,7 +601,9 @@ describe("Zeto based fungible token with anonymity using nullifiers with Kyber e
539
601
  ) {
540
602
  let nullifiers: BigNumberish[];
541
603
  let outputCommitments: BigNumberish[];
542
- let ciphertext: BigNumberish[];
604
+ let encryptionNonce: BigNumberish;
605
+ let outputsCiphertext: BigNumberish[];
606
+ let encapsulatedSharedSecret: BigNumberish[];
543
607
  let encodedProof: any;
544
608
  const circuitToUse = lockDelegate
545
609
  ? circuitForLocked
@@ -568,14 +632,18 @@ describe("Zeto based fungible token with anonymity using nullifiers with Kyber e
568
632
  ) as BigNumberish[];
569
633
  outputCommitments = result.outputCommitments;
570
634
  encodedProof = result.encodedProof;
571
- ciphertext = result.ciphertext;
635
+ encryptionNonce = result.encryptionNonce;
636
+ outputsCiphertext = result.outputsCiphertext;
637
+ encapsulatedSharedSecret = result.encapsulatedSharedSecret;
572
638
 
573
639
  const txResult = await sendTx(
574
640
  signer,
575
641
  nullifiers,
576
642
  outputCommitments,
577
643
  root,
578
- ciphertext,
644
+ encryptionNonce,
645
+ outputsCiphertext,
646
+ encapsulatedSharedSecret,
579
647
  encodedProof,
580
648
  lockDelegate !== undefined,
581
649
  );
@@ -595,33 +663,34 @@ describe("Zeto based fungible token with anonymity using nullifiers with Kyber e
595
663
  nullifiers: BigNumberish[],
596
664
  outputCommitments: BigNumberish[],
597
665
  root: BigNumberish,
598
- ciphertext: BigNumberish[],
666
+ encryptionNonce: BigNumberish,
667
+ outputsCiphertext: BigNumberish[],
668
+ encapsulatedSharedSecret: BigNumberish[],
599
669
  encodedProof: any,
600
670
  isLocked: boolean = false,
601
671
  ) {
602
- const buff = Buffer.alloc(ciphertext.length);
603
- for (let i = 0; i < ciphertext.length; i++) {
604
- buff.writeUInt8(Number(ciphertext[i]), i);
605
- }
606
- const ciphertextHex = "0x" + buff.toString("hex");
607
-
608
672
  const startTx = Date.now();
609
673
  let tx: any;
674
+ const proof = encodeToBytes(
675
+ root,
676
+ encryptionNonce,
677
+ outputsCiphertext,
678
+ encapsulatedSharedSecret,
679
+ encodedProof,
680
+ );
610
681
  if (!isLocked) {
611
682
  tx = await zeto.connect(signer.signer).transfer(
612
683
  nullifiers.filter((ic) => ic !== 0n), // trim off empty utxo hashes to check padding logic for batching works
613
684
  outputCommitments.filter((oc) => oc !== 0n), // trim off empty utxo hashes to check padding logic for batching works
614
- root,
615
- ciphertextHex,
616
- encodedProof,
685
+ proof,
617
686
  "0x",
618
687
  );
619
688
  } else {
620
689
  tx = await zeto.connect(signer.signer).transferLocked(
621
690
  nullifiers.filter((ic) => ic !== 0n), // trim off empty utxo hashes to check padding logic for batching works
691
+ [],
622
692
  outputCommitments.filter((oc) => oc !== 0n), // trim off empty utxo hashes to check padding logic for batching works
623
- root,
624
- encodedProof,
693
+ proof,
625
694
  "0x",
626
695
  );
627
696
  }
@@ -662,25 +731,9 @@ async function prepareProof(
662
731
  (owner) => owner.babyJubPublicKey,
663
732
  ) as BigNumberish[][];
664
733
 
665
- // TODO: construct the message by generating an AES-256 key (the encryption key is the message)
666
- // as part of the KEM protocol. Replace 1 with 1665.
667
- const m = [
668
- 1665, 1665, 0, 1665, 0, 1665, 1665, 0, 1665, 0, 0, 1665, 1665, 1665, 1665,
669
- 0, 0, 1665, 0, 0, 0, 1665, 1665, 0, 1665, 0, 1665, 0, 0, 1665, 1665, 0, 0,
670
- 1665, 0, 0, 1665, 1665, 1665, 0, 0, 0, 0, 0, 0, 1665, 0, 0, 1665, 0, 0,
671
- 1665, 0, 1665, 1665, 0, 1665, 1665, 0, 0, 1665, 1665, 1665, 0, 0, 0, 0, 0,
672
- 0, 1665, 0, 0, 1665, 1665, 0, 0, 0, 1665, 1665, 0, 1665, 1665, 1665, 1665,
673
- 0, 1665, 1665, 0, 1665, 1665, 1665, 1665, 0, 1665, 1665, 0, 0, 0, 1665,
674
- 1665, 0, 1665, 1665, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
675
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
676
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
677
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
678
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
679
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
680
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
681
- ];
682
-
683
- const randomness = randomBytesAsDigitArray(32);
734
+ const randomness = crypto.randomBytes(32);
735
+ const r = bytesToBits(randomness);
736
+ const encryptionNonce = newEncryptionNonce();
684
737
  const startWitnessCalculation = Date.now();
685
738
  const inputObj: any = {
686
739
  nullifiers,
@@ -695,22 +748,13 @@ async function prepareProof(
695
748
  outputValues,
696
749
  outputSalts: outputs.map((output) => output.salt || 0n),
697
750
  outputOwnerPublicKeys,
698
- randomness,
699
- m,
751
+ randomness: r,
752
+ encryptionNonce,
700
753
  };
701
754
  if (lockDelegate) {
702
755
  inputObj["lockDelegate"] = ethers.toBigInt(lockDelegate);
703
756
  }
704
757
 
705
- // first call the calculateWitness function which returns
706
- // the witness as an object, in order to get the ciphertext
707
- const witnessObj = await circuit.calculateWitness(inputObj, true);
708
- const circuitName =
709
- inputs.length > 2
710
- ? "anon_nullifier_qurrency_batch"
711
- : "anon_nullifier_qurrency";
712
- const ciphertext = getKyberCipherText(witnessObj, circuitName);
713
-
714
758
  const witness = await circuit.calculateWTNSBin(inputObj, true);
715
759
  const timeWithnessCalculation = Date.now() - startWitnessCalculation;
716
760
 
@@ -721,6 +765,10 @@ async function prepareProof(
721
765
  )) as { proof: BigNumberish[]; publicSignals: BigNumberish[] };
722
766
  const timeProofGeneration = Date.now() - startProofGeneration;
723
767
 
768
+ const length = outputCommitments.length > 2 ? 64 : 16;
769
+ const encapsulatedSharedSecret = publicSignals.slice(0, 25);
770
+ const outputsCiphertext = publicSignals.slice(25, 25 + length);
771
+
724
772
  console.log(
725
773
  `Witness calculation time: ${timeWithnessCalculation}ms. Proof generation time: ${timeProofGeneration}ms.`,
726
774
  );
@@ -730,10 +778,108 @@ async function prepareProof(
730
778
  inputCommitments,
731
779
  outputCommitments,
732
780
  encodedProof,
733
- ciphertext,
781
+ encryptionNonce,
782
+ outputsCiphertext,
783
+ encapsulatedSharedSecret,
734
784
  };
735
785
  }
736
786
 
787
+ function encodeToBytes(
788
+ root: any,
789
+ encryptionNonce: any,
790
+ encryptedValues: any,
791
+ encapsulatedSharedSecret: any,
792
+ proof: any,
793
+ ) {
794
+ return new AbiCoder().encode(
795
+ [
796
+ "uint256 root",
797
+ "uint256 encryptionNonce",
798
+ "uint256[] encryptedValues",
799
+ "uint256[25] encapsulatedSharedSecret",
800
+ "tuple(uint256[2] pA, uint256[2][2] pB, uint256[2] pC)",
801
+ ],
802
+ [root, encryptionNonce, encryptedValues, encapsulatedSharedSecret, proof],
803
+ );
804
+ }
805
+
737
806
  module.exports = {
738
807
  prepareProof,
739
808
  };
809
+
810
+ describe("encoding test", function () {
811
+ it("should encode the proof correctly", function () {
812
+ const proof = encodeToBytes(
813
+ 2185945469173281998543795100239332646380217964035682609677494700854501229435n, // root
814
+ 275390031262136596949503856056006740272n, // encryptionNonce
815
+ [
816
+ 13715591515004609688233255520139366968347229879226987447392926581641315410365n,
817
+ 12225040792969183937477801836359093706337068545022080407734986798228486880459n,
818
+ 13011843324002630531326495134664720300521666217887617808427836215465667928692n,
819
+ 19856495997717871827317781271670963924363352390548953270211310380014460390334n,
820
+ 10604073410745110687091665574819448938663378994798073962869528739665232014421n,
821
+ 4435178295556424656324960575659262079598790982598728711009699368000570989336n,
822
+ 4933836950213445512336611933470005675174051517599168194217630597808234407822n,
823
+ 4214225226975003066728797596550538286539095487779015468026667054118086708667n,
824
+ 5024576208387901066062709265269626900637589025955141460411534463069531901891n,
825
+ 703973997727387811759298044568434494690485054474094541129706149430879630884n,
826
+ 14507146421329688672993934183526210401463938041762433569084930573959882425326n,
827
+ 14012438595855534325416420918184230363976318221634661889145359708752658755207n,
828
+ 8754932719802650626162524741856226517982355523480941833310179558554675571452n,
829
+ 14352194087842591409364852158942330879045556303811584255462682741598400114507n,
830
+ 930427648599696993608342770250501205956137552217414712238549287557300544904n,
831
+ 21394278059543057034208592185307596281934697437416095108050934185203559222712n,
832
+ ], // encryptedValues
833
+ [
834
+ 288126790059318346139824202713129652229348576996464001952408714015513463993n,
835
+ 237407267603824073552608687931930991963999394428366555167539009382905388537n,
836
+ 114764209448275499414271899760871155095571139138912032913196740291197144696n,
837
+ 436995396164250682578369063006271991698559693192849862783563046924655949369n,
838
+ 240591981726723986881909418996515793567853950883197759098846148099856667367n,
839
+ 423589442784611103138623838389086946618384967919367390938087104637737788216n,
840
+ 145462886897996314213326681029317456734837820615410128121849599895343382705n,
841
+ 389932051522827200062535000655062077695415252609124727680940113692289747665n,
842
+ 243675801576408693743852761736871686197324939358886873348705983761231779940n,
843
+ 87939610206601698004485673787337315272887533489281795861381157598783844367n,
844
+ 11014683993036861793302780310552914749438060162054842543618251146378375526n,
845
+ 111614391393324468932660651857272851218377641294817341376507043259517434344n,
846
+ 435707583091444288657484999813927778656294844261499799508340404768617948216n,
847
+ 256449006844324353610179235842731870600460006591548128221647489805788554815n,
848
+ 418634767833052917835192672729088145298440004524459401783387363547257320986n,
849
+ 103610780261386527074710704895000705809005120944489697847370877795317539063n,
850
+ 127627753495450202619315508879418050934338498775659516820680842878935424334n,
851
+ 46384251041970312953604802331459565502839961155990167432349041542488773332n,
852
+ 59279347778101058820051248467497773070279609242238499827597758128700405210n,
853
+ 401076038589967842843270755588760950994197089793842470053926063226777655114n,
854
+ 437055888722697362599388401811652409455332242376917929776279980055423605099n,
855
+ 382219076120208743166804616016001837790918283786525158013655719261656086690n,
856
+ 412218952494890119014684951992443508961594053505588316664570435208291787650n,
857
+ 362621741079924474296483570929701950283961620929630348838376271651154374200n,
858
+ 3987927141671093050828825554766656132900595007161822411291n,
859
+ ], // encapsulatedSharedSecret
860
+ [
861
+ [
862
+ 549287572509790359685716132453355766491815426087194122700979105235739473130n,
863
+ 15298123219329538989607681043913355391761570794419278588736377843648111671159n,
864
+ ],
865
+ [
866
+ [
867
+ 9440038941921968905445133266072988463231863413680655261260818687531566458108n,
868
+ 2207698080461885696867541047133088519732009024182544199097906381032204346428n,
869
+ ],
870
+ [
871
+ 6577776031418234473059205922833530313720519798861738979049253341371055729708n,
872
+ 11968330310582097325419116485228879165470205732203147205908830680466052312773n,
873
+ ],
874
+ ],
875
+ [
876
+ 3106716200655790292773114695208727957822992667898408535199502363885960505738n,
877
+ 20085498771862832325662320796990160779029948991590746485323346020588480720567n,
878
+ ],
879
+ ], // proof
880
+ );
881
+ expect(proof).to.equal(
882
+ "0x04d53387cb12538667ced7ce8b1846dbdff33fc38784b2604a08125446b4c37b00000000000000000000000000000000cf2e30d59acb9763a0c1626c5e6a0930000000000000000000000000000000000000000000000000000000000000048000a312f09e6066c7aebc7468b5cf1aafa3151c298175dbd658d5acba17e74cb900865e24f8de2a91bdfaaaa40792466eab7b9767f8e8fa1903b80825f3c99df90040f4491d9acb71301b8f394d01b5920669cedd5af8da172226d505d1740e7800f754a41cdcdf6a81a97771a25a885d09c64b8464f53d4b0e0292c8aa9a763900882b9495929d332f40dde4a0ff1b9e162cc2f802a603faabcff12074fc12e700efbe3daa599448fdc6c90e7919ba04a86b0c6accdb304e9f325aafc1ce63380052543e5908a1d6165f2f82e3136c2c95e9e185e2aec7ddf95139401b6ac0b100dcb197a37a65273cf5115a71ab6e24e0a67227303dd03600e34b46d3694ad10089ea65d1df01235226c5985d0e8853f7ba53d641a12948e5a98141aafa18640031c5a56e40a3988cde8b4a2d3baa8a42813226e602951754c3668f8627b00f00063bed560dd4187b7a6ad7e31858dbbf2cf8583c7e1a883124098067387166003f2be7dee087211d4ad509d7385c4cd293052ab7050d6e0ecb224d604af9e800f69a0c789609111b4e125f60324eeb682ee8216ffc19ffec929a77bc2264380091251e55d2b6b1e3b64f803ffac769bba390eee196c95dd718e7d0cb0aa63f00ecf05a8eb06e090213be5b5fd338dbacfc6d18d835dfa7719d763a47b1361a003aa4416f29bc3291dae5fa6dd98e44dc40beef68c6b15e21fb1b15cb7760f700483c187b8e203bf7433a3316ccc9aad2fdcd6aafbb328bf79bf7a2ec9cdd4e001a40a77e1af8c8ac79aa167d1c519a097c76158230b125b9ddd2830905d2d400218d0936c05cae6f1f92d1b5ac105573fd70b2a5f3cb0ac4a0bc6fcab635da00e3004117a1cb79135f18f5de7019a2828ee3f41b1f2b5adf57e891fb16574a00f75d67e80cb479cf92b2ad3c521830c41d1721130d801f6b58f4ffc277d96b00d8540d7b056af7eec2368efb244c68fb684803562bbd14321c2274e33878a200e94ec2bd8059bda202a769b7312c5c194e418cc0eb9b0a27e56fbc627ba38200cd3c93ec8281b7fad9dd5183dd892f98b9b7beae868eb6f8f17d806af32e380000000000000000a2a3e6ee40deb77d25dc4473312ff54bc727758efd4cfa1b0136e2c06cabb082011e47ab176222198f0fa0885e8046650f31aeab65a9f4ea21d26e4f641fe77a3cb7215d4b3c9cec9a1f7148edc75c6b2b9390636f55777714dedf690fa175f2f4a8f9298cead433608482fa3251c9c4df1be18156bf64fc04e18348fd35af148608f6dfccdf42139dd1278a947b119993784074aaf5243c0e8ae3a922c4523d0207bd28e658e37add64feeefcadfcd4feae9b93ceb3ec2c1a75d5bc03c3417b3db41c75a87b563433c27d11efd64439837b0994fcb76ec506de56cc662d32548f11121f83941d43b37a6bdce0c5edf070969dc971c5298a2c67fd4bd7994866b73163e4136ee3d0f6662a529f73c569f8dd606ae7a96eb700000000000000000000000000000000000000000000000000000000000000101e52bfec13e500dee652a10feec8bd596cd62472ad5430ff9b4f3c944780e1bd1b0720bd0450e3d549636d5f23142b50b485f4f4c17323a7809dcf5a1309fccb1cc4713ce4478327e0e5be00dab93879dd260a0d8e2f8f2f905b209d189f22742be660e2dbbd0509b1da03413b66d393cbf348cf51fc2b0fdf7ebf08c876cbbe1771b15f2cbd88f6be76a81e83c776e188643bbafb6dedf729d0ccb0f9842c5509ce38d221fac0e2d5b3ecb54fbdaa45f47a74ed36962b8e882210b132331b180ae873e79f48e142c4ce247a664f22bb5a05872d7c56e5fdb7566f7eecf7a78e09512abd52a1902b33ffdeb72f0fd9b957e52d7b4a30604c47e32471ce2d0dbb0b1bcf31c47aef99da156d515d7b0a7ed4f898bb3580b71f8284de17a70f8fc3018e6f66d2ac7be681123be5cf9f29bdc218250aea1fa2cc20c8905b8170b6242012c0ff596494029442db4331e3e715487b650b39c4342c0c0b34a4eb7543ee1efac25a423edb6db7187e692f0c7d3edd5753d359edd2f35e72ffa4d716ee87135b1dc6ee74854c498020893eeea7047c3dadaf2ff08196f557bdee8289eafc1fbb0dd1dd670fec48828f7aa41bcde200551317cfc3132cdb4e1682a5dd6f4b020e9a7791ce7135d2d847313b73c26cb48ca320f164b12826752d175668e5882f4cbb75ae037a782db136d5e3588575122a44f059298c7148f1482fd89acdb8",
883
+ );
884
+ });
885
+ });