
fhEVM sns-worker 深入解析Switch-and-Squash 128 位密文计算引擎的架构、部署与测试【免费下载链接】fhevmFHEVM, a full-stack framework for integrating Fully Homomorphic Encryption (FHE) with blockchain applications项目地址: https://gitcode.com/GitHub_Trending/fh/fhevm本篇技术指南以 sns-worker/README.md 为骨架结合 fhEVM 协处理器coprocessor源码、数据库迁移脚本与运行脚本系统讲解 SnSSwitch-and-Squash工作器的核心流程、密钥准备、启动参数、并行调度、结果持久化与测试方法。读完本文你将掌握如何在 fhEVM 协处理器集群中部署可横向扩展的 128 位 PBS 计算工作器并理解其与 Postgres 通知机制、S3 上传链路之间的完整协作关系。一、SnS Worker 在 fhEVM 协处理器中的定位fhEVM 是一个把全同态加密FHE与区块链应用结合的全栈框架。在链上完成 FHE 运算后密文仍带有随运算累积的噪声必须经过一次Switch-and-Squash操作将“噪声大、难以进一步处理”的中间密文转换为低噪声的 128 位大密文large_ct即 ct128供后续解密或跨链发布使用。这项计算由协处理器集群中的sns-workerSwitch-and-Squash executor承担。sns-worker 以 Rust 编写同时提供两种形态见 Cargo.tomlLibrary crate包名sns-worker版本0.7.0对外暴露SwitchNSquashService、run_all、Config等核心 APIBinarysns_worker入口为 src/bin/sns_worker.rs运行 sns-executor 守护进程其全部 CLI 参数定义在 src/bin/utils/daemon_cli.rs。二、核心工作流程从数据库通知到 large_ct 就绪根据 README 的描述sns-worker 库在收到一条数据库通知后主要执行以下四步从pbs_computations与ciphertexts两张表中取出(handle, compressed_ct)配对使用 Switch-and-Squash 算法计算得到large_ctct128将large_ct写入数据库对应 handle 的记录发出事件通知large_ct已可用。源码中这四步由 src/executor.rs 的fetch_and_execute_sns_tasks串起完整事务取任务query_sns_tasks执行如下 SQL——以handle关联pbs_computations与ciphertexts筛选ciphertext IS NOT NULL且is_completed FALSE的任务按created_at排序、FOR UPDATE SKIP LOCKED锁定并限制LIMIT $1批次大小。SKIP LOCKED保证多个 worker 并发取任务时不互相阻塞计算process_tasks并行执行compute_task完成解压与 Squash 后得到 ct128持久化update_computations_status将pbs_computations.is_completed置为TRUE并写入completed_atupdate_ciphertext128将 ct128 字节插入ciphertexts128表通知notify_ciphertext128_ready通过pg_notify向notify_channel广播登记上传enqueue_upload_tasks将任务的摘要信息写入ciphertext_digest表交给 S3 上传线程。值得注意README 将第 3 步描述为“更新ciphertexts表的large_ct列”而当前源码的实际实现是把 ct128 单独写入ciphertexts128表建表迁移见 20260106150619_create_ciphertexts128_table.sql同时把 64 位密文与 128 位密文的摘要写入ciphertext_digest见 20250310120834_create_ciphertext_digest.sql。阅读与二次开发时请以源码为准。2.1 事件驱动的唤醒机制run_loop见 executor.rs使用sqlx::postgres::PgListener订阅conf.db.listen_channels所列频道同时在“有任务剩余”“轮询定时器到期”和“GC 定时器到期”三种情况下循环推进。数据库侧的触发器负责产生通知——例如迁移 20250512084614_fhevm_listner_auto_notify_acl.sql 中定义在pbs_computations表插入时触发NOTIFY event_pbs_computations。这样host-listener 写入新计算任务后sns-worker 能第一时间被唤醒无需高频轮询。三、运行前的密钥准备将 SnS 公钥导入 keys 表SnS 计算需要噪声压缩所需的特殊服务端密钥。该密钥sns_pk可以从Large Objects 表pg_largeobject中取回。运行 worker 之前必须先把sns_pk导入keys表。仓库的 fhevm-keys 目录中提供了密钥文件sns_pk、pks、sks、cks、xof-keyset等。README 给出了两种导入方式其一是利用 PostgreSQL 大对象 API-- Example query to import sns_pk from fhevm-keys/sns_pk -- Import the sns_pk into the Large Object storage sns_pk_loid : lo_import(../fhevm-keys/sns_pk); -- Update the keys table with the new Large Object OID UPDATE keys SET sns_pk sns_pk_loid WHERE key_id ...; -- specify the appropriate key_id这里sns_pk列的类型正是OID——它指向pg_largeobject中的大对象。keys表的结构定义于迁移 20260128095635_remove_tenants.sql列类型含义sequence_numberBIGINT自增主键密钥序列号用于轮换与排序key_id_gwBYTEA来自 gateway 事件的密钥 ID可能不同于密钥自身元数据里的key_idkey_idBYTEA服务端密钥元数据中的密钥 IDpks_key/sks_keyBYTEA公钥/私钥cks_keyBYTEA可空Client Key仅测试解密使用sns_pkOID可空SnS 噪声压缩公钥指向大对象keys表最初来源于更早的tenants表迁移 20250212082040_create_sns_keys_columns.sql 曾为tenants增加sns_pk/sns_sk两列。在 worker 运行时keyset.rs 的fetch_latest_keyset会执行SELECT key_id_gw, sequence_number FROM keys ORDER BY sequence_number DESC LIMIT 1取出最新密钥并用一个容量为 10 的lru::LruCache缓存KeySetkey_id_gw、sequence_number、可选client_key与server_key密钥轮换后自动失效重取。服务端密钥支持两种编码CompressedXofXOF 压缩密钥集与Legacy传统格式在gpufeature 下仅接受CompressedXof编码因为 GPU 路径需要CudaServerKey。四、启动 SnS Worker命令与参数详解README 说明可以独立启动多个 worker 实例并行执行 128-PBS 计算彼此通过数据库行锁与SKIP LOCKED天然协调无需额外编排。README 给出的单实例启动命令# Run a single instance of the worker DATABASE_URLpostgresql://postgres:postgreslocalhost:5432/coprocessor \ cargo run --release -- \ --pg-listen-channels event_pbs_computations event_ciphertext_computed \ --pg-notify-channel event_pbs_computed \仓库内还提供了一个更完整的本地启动脚本 run_with_localnet.sh展示了生产可用的参数组合含 S3 桶、签名器、健康检查端口等cargo run --jobs 32 --release ${CARGO_FEATURES[]} -- \ --pg-listen-channels event_pbs_computations event_ciphertext_computed \ --pg-notify-channel event_ciphertext128_computed \ --work-items-batch-size1 \ --pg-polling-interval60 \ --pg-pool-connections10 \ --cleanup-interval7200s \ --pg-auto-explain-with-min-duration10ms \ --bucket-name${BUCKET_NAME:-coproc-0} \ --schedule-policysequential \ --signer-typeprivate-key \ --private-key${TX_SENDER_PRIVATE_KEY} \ --health-check-port10003注意脚本中的通知频道是event_ciphertext128_computed与 README 示例中的event_pbs_computed命名不同——两者都是“ct128 计算完成”的广播频道部署时应保持 worker 与下游消费者如 txn-sender/relayer配置一致。4.1 完整 CLI 参数表所有参数定义于 daemon_cli.rs下表为关键参数及其默认值参数默认值说明--work-items-batch-size4每批处理的任务数--pg-listen-channels必填监听的 Postgres NOTIFY 频道可传多个--pg-notify-channel必填计算完成后广播的 NOTIFY 频道--pg-polling-interval60轮询间隔秒--pg-pool-connections10Postgres 连接池大小--pg-timeout15sPostgres 获取连接超时--pg-auto-explain-with-min-duration无启用auto_explain诊断需时长值--database-url/DATABASE_URL环境变量数据库连接串--service-name/OTEL_SERVICE_NAMEsns-executorOTLP 链路追踪服务名--bucket-name必填S3 桶名ct64/ct128 都存于此桶--s3-max-concurrent-uploads100最大并发上传数--s3-max-retries-per-upload100单次上传最大重试次数--s3-max-backoff10s重试最大退避--s3-max-retries-timeout120s重试总超时--s3-recheck-duration2sS3 不可用时的重查间隔--s3-regular-recheck-duration120s常规重查间隔--s3-disable-sha256-checksumfalse对不兼容 S3 服务器关闭 SHA256 校验--cleanup-interval15minGC 清理周期--gc-batch-size1000每轮 GC 删除的 ct128 行数0关闭 GC--log-levelINFO日志级别--health-check-port8080健康检查 HTTP 端口--metrics-addr0.0.0.0:9100Prometheus 指标地址--liveness-threshold70s活跃阈值超过则判定卡死--lifofalse为true时 LIFO 优先处理最新任务否则 FIFO--enable-compressiontrue上传 S3 前压缩大密文--schedule-policyrayon_parallel任务调度策略见下文--metric-sns-op-latency0.1:10.0:0.1延迟直方图配置--signer-typeprivate-key签名器类型private-key/aws-kms--private-key无私钥private-key模式必需--s3-migrationnoS3 对象格式迁移模式见 7.2 节4.2 签名器与 S3 上传run_allsrc/lib.rs在启动时会构建CoproSignerprivate-key模式解析--private-keyaws-kms模式读取环境变量AWS_KEY_ID并使用AwsSigner。该签名器用于为上传的密文生成可验证的 attestation参见 aws_upload.rs 中对ciphertext-attestation的引用与COPROCESSOR_CONTEXT_ID_1上下文 ID从而让下游能够校验密文来源与格式版本RFC-023 规定的ciphertext128_format10/11 为 CPU 非压缩/压缩20/21 为 GPU 非压缩/压缩。五、并行计算SchedulePolicy 与 RayonConfig.schedule_policy提供两种调度策略定义见 lib.rssequential串行遍历批次任务rayon_parallel默认先通过rayon::broadcast在每个工作线程上调用tfhe::set_server_key注入服务端密钥再以par_iter_mut并行执行整个批次。process_tasks的实现executor.rs同时支持 CPU 与 GPU 两种后端Cargo.toml中的gpufeature 会把ServerKey类型切换为tfhe::CudaServerKey此时单机即可承载多 worker 的 128-PBS 计算且生成的 ct128 格式标记为*OnGpu20/21。六、算法核心squash_noise 与压缩序列化真正的密码学核心在 src/squash_noise.rs。SquashNoiseCiphertext::squash_noise_and_serialize对SupportedFheCiphertexts覆盖FheBool、FheUint4至FheUint256、FheBytes64/128/256逐一实现解压decompress_ct依据 handle 推断密文类型get_ct_type调用SupportedFheCiphertexts::decompress_no_memcheck还原压缩的 64 位密文Squash调用 tfhe 的squash_noise()得到SquashedNoiseFheUint/SquashedNoiseFheBool序列化若enable_compression为真则用CompressedSquashedNoiseCiphertextListBuilder构建压缩列表后序列化否则直接序列化。全部序列化均通过safe_serialize完成受MAX_SNS_CIPHERTEXT_SERIALIZED_SIZEciphertext-attestation crate 定义上限保护防止内存耗尽。6.1 测试专用 featuretest_decrypt_128Cargo.toml提供test_decrypt_128feature对应 README 中描述的decrypt_128。开启后compute_task会在每次 Squash 后调用decrypt_big_ct用可选的client_key解密密文并把明文打印到日志用于仅限测试的校验场景。生产环境不应启用。七、结果持久化、通知、S3 上传与 GC7.1 写入与广播批次计算完成后在同一数据库事务内依次执行UPDATE pbs_computations SET is_completed TRUE, completed_at NOW()executor.rsINSERT INTO ciphertexts128 (handle, ciphertext)——ct128 先临时存于 Postgres 保证可靠性SELECT pg_notify($1, )广播notify_channel向ciphertext_digest登记上传任务enqueue_upload_task含ciphertext128_format。7.2 上传线程、重试与 S3 格式迁移aws_upload.rs 实现上传侧上传通道容量为10 * max_concurrent_uploads配合Semaphore控制并发计算线程通过try_send投递UploadJob失败时依赖数据库级重试兜底三级缓冲并发上传任务 → 通道 → PostgresDBspawn_resubmit_task定期扫描ciphertext_digest中摘要为空的记录把漏网任务重新入队--s3-migration提供no/before/before-and-quit/concurrent/dry-run五种模式也可用环境变量S3_MIGRATION_MODE注入用于在滚动升级期间把旧格式 S3 对象转换为当前格式CURRENT_S3_FORMAT_VERSION S3_FORMAT_VERSION_V1dry-run只扫描不写入。7.3 垃圾回收GCgarbage_collect以gc_batch_limit为上限只删除“ct64 与 ct128 均已上传 S3ciphertext_digest两列非空”的ciphertexts128行SQL 使用FOR UPDATE OF c SKIP LOCKED避免并发冲突。若 txn-sender 工作正常该表通常无需 worker 主动清理代码注释亦注明这一点。八、测试方法README 提供了两套测试方式二者都依赖 test-harness 自动拉起 Postgres以及 localstack 模拟 S3并把 fhevm-keys 中的密钥导入测试库。8.1 使用 Postgres Docker 镜像# Run Postgres as image, execute migrations and populate the DB instance with keys from fhevm-keys cargo test --release -- --nocapture测试会自动完成“启动数据库 → 执行迁移 → 导入密钥 → 运行用例”全流程。8.2 使用本机 localhost 数据库# Use COPROCESSOR_TEST_LOCALHOST_RESET to execute migrations once COPROCESSOR_TEST_LOCALHOST_RESET1 cargo test --release -- --nocapture # Then, on every run COPROCESSOR_TEST_LOCALHOST1 cargo test --release首次运行带COPROCESSOR_TEST_LOCALHOST_RESET1执行迁移并导入密钥之后每次只需COPROCESSOR_TEST_LOCALHOST1复用同一数据库实例加快迭代。测试用例分布在 src/tests/mod.rs含s3_migration与s3_migration_dry_run两个子模块均为 CPU-only、cfg(not(gpu))使用serial_test::serial保证串行执行覆盖任务查询、Squash 计算、S3 上传与格式迁移等路径。九、可观测性指标与健康检查src/metrics.rs 暴露以下 Prometheus 指标coprocessor_sns_op_latency_secondsSquash 计算延迟直方图coprocessor_sns_worker_task_execute_success_counter/task_execute_failure_counter任务成功/失败计数coprocessor_sns_worker_aws_upload_success_counter/aws_upload_failure_counterS3 上传成功/失败计数coprocessor_sns_worker_uncomplete_tasks_gauge/uncomplete_aws_uploads_gauge未完成任务数与未完成上传数。健康检查由SwitchNSquashService实现HealthCheckServiceexecutor.rs除数据库连通性外还会对 S3 桶就绪性s3_buckets与连接性s3_connection做 5 秒超时检查is_alive依据--liveness-threshold判断 worker 是否卡死。容器化部署参考 Dockerfile——两阶段构建最终以sns_worker二进制作为CMD启动。十、小结sns-worker 是 fhEVM 协处理器中负责把中间密文“洗牌压噪”为 128 位大密文的关键计算节点。它通过 PostgresNOTIFY/LISTEN实现事件驱动以SKIP LOCKED支撑多实例横向扩展用 Rayon/GPU 并行加速 Squash 计算并以“数据库暂存 S3 归档 摘要登记”的三段式流水线保证密文可靠、可验证地发布。部署时只需按本文第四节配置数据库、导入 SnS 密钥、指定频道与 S3 桶即可独立起任意数量的 worker 实例参与 128-PBS 计算。【免费下载链接】fhevmFHEVM, a full-stack framework for integrating Fully Homomorphic Encryption (FHE) with blockchain applications项目地址: https://gitcode.com/GitHub_Trending/fh/fhevm创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考