fhevm js-sdk 架构解析:可组合运行时(FhevmRuntime)与可扩展客户端(FhevmClient)的设计与实现

发布时间:2026/9/13 11:22:34

fhevm js-sdk 架构解析:可组合运行时(FhevmRuntime)与可扩展客户端(FhevmClient)的设计与实现 fhevm js-sdk 架构解析可组合运行时FhevmRuntime与可扩展客户端FhevmClient的设计与实现【免费下载链接】fhevmFHEVM, a full-stack framework for integrating Fully Homomorphic Encryption (FHE) with blockchain applications项目地址: https://gitcode.com/GitHub_Trending/fh/fhevm导读fhevm js-sdk 是 fhEVM 全栈框架的前端 JavaScript SDK负责在链下完成 TFHE 密文的加密、解密、签名许可生成与密钥管理。本文以其架构设计文档 sdk/js-sdk/notes/ARCHITECTURE.md 为骨架讲解 SDK 的两大核心抽象——可组合的运行时FhevmRuntime与可扩展的客户端FhevmClient并对照仓库源码运行时实现、模块工厂、初始化链路逐条印证其设计原则。读完本文你将理解 SDK 为何能做到零配置可用、按需加载 WASM、惰性幂等初始化、顺序无关的可链式配置并能正确使用createFhevmClient/createFhevmEncryptClient/createFhevmDecryptClient三种工厂以及extend()、init()、ready等生命周期 API。SDK 设计原则一份可验证的契约清单架构文档开篇即列出约四十条设计原则它们是理解后续所有代码实现的验收标准。将其归纳为几个主题并与源码一一对应顺序无关与可链式配置Order-independent API / Configuration is chainable and order-independent配置项通过withXXX(...)形式链式设置且withPublicKey、fetchPublicKey当前实现为fetchFheEncryptionKeyBytes的调用顺序不影响最终结果配置在调用时解析resolve config at call time而非创建时捕获Extensions must not capture config at creation time。惰性、幂等、共享的初始化Lazy, Idempotent, Sharedinit()无论被手动调用还是被内部首次调用触发永远返回同一个 Promise多个并发调用共享同一次初始化。对应源码见 CoreFhevm-p.ts 中的init/ready实现。创建必须纯净Creation must be pure构造客户端不执行任何异步操作、不加载 WASM、不发 RPCno async at construction一切延后到首次使用。可树摇Treeshackable加密与解密是两个相互独立的模块各自绑定一个独立的 WASM 模块TFHE 与 TKMS未使用的模块绝不加载SDK constraints条目以此避免不必要的网络与内存开销。可组合、可扩展Composable Extensions / Composable runtime modules能力以模块为单位挂载到运行时以动作组actions为单位挂载到客户端扩展物可复用、可自由组合。错误可见性配置缺失或错误时抛出清晰错误信息Throw clear error messages运行时执行校验Validation is performed at runtime绝不静默误用no silent misuse。TypeScript 不做过度约束Avoid over-constraining Typescript类型只描述能力边界不限制扩展组合方式。多运行时共存生产运行时与 mock 运行时可同时存在多个客户端可共享同一个运行时模块可以是 JS 运行时内的单例如 WASM 模块。这些原则并非停留在文档层面下文将从源码结构上逐一给出实现证据。架构总览runtime 与 clients 的两层模型架构文档将 SDK 分为两层runtimeFhevmRuntime可组合的运行时。一个运行时由一组模块module构成模块可动态添加多个运行时可共享同一模块实例某些模块在 JS 运行时内是全局唯一的例如 WASM 模块。运行时的创建与扩展都必须是纯净的不产生副作用。每个模块可能有 CPU 密集的初始化步骤初始化遵循幂等、惰性或手动。clientsFhevmClient每个客户端拥有一个运行时一个运行时可被多个客户端共享。客户端本质上是运行时 一组用于启用特定功能的附加参数。普通 SDK 使用者操作的是客户端而非运行时——运行时始终是内部组件Runtime should remain an internal component。客户端通过extend(...)扩展新函数通过withXXX(...)设置配置参数。这一分层在类型定义中体现得十分清晰FhevmBase持有runtime、chain、client、options四个只读字段见 coreFhevmClient.ts而运行时接口FhevmRuntime只暴露ethereum、relayer两个基础模块、uid、config以及按模块名重载的extend(factory)见 coreFhevmRuntime.ts。// runtime 的类型骨架简化 interface FhevmRuntime { readonly ethereum: EthereumModule; // 链上合约读取模块 readonly relayer: RelayerModule; // 中继器 HTTP 模块 readonly uid: string; readonly config: FhevmRuntimeConfig; extend(factory: DecryptModuleFactory): this { readonly decrypt: DecryptModule }; extend(factory: EncryptModuleFactory): this { readonly encrypt: EncryptModule }; }注意extend返回类型是this { readonly decrypt: ... }——这正是 TypeScript 层面实现组合式扩展、且不破坏原有类型的机制每次扩展都会在类型上累加模块能力而无需在构造时声明全部模块避免构造函数爆炸no constructor explosion。三种工厂函数与部分客户端架构文档给出了三类客户端的构建方式全量客户端、仅解密客户端、仅加密客户端。当前仓库中 ethers 与 viem 两个适配层各有一套同名工厂位于 sdk/js-sdk/src/ethers/clients 与 sdk/js-sdk/src/viem/clients。全量客户端createFhevmClient// full client (chain, provider, encrypt module, decrypt module) const fhevmFull createFhevmClient({ chain, provider });其实现正是基础客户端 解密动作组 加密动作组的两次extend见 ethers/clients/createFhevmClient.tsexport function createFhevmClientchain extends FhevmChain, provider extends EthersT.ContractRunner(parameters: { readonly provider: provider; readonly chain: chain; readonly options?: FhevmOptions | undefined; }): FhevmClientchain, WithAll, provider { const c createFhevmBaseClient(parameters); return c.extend(decryptActions).extend(encryptActions); }而createFhevmBaseClient见 ethers/clients/createFhevmBaseClient.ts先通过createCoreFhevm创建裸客户端再extend(baseActions)挂载基础动作组。也就是说任何客户端都必然包含 base 层extend只会在其之上继续叠加能力。部分客户端按需加载 WASM 的关键// partial decrypt client (chain, provider, decrypt module, no encrypt module) const fhevmDecrypt createFhevmDecryptClient({ chain, provider }); // partial encrypt client (chain, provider, encrypt module, no decrypt module) const fhevmEncrypt createFhevmEncryptClient({ chain, provider }); // create with optional publicKeyBytes, const fhevmEncrypt createFhevmEncryptClient({ chain, provider, publicKeyBytes, });viem 版加密工厂见 viem/clients/createFhevmEncryptClient.ts结构相同createFhevmBaseClient(parameters)后仅extend(encryptActions)。这样创建的加密客户端不会加载 TKMS 解密 WASM解密客户端不会加载 TFHE 加密 WASM——这是两个模块、两个 WASM、按需加载原则的直接落地。说明publicKeyBytes只是架构笔记中描述的预期 API 形态。当前实现中加密公钥通过createFhevmEncryptClient的options.fheEncryptionKey传入或由客户端从 relayer 拉取fetchFheEncryptionKeyBytes见 base.ts。文档中publicKeyBytes can be fetched independently的描述与当前fetchFheEncryptionKeyBytes的设计一致——公钥可独立于客户端获取。部分客户端到全量客户端extend 的升级通道架构文档强调Given clientA and clientB it should always be possible to extend clientA and/or clientB so that clientA clientB给定任意两个客户端总能通过扩展使它们的能力相等并且当部分客户端被创建后SDK 应允许将其扩展为全量客户端。// Convert partial client to full client const fhevmFull fhevmEncrypt.extend(decryptActions);其类型层面等价于FhevmEncryptClientWithEncrypt→FhevmClientWithAll完全符合extend的类型累加语义。decryptActions是一个接收客户端为参数、返回一组闭包捕获客户端的函数Function groups usually depends on modules that must be extended to the client runtime to run properly例如解密动作组依赖decryptModule扩展后客户端必须重新初始化因为底层新增的 decrypt 模块需要初始化after client extend, the client must be initialized again。这一点在源码中有明确的强制约束extendCoreFhevm见 CoreFhevm-p.ts要求 actionsFactory 返回的runtime必须与客户端的 runtime 是同一个实例否则抛错并且把扩展携带的init函数注册进#initFns集合、同时将#readyPromise置为undefined——强制下一次调用必须重新走一遍初始化。extend唯一合法的能力扩展通道运行时层面的extend实现位于 CoreFhevmRuntime-p.ts其机制可以概括为占位符placeholder单次填充 工厂引用幂等构造运行时CoreFhevmRuntimeImpl时#encrypt、#decrypt都是空对象占位符对应模块槽位slot注册在一个Map中L146-L149。createExtendFnL32-L79调用模块工厂moduleFactory(runtime)工厂必须恰好返回一个键如encryptSDK 据此查找对应槽位同一工厂引用再次 extend → 幂等 no-opfactories.has(moduleFactory)直接返回自身槽位已被不同工厂填充 → 抛错Already extended: moduleName不允许二次扩展同一模块未知模块名 → 抛错Unknown module: moduleName。填充后的占位符被Object.freeze运行时实例也在构造末尾Object.freeze(this)L157并冻结类与原型L187-L188——运行时不变量不可被外部篡改。对外校验通过instanceof加私有 token 完成createFhevmRuntime需要调用方持有 owner tokenassertIsFhevmRuntime/verifyFhevmRuntime保证传入的是真实 SDK 运行时L200-L233。模块工厂的真实形态可在加密模块看到encryptModule: EncryptModuleFactory (runtime) Object.freeze({ encrypt: Object.freeze({ initTfheModule, getTfheModuleInfo, parseTFHEProvenCompactCiphertextList, buildWithProofPacked, serialize/deserialize 密钥与 CRS }) })见 modules/encrypt/module/index.ts解密模块则暴露initTkmsModule、getTkmsModuleInfo、decryptAndReconstruct、TKMS 私钥的生成/序列化/校验等见 modules/decrypt/module/index.ts。客户端层面的extend则由extendCoreFhevm实现把 actions 中每个函数通过Object.defineProperty不可写、不可配置挂到客户端实例上并跳过已存在的键if (key in client) continue从而避免动作组之间的命名冲突。init / ready惰性、幂等、共享的初始化链路客户端生命周期 API架构文档给出了完整的生命周期调用方式// returns a promise (eq to { return init(); }) await fhevmEncrypt.ready; // manual init call (fetch key if needed) await fhevmEncrypt.init();源码中CoreFhevm-p.tsinit与ready的实现印证了幂等、共享、惰性三条原则init: { value: (): Promisevoid { this.#readyPromise ?? Promise.all([...this.#initFns].map((fn) fn(this))).then(() {}); return this.#readyPromise; }, }, ready: { get: (): Promisevoid this.init(), },惰性构造时不执行任何初始化#readyPromise初始为undefined幂等??保证无论init()被调用多少次都返回同一个 Promise共享并发调用者await的是同一个 in-flight Promise天然去重可预测每次extend会注册新的 init 函数并清空#readyPromise从而保证扩展后的模块一定被初始化。initPublicAction每个公开动作的标准前奏架构文档强调fhevmClient初始化是可选的吗——若不调用首次调用时自动执行at first call。这一首次使用即初始化由 CoreFhevm-p.ts 的initPublicAction统一保证所有公开 API 动作加密、解密、签名等第一步都调用它await fhevm.ready——触发惰性、共享的初始化读取初始化期间解析并缓存在客户端上的 frozen context版本快照缺失即视为内部不变量被违反抛出明确错误返回一份深拷贝的 frozen contextcloneFhevmClientFrozenContext使动作在整个异步执行期间持有稳定的版本视图不受后续上下文刷新的影响。frozen context一次性解析的版本快照初始化期间SDK 需要从链上解析协议版本、PubKey/CRS 版本、TFHE/TKMS 模块版本与各宿主合约版本打包成不可变的FhevmClientFrozenContext见 fhevmClientFrozenContext-p.ts。其解析只执行一次并做并发去重ensureFrozenContext见 ensureFrozenContext-p.ts在客户端实例上维护已解析的数据 进行中的单一 Promise多个 init 函数并发到达时共享同一个解析 Promise成功后将数据落盘为同步可读状态解析过程纯链上读取、无可重置副作用因此临时 RPC 失败不会污染后续重试。不同路径只解析自己需要的版本子集加密路径需要tfheVersion与协议/ACL 版本解密路径则是tkmsVersion与 KMSVerifier 版本见 fhevmClientFrozenContext-p.ts 的类型注释从而把链上getVersion()调用次数降到最低。客户端protocolVersion、tfheVersion、tkmsVersion等 getter 在 frozen context 未解析时抛出Fhevm context has not been resolved. Await client.ready before.L40。各层的 init 职责base 层_initBase仅解析 frozen contextbase.tsencrypt 层_initEncrypt并行执行拉取约 50MB 的全局 FHE 加密公钥fetchFheEncryptionKeyBytes 初始化 TFHE WASM 模块initTfheModule见 encrypt-p.tsdecrypt 层_initDecrypt类似地初始化 TKMS WASM 模块。这也解释了文档中任何对withPublicKey或fetchPublicKey的调用在init()之后应抛出错误的设计意图配置必须在调用时解析、在初始化前完成固化初始化后变更配置会破坏已建立的版本/密钥快照一致性。WASM 模块的按需加载、单例约束与线程配置两个模块、两个 WASM、一个运行时独占架构文档明确要求encryptModule 和 decryptModule 是两个独立模块分别与两个不同的 WASM 模块交互各一个必须避免在不需要时加载某个 WASM 模块因此 SDK 采用扩展原则extension principle。仓库的 wasm 资产目录印证了这一点sdk/js-sdk/src/wasm/tfhe 存放多个版本的 TFHE WASM如 v1.5.3、v1.6.0-dev、v1.6.2含tfhe_bg.wasm、worker 脚本与 base64 内嵌版本sdk/js-sdk/src/wasm/tkms 存放多个版本的 TKMS WASM如 v0.13.10、v0.13.20-0、v0.14.0-1。每个模块的初始化都按版本缓存整个初始化 PromisecachedTfheModulePromiseByVersion/cachedTkmsModulePromiseByVersion且每个版本的 WASM 模块在同一时刻只能被一个运行时独占initTfheModule/initTkmsModule会检查ownerUidByVersion若该版本已被其他运行时的uid占用则抛错Encrypt WASM module is already owned by runtime ... and cannot be shared with runtime ...见 modules/encrypt/module/init-p.ts。这与文档有些模块在 JS 运行时内是全局唯一的完全对应——WASM 实例及其 worker 池无法安全地在多个运行时间共享。资产加载、SHA 校验与单线程降级TFHE 模块的初始化modules/encrypt/module/init-p.ts定义了完整的资产解析与降级策略资产 URL 解析提供locateFile时按每个资产独立解析返回URL走 URL 加载返回null/undefined走内嵌 base64未提供时Node 端自动推导file://URL 并做磁盘存在性检查任一缺失则整体回退 base64兼容 Turbopack 等打包器搬移场景浏览器端直接使用内嵌 base64WASM 编译有 URL 则isomorphicCompileVerifiedWasmSHA-256 校验后编译否则从内嵌 base64 编译worker 加载模式wasmAssetLoadMode支持auto、embedded-base64、verified-blob、precheck-direct-url、trusted-direct-url五种定义见 wasmAssets.ts其中verified-blob提供真正的完整性保证校验后以 Blob worker 执行precheck-direct-url仅是预检失败即快速报错而非完整性校验trusted-direct-url完全信任运行时加载线程singleThread与numberOfThreads控制线程池检测到不支持 SharedArrayBuffer缺少 COOP/COEP 头或无 worker 来源时自动降级单线程显式 URL 模式_requiresAssetUrl若无 worker URL 则直接抛错而非静默降级L104-L106, L293-L330。这些实现细节共同支撑了初始化惰性、幂等、可预测的文档承诺初始化失败会被缓存为 rejected Promise不重试半初始化状态避免二次错误如 Already started见 L553-L560 注释。链配置与零配置默认路径SDK 内置了四条链定义chains/index.tsmainnet、sepolia、polygon、polygonAmoy另有localTestnet定义文件。以 sepolia 为例chains/definitions/sepolia.ts每条链携带 fhEVM 相关宿主合约地址ACL、InputVerifier、KMSVerifier、ProtocolConfig、relayer URL如https://relayer.testnet.zama.org以及网关侧合约Decryption、InputVerification。加密所需的全局公钥正来源于 relayer 服务这回答了架构文档中的问题Problem: how to get the publicKeyBytes? —— publicKeyBytes can be fetched independently。零配置必须可用Zero config must work的路径是createFhevmClient({ chain, provider })→ 首次调用任意动作 → 惰性 init 自动完成 frozen context 解析与模块初始化 → 从链定义中的 relayerUrl 拉取公钥。而显式初始化Lazy init or Explicitly init must be supported则为高级用户提供两条途径init()手动预热用于预加载、避免延迟尖峰、SSR/受控环境见设计原则Power-user explicit init (this is useful for preloading, avoiding latency spikes, SSR/controlled environments)以及通过options预注入公钥等配置。客户端配置FhevmOptions见 coreFhevmClient.ts包含batchRpcCallsRPC 批量调用默认 false、fheEncryptionKey预置加密公钥可避免后续 50MB 拉取、moduleVersions模块版本覆盖。运行时配置FhevmRuntimeConfig见 coreFhevmRuntime.ts包含locateFile、wasmAssetLoadMode、moduleVersions、logger、singleThread、numberOfThreads、auth。配置对象在创建时被防御性拷贝并冻结resolveOptions返回Object.freeze结果见 CoreFhevm-p.ts与扩展不得在创建时捕获配置、配置应在调用时解析的原则一致。典型动作加密与解密的最小调用路径作为设计落地的实例看两个代表性动作均以initPublicAction开头印证每个公开动作自动触发惰性初始化加密单个值encryptValueactions/encrypt/encryptValue.ts校验value类型与地址 →await initPublicAction(fhevm)触发初始化并取得版本快照 → 调用coprocessor/encrypt生成密文 → 返回{ encryptedValue, inputProof }。批量版本encryptValues结构相同返回encryptedValues数组见 actions/encrypt/encryptValues.ts。解密单个值decryptValueactions/decrypt/decryptValue.ts将encryptedValue归一化为 fhEVM handle与合约地址、密文所有者地址组成pairs配合transportKeyPair与signedPermit交给 TKMS 解密decryptValuesFromPairs返回带类型的明文。配套的generateTransportKeyPair用于生成端到端传输密钥对见 actions/decrypt/generateTransportKeyPair.ts。基础动作组base.ts还提供decryptPublicValue(s)读取已公开的密文明文、decryptPublicValuesWithSignatures明文 可上链校验的签名证明、signLegacyDecryptionPermit/signUnifiedDecryptionPermitV1/V2 解密许可签名后者需协议 API v0.14.0 且链上支持 unified extraData v2、传输密钥对与许可的序列化/反序列化等。小结一张图理解 SDK 的生命周期可以把整个设计收敛为一条主线创建纯函数、无副作用createFhevmBaseClient→createCoreFhevm构造不可变核心extend(baseActions)挂基础能力加密/解密能力由extend(encryptActions/decryptActions)按需叠加运行时同步填充对应模块占位符首次使用惰性自动初始化任意公开动作调用initPublicAction→ready返回共享的单一 Promise → init 函数集并行执行解析并冻结 frozen context 版本快照、拉取加密公钥加密路径、初始化 TFHE/TKMS WASM 模块含 worker 池扩展随时允许extend()注册新 init 函数并作废#readyPromise下次使用自动补齐新模块初始化使用动作从深拷贝的 frozen context 读取稳定版本视图完成加密、解密、签名、公钥管理等操作。文档中SDK design: initialization dependency orchestration problem的结论在此闭环默认路径全惰性自动显式控制权留给高级用户。这也是 fhevm js-sdk 在零配置可用与面向功率用户的显式控制之间取得平衡的完整答案。若需深入代码建议按以下顺序阅读CoreFhevmRuntime-p.ts运行时与模块槽位→ CoreFhevm-p.ts客户端生命周期与动作前奏→ ethers/clients三种工厂→ modules/encrypt/module/init-p.tsWASM 加载与降级细节。【免费下载链接】fhevmFHEVM, a full-stack framework for integrating Fully Homomorphic Encryption (FHE) with blockchain applications项目地址: https://gitcode.com/GitHub_Trending/fh/fhevm创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/9/13 11:17:34

