使用RISC Zero 开发身份认证的零知识证明示例

1. 项目概述

GhostLink 是一个隐私保护的身份认证平台,用户可以将 Web2/Web3 身份凭证转化为链上可验证的 SBT(灵魂绑定代币)。

零知识证明目标:证明"用户满足某条件"而不暴露原始数据。


2. 凭证类型概览

凭证类型 数据来源 采集方 证明目标
GitHub GitHub OAuth API GhostLink 后端 证明拥有 GitHub 账户
支付宝 资产证明 PDF GhostLink 后端 证明资产 ≥ 阈值
Twitter Twitter OAuth API GhostLink 后端 证明拥有 Twitter 账户
钱包资产 区块链 RPC GhostLink 前端 证明链上资产情况

3. 数据流架构

复制代码
┌──────────────────────────────────────────────────────────────┐
│                     GhostLink 系统                            │
├────────────────┬─────────────────┬───────────────────────────┤
│    前端        │     后端        │                           │
│    (React)     │     (Java)      │                           │
├────────────────┼─────────────────┤                           │
│ 钱包资产采集 ──┼─→ API 转发 ─────┼──→ RISC Zero 服务         │
│                │ GitHub OAuth ───┼──→ (由贵方部署)            │
│                │ 支付宝PDF解析 ──┼──→                         │
│                │ Twitter OAuth ──┼──→                         │
└────────────────┴─────────────────┴───────────────────────────┘
                                            │
                                            ▼
                                   ┌─────────────────┐
                                   │  智能合约验证    │
                                   │  铸造 SBT       │
                                   └─────────────────┘

4. 接口规范

4.1 统一请求格式

http 复制代码
POST /api/v1/prove
Content-Type: application/json
Authorization: Bearer {api_key}

{
  "credential_type": "github | alipay | twitter | wallet",
  "data": { ... },
  "recipient": "0x..."
}

4.2 统一响应格式

成功

json 复制代码
{
  "status": "success",
  "receipt_hex": "...",
  "journal_hex": "...",
  "image_id_hex": "...",
  "nullifier_hex": "..."
}

失败

json 复制代码
{
  "status": "error",
  "error_code": "INVALID_DATA | THRESHOLD_NOT_MET | ...",
  "message": "描述信息"
}

5. 凭证类型详细规范

5.1 GitHub 凭证

请求

json 复制代码
{
  "credential_type": "github",
  "data": {
    "user_id": 12345678,
    "username": "ghostlink-user",
    "created_at": "2020-01-01T00:00:00Z",
    "public_repos": 5
  },
  "recipient": "0x..."
}
字段 类型 必填 说明
user_id Number GitHub 用户 ID
username String GitHub 用户名
created_at String 账户创建时间(ISO 8601)
public_repos Number 公开仓库数量

ZK 验证逻辑

  1. 验证数据格式有效
  2. 生成 nullifier = keccak256("github" || user_id)

5.2 支付宝资产凭证

请求

json 复制代码
{
  "credential_type": "alipay",
  "data": {
    "balance": "15975.01",
    "id_number_hash": "0x7a8b9c...",
    "threshold": "10000"
  },
  "recipient": "0x..."
}
字段 类型 必填 说明
balance String 总资产金额(元)
id_number_hash String keccak256(身份证号)
threshold String 资产门槛(元)

ZK 验证逻辑

  1. 验证 balance >= threshold
  2. 生成 nullifier = keccak256("alipay" || id_number_hash)

注意:身份证号由 GhostLink 后端哈希后传入,ZK 服务不接收原文。


5.3 Twitter 凭证

请求

json 复制代码
{
  "credential_type": "twitter",
  "data": {
    "user_id": "987654321",
    "handle": "ghostlink",
    "created_at": "2015-01-01T00:00:00Z",
    "followers_count": 100
  },
  "recipient": "0x..."
}
字段 类型 必填 说明
user_id String Twitter 用户 ID
handle String @ 用户名(不含 @)
created_at String 账户创建时间
followers_count Number 粉丝数(可选)

ZK 验证逻辑

  1. 验证数据格式有效
  2. 生成 nullifier = keccak256("twitter" || user_id)

5.4 钱包资产凭证 ⭐ 新增

请求

json 复制代码
{
  "credential_type": "wallet",
  "data": {
    "address": "0x1234...abcd",
    "balance_wei": "1000000000000000000",
    "transaction_count": 42,
    "chain_id": 11155111,
    "signature": "0xabc123...",
    "message": "GhostLink Asset-Pass Verification..."
  },
  "recipient": "0x..."
}
字段 类型 必填 说明
address String 钱包地址
balance_wei String ETH 余额(Wei 单位)
transaction_count Number 链上交易数量
chain_id Number 链 ID(11155111 = Sepolia)
signature String 用户签名
message String 被签名的消息原文

