Conformance
Conformance
Witness Circles is deliberately small so that a second implementation is realistic. This page states exactly what has to agree.
Three levels
Level 1: parser
Decodes Bitcoin transactions strictly and decodes the WITC marker. Reproduces the marker vectors, including all three rejections. Does not need prevouts, signatures or state.
Level 2: validator
Everything in level 1, plus the seventeen grammar rules, BIP341 key-path sighash, BIP340 verification and the fee allocation. Reproduces the golden transaction vector including txid, wtxid, fee, virtual size and lineage identifiers.
Level 3: indexer
Everything in level 2, plus the state snapshot, its ordering rules, the state hash, ordinary-spend closure and rollback. Reproduces every hash in the state lifecycle vector, forwards and in reverse.
The reference implementation in this repository is a level 3 implementation, and its own test suite runs the same checks that are demanded here.
What must agree, and what may differ
| Must agree exactly | May differ |
|---|---|
| The valid or invalid verdict on every input | Error message wording and language |
| The published error code for each invalid case | Exception type, error hierarchy, logging |
| txid, wtxid, weight and virtual size | Internal representation of amounts and scripts |
| Fee total and the per-slot fee shares | Whether shares are computed eagerly or lazily |
| Slot assignment after sorting | The sorting algorithm used |
| Lineage identifiers | How lineages are stored or cached |
| The state snapshot contents and the state hash | Database schema, indexes, replication, transport |
| Revision numbering across applies and rollbacks | Whether undo data is a journal, a log, or a snapshot store |
The state hash is the single strongest interoperability check. Two indexers that agree on it after every block agree on everything the protocol defines, because no implementation-specific field is allowed inside the hashed object.
Differential testing procedure
- Parse the raw transaction in
golden-circle.jsonwithout using this repository's SDK. - Load the three listed prevouts.
- Verify every BIP341 key-path signature.
- Reproduce the marker fields, fee shares, txid, wtxid, virtual size and lineage identifiers.
- Reject every invalid marker vector at the same semantic boundary, with the published code.
- Apply the three lifecycle transitions and compare each state hash.
- Roll back three times and compare each rollback root, ending at the empty-state hash.
- Publish your implementation language, version, parser digest and result.
Property-based testing is recommended beyond the fixtures: random participant counts from 2 to 16, random fee totals including values that are not divisible by N, values at the 1,000 sat successor boundary, and values at MAX_MONEY. The reference suite uses this approach and it is what catches remainder-assignment and overflow mistakes.
Self-declaration template
There is no certification body and no registry of implementations. Publish a declaration next to your source so that others can check it themselves.
Implementation: <name>
Language and runtime: <for example Rust 1.9x>
Specification version: 1.0.0
Conformance level: 1 | 2 | 3
Vector set: test-vectors/v1 at commit <40 hex sha>
Marker vectors: 1 valid accepted, 3 invalid rejected with matching codes
Golden circle vector: txid, wtxid, fee, vsize, lineage ids reproduced
Lifecycle vector: 3 transition hashes and 3 rollback roots reproduced
Signature verification: yes | no (no means level 1 only)
Networks supported: parse mainnet, testnet3, signet, regtest; create signet, regtest
Known divergences: <none, or an explicit list>
Changing a rule
The rules on this site are final for protocol version 0x01. New behaviour requires a new version byte with its own specification, threat model, schemas, cross-language vectors, activation policy and independent review. An implementation must never reinterpret finalized history under a later version, and an unknown version or operation is retained as an uninterpreted candidate rather than guessed at.
Within version 1, any change to a normative rule requires a vector that fails before the change and passes after it, plus an inverse invalid case where one applies. That is the only mechanism by which the meaning of a rule can move, and it always leaves an auditable artefact.