@lfdecentralizedtrust/zeto-contracts 0.2.2 → 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.
- package/README.md +70 -162
- package/contracts/factory.sol +30 -34
- package/contracts/factory_upgradeable.sol +11 -7
- package/contracts/lib/common/util.sol +40 -0
- package/contracts/lib/interfaces/ILockableCapability.sol +318 -0
- package/contracts/lib/interfaces/{izeto.sol → IZeto.sol} +13 -1
- package/contracts/lib/interfaces/{izeto_initializable.sol → IZetoInitializable.sol} +14 -12
- package/contracts/lib/interfaces/{izeto_kyc.sol → IZetoKyc.sol} +3 -3
- package/contracts/lib/interfaces/IZetoLockableCapability.sol +237 -0
- package/contracts/lib/interfaces/IZetoStorage.sol +106 -0
- package/contracts/lib/interfaces/{izeto_lockable.sol → IZetoVerifier.sol} +8 -21
- package/contracts/lib/registry.sol +74 -26
- package/contracts/lib/storage/base.sol +210 -0
- package/contracts/lib/storage/nullifier.sol +166 -0
- package/contracts/lib/zeto_common.sol +277 -28
- package/contracts/lib/zeto_fungible.sol +451 -33
- package/contracts/lib/zeto_fungible_base.sol +69 -0
- package/contracts/lib/zeto_fungible_burn.sol +83 -53
- package/contracts/lib/zeto_fungible_burn_nullifier.sol +115 -72
- package/contracts/lib/zeto_fungible_nullifier.sol +167 -0
- package/contracts/lib/zeto_lockable.sol +613 -0
- package/contracts/lib/zeto_non_fungible.sol +236 -0
- package/contracts/lib/zeto_non_fungible_base.sol +61 -0
- package/contracts/lib/zeto_non_fungible_nullifier.sol +61 -0
- package/contracts/test/escrow1.sol +90 -34
- package/contracts/test/escrow2.sol +64 -29
- package/contracts/test/qurrency.sol +10 -2
- package/contracts/test/smt.sol +6 -1
- package/contracts/test/tendecimals.sol +14 -12
- package/contracts/verifiers/impl/anon.sol +189 -0
- package/contracts/verifiers/impl/anon_batch.sol +301 -0
- package/contracts/verifiers/impl/anon_enc.sol +266 -0
- package/contracts/verifiers/impl/anon_enc_batch.sol +602 -0
- package/contracts/verifiers/impl/anon_enc_nullifier.sol +287 -0
- package/contracts/verifiers/impl/anon_enc_nullifier_batch.sol +679 -0
- package/contracts/verifiers/impl/anon_enc_nullifier_kyc.sol +294 -0
- package/contracts/verifiers/impl/anon_enc_nullifier_kyc_batch.sol +686 -0
- package/contracts/verifiers/impl/anon_enc_nullifier_non_repudiation.sol +413 -0
- package/contracts/verifiers/impl/anon_enc_nullifier_non_repudiation_batch.sol +1141 -0
- package/contracts/verifiers/impl/anon_nullifier_kyc_transfer.sol +217 -0
- package/contracts/verifiers/impl/anon_nullifier_kyc_transferLocked.sol +196 -0
- package/contracts/verifiers/impl/anon_nullifier_kyc_transferLocked_batch.sol +308 -0
- package/contracts/verifiers/impl/anon_nullifier_kyc_transfer_batch.sol +385 -0
- package/contracts/verifiers/impl/anon_nullifier_qurrency_transfer.sol +497 -0
- package/contracts/verifiers/impl/anon_nullifier_qurrency_transfer_batch.sol +1001 -0
- package/contracts/verifiers/{verifier_anon_nullifier_transferLocked.sol → impl/anon_nullifier_transfer.sol} +12 -19
- package/contracts/verifiers/{verifier_anon_nullifier_transferLocked_batch.sol → impl/anon_nullifier_transfer_batch.sol} +44 -51
- package/contracts/verifiers/impl/burn.sol +182 -0
- package/contracts/verifiers/impl/burn_batch.sol +238 -0
- package/contracts/verifiers/impl/burn_nullifier.sol +203 -0
- package/contracts/verifiers/impl/burn_nullifier_batch.sol +315 -0
- package/contracts/verifiers/impl/deposit.sol +182 -0
- package/contracts/verifiers/impl/deposit_kyc.sol +189 -0
- package/contracts/verifiers/impl/nf_anon.sol +175 -0
- package/contracts/verifiers/{verifier_nf_anon_nullifier_transferLocked.sol → impl/nf_anon_nullifier_transfer.sol} +6 -13
- package/contracts/verifiers/impl/withdraw.sol +189 -0
- package/contracts/verifiers/impl/withdraw_batch.sol +245 -0
- package/contracts/verifiers/impl/withdraw_nullifier.sol +210 -0
- package/contracts/verifiers/impl/withdraw_nullifier_batch.sol +322 -0
- package/contracts/verifiers/verifier_anon.sol +31 -186
- package/contracts/verifiers/verifier_anon_batch.sol +31 -298
- package/contracts/verifiers/verifier_anon_enc.sol +31 -263
- package/contracts/verifiers/verifier_anon_enc_batch.sol +31 -599
- package/contracts/verifiers/verifier_anon_enc_nullifier.sol +31 -284
- package/contracts/verifiers/verifier_anon_enc_nullifier_batch.sol +33 -676
- package/contracts/verifiers/verifier_anon_enc_nullifier_kyc.sol +31 -291
- package/contracts/verifiers/verifier_anon_enc_nullifier_kyc_batch.sol +33 -683
- package/contracts/verifiers/verifier_anon_enc_nullifier_non_repudiation.sol +33 -410
- package/contracts/verifiers/verifier_anon_enc_nullifier_non_repudiation_batch.sol +33 -1138
- package/contracts/verifiers/verifier_anon_nullifier_kyc_transfer.sol +33 -214
- package/contracts/verifiers/verifier_anon_nullifier_kyc_transferLocked.sol +33 -221
- package/contracts/verifiers/verifier_anon_nullifier_kyc_transferLocked_batch.sol +33 -389
- package/contracts/verifiers/verifier_anon_nullifier_kyc_transfer_batch.sol +33 -382
- package/contracts/verifiers/verifier_anon_nullifier_qurrency_transfer.sol +33 -221
- package/contracts/verifiers/verifier_anon_nullifier_qurrency_transfer_batch.sol +33 -389
- package/contracts/verifiers/verifier_anon_nullifier_transfer.sol +33 -207
- package/contracts/verifiers/verifier_anon_nullifier_transfer_batch.sol +33 -375
- package/contracts/verifiers/verifier_burn.sol +31 -179
- package/contracts/verifiers/verifier_burn_batch.sol +31 -235
- package/contracts/verifiers/verifier_burn_nullifier.sol +31 -200
- package/contracts/verifiers/verifier_burn_nullifier_batch.sol +31 -312
- package/contracts/verifiers/verifier_deposit.sol +31 -179
- package/contracts/verifiers/verifier_deposit_kyc.sol +34 -0
- package/contracts/verifiers/verifier_nf_anon.sol +31 -172
- package/contracts/verifiers/verifier_nf_anon_nullifier_transfer.sol +33 -179
- package/contracts/verifiers/verifier_withdraw.sol +31 -186
- package/contracts/verifiers/verifier_withdraw_batch.sol +31 -242
- package/contracts/verifiers/verifier_withdraw_nullifier.sol +31 -207
- package/contracts/verifiers/verifier_withdraw_nullifier_batch.sol +33 -319
- package/contracts/zeto_anon.sol +77 -231
- package/contracts/zeto_anon_burnable.sol +56 -12
- package/contracts/zeto_anon_enc.sol +93 -190
- package/contracts/zeto_anon_enc_nullifier.sol +249 -195
- package/contracts/zeto_anon_enc_nullifier_kyc.sol +51 -232
- package/contracts/zeto_anon_enc_nullifier_non_repudiation.sol +231 -238
- package/contracts/zeto_anon_nullifier.sol +164 -298
- package/contracts/zeto_anon_nullifier_burnable.sol +68 -18
- package/contracts/zeto_anon_nullifier_kyc.sol +40 -345
- package/contracts/zeto_anon_nullifier_qurrency.sol +217 -361
- package/contracts/zeto_nf_anon.sol +55 -130
- package/contracts/zeto_nf_anon_nullifier.sol +90 -152
- package/hardhat.config.ts +9 -3
- package/ignition/modules/lib/deps.ts +8 -0
- package/ignition/modules/zeto_anon_burnable.ts +8 -7
- package/ignition/modules/zeto_anon_enc_nullifier.ts +31 -0
- package/ignition/modules/zeto_anon_enc_nullifier_kyc.ts +2 -2
- package/ignition/modules/zeto_anon_nullifier.ts +28 -4
- package/ignition/modules/zeto_anon_nullifier_burnable.ts +50 -16
- package/ignition/modules/zeto_anon_nullifier_kyc.ts +27 -12
- package/ignition/modules/zeto_nf_anon_nullifier.ts +14 -10
- package/package.json +4 -2
- package/scripts/deploy_cloneable.ts +19 -10
- package/scripts/deploy_upgradeable.ts +9 -5
- package/scripts/tokens/Zeto_Anon.ts +3 -3
- package/scripts/tokens/Zeto_AnonBurnable.ts +1 -1
- package/scripts/tokens/Zeto_AnonEnc.ts +12 -3
- package/scripts/tokens/Zeto_AnonEncNullifier.ts +5 -3
- package/scripts/tokens/Zeto_AnonEncNullifierKyc.ts +1 -1
- package/scripts/tokens/Zeto_AnonEncNullifierNonRepudiation.ts +1 -1
- package/scripts/tokens/Zeto_AnonNullifier.ts +1 -1
- package/scripts/tokens/Zeto_AnonNullifierBurnable.ts +1 -1
- package/scripts/tokens/Zeto_AnonNullifierKyc.ts +1 -1
- package/scripts/tokens/Zeto_AnonNullifierQurrency.ts +1 -1
- package/scripts/tokens/Zeto_NfAnon.ts +2 -2
- package/scripts/tokens/Zeto_NfAnonNullifier.ts +1 -1
- package/test/factory.ts +46 -73
- package/test/lib/anon_nullifier_helpers.ts +89 -0
- package/test/lib/anon_zeto_helpers.ts +76 -0
- package/test/lib/deploy.ts +3 -2
- package/test/lib/utils.ts +74 -35
- package/test/test/escrow1.ts +185 -58
- package/test/test/escrow2.ts +200 -107
- package/test/test/qurrency.ts +13 -33
- package/test/usdc-shielding.ts +39 -26
- package/test/utils.ts +144 -21
- package/test/zeto_anon.ts +956 -465
- package/test/zeto_anon_enc.ts +881 -142
- package/test/zeto_anon_enc_nullifier.ts +847 -38
- package/test/zeto_anon_enc_nullifier_kyc.ts +120 -181
- package/test/zeto_anon_enc_nullifier_non_repudiation.ts +77 -46
- package/test/zeto_anon_nullifier.ts +1212 -953
- package/test/zeto_anon_nullifier_kyc.ts +674 -655
- package/test/zeto_anon_nullifier_qurrency.ts +452 -306
- package/test/zeto_nf_anon.ts +737 -137
- package/test/zeto_nf_anon_nullifier.ts +876 -246
- package/contracts/lib/zeto_base.sol +0 -293
- package/contracts/lib/zeto_fungible_withdraw.sol +0 -132
- package/contracts/lib/zeto_fungible_withdraw_nullifier.sol +0 -144
- package/contracts/lib/zeto_nullifier.sol +0 -340
- package/contracts/zkDvP.sol_ +0 -273
- package/test/zkDvP.ts_ +0 -455
- /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 {
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
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
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
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
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
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
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
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
|
-
|
|
188
|
-
|
|
189
|
-
|
|
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
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
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
|
-
|
|
208
|
-
|
|
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
|
-
|
|
212
|
-
|
|
339
|
+
const proof2 = await smtAlice.generateCircomVerifierProof(
|
|
340
|
+
utxo2.hash,
|
|
341
|
+
root,
|
|
213
342
|
);
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
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
|
-
|
|
246
|
-
|
|
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
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
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
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
666
|
-
|
|
667
|
-
const
|
|
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
|
-
|
|
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
|
-
|
|
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
|
+
});
|