kylemaps/veriseal
GitHub: kylemaps/veriseal
一款对机器人/自动驾驶 MCAP 日志进行 Ed25519 签名和 Bitcoin 时间戳锚定的防篡改封装与独立验证工具。
Stars: 0 | Forks: 0
# veriseal
专为需要在事后证明机器人/自主驾驶日志未被篡改的事故调查员和安全团队打造。
这是一个 CLI 工具,它使用 Ed25519 签名和 Bitcoin 时间戳 (OpenTimestamps) 对机器人/自主驾驶日志 (MCAP) 进行封装,并生成一个 `.seal.json` 清单。无关第三方随后可以证明“此日志与由密钥 K 创建、并在时间 T 锚定的时间戳封装记录相符”——但前提是验证者**固定了签名者的公钥** (`--pubkey`)。如果不固定公钥,使用新密钥篡改并重新封装的日志依然能通过验证。


## 安装
```
pip install git+https://github.com/kylemaps/veriseal
```
或者用于开发:
```
git clone https://github.com/kylemaps/veriseal.git
cd veriseal
pip install -e .
```
## 快速开始
```
# 封装日志(生成新的密钥;默认将 Merkle root 提交到 OpenTimestamps)
veriseal seal log.mcap --out log.seal.json
# 不使用 OpenTimestamps 进行封装 — 快速,完全离线
veriseal seal log.mcap --no-anchor --out log.seal.json
# 验证完整性(警告:如果不使用 --pubkey,嵌入的密钥将被无条件信任)
veriseal verify log.mcap log.seal.json
# INTACT — 签名有效,198 条消息,root 9bfe72f8a52c5ad5...
# 警告:未提供 --pubkey:信任嵌入在 manifest 中的密钥;...
# 验证并固定签名者的密钥 — 唯一能检测篡改重新封装的方法
veriseal verify log.mcap log.seal.json --pubkey signer.pub.pem
# INTACT — 签名有效,198 条消息,root 9bfe72f8a52c5ad5...
# 篡改检测 — 在副本中翻转一个字节并重新验证
python -c "
d = bytearray(open('log.mcap', 'rb').read())
d[1024] ^= 0xFF
open('tampered.mcap', 'wb').write(bytes(d))
"
veriseal verify tampered.mcap log.seal.json --pubkey signer.pub.pem
# TAMPERED
# Source digest 不匹配
# 预期 9bfe72f8a52c5ad5...
# 实际 0816a35ad0908c74...
# Merkle root 不匹配
# 预期 9bfe72f8a52c5ad5...
# 实际 3f4a2b1c8e9d6f7a...
# MODIFIED topic='/pose' log_time=1750032000000000000
# 检查事件的 incident 时间窗口(ISO-8601 或自 epoch 以来的纳秒数)
veriseal inspect log.mcap \
--from 2025-06-16T00:00:01Z \
--to 2025-06-16T00:00:04Z \
--topic /pose
# 将时间窗口导出为新的 MCAP(可在 Foxglove Studio 中打开)
veriseal inspect log.mcap \
--from 2025-06-16T00:00:01Z \
--to 2025-06-16T00:00:04Z \
--out incident.mcap
```
### OpenTimestamps 锚点
默认情况下,`veriseal seal` 会将已签名的 Merkle root 提交到公共 Bitcoin 日历服务器 ([OpenTimestamps](https://opentimestamps.org))。内嵌的证明初始状态为 `status: "pending"`,一旦 Bitcoin 区块包含该 Merkle 路径(大约 1 小时后),状态就会变为 `"confirmed"`。
`veriseal verify` 会报告锚点状态作为**信息参考** —— 除非设置了 `--require-anchor`,否则 INTACT/TAMPERED 的验证结果和退出代码不会受锚点状态的影响:
```
INTACT — signature valid, 198 messages, root 9bfe72f8a52c5ad5...
Anchor: pending (not yet Bitcoin-confirmed)
```
在离线工作流或 CI 中跳过锚定:
```
veriseal seal log.mcap --no-anchor
```
要求有效的锚点(在审计流水线中非常有用):
```
veriseal verify log.mcap log.seal.json --pubkey signer.pub.pem --require-anchor
```
### ROS 1 rosbags
veriseal 封装的是 MCAP;它不直接读取 ROS 1 的 `.bag` 文件。请先进行转换,然后再封装 —— 详见 [docs/ros1.md](docs/ros1.md)。
## 威胁模型
**它能证明什么:** 此日志与由密钥 K 在时间 T 创建的封装记录相符。“独立可验证”需要两个条件:(1) 验证者知道并固定了签名者的公钥 (`--pubkey`);(2) 锚点是可信的。如果没有 `--pubkey`,使用新密钥篡改并重新封装的日志依然能通过验证。如果没有锚点,时间声明仅仅依赖于封装者的单方面主张。
**它不能证明什么:** 日志是捕获时刻物理真实情况的真实记录。封装操作无法复原被伪造的数据。完整性 ≠ 真实性。
**中立性的真正来源:** 尽可能早地进行封装(最好在捕获时或接近捕获时),并将 root 锚定到公共的仅追加日志中,这样任何单方(包括托管者)都无法将其倒填日期或篡改。封装时间越接近捕获时间且锚点越公开,证据的“中立性”就越强。
## 工作原理
1. **Hash** — 每个 MCAP 消息都经过域分离并进行 SHA-256 哈希处理:`SHA-256(b"\x00" + b"veriseal-leaf-v1\x00" + len(topic) + topic + log_time + payload)`。
2. **Merkle tree** — 叶子节点按 `(log_time, topic, leaf_hash)` 排序,并使用 [RFC 6962](https://www.rfc-editor.org/rfc/rfc6962) 二进制 Merkle Tree Hash 算法进行组合。任何单字节的更改都会改变 root;通过叶子节点的差异可以精准定位受影响的 (topic, log_time) 组。
3. **Sign** — 清单(root + 所有叶子节点 + 元数据)被序列化为规范化的 JSON,并使用 Ed25519 进行签名。签名者的公钥会内嵌在清单中。
4. **Anchor** — 已签名的清单经过 SHA-256 哈希处理,并提交给 [OpenTimestamps](https://opentimestamps.org) 公共日历。随后的 Bitcoin 区块会对其进行确认,从而提供一个任何单方(包括封装者)都无法倒签日期的去信任时间戳。
`.seal.json` 格式在 **[SPEC-manifest.md](SPEC-manifest.md)** 中有完整记录 —— 一个合规的验证器只需要该文档、MCAP 以及标准加密库。
## 架构
```
seal ingest MCAP → hash every message → RFC 6962 Merkle tree →
sign manifest (Ed25519) → anchor root (OpenTimestamps/Bitcoin) → *.seal.json
verify recompute Merkle tree from MCAP → check signature → compare roots →
INTACT or TAMPERED (locate modified/added/removed messages)
informational: anchor status (pending / confirmed / invalid)
optional: --pubkey to pin the signer's key, --require-anchor to enforce anchor
inspect filter MCAP to time window → print chronological event timeline →
export window as incident.mcap (openable in Foxglove Studio)
```
## 运行演示
```
cd demo
python make_sample.py # generates sample.mcap (synthetic AV log, ~198 msgs)
bash demo.sh # seal → verify INTACT → tamper → verify TAMPERED → inspect
```
使用 [VHS](https://github.com/charmbracelet/vhs) 录制 `demo.gif`(需要 Docker):
```
docker build -f Dockerfile.vhs -t veriseal-vhs .
docker run --rm -v "$(pwd):/vhs" veriseal-vhs demo/demo.tape
```
## 路线图
- **v0.1:** 对 MCAP 进行封装 / 验证 / 检查 + OpenTimestamps 锚点
- **v0.2:** 监管链日志;RFC 3161 + Sigstore/Rekor 选项;ROS 2 bag 导入;HTML 报告
- **v0.3:** Web 查看器;封装守护进程;可插拔的透明度日志后端
## 许可证
Apache-2.0 © Kyle Mapue
标签:CVE, Python, Zenmap, 区块链时间戳, 数字签名, 数据完整性, 无后门, 机器人日志, 逆向工具, 防篡改