高质量外链建设与SEO优化实战指南

1. 站外SEO的本质与外链价值解析外链建设是站外SEO最核心的工作内容,但很多从业者对其理解仍停留在"数量为王"的初级阶段。实际上,Google的PageRank算法早已从单纯计算外链数量,发展为评估链接来源的权威性、相关性和自然度。一个来…

2026/9/13 11:17:34

vim系列之Tmux

介绍 Tmux 是一个终端复用器(terminal multiplexer)。彻底解决了终端窗口和会话绑定问题,实现了会话与窗口"解绑":窗口关闭时,会话并不终止,而是继续运行,等到以后需要的时候&#x…

2026/9/13 12:12:36

DiffSynth-Studio:AI图像与视频生成、低显存训练的完整路径

DiffSynth-Studio:AI图像与视频生成、低显存训练的完整路径 【免费下载链接】DiffSynth-Studio Enjoy the magic of Diffusion models! 项目地址: https://gitcode.com/GitHub_Trending/dif/DiffSynth-Studio DiffSynth-Studio 是魔搭社区团队开发的开源扩散…

2026/9/13 12:12:36

光热电站储热容量配置优化与经济性分析

1. 光热电站储热容量配置的背景与挑战光热发电技术(CSP)作为可再生能源领域的重要分支,近年来在全球范围内获得了快速发展。与传统光伏发电不同,光热电站通过聚光系统将太阳能转化为热能,再通过热力循环发电&#xff0…

2026/9/13 12:07:36

音乐与科技融合:跨文化传播的创新实践

1. 项目背景与核心价值解析"以乐为桥 以爱为炬 向世界讲好中国故事"这一主题蕴含着文化传播的深层逻辑。音乐作为人类共通的语言,具有跨越国界的天然优势。研究表明,大脑对音乐旋律的处理不依赖特定语言中枢,这使得音乐能直接触发情…

2026/9/13 0:01:16

拯救者Y7000黑屏故障排查与维修实战指南

1. 项目概述:一台黑屏的拯救者Y7000,到底卡在哪一步? 联想拯救者Y7000系列笔记本,从2018年第一代搭载i5-8300H开始,到后来的i7-9750H、i7-10750H、i5-11400H,再到2023年款的R7-7840HS,它始终是学…

2026/9/13 0:01:16

拯救者Y7000黑屏故障排查与维修实战指南

1. 项目概述:一台黑屏的拯救者Y7000,到底卡在哪一步? 联想拯救者Y7000系列笔记本,从2018年第一代搭载i5-8300H开始,到后来的i7-9750H、i7-10750H、i5-11400H,再到2023年款的R7-7840HS,它始终是学…

2026/9/12 6:29:36

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/12 14:32:17

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/13 11:18:28

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码