ZK 应用 — 游戏(Dark Forest)
Dark Forest 架构、ZK fog-of-war、move 电路、MiMC hash 用法
日期: 2026-12-20 方向: ZK工程 / 电路开发 阶段: Phase 4 - ZK电路开发实战 (Day 223-243) 标签: #ZK #Dark-Forest #ZK-game #fog-of-war #autonomous-worlds
今日目标
| 类型 | 内容 |
|---|---|
| 学习 | Dark Forest 架构、ZK fog-of-war、move 电路、MiMC hash 用法 |
| 实操 | 阅读 Dark Forest move/init/biome 电路源码 |
| 产出 | game_zk.md(电路分析 + 游戏模式归纳 + ZK 游戏未来) |
背景与定位
Dark Forest 是什么?/ What is Dark Forest?
由 0xPARC(Brian Gu, Vivek Bhupatiraju 等)2020 年开发,第一个完全链上的 ZK 战略游戏:
- 玩家在一个无限的 ZK MMO 宇宙中探索、占领星球、攻击敌人。
- 游戏地图是 procedurally generated(用 MiMC hash),但只有玩家自己挖出来的部分可见("fog of war")。
- 玩家的星球坐标是私有的(ZK),其他人无法 doxx 你的位置。
- "Dark Forest" 名字来自刘慈欣《三体》的「黑暗森林」隐喻——你不知道敌人在哪,先暴露的死。
为什么是 ZK 游戏的圣杯?/ Why is it the holy grail?
- 传统链上游戏:所有状态公开 → 信息不对称游戏不可玩
- Dark Forest:用 ZK 让 隐藏信息也能验证,开启了「全链上不完全信息游戏」赛道
- 衍生:Lattice/MUD, 0xPARC autonomous worlds, Primodium, Sky Strife
核心架构
1. 地图生成 / Map Generation
For each (x, y) in infinite grid:
h = MiMCSponge(x, y) // deterministic hash
if h % SCALE < THRESHOLD:
planet exists at (x, y)
planet_level = f(h)
planet_type = g(h)
biome = biomeHash(x, y)
地图是 deterministic 的——同样 (x, y) 永远 hash 出同样结果。但游戏只让玩家用 ZK 证明自己的星球存在 + 有效而不暴露坐标。
2. 三大核心电路
| 电路 | 功能 | 输入 | 输出 |
|---|---|---|---|
| init | 初始化星球 | (x, y) private | h = MiMC(x, y), level, type |
| move | 从 A 移动到 B | (xA, yA, xB, yB) private | hA, hB, distance |
| biomebase | 揭示 biome | (x, y) private | biomeBase = perlin-like |
每个电路保证「我知道一对坐标,hash 等于公开的 hash,并满足游戏规则」。
完整 init 电路源码(简化)
pragma circom 2.1.0;
include "circomlib/circuits/mimcsponge.circom";
include "circomlib/circuits/comparators.circom";
template Init(PLANETHASH_KEY, SPACETYPE_KEY, SCALE) {
signal input x; // private
signal input y; // private
signal output pub[3]; // [planetHash, perlin, distFromOrigin]
// 1. compute planetHash = MiMC(x, y, key)
component mimc = MiMCSponge(2, 220, 1);
mimc.ins[0] <== x;
mimc.ins[1] <== y;
mimc.k <== PLANETHASH_KEY;
pub[0] <== mimc.outs[0];
// 2. compute perlin (biome / spacetype)
// real version uses a multi-step deterministic perlin-like hash
component spaceMimc = MiMCSponge(2, 220, 1);
spaceMimc.ins[0] <== x;
spaceMimc.ins[1] <== y;
spaceMimc.k <== SPACETYPE_KEY;
pub[1] <== spaceMimc.outs[0];
// 3. distance from origin = x^2 + y^2 (no sqrt in ZK)
pub[2] <== x*x + y*y;
// 4. range check: |x|, |y| < 2^31 to prevent overflow
component xCheck = Num2Bits(32); // signed 32-bit
xCheck.in <== x + (1 << 31);
component yCheck = Num2Bits(32);
yCheck.in <== y + (1 << 31);
}
component main {public [pub]} = Init(/*HASH_KEY*/420, /*SPACE_KEY*/666, 4096);
move 电路(核心,简化)
template Move(PLANETHASH_KEY, MAX_DISTANCE) {
signal input x1, y1; // private from
signal input x2, y2; // private to
signal output pub[3]; // [hashFrom, hashTo, distSquared]
// 1. hashes
component h1 = MiMCSponge(2, 220, 1);
h1.ins[0] <== x1; h1.ins[1] <== y1;
h1.k <== PLANETHASH_KEY;
pub[0] <== h1.outs[0];
component h2 = MiMCSponge(2, 220, 1);
h2.ins[0] <== x2; h2.ins[1] <== y2;
h2.k <== PLANETHASH_KEY;
pub[1] <== h2.outs[0];
// 2. distance squared = (x2-x1)^2 + (y2-y1)^2
signal dx; dx <== x2 - x1;
signal dy; dy <== y2 - y1;
signal distSq;
distSq <== dx*dx + dy*dy;
pub[2] <== distSq;
// 3. distSq <= MAX_DISTANCE^2 (range proof)
component lt = LessEqThan(64);
lt.in[0] <== distSq;
lt.in[1] <== MAX_DISTANCE * MAX_DISTANCE;
lt.out === 1;
}
链上合约接收 (hashFrom, hashTo, distSq),验证 proof 后做:
- check
hashFromis owned bymsg.sender - transfer 一定量 silver/energy 从 hashFrom 到 hashTo
- 如果 hashTo 已有 owner,触发战斗结算(按 attack power vs defense)
真实游戏数据 / Real Game Data
Dark Forest 历届 round
| Round | 时间 | 玩家数 | 移动次数 | 总 gas |
|---|---|---|---|---|
| v0.5 | 2020-08 | ~500 | ~50k | ETH mainnet (有点疯) |
| v0.6 | 2021-04 | ~1k | ~200k | xDai (gas 低 + 速度快) |
| v0.6.4 | 2021-06 | ~3k | ~500k | xDai |
| v0.6.5 | 2022-01 | ~5k | ~1M | xDai |
后期 round 因 xDai gas 增加移动到 zkSync Lite / Optimism。
性能
| 操作 | Prove (浏览器) | Verify gas |
|---|---|---|
| init | ~3 sec | ~250k |
| move | ~5 sec | ~280k |
| biomebase | ~3 sec | ~250k |
约束数:
- init: ~5,000 (主要是 MiMCSponge × 2)
- move: ~10,000 (MiMCSponge × 2 + range check)
ZK 游戏的设计模式 / ZK Game Design Patterns
Pattern 1: Hidden state with revealable proof
「玩家知道 X,链上只有 Hash(X);玩家可以 ZK proof 关于 X 的属性」
- Dark Forest: 坐标
- Mafia/Werewolf: 角色
- Card game: 手牌
Pattern 2: Commit-reveal with ZK validation
「玩家先 commit Hash(action),后 reveal 时用 ZK 证明 action 满足规则」
- ZK Battleship: 攻击坐标
- ZK Poker: 出牌
Pattern 3: Procedural generation with private discovery
「世界是 deterministic 函数,玩家用 ZK 证明发现的内容是合法生成的」
- Dark Forest 地图
- Lattice's Sky Strife (部分)
Pattern 4: Anti-cheat via ZK
「玩家声称『我连续走了合法路径到这里』,用 ZK proof 证明」
- 移动验证 (Dark Forest move)
- DeFi-style 无信任结算
ZK 游戏的工程挑战 / Engineering Challenges
挑战 1:浏览器 prove 太慢
5 秒生成 move proof,对快节奏游戏不够。优化:
- WASM-based prover(snarkjs)
- Native compile via
circom --c - 后端代理 prover(牺牲信任)
- Plonky2 / 更快 backend
挑战 2:链上 verify gas 高
每个 move 280k gas,xDai 还能接受,主网会爆。Dark Forest 用 L2(zkSync Lite, Optimism)。新趋势:用 application-specific rollup。
挑战 3:地图同步
玩家本地需要扫描 (x, y) grid 找星球(perlin noise → 需要计算大量 hash)。Dark Forest 用 web worker + miner 后台扫描,但还是慢。
挑战 4:协作攻击
两玩家串通可以共享坐标信息。这不是 ZK 能解决的,是 game theory 问题。
衍生项目 / Successors
| 项目 | 创新点 | 状态 |
|---|---|---|
| MUD (Lattice) | ZK 游戏框架 + ECS | 主流框架 |
| Sky Strife | RTS on MUD | 上线 |
| Primodium | 太空 4X | 上线 |
| 0xPARC zkREPL | 浏览器 ZK 编程 | 工具 |
| Conquest.eth | DF 改进版 | 试运行 |
| Tarochi | RPG | 实验 |
0xPARC 的 "Autonomous Worlds" 哲学
0xPARC 提出「Autonomous Worlds」概念:
- 游戏规则完全在链上(不是「链下游戏 + 链上结算」)
- 任何人可以扩展(部署新合约 = 在世界中加新规则)
- ZK 让「不完全信息」成为可能 → 真正的策略游戏
参考 Ludens 文章:Autonomous Worlds (Part 1)
关键速查
Dark Forest 三大电路:
init — 创建星球
move — 移动 + 战斗
biomebase — 揭示 biome
Hash: MiMCSponge (220 rounds, 2 inputs)
约束: ~5k - 10k per circuit
Prove: 3-5 sec (browser, snarkjs)
Verify: ~250-280k gas (Groth16)
面试题
-
Q: 为什么 Dark Forest 用 MiMC 而不是 Poseidon? A: 历史原因——Dark Forest 2020 年开发时 Poseidon 在 Circom 还不流行,MiMC 是当时主流 ZK hash。MiMC 约束 ~220/hash 略多于 Poseidon-2 的 215,但单输入快(用于 biome perlin 计算)。新项目都用 Poseidon。
-
Q: ZK 游戏的「fog of war」是怎么实现的? A: 玩家 client 本地知道完整 (x, y);链上只存 hash。玩家提交 proof 时只暴露公开属性(distance, level)。其他玩家从链上事件看不到坐标,从而实现「迷雾」。
-
Q: 既然 ZK 让 hidden state 可能,为什么链上游戏发展慢? A: 三大瓶颈:(1) ZK prove 慢(5s/move 不适合快节奏);(2) gas 贵(即使 L2 也比 web2 慢且贵);(3) 工具链复杂。MUD 框架 + 更快 prover (Plonky3, RISC0) 在改善这些。
-
Q: Dark Forest 如何防止玩家提交假坐标? A: hash 在电路里强制
MiMC(x, y) === pub[0];玩家不能伪造 (x, y) 让 hash 等于别人的星球(hash 抗碰撞)。如果玩家提交「自己的 hash」但坐标其实是无效的(如出地图),距离/range 约束会失败。
明日预告
Day 234 — zk-Rollup 架构对比:Linea / zkSync Era / Scroll / Polygon zkEVM 横向对比,附真实合约地址、TVL、技术栈。