@lfdecentralizedtrust/zeto-contracts 0.2.2 → 0.5.1

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