-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
test: add tests for EncryptedErrors.sol
- Loading branch information
1 parent
8b82700
commit 4ee560b
Showing
3 changed files
with
372 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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"); | ||
}); | ||
}); |