Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

Encrypting Inputs

encryptInputs encrypts plaintext values into FHE ciphertexts that can be passed as inputs to a confidential smart contract transaction. Values must be encrypted before being passed on-chain to preserve confidentiality.

It returns an EncryptInputsBuilder which lets you configure the encryption and then call .execute() to run it.

The flow is as follows:

  1. Decide which plaintext value(s) you want to encrypt.
  2. Wrap each value with a typing helper (e.g. Encryptable.uint32(…)) to construct typed encryptable inputs (see Encryptable — typing inputs).
  3. Call client.encryptInputs([...]).execute() to produce EncryptedItemInput objects (see Builder API).
  4. Submit a transaction to your contract and pass the encrypted inputs as InE* parameters (see Writing encrypted data to a contract).

Prerequisites

  1. Create and connect a client (see the client page).

encryptInputs(...) requires a connected client so the SDK can resolve chainId, account, and the underlying RPC clients.

  1. Know which encrypted type you want to encode each value as.

The type is chosen by which Encryptable.* factory you use (and must match the Solidity parameter type your contract expects, e.g. InEuint32 vs InEuint64).

Basic usage

await cofheClient.connect(publicClient, walletClient);
 
const encrypted = await cofheClient
  .encryptInputs([
    Encryptable.uint32(42n),
    Encryptable.bool(true),
    Encryptable.address('0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'),
  ])
  .execute();
 
const [eUint32, eBool, eAddress] = encrypted;

The return type is a typed tuple that mirrors the array you pass in — each element is the corresponding Encrypted*Input type. For the exact shape of each item, see EncryptedItemInput — the result type.

What encryptInputs returns

Running .execute() returns a typed tuple of EncryptedItemInput items that mirrors the array you passed to encryptInputs([...]).

Each item contains the handle (ctHash in the SDK type), the encrypted type (utype), the security zone, and a verifier signature authorizing that input.

For the exact shape, see EncryptedItemInput — the result type.

Builder API

.execute() — required, call last

Runs the encryption pipeline and returns the EncryptedItemInput[] tuple.

await cofheClient.connect(publicClient, walletClient);
 
const [encryptedAge, encryptedFlag] = await cofheClient
  .encryptInputs([Encryptable.uint8(25n), Encryptable.bool(true)])
  .execute(); 

.setAccount(address) — optional

Override the address that "owns" the encrypted input. Only that address will be allowed to use the encrypted inputs on-chain. Defaults to the account from the connected WalletClient.

await cofheClient.connect(publicClient, walletClient);
 
const encrypted = await cofheClient
  .encryptInputs([Encryptable.uint64(10n)])
  .setAccount('0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045') 
  .execute();

.setChainId(chainId) — optional

Override the chain the encrypted input will be used on. Defaults to the chain ID of the connected PublicClient.

await cofheClient.connect(publicClient, walletClient);
 
const encrypted = await cofheClient
  .encryptInputs([Encryptable.uint64(10n)])
  .setChainId(11155111) 
  .execute();

.setUseWorker(boolean) — optional

Overrides the useWorkers flag from CofheConfig for this specific call. When true (the default), ZK proof generation runs in a Web Worker to avoid blocking the main thread. No-op in a node environment.

await cofheClient.connect(publicClient, walletClient);
 
const encrypted = await cofheClient
  .encryptInputs([Encryptable.uint32(7n)])
  .setUseWorker(false) 
  .execute();

.onStep(callback) — optional

Registers a callback that fires at the start and end of each encryption step. Useful for building progress indicators.

The callback receives the current EncryptStep enum value and a context object with isStart, isEnd, and duration (milliseconds, only meaningful on isEnd).

await cofheClient.connect(publicClient, walletClient);
 
const encrypted = await cofheClient
  .encryptInputs([Encryptable.uint64(10n)])
  .onStep((step, ctx) => {

    if (ctx?.isStart) console.log(`Starting: ${step}`); 
    if (ctx?.isEnd) console.log(`Done: ${step} (${ctx.duration}ms)`); 
  }) 
  .execute();

The EncryptStep enum values fired in order:

EncryptStep.InitTfhe; // 'initTfhe'
EncryptStep.FetchKeys; // 'fetchKeys'
EncryptStep.Pack; // 'pack'
EncryptStep.Prove; // 'prove'
EncryptStep.Verify; // 'verify'

The encryption flow

Calling .execute() runs five sequential steps. You can observe them via the .onStep() callback.

StepDescription
InitTfheLazy-initializes the TFHE WASM module (browser/Node). A no-op after the first call.
FetchKeysFetches (or loads from cache) the FHE public key and CRS for the target chain.
PackPacks the plaintext values into a ZK list ready for proving.
ProveGenerates the ZK proof of knowledge (ZKPoK). Uses a Web Worker when available.
VerifySends the proof to the CoFHE verifier. Returns signed EncryptedItemInput objects.

Encryptable — typing inputs

Use the Encryptable factory to create the items you want to encrypt. Each factory function accepts the plaintext value and an optional securityZone.

FactoryData typeSolidity input param
Encryptable.bool(value)booleanInEbool
Encryptable.uint8(value)bigint | stringInEuint8
Encryptable.uint16(value)bigint | stringInEuint16
Encryptable.uint32(value)bigint | stringInEuint32
Encryptable.uint64(value)bigint | stringInEuint64
Encryptable.uint128(value)bigint | stringInEuint128
Encryptable.address(value)bigint | stringInEaddress

You can also use the generic Encryptable.create(type, value) form:

Encryptable.create('uint32', 42n);
Encryptable.create('bool', false);
Encryptable.create('address', '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045');

Bit limit: A single encryptInputs call may encrypt at most 2048 bits of plaintext in total. Exceeding this limit throws a ZkPackFailed error.

EncryptedItemInput — the result type

Each element of the returned array is an EncryptedItemInput:

type EncryptedItemInput = {
  ctHash: bigint; // The handle registered with CoFHE
  securityZone: number; // The security zone the input was encrypted under
  utype: FheTypes; // The FHE type (Bool, Uint8, …, Uint160)
  signature: string; // CoFHE verifier signature authorizing this input
};

Pass these directly into a contract function that accepts InEuint* structs. The contract's CoFHE library validates the signature on-chain before operating on the ciphertext.

Common pitfalls

  • Wrong Encryptable type: Encryptable.uint32(...) must match what your Solidity function expects (e.g. InEuint32).
  • Wrong account / chain: encrypted inputs are authorized for a specific account + chainId. If you override these (or connect to the wrong network/wallet), your inputs may not be usable for the intended transaction.
  • Bit limit exceeded: a single call can encrypt at most 2048 bits of plaintext. Exceeding this throws ZkPackFailed.