-
Notifications
You must be signed in to change notification settings - Fork 0
RDFC 1.0 Canonicalization
Underwrites Design Spec §4.8 (three-layer certification artifact: the transcript references hashes taken over canonical inputs) and the cross-cutting acceptance criteria X1 (Determinism) and X2 (Replay) in §9.A.5. Companion to Verifiable Self-Certification, Transcript Replay Semantics, and Lossless Roundtrip Definition.
RDFC-1.0 is the W3C Recommendation RDF Dataset Canonicalization 1.0 — a settled standard that defines, for any RDF dataset, a single canonical serialization to which all byte-equivalent graphs reduce. It fixes three things that vary in ordinary RDF: blank node labels, statement ordering, and serialized form. Once those are pinned, two parties holding "the same graph" — regardless of which Turtle, JSON-LD, or N-Quads file they loaded — compute the same bytes, and therefore the same hash.
flexo-rtm uses RDFC-1.0 as the identity function for its cert inputs. Every claim that the oracle makes about "what was certified" is anchored to a content-hash over the RDFC-1.0 canonical form of the scope-resolved graph. The hash algorithm itself is a suite parameter — read from the active cryptographic suite (W3C VC Data Integrity 2.0 sec:cryptosuite, or the multihash-style prefix on rtm:hasContentHash) rather than hardcoded. SHA-256 is the v0.1 default because it is the W3C Data Integrity 2.0 default for the ecdsa-rdfc-2019 and eddsa-rdfc-2022 cryptosuites and aligned with cosign and OCI image-signature defaults; the choice is suite-driven, not hardwired. See ADR-026 Cryptographic Agility via Algorithm Profiles. Without canonicalization, the oracle's hashes would describe one party's serialization choice, not the underlying RDF.
The recommendation defines an algorithm (often abbreviated URDNA2015, later URDNA2017, and standardized as RDFC-1.0) that takes an RDF dataset as input and produces:
- Canonical blank node identifiers. Blank nodes have no globally stable name. RDFC-1.0 relabels them deterministically, using a hash-based fixed-point computation over the local structure each blank node participates in. Isomorphic graphs end up with identical labels regardless of input labeling.
- Canonical statement ordering. N-Quads lines are sorted lexicographically after canonical labeling, producing a unique byte sequence.
- Canonical serialization. Output is N-Quads with one statement per line, canonical lexical forms for literals, and explicit datatype/language tags as required by the N-Quads specification.
The output is a deterministic byte stream. Hashing that stream (using the active suite's content-hash algorithm — SHA-256 by default per §4.9 of the Design Spec and per the VC-DI 2.0 ecdsa-rdfc-2019 / eddsa-rdfc-2022 cryptosuites; see ADR-026 Cryptographic Agility via Algorithm Profiles) gives the input-hash that the transcript records.
- Hash-based equivalence. The transcript records input-hash + result-hash per SPARQL/SHACL step. Two graphs with the same input-hash are guaranteed RDF-equivalent (modulo blank node renaming) — independent of who serialized them, in what order, with which prefixes.
- Reproducibility across implementations. Conformant RDFC-1.0 implementations produce identical output. A verifier may use a different RDF stack than the certifier and still confirm byte-identical hashes.
- Settled spec. RDFC-1.0 is a published W3C Recommendation, not a moving target. We pin the recommendation, not a vendor's API. The previous URDNA2015 drafts converged into this normative form, so legacy interop is well-understood.
- No proprietary surface. Pure-Python implementations satisfy acceptance criterion X4 (no proprietary deps) in Design Spec §9.A.5.
Take a fragment with blank nodes:
_:a rtm:satisfies :Req1 .
_:a rtm:approvedBy <urn:approver:alice> .
_:b rtm:satisfies :Req2 .
Re-serialize with different blank node labels (_:x, _:y) and different statement order — RDFC-1.0 produces the same canonical N-Quads, because each blank node's canonical label is derived from its connection pattern (which predicates and objects it touches), not from the label the author happened to type.
For literals, RDFC-1.0 requires canonical lexical forms per XSD: "01"^^xsd:integer and "1"^^xsd:integer denote the same value, but only the canonical lexical form ("1") appears in canonical output. Authors should produce canonical lexical forms upstream; otherwise canonicalization will surface the difference as a hash divergence.
Three usage sites in the codebase, each enforcing a different acceptance criterion from §9.A.5:
- At cert time — the scope-resolved graph (Scope IRI → union of named graphs → SPARQL/SHACL inputs) is canonicalized; the content-hash of the canonical form (algorithm fixed by the active suite; SHA-256 by default — see ADR-026 Cryptographic Agility via Algorithm Profiles) becomes the input-hash recorded in the transcript. This pins exactly which graph the oracle saw. Enforces X1: same canonical input → byte-identical transcript across runs, machines, and times.
- At verify time — the verifier canonicalizes their copy of the input, compares to the transcript's input-hash. Equal hashes ⇒ same input ⇒ replaying the recorded SPARQL/SHACL steps must produce byte-identical result hashes. Unequal hashes ⇒ the verifier and certifier are not looking at the same RDF, and the divergence is named explicitly. Enforces X2: canonical input-hash + transcript replays identically.
- At roundtrip — when a Lossless Roundtrip Definition check runs, the parsed input is canonicalized and the re-serialized output is canonicalized; the two canonical forms are compared byte-for-byte. Any drift (lost triples, datatype coercion, namespace mangling) shows up as a hash divergence.
rdflib exposes RDFC-1.0 via its Graph.serialize(format='application/n-quads') path combined with the canonicalization helper, currently labeled experimental in rdflib.compare / rdflib.graph (specifically to_canonical_graph). The mature alternative is pyld, which ships a normalization API rooted in URDNA2015 and aligned with RDFC-1.0. A custom implementation against the W3C test suite is also viable for environments needing tighter control.
The decision is to pin one implementation in pyproject.toml and gate it behind a stable interface (flexo_rtm.canon.canonicalize(dataset) -> bytes). The choice is recorded in the transcript's reproducibility manifest, so verifiers know which implementation produced the recorded hashes. Switching implementations is a major version bump on the cert artifact format.
-
Blank node cycles. RDFC-1.0's hash-based labeling iterates to a fixed point even when blank nodes participate in cycles. No special handling required from
flexo-rtm; we rely on the implementation being conformant. - Large-graph performance. Canonicalization scales worse than linearly with blank node count (it is essentially graph isomorphism over the blank node subgraph). For very large datasets, canonicalization is the dominant cert-time cost. Mitigation: cache canonical forms keyed by upstream content hash, so unchanged graphs skip re-canonicalization.
-
Datatype literal canonical forms. RDFC-1.0 does not normalize literal values — it only sorts and labels. Authors are responsible for canonical XSD lexical forms upstream (
"true"not"1"forxsd:boolean, normalized form forxsd:decimal, etc.). The roundtrip check catches non-canonical lexical forms as divergences and surfaces them as fixable warnings rather than silent re-writes. - Language tags vs. datatypes. N-Quads serialization is precise about which appears; we follow the spec and reject malformed inputs at the parser, before canonicalization.
flexo-rtm's canonicalization tests use the official W3C RDFC-1.0 test suite as the conformance baseline — vendored at a pinned commit and re-run against every release. Beyond the W3C suite, project-local fixtures cover the edge cases above (cyclic blank nodes drawn from real cert artifacts, large-graph performance benchmarks against representative scope-resolved graphs, and round-trip fixtures for each datatype flexo-rtm emits).
- Verifiable Self-Certification — RDFC-1.0 is the "canonical inputs" component of verifiability
- Transcript Replay Semantics — replay compares hashes taken over RDFC-1.0 canonical forms
- Lossless Roundtrip Definition — roundtrip is defined as canonical-form equality
- Design Spec §4.8 (three-layer artifact), §4.9 (RDF-internal reproducibility), §9.A.5 X1 / X2
- Flexo Git Coexistence
- ADCS Prototype Lessons
- MVC Pattern from RIME TRL ANT
- Human-AI Accountability
- Multi-Agent Discourse Graph Precedent
- OSLC RM and QM Review
- INCOSE V2 Review
- OMG SysMLv2
- PROV EARL GSN P-PLAN
- Dragon Architecture and Mission Enterprise
- Traditional Forward and Backward Analysis
- Attestation Infrastructure in v0.1
- Identity Boundaries and Policy Projections
- External URI References
- Signed Envelopes and Established Standards
- Aspect Coverage with Adequacy and Sufficiency
- Federated Audit and Composition
- Certification Predicate
- Gap Taxonomy
- Quantitative Outcomes
- Engineering Lifecycle Stages (v0.2)
- Topological Framework Future Work (research phase)
- Vertices Edges Faces (research phase)
- Three-Layer Architecture
- Operational Layer UX Discipline
- Storage Layer Flexo Conventions
- Analysis Layer Scope Algebra
- OSLC Roundtrip Acceptance
- Identity Adapter Contract
- Flexo REST Binding
- SysMLv2 Ingestion Contract
- External URI Rules
- Signed Envelope Shapes
- Parsimony Manifest
- Lossless Roundtrip Definition
- Vendor Extension Carry-Through
- OSLC RM Adapter Contract
- OSLC QM Adapter Contract
- ADR Template
- ADR-001 Foundations First Approach
- ADR-002 SysMLv2 Anchoring
- ADR-003 Topological Framework Documented as Future Work
- ADR-003a v0.1 Ships Traditional Analysis Only
- ADR-004 Quantitative Certification Outcome
- ADR-005 Adequacy and Sufficiency as Guidance Subtypes
- ADR-006 Three-Layer Architecture
- ADR-007 Scope as First-Class RDF Resource
- ADR-008 Repo Name and Org Transfer Plan
- ADR-009 Two-Repo Strategy
- ADR-010 OSLC-RM and OSLC-QM in v0.1
- ADR-011 Lossless Criterion A plus C
- ADR-012 Direct RDF Properties over Reified Edges
- ADR-013 Simplicial Complex as Derived View When Built
- ADR-014 Parsimony Layer Build-Time Extraction
- ADR-015 GSN Adoption for Adequacy and Sufficiency
- ADR-016 Composable SHACL Profiles
- ADR-017 knowledgecomplex as Optional Extras
- ADR-018 V minus F Invariant Deferred with Topological Framework
- ADR-019 Derived Binary View from Quantitative Metrics
- ADR-020 Vocabulary Alignment with Zargham 2026
- ADR-021 Three Attestation Subclasses Ship in v0.1
- ADR-022 External URI References as Open-Source Foundation
- ADR-023 Cryptography by Composition of Battle-Tested Standards
- ADR-024 Identity by Thin Projection of External Sources
- ADR-025 Reproducibility is Structural and Local
- ADR-026 Cryptographic Agility via Algorithm Profiles
- ADR-027 Bit-Exactness vs Numerical Tolerances Are Both First-Class
- ADR-028 Scope-Level Adequacy and Sufficiency for Federated Audit
- ADR-029 Engineering Lifecycle Stages as Scope Metadata
- ADR-030 Polycentric ASOT Authority Model
- ADR-031 Attestation Status Pass Fail Deferred Deprecated
- ADR-032 Methodology Agnosticism as Foundational Axiom
- ADR-033 Generalized ASOT Principle for All Identified Things