Skip to content

Commit

Permalink
add withdraw tests with larger inputs
Browse files Browse the repository at this point in the history
Signed-off-by: Chengxuan Xing <[email protected]>
  • Loading branch information
Chengxuan committed Oct 3, 2024
1 parent cfcd2bc commit 4b14d2e
Show file tree
Hide file tree
Showing 9 changed files with 522 additions and 102 deletions.
112 changes: 65 additions & 47 deletions solidity/test/gas_cost/zeto_anon_enc_nullifier_kyc_cost_analysis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -295,13 +295,14 @@ describe.skip("(Gas cost analysis) Zeto based fungible token with anonymity usin
_outUtxos.push(_oUtox);
unspentBobUTXOs.push(_oUtox);
} else {
// _inUtxos.push(ZERO_UTXO);
// const inProof = await smtAlice.generateCircomVerifierProof(
// BigInt(0),
// utxosRoot
// );
// _mtps.push(inProof.siblings.map((s) => s.bigInt()));
// _nullifiers.push(ZERO_UTXO);
_inUtxos.push(ZERO_UTXO);
_nullifiers.push(ZERO_UTXO);
const inProof = await smtAlice.generateCircomVerifierProof(
0n,
utxosRoot,
);
_outUtxos.push(ZERO_UTXO);
_mtps.push(inProof.siblings.map((s) => s.bigInt()));
}
}
const owners = [];
Expand Down Expand Up @@ -348,51 +349,68 @@ describe.skip("(Gas cost analysis) Zeto based fungible token with anonymity usin
);
}).timeout(6000000000000);

