Midnight隐私模式指南Skill midnight-core-concepts:privacy-patterns

本技能详细介绍了在Midnight区块链平台中实现隐私保护的四种核心模式:哈希、承诺、默克尔树和承诺+无效符组合。内容涵盖隐私模式选择指南、具体实现代码示例、常见错误及解决方案,适用于区块链开发者、隐私保护工程师、智能合约开发者、密码学应用开发者、Web3开发者和零知识证明实现者。关键词包括:区块链隐私、Midnight开发、隐私模式、哈希承诺、默克尔树、无效符、零知识证明、智能合约隐私、链上数据保护、隐私保护技术。

加密算法 0 次安装 7 次浏览 更新于 2/26/2026

name: midnight-core-concepts:privacy-patterns description: 在Compact中实现隐私保护逻辑时使用,涉及哈希、承诺、默克尔树、无效符模式或链上数据隐私保护。

Midnight中的隐私模式

基本原则:传递给账本操作的任何内容都是公开可见的,除了MerkleTree类型。使用以下模式来保护数据隐私。

模式选择指南

目标 模式 使用场景
隐藏数据,稍后证明 哈希 需要简单验证
隐藏数据,防止关联 承诺 相同值必须看起来不同
秘密证明成员资格 默克尔树 集合成员资格证明,不透露具体元素
一次性令牌 承诺 + 无效符 防止隐私泄露的双重花费

模式1:哈希

使用persistentHash隐藏数据,同时允许后续验证。

import { persistentHash } from "std/compact/hashes";

// 存储秘密的哈希值
ledger.stored_hash = persistentHash(secret_data);

// 稍后,通过重新哈希来证明知识
assert persistentHash(provided_data) == ledger.stored_hash;

局限性

  • 相同输入 → 相同哈希(可关联)
  • 小值集合易受暴力破解攻击

适用于:不会重复且具有高熵的数据。

模式2:承诺

当相同值必须看起来不同时,使用persistentCommit

import { persistentCommit } from "std/compact/commitments";

// 使用随机数防止关联
const commitment = persistentCommit(value, randomness);
ledger.stored_commitment = commitment;

随机数的重要性

没有随机数,对“是”的承诺总是看起来相同。使用随机数:

  • commit(“是”, random1) ≠ commit(“是”, random2)
  • 防止相同值之间的关联
  • 对投票、竞价、任何重复值至关重要
// 错误:可关联
const bad = persistentCommit(vote, Bytes<32>::zero());

// 正确:不可链接
const good = persistentCommit(vote, fresh_randomness);

随机数来源

// 选项1:新鲜随机数(理想)
const r = generateRandomness();

// 选项2:从秘密密钥+计数器派生(确定性)
const r = persistentHash(secret_key, counter);

适用于:任何可能重复的值(投票、竞价、选择)。

模式3:默克尔树

使用MerkleTree证明集合成员资格,而不透露具体元素。

ledger authorized_keys: MerkleTree<32, Bytes<32>>;

export circuit authenticate(
  secret_key: Bytes<32>,
  merkle_path: MerkleTreePath<32, Bytes<32>>
): Void {
  // 证明密钥在树中,不透露是哪个密钥
  const public_key = persistentHash(secret_key);
  assert ledger.authorized_keys.member(public_key, merkle_path);
}

树类型

类型 使用场景
MerkleTree<n, T> 静态集合,针对当前根进行证明
HistoricMerkleTree<n, T> 频繁插入,针对过去根进行证明

使用HistoricMerkleTree:元素频繁添加,用户需要针对他们获取路径时的根证明成员资格。

模式4:承诺 + 无效符

最强大的模式:具有完全隐私的一次性令牌。

工作原理

  1. 承诺阶段:将commit(value, secret)存储在默克尔树中
  2. 花费阶段:揭示nullifier = hash(commitment, secret)
  3. 验证:证明承诺存在,无效符未被使用过
ledger commitments: MerkleTree<32, Bytes<32>>;
ledger nullifiers: Set<Bytes<32>>;

export circuit spend(
  value: Field,
  secret: Bytes<32>,
  path: MerkleTreePath<32, Bytes<32>>
): Void {
  // 重构承诺
  const commitment = persistentCommit(value, secret);

  // 证明承诺存在于树中
  assert ledger.commitments.member(commitment, path);

  // 计算并记录无效符
  const nullifier = persistentHash(commitment, secret);
  assert !ledger.nullifiers.member(nullifier);
  ledger.nullifiers.insert(nullifier);
}

隐私属性

  • 承诺:隐藏值和所有者
  • 无效符:防止双重花费,不与承诺关联
  • 默克尔证明:证明存在性,不透露具体承诺

这是Zerocash和Zswap的屏蔽UTXO的基础。

认证模式

证明身份而不透露凭证:

export circuit authenticate(secret_key: Bytes<32>): Void {
  const public_key = persistentHash(secret_key);
  assert public_key == ledger.authorized_key;
  // 已授权!secret_key从未被揭示
}

常见错误

错误1:重用随机数

// 错误:相同随机数 = 可关联
const r = fixed_value;
commit(vote1, r); commit(vote2, r);

// 正确:每次使用新鲜随机数
commit(vote1, random1); commit(vote2, random2);

错误2:小值集合不使用随机数

// 错误:只有2个可能值,易受暴力破解
hash(vote); // vote是“是”或“否”

// 正确:使用随机数的承诺
persistentCommit(vote, randomness);

错误3:忘记什么是公开的

// 错误:这会暴露秘密!
ledger.public_field = secret_value;

// 正确:仅存储承诺
ledger.public_field = persistentCommit(secret_value, randomness);

参考资料

详细技术信息:

  • references/commitment-schemes.md - Pedersen承诺,绑定/隐藏属性
  • references/merkle-tree-usage.md - 树操作,路径生成,历史树

示例

工作模式:

  • examples/private-voting.compact - 使用承诺/无效符的完整投票系统
  • examples/auth-patterns.compact - 不透露密钥的认证模式