# OMNX Chain（omnx-1）· 分层隐私账本设计

> 状态：**设计稿**。本文件描述目标形态与分期实施边界，**尚未全部实现**。
> 改造完成前，链上不得导入任何真实业务数据。
> 本链为测试网，主网闸门保持关闭。

---

## 零、先看这个：一个必须先解决的根本冲突

当前链是 **EVM 账户模型**，而「隐藏单笔金额与 from/to」这件事在账户模型下**做不到**。原因：

```
node/chain.py:397      self.balances = {}          # addr -> 明文余额
node/evm_layer.py:124      return int(chain.balances.get(a, 0)) * WEI   # 直接读明文余额
node/evm_layer.py:293      if balance_wei(chain, sender) < total: ...   # 余额不足检查
```

账户模型下，`eth_getBalance` 必须返回一个确切数字；只要返回，余额就公开了；
而只要余额公开，**单笔转账金额可以被反推出来**（前后差一笔就知道）。
把 `value` 字段加密、却保留明文余额，等于没做隐私。

**所以隐私转账必须换成 note（钞票）模型**：余额不再是一行明文数字，而是「我持有哪些钞票」，
每张钞票只以承诺的形式上链。这与 EVM 账户模型**不兼容**——这正是本设计必须做双账本的原因。

---

## 一、分层可见性模型

按确认口径，数据分三层。**「公开聚合、隐私单笔」是核心原则**：

| 层 | 可见性 | 内容 | 谁来读 |
|---|---|---|---|
| **L0 公开透明** | 明文上链、任何人可读 | OMNX 总量、RWA 总发行量、底层资产储备、审计信息、资产池总额、总股本、标的信息、股权凭证哈希摘要、销毁总量、每块手续费总额、块高 | 浏览器、RPC、审计方、机构准入 |
| **L1 机密金额** | 只上承诺，链可验不可读 | 单笔转账金额、单笔手续费、单用户持仓数量 | 只有持密钥者能读 |
| **L2 完全遮蔽** | 密文上链 | 转账 from / to、单用户持股明细、单笔股权转让记录 | 只有持密钥者（及可选择披露的审计密钥）能读 |

关键点：**L1 的金额之所以能「链可验不可读」，靠的是 Pedersen 承诺的加法同态**——
链不需要知道金额，只要验证「输入之和 − 输出之和 − 手续费 = 0」这个等式在承诺上成立。

---

## 二、双账本架构

```
┌──────────────────────────────────────────────────────────────┐
│  透明账本（EVM 账户模型）—— 保持不变，承载 L0                 │
│   · 18 个系统合约、合约调用、eth_call / eth_sendRawTransaction │
│   · RWA 公开头：总量 / 储备 / 审计摘要 / 池总额                │
│   · 股权公开头：总股本 / 标的 / 凭证哈希摘要                   │
├──────────────────────────────────────────────────────────────┤
│  隐私账本（Note 模型）—— 新增，承载 L1 / L2                    │
│   · 每张 note = 承诺(owner, value, rho, r)                     │
│   · 花费时公开 nullifier（防双花），不公开 note 本身           │
│   · 金额与所有权以密文随交易附带，仅收款人可解                 │
├──────────────────────────────────────────────────────────────┤
│  跨层桥：shield / unshield                                     │
│   · shield  ：透明层 → 隐私层（金额在跨越瞬间公开一次）         │
│   · unshield：隐私层 → 透明层（同理）                          │
└──────────────────────────────────────────────────────────────┘
```

这个结构天然对上「分层」要求：**RWA 公开部分留在透明层，单笔用户明细进隐私层**。
桥接点是唯一会短暂暴露金额的位置，属于有意的设计取舍。

---

## 三、密码学构造

### 3.1 曲线与生成元（已实测）

用 `node/vendor/Crypto/PublicKey/ECC` 的 **P-256**。本机实测结论：

