Skip to content

Commit

Permalink
test: add tests for EncryptedErrors.sol
Browse files Browse the repository at this point in the history
  • Loading branch information
PacificYield committed Nov 29, 2024
1 parent 8b82700 commit 4ee560b
Show file tree
Hide file tree
Showing 3 changed files with 372 additions and 0 deletions.
79 changes: 79 additions & 0 deletions contracts/test/utils/TestEncryptedErrors.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
pragma solidity ^0.8.24;

import "fhevm/lib/TFHE.sol";
import { EncryptedErrors } from "../../utils/EncryptedErrors.sol";
import { MockZamaFHEVMConfig } from "fhevm/config/ZamaFHEVMConfig.sol";

contract TestEncryptedErrors is MockZamaFHEVMConfig, EncryptedErrors {
constructor(uint8 totalNumberErrorCodes_) EncryptedErrors(totalNumberErrorCodes_) {
for (uint8 i; i <= totalNumberErrorCodes_; i++) {
/// @dev It is not possible to access the _errorCodeDefinitions since it is private.
TFHE.allow(TFHE.asEuint8(i), msg.sender);
}
}

function errorChangeIf(
einput encryptedCondition,
einput encryptedErrorCode,
bytes calldata inputProof,
uint8 indexCode
) external returns (euint8 newErrorCode) {
ebool condition = TFHE.asEbool(encryptedCondition, inputProof);
euint8 errorCode = TFHE.asEuint8(encryptedErrorCode, inputProof);
newErrorCode = _errorChangeIf(condition, indexCode, errorCode);
_errorSave(newErrorCode);
TFHE.allow(newErrorCode, msg.sender);
}

function errorChangeIfNot(
einput encryptedCondition,
einput encryptedErrorCode,
bytes calldata inputProof,
uint8 indexCode
) external returns (euint8 newErrorCode) {
ebool condition = TFHE.asEbool(encryptedCondition, inputProof);
euint8 errorCode = TFHE.asEuint8(encryptedErrorCode, inputProof);
newErrorCode = _errorChangeIfNot(condition, indexCode, errorCode);
_errorSave(newErrorCode);
TFHE.allow(newErrorCode, msg.sender);
}

function errorDefineIf(
einput encryptedCondition,
bytes calldata inputProof,
uint8 indexCode
) external returns (euint8 errorCode) {
ebool condition = TFHE.asEbool(encryptedCondition, inputProof);
errorCode = _errorDefineIf(condition, indexCode);
_errorSave(errorCode);
TFHE.allow(errorCode, msg.sender);
}

function errorDefineIfNot(
einput encryptedCondition,
bytes calldata inputProof,
uint8 indexCode
) external returns (euint8 errorCode) {
ebool condition = TFHE.asEbool(encryptedCondition, inputProof);
errorCode = _errorDefineIfNot(condition, indexCode);
_errorSave(errorCode);
TFHE.allow(errorCode, msg.sender);
}

function errorGetCodeDefinition(uint8 indexCodeDefinition) external view returns (euint8 errorCode) {
errorCode = _errorGetCodeDefinition(indexCodeDefinition);
}

function errorGetCodeEmitted(uint256 errorId) external view returns (euint8 errorCode) {
errorCode = _errorGetCodeEmitted(errorId);
}

function errorGetCounter() external view returns (uint256 countErrors) {
countErrors = _errorGetCounter();
}

function errorGetNumCodesDefined() external view returns (uint8 totalNumberErrorCodes) {
totalNumberErrorCodes = _errorGetNumCodesDefined();
}
}
11 changes: 11 additions & 0 deletions test/utils/EncryptedErrors.fixture.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { ethers } from "hardhat";

import type { TestEncryptedErrors } from "../../types";
import { Signers } from "../signers";

export async function deployEncryptedErrors(signers: Signers, numberErrors: number): Promise<TestEncryptedErrors> {
const contractFactory = await ethers.getContractFactory("TestEncryptedErrors");
const contract = await contractFactory.connect(signers.alice).deploy(numberErrors);
await contract.waitForDeployment();
return contract;
}
282 changes: 282 additions & 0 deletions test/utils/EncryptedErrors.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,282 @@
import { expect } from "chai";
import { ethers } from "hardhat";

