src/pqc_content_provenance/assertions/base.py
963 B · 36 lines · python Raw
1 """Assertion base class -- pluggable claims about content."""
2
3 from __future__ import annotations
4
5 import hashlib
6 import json
7 from dataclasses import asdict, dataclass
8 from typing import Any, ClassVar
9
10
11 @dataclass
12 class Assertion:
13 """Base class for provenance assertions (C2PA-style claim facts)."""
14
15 label: ClassVar[str] = "c2pa.generic"
16
17 def to_dict(self) -> dict[str, Any]:
18 d = asdict(self)
19 d["label"] = self.label
20 return d
21
22 @classmethod
23 def from_dict(cls, data: dict[str, Any]) -> Assertion:
24 d = dict(data)
25 d.pop("label", None)
26 return cls(**d)
27
28 def canonical_bytes(self) -> bytes:
29 """Deterministic serialization used for hashing assertions."""
30 return json.dumps(
31 self.to_dict(), sort_keys=True, separators=(",", ":"), ensure_ascii=False
32 ).encode("utf-8")
33
34 def hash(self) -> str:
35 return hashlib.sha3_256(self.canonical_bytes()).hexdigest()
36