it(`Bob withdraw ${TOTAL_AMOUNT} tokens`, async function () {
it(`Bob withdraw ${TOTAL_AMOUNT} tokens in ${transferCount} transactions`, async function () {
const startingBalance = await erc20.balanceOf(Bob.ethAddress);

const root = await smtBob.root();
let promises = [];
for (let i = 0; i < unspentBobUTXOs.length; i++) {
if (unspentBobUTXOs[i].value) {
promises.push(
(async () => {
const utxoToWithdraw = unspentBobUTXOs[i];
const nullifier1 = newNullifier(utxoToWithdraw, Bob);

const proof1 = await smtBob.generateCircomVerifierProof(
utxoToWithdraw.hash,
root,
);
const proof2 = await smtBob.generateCircomVerifierProof(0n, root);
const merkleProofs = [
proof1.siblings.map((s) => s.bigInt()),
proof2.siblings.map((s) => s.bigInt()),
];
const { nullifiers, outputCommitments, encodedProof } =
await prepareNullifierWithdrawProof(
Bob,
[utxoToWithdraw, ZERO_UTXO],
[nullifier1, ZERO_UTXO],
newUTXO(0, Bob),
root.bigInt(),
merkleProofs,
for (let i = 0; i < transferCount; i++) {
promises.push(
(async () => {
const _inUtxos = [];
const _mtps = [];
const _nullifiers = [];
let amount = 0;
for (let j = 0; j < UTXO_PER_TX; j++) {
if (
i !== transferCount - 1 ||
unspentBobUTXOs.length % UTXO_PER_TX === 0 ||
j < unspentBobUTXOs.length % UTXO_PER_TX
) {
amount++;
const _iUtxo = unspentBobUTXOs[i * UTXO_PER_TX + j];
_inUtxos.push(_iUtxo);
_nullifiers.push(newNullifier(_iUtxo, Bob));
// Alice generates inclusion proofs for the UTXOs to be spent
const inProof = await smtBob.generateCircomVerifierProof(
_iUtxo.hash,
root,
);

// Bob withdraws UTXOs to ERC20 tokens
await doWithdraw(
zeto,
Bob.signer,
1,
nullifiers,
outputCommitments[0],
_mtps.push(inProof.siblings.map((s) => s.bigInt()));
} else {
_inUtxos.push(ZERO_UTXO);
_nullifiers.push(ZERO_UTXO);
const inProof = await smtBob.generateCircomVerifierProof(
0n,
root,
);
_mtps.push(inProof.siblings.map((s) => s.bigInt()));
}
}
const { nullifiers, outputCommitments, encodedProof } =
await prepareNullifierWithdrawProof(
Bob,
_inUtxos,
_nullifiers,
ZERO_UTXO,
root.bigInt(),
encodedProof,
withdrawGasCostHistory,
_mtps,
);
})(),
);
}

// Bob withdraws UTXOs to ERC20 tokens
await doWithdraw(
zeto,
Bob.signer,
amount,
nullifiers,
outputCommitments[0],
root.bigInt(),
encodedProof,
withdrawGasCostHistory,
);
})(),
);

// If we reach the concurrency limit, wait for the current batch to finish
if (promises.length >= TX_CONCURRENCY) {
await Promise.all(promises);
Expand Down Expand Up @@ -556,8 +574,8 @@ describe.skip("(Gas cost analysis) Zeto based fungible token with anonymity usin

const encodedProof = encodeProof(proof);
const encryptedValues = isBatch
? publicSignals.slice(0, 22)
: publicSignals.slice(0, 7);
? publicSignals.slice(2, 42)
: publicSignals.slice(2, 10);
return {
inputCommitments,
outputCommitments,
Expand Down
30 changes: 19 additions & 11 deletions solidity/test/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,9 @@ export async function prepareNullifierWithdrawProof(
root: BigInt,
merkleProof: BigInt[][],
) {
const nullifiers = _nullifiers.map((nullifier) => nullifier.hash) as [
BigNumberish,
BigNumberish,
];
const nullifiers = _nullifiers.map(
(nullifier) => nullifier.hash,
) as BigNumberish[];
const inputCommitments: BigNumberish[] = inputs.map(
(input) => input.hash,
) as BigNumberish[];
Expand All @@ -111,15 +110,19 @@ export async function prepareNullifierWithdrawProof(
inputSalts,
inputOwnerPrivateKey: signer.formattedPrivateKey,
root,
enabled: [nullifiers[0] !== 0n ? 1 : 0, nullifiers[1] !== 0n ? 1 : 0],
enabled: nullifiers.map((n) => (n !== 0n ? 1 : 0)),
merkleProof,
outputCommitments,
outputValues,
outputSalts: [output.salt],
outputSalts: [output.salt || 0n],
outputOwnerPublicKeys,
};
const circuit = await loadCircuit("check_nullifier_value");
const { provingKeyFile } = loadProvingKeys("check_nullifier_value");
let circuit = await loadCircuit("check_nullifier_value");
let { provingKeyFile } = loadProvingKeys("check_nullifier_value");
if (inputCommitments.length > 2) {
circuit = await loadCircuit("check_nullifier_value_batch");
({ provingKeyFile } = loadProvingKeys("check_nullifier_value_batch"));
}

const startWitnessCalculation = Date.now();
const witness = await circuit.calculateWTNSBin(inputObj, true);
Expand Down Expand Up @@ -167,11 +170,16 @@ export async function prepareWithdrawProof(
inputOwnerPrivateKey: signer.formattedPrivateKey,
outputCommitments,
outputValues,
outputSalts: [output.salt],
outputSalts: [output.salt || 0n],
outputOwnerPublicKeys,
};
const circuit = await loadCircuit("check_inputs_outputs_value");
const { provingKeyFile } = loadProvingKeys("check_inputs_outputs_value");

let circuit = await loadCircuit("check_inputs_outputs_value");
let { provingKeyFile } = loadProvingKeys("check_inputs_outputs_value");
if (inputCommitments.length > 2) {
circuit = await loadCircuit("check_inputs_outputs_value_batch");
({ provingKeyFile } = loadProvingKeys("check_inputs_outputs_value_batch"));
}

const startWitnessCalculation = Date.now();
const witness = await circuit.calculateWTNSBin(inputObj, true);
Expand Down
43 changes: 37 additions & 6 deletions solidity/test/zeto_anon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ describe("Zeto based fungible token with anonymity without encryption or nullifi
({ provingKeyFile: batchProvingKey } = loadProvingKeys("anon_batch"));
});

it("(batch) mint to Alice and batch transfer 10 UTXOs honestly to Bob and Charlie should succeed", async function () {
it("(batch) mint to Alice and batch transfer 10 UTXOs honestly to Bob & Charlie then withdraw should succeed", async function () {
// first mint the tokens for batch testing
const inputUtxos = [];
for (let i = 0; i < 10; i++) {
Expand All @@ -85,12 +85,17 @@ describe("Zeto based fungible token with anonymity without encryption or nullifi
}
await doMint(zeto, deployer, inputUtxos);

// Alice proposes the output UTXOs, 1 utxo to bob, 1 utxo to charlie and 1 utxo to alice
const _bOut1 = newUTXO(8, Bob);
const aliceUTXOsToBeWithdrawn = [
newUTXO(1, Alice),
newUTXO(1, Alice),
newUTXO(1, Alice),
];
// Alice proposes the output UTXOs, 1 utxo to bob, 1 utxo to charlie and 3 utxos to alice
const _bOut1 = newUTXO(6, Bob);
const _bOut2 = newUTXO(1, Charlie);
const _bOut3 = newUTXO(1, Alice);
const outputUtxos = [_bOut1, _bOut2, _bOut3];
const outputOwners = [Bob, Charlie, Alice];

const outputUtxos = [_bOut1, _bOut2, ...aliceUTXOsToBeWithdrawn];
const outputOwners = [Bob, Charlie, Alice, Alice, Alice];
const inflatedOutputUtxos = [...outputUtxos];
const inflatedOutputOwners = [...outputOwners];
for (let i = 0; i < 10 - outputUtxos.length; i++) {
Expand Down Expand Up @@ -126,6 +131,32 @@ describe("Zeto based fungible token with anonymity without encryption or nullifi
for (let i = outputUtxos.length; i < 10; i++) {
expect(incomingUTXOs[i]).to.equal(0);
}

// mint sufficient balance in Zeto contract address for Alice to withdraw
const mintTx = await erc20.connect(deployer).mint(zeto, 3);
await mintTx.wait();
const startingBalance = await erc20.balanceOf(Alice.ethAddress);

// Alice generates the nullifiers for the UTXOs to be spent
const inflatedWithdrawInputs = [...aliceUTXOsToBeWithdrawn];

// Alice generates inclusion proofs for the UTXOs to be spent

for (let i = aliceUTXOsToBeWithdrawn.length; i < 10; i++) {
inflatedWithdrawInputs.push(ZERO_UTXO);
}
const { inputCommitments, outputCommitments, encodedProof } =
await prepareWithdrawProof(Alice, inflatedWithdrawInputs, ZERO_UTXO);

// Alice withdraws her UTXOs to ERC20 tokens
const tx = await zeto
.connect(Alice.signer)
.withdraw(3, inputCommitments, outputCommitments[0], encodedProof);
await tx.wait();

// Alice checks her ERC20 balance
const endingBalance = await erc20.balanceOf(Alice.ethAddress);
expect(endingBalance - startingBalance).to.be.equal(3);
});

it("mint ERC20 tokens to Alice to deposit to Zeto should succeed", async function () {
Expand Down
43 changes: 37 additions & 6 deletions solidity/test/zeto_anon_enc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ describe("Zeto based fungible token with anonymity and encryption", function ()
({ provingKeyFile: batchProvingKey } = loadProvingKeys("anon_enc_batch"));
});

it("(batch) mint to Alice and batch transfer 10 UTXOs honestly to Bob and Charlie should succeed", async function () {
it("(batch) mint to Alice and batch transfer 10 UTXOs honestly to Bob & Charlie then withdraw should succeed", async function () {
// first mint the tokens for batch testing
const inputUtxos = [];
for (let i = 0; i < 10; i++) {
Expand All @@ -92,12 +92,17 @@ describe("Zeto based fungible token with anonymity and encryption", function ()
}
await doMint(zeto, deployer, inputUtxos);

// Alice proposes the output UTXOs, 1 utxo to bob, 1 utxo to charlie and 1 utxo to alice
const _bOut1 = newUTXO(8, Bob);
const aliceUTXOsToBeWithdrawn = [
newUTXO(1, Alice),
newUTXO(1, Alice),
newUTXO(1, Alice),
];
// Alice proposes the output UTXOs, 1 utxo to bob, 1 utxo to charlie and 3 utxos to alice
const _bOut1 = newUTXO(6, Bob);
const _bOut2 = newUTXO(1, Charlie);
const _bOut3 = newUTXO(1, Alice);
const outputUtxos = [_bOut1, _bOut2, _bOut3];
const outputOwners = [Bob, Charlie, Alice];

const outputUtxos = [_bOut1, _bOut2, ...aliceUTXOsToBeWithdrawn];
const outputOwners = [Bob, Charlie, Alice, Alice, Alice];
const inflatedOutputUtxos = [...outputUtxos];
const inflatedOutputOwners = [...outputOwners];
for (let i = 0; i < 10 - outputUtxos.length; i++) {
Expand Down Expand Up @@ -147,6 +152,32 @@ describe("Zeto based fungible token with anonymity and encryption", function ()
for (let i = outputUtxos.length; i < 10; i++) {
expect(incomingUTXOs[i]).to.equal(0);
}

// mint sufficient balance in Zeto contract address for Alice to withdraw
const mintTx = await erc20.connect(deployer).mint(zeto, 3);
await mintTx.wait();
const startingBalance = await erc20.balanceOf(Alice.ethAddress);

// Alice generates the nullifiers for the UTXOs to be spent
const inflatedWithdrawInputs = [...aliceUTXOsToBeWithdrawn];

// Alice generates inclusion proofs for the UTXOs to be spent

for (let i = aliceUTXOsToBeWithdrawn.length; i < 10; i++) {
inflatedWithdrawInputs.push(ZERO_UTXO);
}
const { inputCommitments, outputCommitments, encodedProof } =
await prepareWithdrawProof(Alice, inflatedWithdrawInputs, ZERO_UTXO);

// Alice withdraws her UTXOs to ERC20 tokens
const tx = await zeto
.connect(Alice.signer)
.withdraw(3, inputCommitments, outputCommitments[0], encodedProof);
await tx.wait();

// Alice checks her ERC20 balance
const endingBalance = await erc20.balanceOf(Alice.ethAddress);
expect(endingBalance - startingBalance).to.be.equal(3);
});

it("mint ERC20 tokens to Alice to deposit to Zeto should succeed", async function () {
Expand Down
Loading

0 comments on commit 4b14d2e

Please sign in to comment.