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 exactlyMay differ
The valid or invalid verdict on every inputError message wording and language
The published error code for each invalid caseException type, error hierarchy, logging
txid, wtxid, weight and virtual sizeInternal representation of amounts and scripts
Fee total and the per-slot fee sharesWhether shares are computed eagerly or lazily
Slot assignment after sortingThe sorting algorithm used
Lineage identifiersHow lineages are stored or cached
The state snapshot contents and the state hashDatabase schema, indexes, replication, transport
Revision numbering across applies and rollbacksWhether 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

  1. Parse the raw transaction in golden-circle.json without using this repository's SDK.
  2. Load the three listed prevouts.
  3. Verify every BIP341 key-path signature.
  4. Reproduce the marker fields, fee shares, txid, wtxid, virtual size and lineage identifiers.
  5. Reject every invalid marker vector at the same semantic boundary, with the published code.
  6. Apply the three lifecycle transitions and compare each state hash.
  7. Roll back three times and compare each rollback root, ending at the empty-state hash.
  8. 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.