Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Docs/mocked frontend #665

Merged
merged 10 commits into from
Dec 20, 2024
44 changes: 35 additions & 9 deletions codegen/templates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,16 @@ ${commonSolLib()}
* that interact with TFHE.
*/
library TFHE {

/// @notice Returned if the input's length is greater than 64 bytes.
error InputLengthAbove64Bytes(uint256 inputLength);

/// @notice Returned if the input's length is greater than 128 bytes.
error InputLengthAbove128Bytes(uint256 inputLength);

/// @notice Returned if the input's length is greater than 256 bytes.
error InputLengthAbove256Bytes(uint256 inputLength);

function setFHEVM(FHEVMConfigStruct memory fhevmConfig) internal {
Impl.setFHEVM(fhevmConfig);
}
Expand Down Expand Up @@ -1011,13 +1021,19 @@ function tfheCustomMethods(): string {

// Left-pad a bytes array with zeros such that it becomes of length 64.
function padToBytes64(bytes memory input) internal pure returns (bytes memory) {
require(input.length <= 64, "Input exceeds 64 bytes");
uint256 inputLength = input.length;

if (inputLength > 64) {
revert InputLengthAbove64Bytes(inputLength);
}

bytes memory result = new bytes(64);
uint256 paddingLength = 64 - input.length;
uint256 paddingLength = 64 - inputLength;

for (uint256 i = 0; i < paddingLength; i++) {
result[i] = 0;
}
for (uint256 i = 0; i < input.length; i++) {
for (uint256 i = 0; i < inputLength; i++) {
result[paddingLength + i] = input[i];
}
return result;
Expand All @@ -1035,13 +1051,18 @@ function tfheCustomMethods(): string {

// Left-pad a bytes array with zeros such that it becomes of length 128.
function padToBytes128(bytes memory input) internal pure returns (bytes memory) {
require(input.length <= 128, "Input exceeds 128 bytes");
uint256 inputLength = input.length;

if (inputLength > 128) {
revert InputLengthAbove128Bytes(inputLength);
}

bytes memory result = new bytes(128);
uint256 paddingLength = 128 - input.length;
uint256 paddingLength = 128 - inputLength;
for (uint256 i = 0; i < paddingLength; i++) {
result[i] = 0;
}
for (uint256 i = 0; i < input.length; i++) {
for (uint256 i = 0; i < inputLength; i++) {
result[paddingLength + i] = input[i];
}
return result;
Expand All @@ -1059,13 +1080,18 @@ function tfheCustomMethods(): string {

// Left-pad a bytes array with zeros such that it becomes of length 256.
function padToBytes256(bytes memory input) internal pure returns (bytes memory) {
require(input.length <= 256, "Input exceeds 256 bytes");
uint256 inputLength = input.length;

if (inputLength > 256) {
revert InputLengthAbove256Bytes(inputLength);
}

bytes memory result = new bytes(256);
uint256 paddingLength = 256 - input.length;
uint256 paddingLength = 256 - inputLength;
for (uint256 i = 0; i < paddingLength; i++) {
result[i] = 0;
}
for (uint256 i = 0; i < input.length; i++) {
for (uint256 i = 0; i < inputLength; i++) {
result[paddingLength + i] = input[i];
}
return result;
Expand Down
4 changes: 4 additions & 0 deletions docs/guides/frontend/webapp.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ You can also use [this template](https://github.com/zama-ai/fhevmjs-vue-template

You can also use [this template](https://github.com/zama-ai/fhevmjs-next-template) to start an application with fhevmjs, using Next + TypeScript.

## Using the mocked coprocessor for front end

As an alternative to use the real coprocessor deployed on Sepolia to help you develop your dApp faster and without needing testnet tokens, you can use a mocked fhevm. Currently, we recommend you to use the `ConfidentialERC20` dApp example available on the `mockedFrontend` branch of the [React template](https://github.com/zama-ai/fhevm-react-template/tree/mockedFrontend). Follow the README on this branch, and you will be able to deploy exactly the same dApp both on Sepolia as well as on the mocked coprocessor seamlessly.

## Using directly the library

### Step 1: Setup the library
Expand Down
23 changes: 23 additions & 0 deletions examples/tests/TFHERevertTest.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
pragma solidity ^0.8.24;

import "../../lib/TFHE.sol";
import "../FHEVMConfig.sol";

contract TFHERevertTest {
constructor() {
TFHE.setFHEVM(FHEVMConfig.defaultConfig());
}

function padToBytes64(bytes memory input) public pure {
TFHE.padToBytes64(input);
}

function padToBytes128(bytes memory input) public pure {
TFHE.padToBytes128(input);
}

function padToBytes256(bytes memory input) public pure {
TFHE.padToBytes256(input);
}
}
43 changes: 34 additions & 9 deletions lib/TFHE.sol
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,15 @@ library Common {
* that interact with TFHE.
*/
library TFHE {
/// @notice Returned if the input's length is greater than 64 bytes.
error InputLengthAbove64Bytes(uint256 inputLength);

/// @notice Returned if the input's length is greater than 128 bytes.
error InputLengthAbove128Bytes(uint256 inputLength);

/// @notice Returned if the input's length is greater than 256 bytes.
error InputLengthAbove256Bytes(uint256 inputLength);

function setFHEVM(FHEVMConfigStruct memory fhevmConfig) internal {
Impl.setFHEVM(fhevmConfig);
}
Expand Down Expand Up @@ -10430,13 +10439,19 @@ library TFHE {

// Left-pad a bytes array with zeros such that it becomes of length 64.
function padToBytes64(bytes memory input) internal pure returns (bytes memory) {
require(input.length <= 64, "Input exceeds 64 bytes");
uint256 inputLength = input.length;

if (inputLength > 64) {
revert InputLengthAbove64Bytes(inputLength);
}

bytes memory result = new bytes(64);
uint256 paddingLength = 64 - input.length;
uint256 paddingLength = 64 - inputLength;

for (uint256 i = 0; i < paddingLength; i++) {
result[i] = 0;
}
for (uint256 i = 0; i < input.length; i++) {
for (uint256 i = 0; i < inputLength; i++) {
result[paddingLength + i] = input[i];
}
return result;
Expand All @@ -10454,13 +10469,18 @@ library TFHE {

// Left-pad a bytes array with zeros such that it becomes of length 128.
function padToBytes128(bytes memory input) internal pure returns (bytes memory) {
require(input.length <= 128, "Input exceeds 128 bytes");
uint256 inputLength = input.length;

if (inputLength > 128) {
revert InputLengthAbove128Bytes(inputLength);
}

bytes memory result = new bytes(128);
uint256 paddingLength = 128 - input.length;
uint256 paddingLength = 128 - inputLength;
for (uint256 i = 0; i < paddingLength; i++) {
result[i] = 0;
}
for (uint256 i = 0; i < input.length; i++) {
for (uint256 i = 0; i < inputLength; i++) {
result[paddingLength + i] = input[i];
}
return result;
Expand All @@ -10478,13 +10498,18 @@ library TFHE {

// Left-pad a bytes array with zeros such that it becomes of length 256.
function padToBytes256(bytes memory input) internal pure returns (bytes memory) {
require(input.length <= 256, "Input exceeds 256 bytes");
uint256 inputLength = input.length;

if (inputLength > 256) {
revert InputLengthAbove256Bytes(inputLength);
}

bytes memory result = new bytes(256);
uint256 paddingLength = 256 - input.length;
uint256 paddingLength = 256 - inputLength;
for (uint256 i = 0; i < paddingLength; i++) {
result[i] = 0;
}
for (uint256 i = 0; i < input.length; i++) {
for (uint256 i = 0; i < inputLength; i++) {
result[paddingLength + i] = input[i];
}
return result;
Expand Down
45 changes: 45 additions & 0 deletions test/tfheOperations/tfheRevertPaths.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { expect } from 'chai';
import { randomBytes } from 'crypto';
import { ethers } from 'hardhat';

import { getSigners, initSigners } from '../signers';

describe('TFHE revert paths', function () {
before(async function () {
await initSigners(1);
this.signers = await getSigners();

const contractFactory = await ethers.getContractFactory('TFHERevertTest');
const contract = await contractFactory.connect(this.signers.alice).deploy();
await contract.waitForDeployment();

this.contract = contract;
});

it('padToBytes64 reverts if input > 64 bytes', async function () {
const numberBytes = 65;
const input = randomBytes(numberBytes);

await expect(this.contract.padToBytes64(input))
.to.be.revertedWithCustomError(this.contract, 'InputLengthAbove64Bytes')
.withArgs(numberBytes);
});

it('padToBytes128 reverts if input > 128 bytes', async function () {
const numberBytes = 129;
const input = randomBytes(numberBytes);

await expect(this.contract.padToBytes128(input))
.to.be.revertedWithCustomError(this.contract, 'InputLengthAbove128Bytes')
.withArgs(numberBytes);
});

it('padToBytes256 reverts if input > 256 bytes', async function () {
const numberBytes = 257;
const input = randomBytes(numberBytes);

await expect(this.contract.padToBytes256(input))
.to.be.revertedWithCustomError(this.contract, 'InputLengthAbove256Bytes')
.withArgs(numberBytes);
});
});
Loading