ZK 验证逻辑

  1. 验证签名ecrecover(message, signature) == address
  2. 验证 transaction_count >= 10(可选门槛)
  3. 生成 nullifier = keccak256("wallet" || address || chain_id)

重要:钱包数据由前端采集,需要在 ZK 电路中验证签名以防伪造。


6. Nullifier 规范

凭证类型 Nullifier 计算公式
GitHub `keccak256("github"
Alipay `keccak256("alipay"
Twitter `keccak256("twitter"
Wallet `keccak256("wallet"

同一用户使用同一身份只能铸造一次 SBT。


问题发现方法论总结

目的 : 总结如何系统性地发现和修复 RISC Zero 集成中的错误
更新日期: 2026-01-26


📋 目录

  1. 问题发现流程
  2. 具体问题分析
  3. 依据来源总结
  4. 避免错误的检查清单

1. 问题发现流程

1.1 系统性检查方法

复制代码
1. 对比官方实现
   ↓
2. 检查接口定义
   ↓
3. 验证数据格式匹配
   ↓
4. 测试端到端流程

1.2 关键检查点

检查项 检查方法 依据来源
接口定义 对比官方源码 risc0-ethereum/contracts/src/IRiscZeroVerifier.sol
数据格式 对比 Guest 和合约 Guest 代码 vs 合约代码
哈希算法 查看 RISC Zero 实现 risc0/zkvm/src/receipt.rs
证明格式 对比 v1 和 v2 工作版本 vs 新版本

2. 具体问题分析

问题 1: 合约验证接口返回值类型错误

🔍 发现过程

步骤 1: 查看用户代码

solidity 复制代码
// ghostlinkV2/contract/IRiscZeroVerifier.sol (原始版本)
function verify(...) external view returns (bool success);

步骤 2: 对比官方实现

bash 复制代码
# 搜索 RISC Zero 官方接口定义
grep -r "function verify" risc0-ethereum/contracts/src/

步骤 3: 找到官方定义

solidity 复制代码
// risc0-ethereum/contracts/src/IRiscZeroVerifier.sol
function verify(bytes calldata seal, bytes32 imageId, bytes32 journalDigest) external view;
// ✅ 注意:没有 returns (bool)

步骤 4: 查看文档注释

solidity 复制代码
/// @notice Verify that the given seal is a valid RISC Zero proof...
///     Reverts on failure.  // ✅ 关键:验证失败时 revert,不返回 bool

步骤 5: 验证合约调用

solidity 复制代码
// ghostlinkV2/contract/GhostLinkSBT.sol (原始版本)
bool verified = verifier.verify(seal, imageId, journalHash);  // ❌ 错误
require(verified, "ZK proof verification failed");

发现:

  • 接口定义返回 bool,但官方接口不返回值
  • 合约中尝试读取返回值,但函数不返回任何值
  • 这会导致编译错误或运行时错误
📚 依据来源
  1. 官方源码 : risc0-ethereum/contracts/src/IRiscZeroVerifier.sol

    • 第 207 行:函数签名明确不返回值
    • 第 200 行:注释说明 "Reverts on failure"
  2. 官方文档注释:

    solidity 复制代码
    /// @dev This method additionally ensures that the input hash is all-zeros...
    ///     and there are no assumptions (i.e. the receipt is unconditional).

    说明验证失败时会 revert,而不是返回 false

  3. Solidity 最佳实践:

    • 验证函数通常使用 revert 模式(如 OpenZeppelin 的 require()
    • 返回 bool 的模式较少使用,因为需要额外的 require() 检查
✅ 修复方法
solidity 复制代码
// 1. 修正接口定义
function verify(...) external view;  // 移除 returns (bool)

// 2. 修正调用方式
verifier.verify(seal, imageId, journalHash);  // 直接调用,失败时自动 revert

问题 2: Groth16 证明格式问题

🔍 发现过程

步骤 1: 用户提问

"你之前的方案已经是可以了。现在我写了第二代的代码,但是我不知道这里是否是Groth16的格式"

步骤 2: 对比 v1 和 v2 的配置

toml 复制代码
# ghostlink (v1) - 工作版本
risc0-zkvm = { version = "3.0.0", features = ["docker"] }

# ghostlinkV2 - 新版本
risc0-zkvm = { workspace = true, features = ["client", "std"] }

步骤 3: 检查 Host 代码

rust 复制代码
// 两个版本都使用了
prover.compress(&ProverOpts::groth16(), &receipt);

步骤 4: 发现差异

  • v1 有 docker feature
  • v2 缺少 docker feature
  • 缺少 docker feature 可能导致无法生成 Groth16 证明

步骤 5: 验证 Docker Feature 的作用

rust 复制代码
// 查看 RISC Zero 文档和代码
// docker feature 用于通过 Docker 容器执行 Groth16 压缩
📚 依据来源
  1. 代码对比:

    • v1(工作版本)使用了 docker feature
    • v2(新版本)没有使用 docker feature
  2. RISC Zero 文档:

    • Docker feature 允许通过容器执行 Groth16 压缩
    • 无需本地安装 Groth16 组件
  3. 实际测试:

    • v1 能生成 Groth16 证明
    • v2 在 Dev Mode 下生成假证明
✅ 修复方法
toml 复制代码
# 添加 docker feature
risc0-zkvm = { workspace = true, features = ["client", "std", "docker"] }

问题 3: Journal Hash 必须使用 SHA-256

🔍 发现过程

步骤 1: 查看合约代码

solidity 复制代码
// 用户可能使用 keccak256(以太坊常用)
bytes32 journalHash = keccak256(abi.encodePacked(...));  // ❌ 错误假设

步骤 2: 查看 RISC Zero 源码实现

rust 复制代码
// risc0/zkvm/src/receipt.rs
impl risc0_binfmt::Digestible for Journal {
    fn digest<S: Sha256>(&self) -> Digest {
        *S::hash_bytes(&self.bytes)  // ✅ 使用 SHA-256
    }
}

步骤 3: 查看合约中的注释

solidity 复制代码
// ghostlinkV2/contract/GhostLinkSBT.sol
// IMPORTANT: RISC Zero on-chain verifier requires SHA-256 for the journal hash
bytes32 journalHash = sha256(...);  // ✅ 正确

步骤 4: 验证 RISC Zero 合约库

solidity 复制代码
// risc0-ethereum/contracts/src/IRiscZeroVerifier.sol
function digest(ReceiptClaim memory claim) internal pure returns (bytes32) {
    return sha256(abi.encodePacked(...));  // ✅ 所有地方都使用 sha256
}
📚 依据来源
  1. RISC Zero 源码:

    • risc0/zkvm/src/receipt.rs 第 291 行:fn digest<S: Sha256>
    • 明确使用 SHA-256 trait
  2. RISC Zero 合约库:

    • risc0-ethereum/contracts/src/IRiscZeroVerifier.sol
    • 所有哈希计算都使用 sha256()
  3. 合约注释:

    • 明确说明 "requires SHA-256"
  4. 常见错误模式:

    • 以太坊开发者习惯使用 keccak256
    • 但 RISC Zero 使用 SHA-256(这是设计选择)
✅ 修复方法
solidity 复制代码
// ✅ 正确:使用 sha256
bytes32 journalHash = sha256(abi.encodePacked(msg.sender, nullifier, uint8(credType)));

// ❌ 错误:不要使用 keccak256
// bytes32 journalHash = keccak256(abi.encodePacked(...));

问题 4: 依赖配置导致构建错误

🔍 发现过程

步骤 1: 用户报告构建错误

复制代码
error: failed to run custom build command for `risc0-sys`
Could not build metal kernels

步骤 2: 对比 v1 和 v2 的依赖配置

toml 复制代码
# v1 - 使用 crates.io 预编译版本
risc0-zkvm = { version = "3.0.0" }

# v2 - 使用本地源码路径
risc0-zkvm = { path = "../risc0/zkvm" }

步骤 3: 理解差异

  • 预编译版本: 已包含编译好的 Metal kernels,无需本地构建
  • 本地路径: 需要从源码编译,包括 Metal kernels

步骤 4: 检查构建要求

  • Metal kernels 需要 Xcode Command Line Tools
  • macOS 上如果未安装,构建会失败
📚 依据来源
  1. 构建错误信息:

    复制代码
    xcrun: error: unable to find utility "metal"

    明确指向 Metal 工具缺失

  2. 代码对比:

    • v1 使用预编译版本,无需构建
    • v2 使用本地路径,需要构建
  3. RISC Zero 构建系统:

    • risc0/sys/build.rs 检查是否需要构建 Metal kernels
    • 预编译版本跳过构建步骤
✅ 修复方法
toml 复制代码
# 使用预编译版本(与 v1 一致)
risc0-zkvm = { version = "3.0.0", default-features = false }

3. 依据来源总结

3.1 官方源码(最可靠)

位置 : risc0-ethereum/contracts/src/risc0/zkvm/src/

用途:

  • ✅ 接口定义(函数签名)
  • ✅ 数据格式(Journal digest 实现)
  • ✅ 哈希算法(SHA-256 vs Keccak256)

检查方法:

bash 复制代码
# 搜索接口定义
grep -r "function verify" risc0-ethereum/contracts/src/

# 搜索实现细节
grep -r "sha256\|Sha256" risc0/zkvm/src/

3.2 工作版本对比(快速验证)

位置 : ghostlink/ (v1 工作版本)

用途:

  • ✅ 配置对比(Cargo.toml)
  • ✅ 代码模式对比(Host 代码)
  • ✅ 已验证的工作方案

检查方法:

bash 复制代码
# 对比配置
diff ghostlink/host/Cargo.toml ghostlinkV2/host/Cargo.toml

# 对比代码
diff ghostlink/host/src/main.rs ghostlinkV2/host/src/main.rs

3.3 官方文档(理解设计)

位置 : website/ 和 RISC Zero 官方文档

用途:

  • ✅ 理解设计意图
  • ✅ 最佳实践
  • ✅ 常见问题

检查方法:

  • 查看官方文档网站
  • 搜索 GitHub Issues
  • 查看示例代码

3.4 实际测试(最终验证)

方法:

bash 复制代码
# 1. 构建测试
cargo build --release

# 2. 运行测试
cargo run

# 3. API 测试
curl -X POST http://localhost:3000/api/v1/prove ...

# 4. 合约测试
cast send $CONTRACT "mint(...)" ...

4. 避免错误的检查清单

4.1 接口定义检查

  • 对比官方接口 : 检查 risc0-ethereum/contracts/src/IRiscZeroVerifier.sol
  • 函数签名: 参数类型、返回值类型必须完全匹配
  • 文档注释: 注意 "Reverts on failure" 等关键说明
  • 调用方式: 根据接口定义决定是否需要检查返回值

检查命令:

bash 复制代码
# 查看官方接口定义
cat risc0-ethereum/contracts/src/IRiscZeroVerifier.sol | grep -A 5 "function verify"

4.2 数据格式检查

  • Journal 格式: Guest 代码输出的字节序列
  • Journal Hash: 合约中计算的哈希值
  • 哈希算法 : 必须使用 sha256()(不是 keccak256()
  • 字节对齐 : abi.encodePacked() 的打包方式

检查方法:

rust 复制代码
// Guest 代码
let mut journal = Vec::new();
journal.extend_from_slice(&address);    // 20 bytes
journal.extend_from_slice(&nullifier);  // 32 bytes
journal.push(type_id);                  // 1 byte
// 总计: 53 bytes
solidity 复制代码
// 合约代码
bytes32 journalHash = sha256(
    abi.encodePacked(msg.sender, nullifier, uint8(credType))
);
// 必须匹配 Guest 输出的 53 字节

4.3 证明格式检查

  • Groth16 压缩 : 使用 ProverOpts::groth16()
  • Docker Feature : 确保启用了 docker feature
  • Seal 格式 : [4字节选择器][192字节Groth16证明]
  • 选择器 : 从 verifier_parameters 的前 4 字节提取

检查代码:

rust 复制代码
// Host 代码
let compress_result = prover.compress(&ProverOpts::groth16(), &receipt);
let groth16_inner = groth16_receipt.inner.groth16().unwrap();
let selector = &verifier_params.as_bytes()[..4];
let mut seal_bytes = Vec::new();
seal_bytes.extend_from_slice(selector);
seal_bytes.extend_from_slice(seal_data.as_ref());

4.4 依赖配置检查

  • 版本选择 : 使用预编译版本(version = "3.0.0")还是本地路径(path = "..."
  • Feature 启用 : 确保启用了必要的 features(如 docker
  • 构建要求: 如果使用本地路径,需要满足构建要求(Xcode Command Line Tools)

检查配置:

toml 复制代码
# ✅ 推荐:预编译版本 + docker feature
risc0-zkvm = { version = "3.0.0", features = ["docker"] }

# ⚠️ 需要构建:本地路径
risc0-zkvm = { path = "../risc0/zkvm", features = ["docker"] }

5. 问题发现的关键技巧

5.1 对比法

原理: 对比工作版本和新版本,找出差异

步骤:

  1. 找到工作版本(v1)
  2. 对比关键配置和代码
  3. 找出差异点
  4. 分析差异是否导致问题

示例:

bash 复制代码
# 对比 Cargo.toml
diff ghostlink/host/Cargo.toml ghostlinkV2/host/Cargo.toml

# 对比接口定义
diff ghostlink/contracts/IRiscZeroVerifier.sol ghostlinkV2/contract/IRiscZeroVerifier.sol

5.2 源码追踪法

原理: 从用户代码追溯到官方实现,验证正确性

步骤:

  1. 找到用户代码中的关键调用
  2. 搜索官方源码中的对应实现
  3. 对比函数签名、参数类型、返回值
  4. 检查文档注释

示例:

solidity 复制代码
// 用户代码
verifier.verify(seal, imageId, journalHash);

// 追踪到官方源码
// risc0-ethereum/contracts/src/IRiscZeroVerifier.sol
function verify(...) external view;  // 不返回 bool

5.3 文档注释分析法

原理: 官方代码的注释通常包含关键信息

关键注释模式:

  • /// Reverts on failure → 不返回 bool
  • /// IMPORTANT: → 重要提示
  • /// @dev → 实现细节
  • /// @notice → 功能说明

示例:

solidity 复制代码
/// @notice Verify that the given seal is a valid RISC Zero proof...
///     Reverts on failure.  // ✅ 关键信息
function verify(...) external view;

5.4 错误信息分析法

原理: 构建错误和运行时错误通常指向根本原因

错误类型:

  • 编译错误: 类型不匹配、函数不存在
  • 运行时错误: 验证失败、哈希不匹配
  • 构建错误: 缺少工具、依赖问题

分析步骤:

  1. 提取错误关键词
  2. 搜索相关代码位置
  3. 对比正确实现
  4. 找出差异

6. 总结:避免错误的黄金法则

✅ 法则 1: 始终对比官方实现

操作:

bash 复制代码
# 1. 找到官方源码位置
find . -name "IRiscZeroVerifier.sol" -path "*/risc0-ethereum/*"

# 2. 对比接口定义
diff your_interface.sol official_interface.sol

# 3. 确保完全匹配

✅ 法则 2: 使用工作版本作为参考

操作:

  • 保留一个已知工作的版本(如 v1)
  • 新版本开发时,对比关键配置
  • 发现差异时,分析是否必要

✅ 法则 3: 验证端到端流程

操作:

bash 复制代码
# 1. 生成证明
curl -X POST http://localhost:3000/api/v1/prove ...

# 2. 检查证明格式
# receipt_hex 应该是真实的 Groth16 证明(不是 fake_receipt)

# 3. 调用合约
cast send $CONTRACT "mint(...)" ...

# 4. 验证是否成功

✅ 法则 4: 阅读文档注释

操作:

  • 不要只看函数签名,还要看注释
  • 特别注意 IMPORTANT@dev@notice 标记
  • 理解设计意图,而不只是语法

✅ 法则 5: 测试驱动开发

操作:

  • 先写测试用例
  • 运行测试发现错误
  • 修复错误后再继续

7. 快速检查命令

检查接口定义

bash 复制代码
# 查看官方接口
grep -A 3 "function verify" risc0-ethereum/contracts/src/IRiscZeroVerifier.sol

# 对比用户接口
diff ghostlinkV2/contract/IRiscZeroVerifier.sol risc0-ethereum/contracts/src/IRiscZeroVerifier.sol

检查哈希算法

bash 复制代码
# 查看 RISC Zero 实现
grep -r "Sha256\|sha256" risc0/zkvm/src/receipt.rs

# 检查合约中的使用
grep -r "sha256\|keccak256" ghostlinkV2/contract/

检查配置

bash 复制代码
# 对比 Cargo.toml
diff ghostlink/host/Cargo.toml ghostlinkV2/host/Cargo.toml

# 检查 features
grep "features" ghostlinkV2/host/Cargo.toml

相关推荐
MicroTech20252 小时前
微算法科技(NASDAQ:MLGO)基于后量子阈值算法的区块链隐私保护技术
科技·算法·区块链
SteveCode.2 小时前
MetaMask 配合Ganache-CLI 部署合约失败问题
区块链
栗子~~2 小时前
Solidity 合约权限控制模板
区块链
voidmort4 小时前
web3中的共识:以太坊共识
web3·区块链
傻小胖4 小时前
12.BTC-匿名性-北大肖臻老师客堂笔记
区块链
傻小胖4 小时前
16.ETH-状态树-北大肖臻老师客堂笔记
笔记·算法·区块链·哈希算法
傻小胖4 小时前
14.ETH-以太坊概述-北大肖臻老师客堂笔记
笔记·区块链
henujolly15 小时前
Why do multiple blockchains exist?
区块链
voidmort1 天前
Web3 中的 DEX 流程详解:从原理到实现
web3·区块链