Think·two-phase async
ᚦ
FHE Inference
Encrypted ML
Run inference on CKKS-encrypted tensors. Plaintext never leaves the user.
0x0000000000000000000000000000000000000807Explorer
CKKS encryption. Encrypt input client-side (e.g.
tfhe-rs WASM, node-seal). Plaintext never touches the chain. Output is also encrypted — only key holder decrypts.click 'auto' (capability = 10)
hex bytes (CKKS ciphertext)
hex bytes (StorageRef)
≤ 500
min escrow: 0.1000 RITUALyou have: — RITUAL
Connect your wallet to submit a real transaction.
to: 0x0000000000000000000000000000000000000807chainId 1979 · two-phase · 19 fields
Output
Click Validate to encode the FHE inference request.
Plaintext never reaches the chain.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import {PrecompileConsumer} from "./utils/PrecompileConsumer.sol";
contract FHEInferenceConsumer is PrecompileConsumer {
address constant FHE = address(0x807);
address constant ASYNC_DELIVERY = 0x5A16214fF555848411544b005f7Ac063742f39F6;
event FHERequested(bytes32 indexed jobId);
event FHEDelivered(bytes32 indexed jobId, bytes encryptedOutput);
/// @notice Run FHE inference on CKKS-encrypted input. The plaintext
/// never touches the chain — only the encrypted ciphertext does.
/// Decryption happens off-chain with the user's secret key.
function infer(address executor, bytes calldata encryptedInput, bytes calldata evkRef) external {
bytes memory encoded = abi.encode(
executor,
new bytes[](0), uint256(500), new bytes[](0), bytes(""),
"ckks/mnist-classifier-3-layer",
encryptedInput, bytes(""), evkRef,
uint8(3), // numLayers
uint64(block.number + 5000), // maxInferenceBlock
address(this), this.onFHEResult.selector,
uint256(500_000), uint256(1_000_000_000),
uint256(100_000_000), uint256(0),
bytes(""), bytes("")
);
(bool ok,) = FHE.call(encoded);
require(ok, "fhe call failed");
}
function onFHEResult(bytes32 jobId, bytes calldata encryptedOutput) external {
require(msg.sender == ASYNC_DELIVERY, "unauth");
// Encrypted output — only the key holder can decrypt off-chain.
emit FHEDelivered(jobId, encryptedOutput);
}
}