|
| 1 | +# Anchor Predicates |
| 2 | + |
| 3 | +## BCR-2026-004 |
| 4 | + |
| 5 | +**© 2026 Blockchain Commons** |
| 6 | + |
| 7 | +Authors: Christopher Allen<br/> |
| 8 | +Date: February 2, 2026 |
| 9 | + |
| 10 | +--- |
| 11 | + |
| 12 | +## Abstract |
| 13 | + |
| 14 | +This document specifies Known Value predicates for anchoring assertions to cryptographic event logs in Gordian Envelopes. These predicates enable independent attestation that an assertion exists, providing verifiable proof of existence and ordering without implying consent or approval. |
| 15 | + |
| 16 | +These predicates are proposed for the **core registry** (codepoints 87-93), as they represent fundamental cryptographic infrastructure for envelopes. |
| 17 | + |
| 18 | +## Status: Core Registry Proposal |
| 19 | + |
| 20 | +This BCR proposes additions to the **Blockchain Commons Core Registry** (codepoints 0-99) as defined in [BCR-2023-002](https://github.com/BlockchainCommons/Research/blob/master/papers/bcr-2023-002-known-value.md). |
| 21 | + |
| 22 | +### Placement Rationale |
| 23 | + |
| 24 | +The proposed codepoints (87-93) follow the XID Privileges range (70-86), which ends with `Revoke` (86). This placement is logical because: |
| 25 | +- Anchoring is cryptographic infrastructure, like XID operations |
| 26 | +- Both anchoring and revocation deal with assertion state management |
| 27 | +- The 87-100 range is currently unassigned |
| 28 | + |
| 29 | +### Request for Community Review |
| 30 | + |
| 31 | +We invite feedback on: |
| 32 | +- Whether these predicates belong in the core registry |
| 33 | +- Whether the proposed codepoint assignments are appropriate |
| 34 | +- Any conflicts with existing or planned predicates |
| 35 | +- Suggested refinements to predicate definitions |
| 36 | + |
| 37 | +Please submit feedback via: |
| 38 | +- [Gordian Developer Community Discussions](https://github.com/BlockchainCommons/Gordian-Developer-Community/discussions) |
| 39 | +- Pull requests to this specification |
| 40 | + |
| 41 | +## Introduction |
| 42 | + |
| 43 | +### Problem Statement |
| 44 | + |
| 45 | +Assertions in Gordian Envelopes may need independent attestation that they exist at a particular point in time. This is distinct from: |
| 46 | +- **Signing** — which implies consent or authorship |
| 47 | +- **Witnessing** (human) — which implies observation of events |
| 48 | + |
| 49 | +Cryptographic event logs (as in Certificate Transparency, Key Transparency, and CEL) provide append-only structures where independent parties can attest to having observed an assertion, without implying approval. |
| 50 | + |
| 51 | +### Terminology Distinction |
| 52 | + |
| 53 | +The term "witness" is overloaded: |
| 54 | +- **Fair Witness** (human attestation) — a neutral party observing and attesting to facts |
| 55 | +- **Cryptographic witness** — an entity anchoring assertions to a log |
| 56 | + |
| 57 | +This BCR uses **anchor** terminology to avoid confusion with human witnessing concepts. |
| 58 | + |
| 59 | +### Solution |
| 60 | + |
| 61 | +This specification defines predicates for cryptographic log anchoring: |
| 62 | + |
| 63 | +| Predicate | Purpose | |
| 64 | +|-----------|---------| |
| 65 | +| `anchoredBy` | Who anchored the assertion | |
| 66 | +| `anchors` | What assertion is anchored | |
| 67 | +| `anchoredAt` | When it was anchored | |
| 68 | +| `anchorHash` | Cryptographic binding | |
| 69 | +| `anchorLog` | Which log contains the anchor | |
| 70 | + |
| 71 | +Optional extensions for multi-anchor scenarios: |
| 72 | +| Predicate | Purpose | |
| 73 | +|-----------|---------| |
| 74 | +| `anchorQuorum` | Minimum anchors required | |
| 75 | +| `anchorIndex` | Position in log | |
| 76 | + |
| 77 | +### Inference Source |
| 78 | + |
| 79 | +These predicates are derived from concepts in: |
| 80 | +- [Cryptographic Event Logs (CEL)](https://digitalbazaar.github.io/cel-spec/) |
| 81 | +- Certificate Transparency (RFC 6962) |
| 82 | +- Key Transparency systems |
| 83 | + |
| 84 | +## Terminology |
| 85 | + |
| 86 | +**Anchor**: A cryptographic attestation that an assertion exists in a log, without implying consent or approval. |
| 87 | + |
| 88 | +**Anchor Assertion**: An envelope asserting that another assertion has been anchored to a log. |
| 89 | + |
| 90 | +**Event Log**: An append-only, cryptographically verifiable data structure (e.g., Merkle tree). |
| 91 | + |
| 92 | +**Checkpoint**: A signed summary of log state at a point in time. |
| 93 | + |
| 94 | +## Proposed Known Value Assignments |
| 95 | + |
| 96 | +All proposed codepoints are in the **Core Registry** range (0-99). |
| 97 | + |
| 98 | +### Anchor Predicates (87-93) |
| 99 | + |
| 100 | +--- |
| 101 | + |
| 102 | +#### 87: `anchoredBy` |
| 103 | + |
| 104 | +**Type**: property |
| 105 | +**Definition**: Identifies the entity that anchored an assertion to a cryptographic event log. |
| 106 | +**Domain**: Any assertion |
| 107 | +**Range**: XID, DID, or URI identifying the anchoring entity |
| 108 | +**Usage**: Declares which entity provided the anchor attestation. |
| 109 | + |
| 110 | +``` |
| 111 | +{ |
| 112 | + CID(my-assertion) [ |
| 113 | + 'anchoredBy': XID(log-operator) |
| 114 | + 'anchoredAt': 2026-02-02T12:00:00Z |
| 115 | + ] |
| 116 | +} |
| 117 | +``` |
| 118 | + |
| 119 | +**Notes**: |
| 120 | +- Anchoring is attestation of existence, not consent or approval |
| 121 | +- Multiple `anchoredBy` assertions may exist for the same assertion (different anchors) |
| 122 | + |
| 123 | +--- |
| 124 | + |
| 125 | +#### 88: `anchors` |
| 126 | + |
| 127 | +**Type**: property |
| 128 | +**Definition**: References the assertion that is being anchored. |
| 129 | +**Domain**: Anchor assertion |
| 130 | +**Range**: CID or URI of the anchored assertion |
| 131 | +**Usage**: Establishes an explicit, verifiable link between an anchor assertion and the assertion it attests to. |
| 132 | + |
| 133 | +``` |
| 134 | +{ |
| 135 | + CID(anchor-assertion) [ |
| 136 | + 'anchors': CID(original-assertion) |
| 137 | + 'anchoredBy': XID(log-operator) |
| 138 | + 'anchorHash': "sha256:abc123..." |
| 139 | + ] |
| 140 | +} |
| 141 | +``` |
| 142 | + |
| 143 | +--- |
| 144 | + |
| 145 | +#### 89: `anchoredAt` |
| 146 | + |
| 147 | +**Type**: property |
| 148 | +**Definition**: The time at which the assertion was anchored to the log. |
| 149 | +**Domain**: Anchor assertion |
| 150 | +**Range**: xsd:dateTime (ISO 8601) |
| 151 | +**Usage**: Supports temporal ordering, auditability, and equivocation detection. |
| 152 | + |
| 153 | +**Notes**: |
| 154 | +- This is when the anchor was created, not when the original assertion was created |
| 155 | +- Use `date` (16) or `validFrom` (21) for the original assertion's timestamp |
| 156 | + |
| 157 | +--- |
| 158 | + |
| 159 | +#### 90: `anchorHash` |
| 160 | + |
| 161 | +**Type**: property |
| 162 | +**Definition**: A cryptographic hash of the canonical form of the assertion being anchored. |
| 163 | +**Domain**: Anchor assertion |
| 164 | +**Range**: Multihash or hash string |
| 165 | +**Usage**: Cryptographically binds the anchor to a specific assertion representation. |
| 166 | + |
| 167 | +``` |
| 168 | +{ |
| 169 | + CID(anchor-assertion) [ |
| 170 | + 'anchors': CID(original-assertion) |
| 171 | + 'anchorHash': "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" |
| 172 | + ] |
| 173 | +} |
| 174 | +``` |
| 175 | + |
| 176 | +**Notes**: |
| 177 | +- Enables verification that the anchored content hasn't changed |
| 178 | +- Should use the canonical envelope hash |
| 179 | + |
| 180 | +--- |
| 181 | + |
| 182 | +#### 91: `anchorLog` |
| 183 | + |
| 184 | +**Type**: property |
| 185 | +**Definition**: Identifies the cryptographic event log in which the assertion was anchored. |
| 186 | +**Domain**: Anchor assertion |
| 187 | +**Range**: URI identifying the log |
| 188 | +**Usage**: Enables cross-log comparison and detection of inconsistent log views. |
| 189 | + |
| 190 | +``` |
| 191 | +{ |
| 192 | + CID(anchor-assertion) [ |
| 193 | + 'anchors': CID(original-assertion) |
| 194 | + 'anchorLog': "https://log.example.com/v1" |
| 195 | + ] |
| 196 | +} |
| 197 | +``` |
| 198 | + |
| 199 | +--- |
| 200 | + |
| 201 | +#### 92: `anchorQuorum` |
| 202 | + |
| 203 | +**Type**: property |
| 204 | +**Definition**: Specifies the minimum number of distinct anchors required for an assertion to satisfy anchoring requirements. |
| 205 | +**Domain**: Any assertion |
| 206 | +**Range**: Integer or policy expression |
| 207 | +**Usage**: Expresses governance or trust thresholds independently of verification. |
| 208 | + |
| 209 | +``` |
| 210 | +{ |
| 211 | + CID(high-value-assertion) [ |
| 212 | + 'anchorQuorum': 3 |
| 213 | + ] |
| 214 | +} |
| 215 | +``` |
| 216 | + |
| 217 | +**Notes**: |
| 218 | +- This is a policy declaration, not a verification mechanism |
| 219 | +- Verification of quorum satisfaction is application-specific |
| 220 | + |
| 221 | +--- |
| 222 | + |
| 223 | +#### 93: `anchorIndex` |
| 224 | + |
| 225 | +**Type**: property |
| 226 | +**Definition**: The index or position of the anchored assertion in the log. |
| 227 | +**Domain**: Anchor assertion |
| 228 | +**Range**: Integer |
| 229 | +**Usage**: Supports detection of log equivocation and inconsistent ordering claims. |
| 230 | + |
| 231 | +``` |
| 232 | +{ |
| 233 | + CID(anchor-assertion) [ |
| 234 | + 'anchors': CID(original-assertion) |
| 235 | + 'anchorLog': "https://log.example.com/v1" |
| 236 | + 'anchorIndex': 12345 |
| 237 | + ] |
| 238 | +} |
| 239 | +``` |
| 240 | + |
| 241 | +--- |
| 242 | + |
| 243 | +## Usage Patterns |
| 244 | + |
| 245 | +### Basic Anchoring |
| 246 | + |
| 247 | +``` |
| 248 | +{ |
| 249 | + CID(anchor-assertion) [ |
| 250 | + 'anchors': CID(original-document) |
| 251 | + 'anchoredBy': XID(transparency-log) |
| 252 | + 'anchoredAt': 2026-02-02T12:00:00Z |
| 253 | + 'anchorHash': "sha256:..." |
| 254 | + 'anchorLog': "https://log.example.com/v1" |
| 255 | + ] |
| 256 | +} |
| 257 | +``` |
| 258 | + |
| 259 | +### Multiple Anchors (Quorum) |
| 260 | + |
| 261 | +``` |
| 262 | +{ |
| 263 | + CID(important-assertion) [ |
| 264 | + 'anchorQuorum': 2 |
| 265 | + ] |
| 266 | +} |
| 267 | +
|
| 268 | +// Anchor 1 |
| 269 | +{ |
| 270 | + CID(anchor-1) [ |
| 271 | + 'anchors': CID(important-assertion) |
| 272 | + 'anchoredBy': XID(log-operator-a) |
| 273 | + ] |
| 274 | +} |
| 275 | +
|
| 276 | +// Anchor 2 |
| 277 | +{ |
| 278 | + CID(anchor-2) [ |
| 279 | + 'anchors': CID(important-assertion) |
| 280 | + 'anchoredBy': XID(log-operator-b) |
| 281 | + ] |
| 282 | +} |
| 283 | +``` |
| 284 | + |
| 285 | +### Anchor with Revocation |
| 286 | + |
| 287 | +Using `supersedes` from BCR-2026-005 (General Assertions): |
| 288 | + |
| 289 | +``` |
| 290 | +{ |
| 291 | + CID(revocation-anchor) [ |
| 292 | + 'anchors': CID(revoked-assertion) |
| 293 | + 'supersedes': CID(original-anchor) |
| 294 | + 'anchoredBy': XID(log-operator) |
| 295 | + ] |
| 296 | +} |
| 297 | +``` |
| 298 | + |
| 299 | +## Relationship to Other Predicates |
| 300 | + |
| 301 | +### Core Registry |
| 302 | + |
| 303 | +| Codepoint | Predicate | Relationship | |
| 304 | +|-----------|-----------|--------------| |
| 305 | +| 21 | `validFrom` | Use for assertion validity, not anchor time | |
| 306 | +| 22 | `validUntil` | Use for assertion expiry | |
| 307 | +| 86 | `Revoke` | XID key revocation (different from assertion supersession) | |
| 308 | + |
| 309 | +### BCR-2026-005 (General Assertions) |
| 310 | + |
| 311 | +| Predicate | Usage with Anchors | |
| 312 | +|-----------|-------------------| |
| 313 | +| `supersedes` | Anchor revocation/updates | |
| 314 | +| `revocationReason` | Why an anchor was superseded | |
| 315 | + |
| 316 | +## Security Considerations |
| 317 | + |
| 318 | +### Anchoring vs. Signing |
| 319 | + |
| 320 | +Anchoring attests to **existence**, not **approval**. An anchor assertion means "I observed this assertion in my log view" — it does not mean "I agree with this assertion" or "I authorize this assertion." |
| 321 | + |
| 322 | +### Log Trust |
| 323 | + |
| 324 | +Relying parties must evaluate: |
| 325 | +- Whether they trust the log operator (`anchoredBy`) |
| 326 | +- Whether the log itself is trustworthy (`anchorLog`) |
| 327 | +- Whether sufficient anchors exist (`anchorQuorum`) |
| 328 | + |
| 329 | +### Equivocation Detection |
| 330 | + |
| 331 | +The `anchorIndex` predicate supports detection of log equivocation — where a log operator presents different views to different parties. Cross-log comparison using `anchorLog` and `anchorIndex` can reveal inconsistencies. |
| 332 | + |
| 333 | +### Hash Binding |
| 334 | + |
| 335 | +The `anchorHash` provides cryptographic binding between the anchor and the anchored content. Verifiers should confirm that the hash matches the canonical form of the referenced assertion. |
| 336 | + |
| 337 | +## Open Questions |
| 338 | + |
| 339 | +### Relationship to Provenance Marks |
| 340 | + |
| 341 | +[BCR-2025-001: Provenance Marks](https://github.com/BlockchainCommons/Research/blob/master/papers/bcr-2025-001-provenance-mark.md) provides a powerful mechanism for **self-sovereign, permissionless provenance** through forward-commit chains. Provenance Marks: |
| 342 | + |
| 343 | +- Require no external infrastructure — they are self-proving |
| 344 | +- Enable permissionless operation — no log operators needed |
| 345 | +- Use forward commits to establish temporal ordering |
| 346 | +- Create cryptographic chains within a document series |
| 347 | + |
| 348 | +Anchor predicates address a **different use case**: external attestation by independent parties. They are useful when: |
| 349 | + |
| 350 | +- Third-party attestation is required (regulatory, compliance) |
| 351 | +- Cross-organization verification is needed |
| 352 | +- Independent witnesses add trust beyond self-attestation |
| 353 | +- Integration with existing transparency log infrastructure is desired |
| 354 | + |
| 355 | +| Aspect | Provenance Marks | Anchor Predicates | |
| 356 | +|--------|------------------|-------------------| |
| 357 | +| Infrastructure | None required (self-sovereign) | Requires log operators | |
| 358 | +| Permission model | Permissionless | Depends on log access | |
| 359 | +| Proof type | Forward-commit chain | External attestation | |
| 360 | +| Trust model | Self-proving sequence | Independent witnesses | |
| 361 | +| Primary use | Document series integrity | Cross-party attestation | |
| 362 | + |
| 363 | +**These mechanisms are independent**: Anchor predicates can be used without Provenance Marks, and Provenance Marks work without external anchoring. They may also be **complementary** — external anchors could potentially strengthen Provenance Mark chains for high-assurance scenarios. |
| 364 | + |
| 365 | +**Questions for community review:** |
| 366 | + |
| 367 | +1. When both mechanisms are used together, what is the recommended pattern? |
| 368 | +2. Should external anchors reference Provenance Mark chain hashes, or individual assertions? |
| 369 | +3. Are there use cases where one mechanism clearly subsumes the other? |
| 370 | + |
| 371 | +We invite feedback on how these specifications should interoperate. See also the [Provenance Mark developer documentation](https://developer.blockchaincommons.com/provemark/). |
| 372 | + |
| 373 | +## References |
| 374 | + |
| 375 | +- [BCR-2023-002: Known Value Registry](https://github.com/BlockchainCommons/Research/blob/master/papers/bcr-2023-002-known-value.md) |
| 376 | +- [Cryptographic Event Logs (CEL)](https://github.com/w3c-ccg/cel-spec) |
| 377 | +- [Certificate Transparency (RFC 6962)](https://datatracker.ietf.org/doc/html/rfc6962) |
| 378 | +- [Gordian Envelope Specification](https://github.com/BlockchainCommons/Research/blob/master/papers/bcr-2024-001-envelope.md) |
| 379 | +- [BCR-2025-001: Provenance Marks](https://github.com/BlockchainCommons/Research/blob/master/papers/bcr-2025-001-provenance-mark.md) |
| 380 | + |
| 381 | +## Related BCRs |
| 382 | + |
| 383 | +- **BCR-2026-005: General Assertion Predicates** — `supersedes` for anchor updates |
| 384 | +- **BCR-2026-007: Principal Authority Predicates** — Authority relationships |
| 385 | + |
| 386 | +--- |
| 387 | + |
| 388 | +*BCR-2026-004: Anchor Predicates* |
| 389 | +*Draft - February 2, 2026* |
0 commit comments