import { createInstances } from "../instance";
import { reencryptEuint8 } from "../reencrypt";
import { getSigners, initSigners } from "../signers";
import { deployEncryptedErrors } from "./EncryptedErrors.fixture";

describe("EncryptedErrors", function () {
const NO_ERROR_CODE = BigInt(0);

before(async function () {
await initSigners(3);
this.signers = await getSigners();
this.instances = await createInstances(this.signers);
});

beforeEach(async function () {
const contract = await deployEncryptedErrors(this.signers, 3);
this.encryptedErrorsAddress = await contract.getAddress();
this.encryptedErrors = contract;
});

it.only("post-deployment", async function () {
expect(await this.encryptedErrors.errorGetCounter()).to.be.eq(BigInt("0"));
expect(await this.encryptedErrors.errorGetNumCodesDefined()).to.be.eq(BigInt("3"));

for (let i = 0; i < 3; i++) {
const handle = await this.encryptedErrors.connect(this.signers.alice).errorGetCodeDefinition(i);
expect(
await reencryptEuint8(this.signers, this.instances, "alice", handle, this.encryptedErrorsAddress),
).to.be.eq(i);
}
});

it.only("errorDefineIf --> true", async function () {
// True --> errorId=0 has errorCode=2
const condition = true;
const targetErrorCode = 2;

const input = this.instances.alice.createEncryptedInput(this.encryptedErrorsAddress, this.signers.alice.address);
const encryptedData = await input.addBool(condition).encrypt();

await this.encryptedErrors
.connect(this.signers.alice)
.errorDefineIf(encryptedData.handles[0], encryptedData.inputProof, targetErrorCode);

const handle = await this.encryptedErrors.connect(this.signers.alice).errorGetCodeEmitted(0);
expect(await reencryptEuint8(this.signers, this.instances, "alice", handle, this.encryptedErrorsAddress)).to.be.eq(
targetErrorCode,
);
expect(await this.encryptedErrors.errorGetCounter()).to.be.eq(BigInt("1"));
});

it.only("errorDefineIf --> false", async function () {
// False --> errorId=1 has errorCode=0
const condition = false;
const targetErrorCode = 2;

const input = this.instances.alice.createEncryptedInput(this.encryptedErrorsAddress, this.signers.alice.address);
const encryptedData = await input.addBool(condition).encrypt();

await this.encryptedErrors
.connect(this.signers.alice)
.errorDefineIf(encryptedData.handles[0], encryptedData.inputProof, targetErrorCode);

const handle = await this.encryptedErrors.connect(this.signers.alice).errorGetCodeEmitted(0);
expect(await reencryptEuint8(this.signers, this.instances, "alice", handle, this.encryptedErrorsAddress)).to.be.eq(
NO_ERROR_CODE,
);
expect(await this.encryptedErrors.errorGetCounter()).to.be.eq(BigInt("1"));
});

it.only("errorDefineIfNot --> true", async function () {
// True --> errorId=0 has errorCode=0
const condition = true;
const targetErrorCode = 2;

const input = this.instances.alice.createEncryptedInput(this.encryptedErrorsAddress, this.signers.alice.address);
const encryptedData = await input.addBool(condition).encrypt();

await this.encryptedErrors
.connect(this.signers.alice)
.errorDefineIfNot(encryptedData.handles[0], encryptedData.inputProof, targetErrorCode);

const handle = await this.encryptedErrors.connect(this.signers.alice).errorGetCodeEmitted(0);
expect(await reencryptEuint8(this.signers, this.instances, "alice", handle, this.encryptedErrorsAddress)).to.be.eq(
NO_ERROR_CODE,
);
expect(await this.encryptedErrors.errorGetCounter()).to.be.eq(BigInt("1"));
});

it.only("errorDefineIf --> false", async function () {
// False --> errorId=1 has errorCode=2
const condition = false;
const targetErrorCode = 2;

const input = this.instances.alice.createEncryptedInput(this.encryptedErrorsAddress, this.signers.alice.address);
const encryptedData = await input.addBool(condition).encrypt();

await this.encryptedErrors
.connect(this.signers.alice)
.errorDefineIfNot(encryptedData.handles[0], encryptedData.inputProof, targetErrorCode);

const handle = await this.encryptedErrors.connect(this.signers.alice).errorGetCodeEmitted(0);
expect(await reencryptEuint8(this.signers, this.instances, "alice", handle, this.encryptedErrorsAddress)).to.be.eq(
targetErrorCode,
);
expect(await this.encryptedErrors.errorGetCounter()).to.be.eq(BigInt("1"));
});

it.only("errorChangeIf --> true --> change error code", async function () {
// True --> change errorCode
const condition = true;
const errorCode = 1;
const targetErrorCode = 2;

const input = this.instances.alice.createEncryptedInput(this.encryptedErrorsAddress, this.signers.alice.address);
const encryptedData = await input.addBool(condition).add8(errorCode).encrypt();

await this.encryptedErrors
.connect(this.signers.alice)
.errorChangeIf(encryptedData.handles[0], encryptedData.handles[1], encryptedData.inputProof, targetErrorCode);

const handle = await this.encryptedErrors.connect(this.signers.alice).errorGetCodeEmitted(0);
expect(await reencryptEuint8(this.signers, this.instances, "alice", handle, this.encryptedErrorsAddress)).to.be.eq(
targetErrorCode,
);
expect(await this.encryptedErrors.errorGetCounter()).to.be.eq(BigInt("1"));
});

it.only("errorChangeIf --> false --> no change for error code", async function () {
// False --> no change in errorCode
const condition = false;
const errorCode = 1;
const targetErrorCode = 2;

const input = this.instances.alice.createEncryptedInput(this.encryptedErrorsAddress, this.signers.alice.address);
const encryptedData = await input.addBool(condition).add8(errorCode).encrypt();

await this.encryptedErrors
.connect(this.signers.alice)
.errorChangeIf(encryptedData.handles[0], encryptedData.handles[1], encryptedData.inputProof, targetErrorCode);

const handle = await this.encryptedErrors.connect(this.signers.alice).errorGetCodeEmitted(0);
expect(await reencryptEuint8(this.signers, this.instances, "alice", handle, this.encryptedErrorsAddress)).to.be.eq(
errorCode,
);
expect(await this.encryptedErrors.errorGetCounter()).to.be.eq(BigInt("1"));
});

it.only("errorChangeIfNot --> true --> no change for error code", async function () {
// True --> no change errorCode
const condition = true;
const errorCode = 1;
const targetErrorCode = 2;

const input = this.instances.alice.createEncryptedInput(this.encryptedErrorsAddress, this.signers.alice.address);
const encryptedData = await input.addBool(condition).add8(errorCode).encrypt();

await this.encryptedErrors
.connect(this.signers.alice)
.errorChangeIfNot(encryptedData.handles[0], encryptedData.handles[1], encryptedData.inputProof, targetErrorCode);

const handle = await this.encryptedErrors.connect(this.signers.alice).errorGetCodeEmitted(0);
expect(await reencryptEuint8(this.signers, this.instances, "alice", handle, this.encryptedErrorsAddress)).to.be.eq(
errorCode,
);
expect(await this.encryptedErrors.errorGetCounter()).to.be.eq(BigInt("1"));
});

it.only("errorChangeIfNot --> false --> change error code", async function () {
// False --> change in errorCode
const condition = false;
const errorCode = 1;
const targetErrorCode = 2;

const input = this.instances.alice.createEncryptedInput(this.encryptedErrorsAddress, this.signers.alice.address);
const encryptedData = await input.addBool(condition).add8(errorCode).encrypt();

await this.encryptedErrors
.connect(this.signers.alice)
.errorChangeIfNot(encryptedData.handles[0], encryptedData.handles[1], encryptedData.inputProof, targetErrorCode);

const handle = await this.encryptedErrors.connect(this.signers.alice).errorGetCodeEmitted(0);
expect(await reencryptEuint8(this.signers, this.instances, "alice", handle, this.encryptedErrorsAddress)).to.be.eq(
targetErrorCode,
);
expect(await this.encryptedErrors.errorGetCounter()).to.be.eq(BigInt("1"));
});

it.only("cannot deploy if totalNumberErrorCodes_ == 0", async function () {
const numberErrors = 0;
const contractFactory = await ethers.getContractFactory("TestEncryptedErrors");
await expect(contractFactory.connect(this.signers.alice).deploy(numberErrors)).to.be.revertedWithCustomError(
this.encryptedErrors,
"TotalNumberErrorCodesEqualToZero",
);
});

it.only("cannot define errors if indexCode is greater or equal than totalNumberErrorCodes", async function () {
const condition = true;
const targetErrorCode = await this.encryptedErrors.errorGetNumCodesDefined();

const input = this.instances.alice.createEncryptedInput(this.encryptedErrorsAddress, this.signers.alice.address);
const encryptedData = await input.addBool(condition).encrypt();

await expect(
this.encryptedErrors
.connect(this.signers.alice)
.errorDefineIf(encryptedData.handles[0], encryptedData.inputProof, targetErrorCode),
).to.be.revertedWithCustomError(this.encryptedErrors, "ErrorIndexInvalid");

await expect(
this.encryptedErrors
.connect(this.signers.alice)
.errorDefineIfNot(encryptedData.handles[0], encryptedData.inputProof, targetErrorCode),
).to.be.revertedWithCustomError(this.encryptedErrors, "ErrorIndexInvalid");
});

it.only("cannot define errors if indexCode is 0 or equal", async function () {
const condition = true;
const targetErrorCode = 0;

const input = this.instances.alice.createEncryptedInput(this.encryptedErrorsAddress, this.signers.alice.address);
const encryptedData = await input.addBool(condition).encrypt();

await expect(
this.encryptedErrors
.connect(this.signers.alice)
.errorDefineIf(encryptedData.handles[0], encryptedData.inputProof, targetErrorCode),
).to.be.revertedWithCustomError(this.encryptedErrors, "ErrorIndexIsNull");

await expect(
this.encryptedErrors
.connect(this.signers.alice)
.errorDefineIfNot(encryptedData.handles[0], encryptedData.inputProof, targetErrorCode),
).to.be.revertedWithCustomError(this.encryptedErrors, "ErrorIndexIsNull");
});

it.only("cannot change errors if indexCode is greater or equal than totalNumberErrorCodes", async function () {
const condition = true;
const errorCode = 1;
const targetErrorCode = await this.encryptedErrors.errorGetNumCodesDefined();

const input = this.instances.alice.createEncryptedInput(this.encryptedErrorsAddress, this.signers.alice.address);
const encryptedData = await input.addBool(condition).add8(errorCode).encrypt();

await expect(
this.encryptedErrors
.connect(this.signers.alice)
.errorChangeIf(encryptedData.handles[0], encryptedData.handles[1], encryptedData.inputProof, targetErrorCode),
).to.be.revertedWithCustomError(this.encryptedErrors, "ErrorIndexInvalid");

await expect(
this.encryptedErrors
.connect(this.signers.alice)
.errorChangeIfNot(
encryptedData.handles[0],
encryptedData.handles[1],
encryptedData.inputProof,
targetErrorCode,
),
).to.be.revertedWithCustomError(this.encryptedErrors, "ErrorIndexInvalid");
});

it.only("cannot call _errorGetCodeDefinition if indexCode is greater or equal than totalNumberErrorCodes", async function () {
const indexCodeDefinition = await this.encryptedErrors.errorGetNumCodesDefined();

await expect(
this.encryptedErrors.connect(this.signers.alice).errorGetCodeDefinition(indexCodeDefinition),
).to.be.revertedWithCustomError(this.encryptedErrors, "ErrorIndexInvalid");
});

it.only("cannot call _errorGetCodeEmitted if errorId is greater than errorCounter", async function () {
const errorCounter = await this.encryptedErrors.errorGetCounter();

await expect(
this.encryptedErrors.connect(this.signers.alice).errorGetCodeEmitted(errorCounter),
).to.be.revertedWithCustomError(this.encryptedErrors, "ErrorIndexInvalid");
});
});

0 comments on commit 4ee560b

Please sign in to comment.