| 能力 | 实测结果 |
|---|---|
| 点加法 `P + Q` | ✅ 可用 |
| 标量乘 `k*P` | ✅ 可用（仅接受非负整数） |
| 同态 `a*G + b*G == (a+b)*G` | ✅ 成立 |
| 单位元表示 | `x == 0 and y == 0`（可判定） |
| 减法 | ❌ 无运算符 → 用 `P + Q*(n-1)` 等价实现 |
| 负标量 | ❌ 不支持 → 同上用 `n-1` 取反 |
| 点序列化 | ❌ 无 `export_key` → 手工拼 SEC1（`0x04‖x‖y`，65 字节），已验证可往返 |

第二个生成元 **H 必须与 G 无已知离散对数关系** —— 不能用 `H = h*G`（h 已知则承诺可伪造）。
需用 try-and-increment 的 hash-to-curve 自行构造。

### 3.2 Pedersen 承诺

```
C = v*H + r*G          v = 金额，r = 盲因子
```

- **隐藏性**：给定 C 无法求 v（离解困难 + r 随机）
- **绑定性**：找不到 (v', r') ≠ (v, r) 使承诺相同
- **加法同态**：`C(v1) + C(v2) = C(v1+v2)` —— 链能「盲验」守恒的基础

链上校验只需一次点运算：

```
sum(C_in) + C_fee  −  sum(C_out)  ==  单位元      （等价于 v_in = v_out + fee）
```

### 3.3 金额范围证明（**必需，已实现 —— `node/rangeproof.py`**）

⚠️ **最关键的安全缺口**：

同态校验只能保证「输入输出之差为零」，**不能阻止负数**。
若金额可为负，攻击者可构造 `+100` 与 `-100` 两个输出，凭空造币。

因此每个金额必须附带**范围证明**，证明 `v ∈ [0, 2^64)`。

| 方案 | 说明 | 判断 |
|---|---|---|
| 按位分解 + 批量 Chaum–Pedersen 或证明 | 与 Borromean 同源；纯 Python 可写，无需可信设置 | ✅ **已落地**（第 2 期） |
| Bulletproofs | 证明体积极小（约 674 B），实现复杂 | 后期压缩优化再考虑 |
| `ckzg`（vendor 已提供） | KZG 做范围证明 | 需可信设置文件，API 面向 EIP-4844 blob，适配成本高 |
| 仅审计方校验 | 链不验范围，靠审计密钥解密后人工核 | ❌ 不采纳：把防通胀降级成信任假设 |

已实现构造（`node/rangeproof.py`）：

```
1. v 拆成 bits 个比特：v = Σ b_i·2^i
2. 每个比特单独承诺 C_i = b_i·H + r_i·G，盲因子满足 Σ r_i·2^i = r
   → 于是 Σ 2^i·C_i == C，验证方 n 次点运算即可确认分解与 C 一致
3. 每个 C_i 做一次「二选一」或证明：
      Y_{i,0} = C_i        （比特 0）
      Y_{i,1} = C_i − H    （比特 1）
   谁手里有 r_i，谁就知道其中一个位置的离散对数
4. 所有比特共用一个全局挑战 e（批量版 Borromean），
   每个比特只公开一个位置的分挑战 e_{i,0}，另一个由 e − e_{i,0} 推出
```

验证两条缺一不可：

| 检查 | 作用 |
|---|---|
| `Σ 2^i·C_i == C` | 分解必须真的还原出链上承诺（防拼装） |
| 全局挑战闭链 `e == H(transcript)` | 每个比特确实要么是 0 要么是 1 |

**体积代价（诚实交代）**：64 位证明约 **10.4 KB**
（64 个比特承诺 4160 B + 1+3×64=193 个标量 6176 B），
生成约 280 ms、校验约 410 ms（本机 P-256，纯 Python）。
Bulletproofs 同强度约 674 B，但实现复杂度高出一个量级 ——
测试网阶段取「先正确、后压缩」，压缩列为后续优化项。

