antrixy/toon-diff
GitHub: antrixy/toon-diff
toon-diff 通过跨实现的 N×N 差异化交叉编解码测试,发现 TOON 格式各语言实现之间单实现一致性测试无法察觉的静默往返数据损坏问题。
Stars: 0 | Forks: 0
# toon-diff
一个用于 [TOON](https://github.com/toon-format/spec)
(Token-Oriented Object Notation)实现的差异化一致性测试工具。
TOON 承诺**无损**往返:`JSON → TOON → JSON` 应当返回你初始输入
的内容。目前已存在 25+ 种语言的独立实现。该工具
通过将数据经过一个实现的 encoder 和*不同*实现的 decoder 进行处理,并验证往返过程是否成功,以此来检查它们是否真正达成共识。
```
decode_Y( encode_X( value ) ) == value for every ordered pair (X, Y)
```
它**不是**一个 fixtures/conformance 测试套件(即根据预先指定的预期输出来检查单一实现)。
它是在 fixture 未预料到的输入上,将各个实现*相互之间*进行对比检查——而这正是隐藏无声分歧的地方。
## 为什么它能发现一致性测试套件遗漏的问题
每个实现对其*自身*的输出都能很好地完成往返,因此单实现
测试看起来一切正常(绿灯)。Bug 往往存在于不同实现之间的边界处,并且
通常是**无声的**——数据错误却没有抛出任何错误。从首次针对
两个已发布实现的实际运行中,就发现了两个此类 Bug:
| 案例 | 发生了什么 | 已向上游提交 |
|---|---|---|
| 整数 `2^53 + 1` | TS 路径无声地将 `9007199254740993` 舍入为 `…992`;而 Python 则保留了它。每一方都能正常往返自身的值;只有交叉测试才会暴露这种精度丢失 | 规范 §2 允许在*有文档说明*的情况下对超出范围的数字进行精度丢失——目前仍在追踪中,尚未提交 |
| 空数组 `[]` | TS 编码为 `[]`(非规范);Python 的 decoder 返回字符串 `'['`,丢掉了一个字符;规范格式应为 `[0]:`。每个 decoder 读取自身 encoder 的输出时都没问题 | encoder: [toon#322](https://github.com/toon-format/toon/issues/322) · decoder: [toon-python#61](https://github.com/toon-format/toon-python/issues/61) |
两者都是**无声的数据损坏**——这是该项目的主线。一个
没有任何信号就向下游流动的错误值,比直接抛出的错误更危险,
而这正是差异化交叉解码所能暴露的问题,也是同实现
测试所无法发现的。
# 预言机是难点所在
一个简单的比较器在比较数字时本身就会损坏数据(原生的 `JSON.parse`
会将 `2^53+1` 舍入),并且会在最重要的案例上报告错误的 PASS(通过)。
这里的预言机:
- 在**精确的源词法单元**(ES2023 `ctx.source`)级别摄取数字,绝不会
经过 `f64`,因此任意精度的整数能够安全通过比较;
- 按**值**进行比较(`1.0 == 1`,`-0 == 0`),并具备精确的整数精度
(`2^53+1 != 2^53`);
- 是**类型严格**的(`"123" != 123`),对数组顺序敏感,能够区分
缺失键和显式 null,并且**不**应用任何 Unicode 规范化
(`e + U+0301 != U+00E9`)。
在任何跨实现比较运行之前,它会通过自测
(`oracle/selftest-numbers.ts`)证明自身独立于任何 TOON 实现。
## 布局
```
cli-v2.ts # runs the N×N differential matrix over the corpus
oracle/
ingest.ts # v2 lossless number-faithful ingestion + canonical compare
compare.ts # v1 comparator + ingestionFidelity (used for the v1-vs-v2 note)
canonicalize.ts # v1 canonical form (key sort, type-strict equality)
selftest.ts # proves the v1 oracle
selftest-numbers.ts # proves the v2 oracle, no implementation needed
adapters/
contract.ts # one text-in/text-out protocol per implementation
ts.ts # @toon-format/toon (reference TS/JS)
python.ts # toon_format (official Python)
probe/cases/ # 13 hand-designed cases targeting known fault lines
```
添加一个实现只需要一个 `Adapter`(文本输入,文本输出)。更多
具有不同数字/字符串模型的实现 = 能发现更多分歧;
TS (f64)、Python (任意精度 int) 和 Rust (i64/u64/f64) 涵盖了三种
截然不同的数字模型,而这正是往返 Bug 集中爆发的地方。
## 运行
```
npm install @toon-format/toon
pip install git+https://github.com/toon-format/toon-python.git # use a venv
npm pkg set type=module
node --experimental-strip-types oracle/selftest-numbers.ts # prove the oracle
node --experimental-strip-types cli-v2.ts # run the matrix
```
## 状态
早期阶段。语料库由 13 个手动设计的探针组成,尚未成为生成式 fuzzer;
路线图是计划开发一个基于变异且带有 input 缩减功能的生成器,并增加 Rust 及其他
adapters。发现的问题已向各个独立的实现上游提交
([toon#322](https://github.com/toon-format/toon/issues/322),
[toon-python#61](https://github.com/toon-format/toon-python/issues/61))。
## License
MIT — 见 [LICENSE](./LICENSE)。
标签:MITM代理, TOON, Zenmap, 一致性测试, 差分测试, 数据完整性, 数据序列化, 暗色界面, 测试工具, 自动化攻击, 逆向工具