87 lines
2.9 KiB
Python
87 lines
2.9 KiB
Python
# ============================================================
|
||
# 完整 Merkle 树黄金测试(plan.md §3.6 / 矩阵「全审计」剩余项)
|
||
# 覆盖:确定性、顺序/数量/内容敏感、成员证明校验、篡改检测、导出携带根。
|
||
# ============================================================
|
||
from __future__ import annotations
|
||
|
||
import copy
|
||
import hashlib
|
||
import json
|
||
|
||
from server.agent_core.audit_export import export_events
|
||
from server.agent_core.audit_ledger import GENESIS_ROOT
|
||
from server.agent_core.audit_merkle import (
|
||
_leaf_hash,
|
||
merkle_proof,
|
||
merkle_root,
|
||
verify_proof,
|
||
)
|
||
|
||
|
||
def _events(n: int = 5) -> list[dict]:
|
||
out: list[dict] = []
|
||
prev = "GENESIS"
|
||
for i in range(n):
|
||
ev = {"id": i + 1, "action": f"action-{i}", "prevHash": prev}
|
||
prev = hashlib.sha256((prev + json.dumps(ev, sort_keys=True)).encode()).hexdigest()
|
||
ev["hash"] = prev
|
||
out.append(ev)
|
||
return out
|
||
|
||
|
||
def test_merkle_root_deterministic_and_sensitive():
|
||
"""Merkle 根:同事件同根;空树=创世根;顺序/数量/内容变化均断根。"""
|
||
evs = _events()
|
||
assert merkle_root(evs) == merkle_root(evs)
|
||
assert merkle_root([]) == GENESIS_ROOT
|
||
assert merkle_root(evs) != merkle_root(list(reversed(evs)))
|
||
assert merkle_root(evs) != merkle_root(evs[:-1])
|
||
tampered = copy.deepcopy(evs)
|
||
tampered[2]["hash"] = "0" * 64
|
||
assert merkle_root(evs) != merkle_root(tampered)
|
||
|
||
|
||
def test_merkle_proof_every_index_verifies():
|
||
"""成员证明:每个事件都能给出 O(log n) proof 且 verify_proof 通过。"""
|
||
evs = _events(8)
|
||
root = merkle_root(evs)
|
||
for i in range(len(evs)):
|
||
proof = merkle_proof(evs, i)
|
||
assert proof["root"] == root
|
||
assert verify_proof(root, _leaf_hash(evs[i]), proof) is True
|
||
# sibling 数应等于树高(8 叶 → 3 层)
|
||
assert len(proof["siblings"]) >= 2
|
||
|
||
|
||
def test_merkle_proof_rejects_wrong_leaf():
|
||
"""错误叶子无法通过证明校验(防伪造成员)。"""
|
||
evs = _events(6)
|
||
root = merkle_root(evs)
|
||
proof = merkle_proof(evs, 1)
|
||
other_leaf = _leaf_hash(evs[4])
|
||
assert verify_proof(root, other_leaf, proof) is False
|
||
|
||
|
||
def test_merkle_proof_out_of_range():
|
||
"""越界索引返回错误,不抛异常。"""
|
||
evs = _events(3)
|
||
assert merkle_proof(evs, -1)["error"]
|
||
assert merkle_proof(evs, 99)["error"]
|
||
|
||
|
||
def test_merkle_single_and_empty():
|
||
"""单事件/空事件边界:根互异且可复算。"""
|
||
one = _events(1)
|
||
root1 = merkle_root(one)
|
||
assert root1 != GENESIS_ROOT
|
||
assert merkle_root(_events(1)) == root1
|
||
proof = merkle_proof(one, 0)
|
||
assert verify_proof(root1, _leaf_hash(one[0]), proof) is True
|
||
|
||
|
||
def test_export_json_carries_merkle_root():
|
||
"""合规导出 JSON 携带 merkleRoot,且与本地复算一致。"""
|
||
evs = _events(4)
|
||
payload = json.loads(export_events(evs, fmt="json"))
|
||
assert payload["merkleRoot"] == merkle_root(evs)
|