### 3.4 Note 与所有权

```
note      = (owner_pk, value, rho, r)
C         = value*H + r*G
nullifier = SHA3(owner_sk, rho)        # 花费时公开，防双花
```

链上维护已花费 nullifier 集合。花费时须同时给出：承诺 C（或 Merkle 路径）、nullifier、
以及**所有权证明**（证明知道 owner_sk 且 note 属于自己）——终态需 zk 证明。

> 阶段性替代：用签名验证代替 zk 所有权证明。**代价是发送方可被关联**，
> 属妥协方案，必须记录在案，不能当终态。

### 3.5 金额与地址的保密传输

用 ECDH 共享密钥 + AES-GCM 加密 note 内容，密文随交易上链（`enc_note` 字段）。
链与浏览器**无私钥，解不开** —— 正面满足「区块浏览器、RPC 节点均不可解密用户身份数据」。

---

## 四、原机制按隐私版重设计

### 4.1 手续费与分账

冲突：0.1% 底座费与 70/30 分账**都需要知道金额**。

- 每笔交易附带 `C_fee`，链上只验 `sum(C_in) − sum(C_out) − C_fee == 0`
- **单笔手续费不可见**；出块时链上累计出**该块手续费总额**（公开聚合，L0）
- 分账按**块级聚合值**执行：70% → 生态池，30% → `0x…0006` 生态金库
  —— 池子/金库之间的划转金额公开（属 L0），**单笔来源仍不可见**

既满足 70/30 可验证分账，又不暴露单笔用户明细。

### 4.2 质押折扣（三档）

冲突：折扣资格要判断「质押 ≥1万 / ≥5万 / ≥20万」，等于要读质押余额。

- 质押余额进入隐私层（note 形式）
- 资格用**范围证明**表达：「我的质押承诺对应金额 ≥ 50000」，只暴露落在哪一档
- 范围证明落地前的过渡：质押金额公开（质押是主动的公开承诺行为），
  但**用户身份仍匿名**。属阶段性方案，需明确标注

### 4.3 回购销毁

- 回购**总量**公开（符合「总量公开、可审计」）
- 每笔销毁 txhash 公开（已有要求，不变）
- 回购**资金来源**（底座 0.1% 收入、挂牌费、我方撮合手续费）走聚合值，不暴露单笔
- 销毁调用合约销毁接口打入黑洞地址；**无后门、不可恢复**这条保持

---

## 五、RWA 分层与股权扩展

### 5.1 RWA

| 部分 | 层 | 内容 |
|---|---|---|
| 公开头 | L0 | 资产总发行量、底层资产储备、审计信息、资产池总额 |
| 用户明细 | L1/L2 | 单笔认购/赎回的地址与金额、单用户持仓 |

现有 `node/modules_rwa.py` 已是「只上哈希、原始资料不上链」，方向一致，
只需补齐「用户明细进隐私层」。

### 5.2 股权类资产

| 部分 | 层 | 内容 |
|---|---|---|
| 公开头 | L0 | 总股本、标的信息、股权凭证哈希摘要 |
| 用户明细 | L1/L2 | 单用户持股数量、单笔股权转让记录 |

⚠️ 边界重申：**链上只做凭证存证与流转存证**，
确权的法律效力仍取决于线下工商登记等配套手续，链不替代法律程序。

---

## 六、KYC 与可选择披露

- KYC 是**链下独立系统**（含硬件 KYC），原始身份资料不上链
- 上链的只有**核验后的匿名凭证**：一个承诺 + 颁发者签名
- 交易时证明「我持有有效凭证」，不透露身份
- 防重复使用：凭证附带一次性 nullifier
- **可选择披露**：审计/监管方持独立 view key 才能解密指定交易；
  **节点、RPC 网关、区块浏览器都不持有该密钥**，因此无法解密 ——
  正面满足「均不可解密用户身份数据」

