Aptos Keyless Pepper Service 开发指南:本地运行、Firestore 集成与客户端交互实战
【免费下载链接】aptos-coreAptos is a layer 1 blockchain built to support the widespread use of blockchain through better technology and user experience.项目地址: https://gitcode.com/GitHub_Trending/ap/aptos-core
导读
本文是 Aptos 仓库中 keyless/pepper/README.md 的深度开发指南,围绕Pepper Service(无密钥账户方案中的关键服务)与其 Rust 示例客户端展开。通过本文,你将掌握 Pepper Service 的本地开发模式启动、Firestore 模拟器集成、完整的命令行参数含义、REST API 端点与客户端交互流程,并结合仓库源码理解其 VUF 密钥管理与启动自检机制,为二次开发或接入 keyless 账户体系打下基础。
一、Pepper Service 是什么
在 Aptos 的无密钥(keyless)账户方案中,Pepper Service扮演"pepper"(胡椒盐)生成与签名的可信第三方角色:它接收携带 OIDC JWT 的 pepper 请求,验证后将 JWT 中的身份信息(issuer、sub、aud 等)与一个随机 blinder 一起映射到一个确定性的 pepper 值,并基于该值派生账户地址,为临时公钥签署ephemeral signature。这样用户既可以通过 OAuth 身份登录,又不需要在链上直接暴露 JWT 原始信息。
本目录包含两大组成部分:
- Pepper Service:位于 keyless/pepper/service,一个基于 Rust + Hyper 的 HTTP 服务,是本文的绝对主体;
- Pepper Client 示例:位于 keyless/pepper/example-client-rust,一个 Rust 实现的交互式控制台客户端,用于演示完整用户流程。README 特别提示:如果你是前端开发者,可以直接以该 Client 示例为参考,理解如何与 Pepper Service API 交互。
两者共享的公共类型(PepperInput、PepperRequest、PepperResponse、VUF 实现、账户恢复数据库抽象等)位于 keyless/pepper/common。
二、本地开发模式快速启动
README 推荐的最简启动方式是直接使用仓库内的示例脚本。整个流程只需要两个终端窗口。
2.1 启动 Pepper Service
cd keyless/pepper/scripts ./start-pepper-service.sh该脚本会在前台运行 Pepper Service,监听8000 端口(即request_handler.rs中定义的DEFAULT_PEPPER_SERVICE_PORT: u16 = 8000),并处于本地开发模式。本地开发模式的三个关键特性:
- 使用临时文件型数据库(
TestAccountRecoveryDB)代替 Firestore,不产生任何持久化数据; - 连接 Aptosdevnet拉取链上资源(Groth16 验证密钥与 keyless 配置);
- 跳过生产环境的常量时间标量乘法校验(详见下文"启动自检"小节)。
从脚本源码可以看到实际执行的命令(start-pepper-service.sh):
cargo run -p aptos-keyless-pepper-service -- \ --local-development-mode \ --expected-derived-pepper-on-startup=${EXPECTED_DERIVED_PEPPER_ON_STARTUP} \ --expected-vuf-pubkey-on-startup=${EXPECTED_VUF_PUBKEY_ON_STARTUP} \ --on-chain-groth16-vk-url=${ON_CHAIN_GROTH16_VK_URL} \ --on-chain-keyless-config-url=${ON_CHAIN_KEYLESS_CONFIG_URL} \ --vuf-private-key-seed-hex=${VUF_KEY_SEED_HEX}脚本内置的测试用常量值得关注:
| 常量 | 值 | 说明 |
|---|---|---|
VUF_KEY_SEED_HEX | 全f的 64 位十六进制 | 测试专用 VUF 私钥种子,生产环境必须更换 |
EXPECTED_VUF_PUBKEY_ON_STARTUP | 以b601ec18...开头的公钥 | 与该种子对应的期望 VUF 公钥,用于启动校验 |
EXPECTED_DERIVED_PEPPER_ON_STARTUP | 72c147eb... | 期望的派生 pepper 值,用于启动校验 |
ON_CHAIN_GROTH16_VK_URL | https://fullnode.devnet.aptoslabs.com/v1/accounts/0x1/resource/0x1::keyless_account::Groth16VerificationKey | devnet 上的 Groth16 验证密钥资源 |
ON_CHAIN_KEYLESS_CONFIG_URL | https://fullnode.devnet.aptoslabs.com/v1/accounts/0x1/resource/0x1::keyless_account::Configuration | devnet 上的 keyless 配置资源 |
注意:Pepper Service 在前台运行,整个交互过程中必须保持该终端窗口开启。
2.2 启动 Pepper Client 示例
保持服务端终端运行,另开一个终端执行:
cd keyless/pepper/scripts ./start-pepper-client.sh脚本实际执行(start-pepper-client.sh):
cargo run -p aptos-keyless-pepper-example-client-rust -- --pepper-service-url="http://localhost:8000"Pepper Client 是交互式控制台程序,会依次调用 Pepper Service 的多个 API 端点演示完整用户流程,需要你按提示手动完成一次会话(例如通过 Google OAuth Playground 获取带 nonce 的 JWT 后粘贴给客户端)。其完整流程定义在 example-client-rust/src/lib.rs 的run_client_example中,共包含以下步骤:
- 获取验证公钥:调用
/v0/vuf-pub-key端点拉取 VUF 验证公钥; - 生成 blinder 与临时密钥:生成 31 字节 blinder、临时公钥与临时密钥过期时间;
- 构造 OAuth nonce:将 blinder、过期时间与临时公钥绑定生成 nonce 字符串;
- 获取带 nonce 的 JWT:引导用户在 Google Playground 完成授权,获取包含该 nonce 的 JWT;
- 请求 pepper:调用
/v0/fetch端点,提交PepperRequest(含 JWT、blinder、临时公钥、过期时间); - 请求签名:调用
/v0/signature端点,获取服务端对临时密钥的签名。
在本地开发模式下,客户端使用内置的测试 JWT 与默认sub作为 UID key,无需真实登录即可跑通全流程。
三、Firestore Emulator 集成模式
如果你的目标是贴近生产环境、测试账户恢复数据库的读写行为,README 提供了完整的 Firestore Emulator 方案。与本地开发模式的核心区别在于:账号恢复数据库从临时内存库切换为 Firestore,同时服务不再处于--local-development-mode。
3.1 前置条件
要使用 Firestore 数据库运行 Pepper Service,需要准备两项 GCP 资源(均可通过 GCP Console 完成):
- GCP Project:一个已创建好的 GCP 项目;
- Service Account:一个具有 Firestore 访问权限的服务账号,并下载其JSON 格式的凭据文件(即
GOOGLE_APPLICATION_CREDENTIALS指向的文件)。
3.2 启动 Firestore Emulator
cd keyless/pepper/scripts ./start-firestore-emulator.sh 8081脚本参数:
<FIRESTORE_PORT>:Firestore 模拟器的监听端口。
执行后模拟器将运行在8081 端口,同样在前台运行,需保持该终端开启。脚本底层命令是gcloud emulators firestore start --host-port=localhost:${FIRESTORE_PORT}(见 start-firestore-emulator.sh),因此需要本机已安装并登录gcloudCLI。
3.3 停止 Firestore Emulator
cd keyless/pepper/scripts ./stop-firestore-emulator.sh 8081脚本参数:
<FIRESTORE_PORT>:正在运行的 Firestore 模拟器端口。
停止时务必输入正确的端口号,脚本会通过lsof -t -i:<port>找到占用该端口的进程并强制结束(见 stop-firestore-emulator.sh)。请谨慎确认没有其他服务复用该端口。
3.4 使用 Firestore 启动 Pepper Service
cd keyless/pepper/scripts ./start-pepper-service-with-firestore.sh <FIRESTORE_EMULATOR_HOST> <GOOGLE_APPLICATION_CREDENTIALS> <GOOGLE_PROJECT_ID>三个参数的说明:
| 参数 | 示例 | 含义 |
|---|---|---|
<FIRESTORE_EMULATOR_HOST> | http://localhost:8081 | Firestore 模拟器的主机与端口 |
<GOOGLE_APPLICATION_CREDENTIALS> | /path/to/credential.json | 服务账号凭据文件(JSON)路径 |
<GOOGLE_PROJECT_ID> | my-gcp-project | GCP 项目 ID |
从脚本源码(start-pepper-service-with-firestore.sh)可以看到,该模式还会:
- 将
FIRESTORE_EMULATOR_HOST、GOOGLE_APPLICATION_CREDENTIALS导出为环境变量; - 使用模拟器默认数据库 ID
(default); - 配置账户恢复管理器(Account Recovery Manager),脚本内置了 Google 示例:
export ACCOUNT_MANAGER_0_ISSUER=https://accounts.google.com export ACCOUNT_MANAGER_0_AUD=407408718192.apps.googleusercontent.com如需支持更多 OAuth 提供商,可依注释追加(Facebook、Apple 等):
# export ACCOUNT_MANAGER_1_ISSUER=https://www.facebook.com # export ACCOUNT_MANAGER_1_AUD=999999999.apps.fbusercontent.com # export ACCOUNT_MANAGER_2_ISSUER=https://appleid.apple.com # export ACCOUNT_MANAGER_2_AUD=88888888.apps.appleusercontent.com该模式下实际运行的命令不再带--local-development-mode,而是显式传入 Firestore 参数:
cargo run -p aptos-keyless-pepper-service -- \ --expected-derived-pepper-on-startup=${EXPECTED_DERIVED_PEPPER_ON_STARTUP} \ --expected-vuf-pubkey-on-startup=${EXPECTED_VUF_PUBKEY_ON_STARTUP} \ --google-project-id=${GOOGLE_PROJECT_ID} \ --firestore-database-id=${FIRESTORE_DATABASE_ID} \ --on-chain-groth16-vk-url=${ON_CHAIN_GROTH16_VK_URL} \ --on-chain-keyless-config-url=${ON_CHAIN_KEYLESS_CONFIG_URL} \ --vuf-private-key-seed-hex=${VUF_KEY_SEED_HEX}3.5 使用 Firestore 启动 Pepper Client
cd keyless/pepper/scripts ./start-pepper-client-with-firestore.sh <FIRESTORE_EMULATOR_HOST> <GOOGLE_APPLICATION_CREDENTIALS> <PEPPER_SERVICE_URL> <GOOGLE_PROJECT_ID> <FIRESTORE_DATABASE_ID>五个参数说明:
| 参数 | 示例 | 含义 |
|---|---|---|
<FIRESTORE_EMULATOR_HOST> | http://localhost:8081 | Firestore 模拟器主机与端口 |
<GOOGLE_APPLICATION_CREDENTIALS> | /path/to/credential.json | 服务账号凭据文件(JSON)路径 |
<PEPPER_SERVICE_URL> | http://localhost:8000 | Pepper Service 主机与端口 |
<GOOGLE_PROJECT_ID> | my-gcp-project | GCP 项目 ID |
<FIRESTORE_DATABASE_ID> | (default) | Firestore 数据库 ID |
客户端对应的底层命令(start-pepper-client-with-firestore.sh):
cargo run -p aptos-keyless-pepper-example-client-rust -- \ --pepper-service-url=${PEPPER_SERVICE_URL} \ --firestore-google-project-id=${GOOGLE_PROJECT_ID} \ --firestore-database-id=${FIRESTORE_DATABASE_ID}该模式下客户端会额外把FIRESTORE_EMULATOR_HOST与GOOGLE_APPLICATION_CREDENTIALS导出为环境变量,以便在完整流程中读写 Firestore 中的账户恢复记录(默认集合名为accounts,定义于客户端源码的DEFAULT_FIRESTORE_COLLECTION)。
四、服务端命令行参数全解(源码级)
Pepper Service 的全部启动参数由 service/src/main.rs 中基于clap的Args结构定义,是理解服务行为的一手资料:
| 参数 | 类型/默认值 | 说明 |
|---|---|---|
--local-development-mode | bool,默认 false | 使用测试账户恢复数据库(TestAccountRecoveryDB),与firestore_database_id/google_project_id互斥 |
--firestore-database-id | Option<String> | Firestore 数据库 ID,非本地模式必填,且必须与google_project_id同时出现 |
--google-project-id | Option<String> | GCP 项目 ID,非本地模式必填 |
--vuf-private-key-seed-hex | Option<String> | 十六进制 VUF 私钥种子(用于派生私钥),与vuf_private_key_hex二选一 |
--vuf-private-key-hex | Option<String> | 直接提供十六进制 VUF 私钥,与vuf_private_key_seed_hex二选一 |
--expected-vuf-pubkey-on-startup | Option<String> | 启动时校验 VUF 公钥与期望值一致,防止用错密钥对 |
--expected-derived-pepper-on-startup | Option<String> | 启动时用固定输入派生 pepper 并与期望值比对,保证派生逻辑前后兼容 |
--on-chain-groth16-vk-url | Option<String> | 拉取链上 Groth16 验证密钥的 REST 地址 |
--on-chain-keyless-config-url | Option<String> | 拉取链上 keyless 配置的 REST 地址 |
--pepper-service-port | u16,默认 8000 | Pepper Service 监听端口 |
--account-recovery-managers | Vec | 允许在处理 pepper 请求时覆盖 JWTaud声明的账户恢复管理器列表 |
--disable-async-db-updates | bool,默认 false | 关闭账户恢复数据库的异步更新(默认异步,避免阻塞请求处理) |
--resource-fetch-headers | Vec<HttpHeader> | 拉取链上资源时附加的 HTTP 头,适用于内部 API 网关鉴权 |
--jwk-issuers-override | Vec<JWKIssuer> | 额外监控的 JWK URL 列表,也可覆盖默认发行者的 JWK 地址 |
除 CLI 参数外,main.rs还支持两个环境变量注入的配置:
INTERNAL_NODE_API:若设置,则作为链上资源拉取的 base URL,自动拼接/v1/accounts/0x1/resource/0x1::keyless_account::Groth16VerificationKey与...::Configuration两个路径,覆盖对应 CLI 参数;INTERNAL_NODE_API_HEADER_<i>_NAME/INTERNAL_NODE_API_HEADER_<i>_VALUE:成对设置,追加到资源拉取请求头。
五、HTTP API 端点一览
Pepper Service 的全部端点集中定义在 service/src/request_handler.rs:
| 路径 | 用途 |
|---|---|
/about | 服务基本信息 |
/v0/fetch | 提交 pepper 请求,获取派生 pepper 与账户地址(核心流程) |
/v0/signature | 为临时公钥签发 ephemeral signature |
/v0/verify | 验证 pepper / 签名 |
/v0/delegated-fetch | 委托模式下的 pepper 获取 |
/v0/vuf-pub-key | 返回 VUF 验证公钥 |
/cached/groth16-vk | 缓存的链上 Groth16 验证密钥 |
/cached/jwk | 缓存的 JWK(JSON Web Key) |
/cached/keyless-config | 缓存的链上 keyless 配置 |
其中/cached/*三个端点由后台的start_cached_resource_fetcher周期拉取并缓存,/v0/*端点由request_handler::handle_request统一分发到dedicated_handlers中的各个处理器(V0FetchHandler、V0SignatureHandler、V0VerifyHandler、V0DelegatedFetchHandler等,见 service/src/dedicated_handlers/handlers.rs)。请求体以 JSON 反序列化(serde_json),非法请求返回 400,内部异常统一返回 500。
六、启动自检:VUF 密钥与派生逻辑的一致性保障
main.rs的verify_critical_service_invariants在服务启动时执行三道关键检查,任何一项失败都会直接 panic,防止错误配置上线:
- 常量时间标量乘法校验(生产模式):使用 dudect 统计测试(
ctbench)分别对随机基与固定基运行 BLS 标量乘法基准,要求max_t绝对值不超过 5(ABS_MAX_T),确保私钥操作不存在明显的时间侧信道;本地开发模式下跳过此项; - VUF 公钥校验:将本地 VUF 公钥序列化为 JSON 后取出
public_key字段与--expected-vuf-pubkey-on-startup比对; - 派生 pepper 校验:使用硬编码的固定输入(
fixed_issuer/fixed_sub/fixed_user_id/fixed_audience,常量定义于 service/src/main.rs)调用derive_pepper_and_account_address本地派生 pepper,与--expected-derived-pepper-on-startup比对,并将结果写入部署信息(deployment_information)便于可观测性。
VUF 密钥对的生成逻辑在 service/src/vuf_keypair.rs:
- 若提供
vuf_private_key_seed_hex,先 hex 解码,要求种子至少 32 字节,再用SHA3-512哈希后经scalar_from_uniform_be_bytes派生私钥标量; - 若直接提供
vuf_private_key_hex,则直接反序列化为标量; - 公钥为
G2Projective群元素,VUF 实现采用 BLS12-381 曲线(Bls12381G1Bls,见 keyless/pepper/common/src/vuf/bls12381_g1_bls.rs)。
这就是为什么脚本中的VUF_KEY_SEED_HEX(测试用全f种子)能对应到固定的期望公钥与派生 pepper——服务用启动自检保证"你手里的私钥种子派生出的确实是预期的密钥与 pepper"。
七、测试与验证
仓库为 Pepper Service 提供了较完整的单元与集成测试,集中在 service/src/tests:
pepper_request.rs:pepper 请求处理的核心逻辑测试;request_handler.rs:HTTP 请求分发与响应构造测试;jwk_fetcher.rs/federated_jwk.rs:JWK 拉取与联合发行者处理测试;resource_fetcher.rs:链上资源(Groth16 VK / keyless 配置)缓存拉取测试。
运行方式:
cargo test -p aptos-keyless-pepper-service本地联调时建议的完整验证路径:
- 终端 A:
./start-pepper-service.sh启动服务(前台); - 终端 B:
./start-pepper-client.sh启动客户端,观察其依次完成"获取 VUF 公钥 → 生成 blinder/临时密钥 → 构造 nonce → 获取 JWT → 请求 pepper → 请求签名"的完整会话; - 如需验证 Firestore 持久化:依次执行
start-firestore-emulator.sh 8081、start-pepper-service-with-firestore.sh、start-pepper-client-with-firestore.sh,并可通过stop-firestore-emulator.sh 8081清理环境。
结语
本文以 keyless/pepper/README.md 为骨架,完整覆盖了 Pepper Service 的本地开发模式、Firestore Emulator 集成、全部启动参数与 HTTP 端点,并深入源码揭示了 VUF 密钥派生、启动自检与客户端交互流程。无论你是前端开发者(以 Rust Client 为 API 交互参考),还是后端/链上开发者(需要部署或扩展 Pepper Service),都可以直接依据上述命令与参数在本地复现整套环境,再对照 keyless/pepper/service/src 的源码继续深入。
【免费下载链接】aptos-coreAptos is a layer 1 blockchain built to support the widespread use of blockchain through better technology and user experience.项目地址: https://gitcode.com/GitHub_Trending/ap/aptos-core
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考