---

## 七、实施分期与当前边界

| 期 | 内容 | 状态 |
|---|---|---|
| 0 | 密码学底座（曲线封装、Pedersen 承诺、hash-to-curve、SEC1 编解码） | ✅ 完成 |
| 1 | note 结构、金额加密、nullifier 集合、守恒校验 | ✅ **引擎完成**（`node/notes.py` + 101 项自检）；链上状态接入未做 |
| 2 | **范围证明（防通胀）** | ✅ **完成**（`node/rangeproof.py` + 59 项自检） |
| 3 | 隐私层与透明层的 shield / unshield 桥 | ✅ **引擎完成**（同上）；**透明账本挂接已由 T3 打通**（见 `docs/隐私资金通道设计.md`） |
| 4 | 手续费聚合分账、质押折扣改造、回购销毁改造 | 未开始 |
| 5 | RWA / 股权分层落地 | 未开始 |
| 6 | 匿名凭证验证器与可选择披露 | 未开始 |
| 7 | 浏览器与 RPC 的分层呈现改造 | 未开始 |

### ✅ 已验证可用（`node/notes.py`）

| 能力 | 说明 |
|---|---|
| Merkle 稀疏树 | 零填充，深度 32；根与朴素全树实现在 5 种叶子数下逐一对照一致 |
| note 派生量 | `cm = SHA3(owner_pk ‖ cv ‖ rho ‖ memo_hash)`，把公开字段全部绑死 |
| nullifier | `nf = SHA3(owner_pk ‖ rho)`；同一张 note 只有唯一合法 nf |
| 所有权证明 | Schnorr 知识证明，转录绑定 nf 与 Merkle 根，跨交易不可重放 |
| shield / transfer / unshield | 三种操作全链路跑通，含多输入多输出与找零 |
| 攻击面矩阵 | 16 项：双花、偷换 cv、伪造 cm/nf、篡改路径、替换根、越权签名、篡改范围证明、篡改 txid、盲因子不配平、畸形输入……全部拒绝 |

**每一条篡改都断言了「具体哪一步拒绝」**，不是只看返回 False ——
否则容易被 txid 校验提前拦下而误判为某项检查生效（实测踩过这个坑）。

### ⚠️ 当前明确未实现（不得对外声称已具备）

- 链上交易仍是**完全明文**（`from` / `to` / `value`），与隐私要求相反
  —— 第 1/2/3 期完成的是**独立引擎**，一行都还没接进 `chain.py` / `rpc.py`
- 隐私账本目前是**内存态**：Merkle 树与 nullifier 集合没有任何持久化
- **发送方关联性未解决**：没有环签名、没有 zk-SNARK，花费时公开的
  `owner_pk` 是可关联的（note 密钥与账户地址解耦，缓解但不等于匿名）
- **手续费分账未接**：0.1% 底座费、70/30 分账、质押折扣、回购销毁
  仍走第 4 期的改造，本次未动
- 范围证明体积 10.4 KB / 张，链上带宽与存储代价未评估
- 因此「金额可被反推」这个事实**在链上仍然成立**
- 区块浏览器与 RPC 仍展示明文金额与地址

**第 2 期的意义是把「能不能防通胀」这个问题解决了；
但「链上是不是隐私的」在第 3 期（note 模型 + shield/unshield 上链）之前仍然是否定的。**

⚠️ 导入真实业务数据的闸门因此**仍未打开**。引擎已经跑通，但闸门条件现在是：

1. `notes.py` 接入 `chain.py` / `rpc.py`（链上状态 + 持久化）
2. 透明账本与隐私账本的挂接（shield/unshield 真正扣加余额）—— **已由 T3 完成（2026-09-25）**
3. 全量回归通过

**引擎完成 ≠ 链上隐私生效。** 在第 1 步落地之前，链上一切照旧是明文。
