Normative

Witness Circles specification

Version 1.0.0. Protocol magic WITC, protocol version byte 0x01, operation CIRCLE (0x01). This page mirrors SPECIFICATION.md in the owning repository, which is the source of truth if the two ever differ.

The key words MUST, MUST NOT, REQUIRED, SHALL, SHALL NOT, SHOULD, SHOULD NOT, RECOMMENDED, NOT RECOMMENDED, MAY and OPTIONAL are interpreted as described by RFC 2119 and RFC 8174 when written in uppercase.

1. Claim boundary

A valid Circle establishes only that distinct native P2TR output keys authorized the exact transaction under Bitcoin's Taproot key-path signature rules.

A compliant application MUST NOT present a Circle as proof of human identity or personhood, attendance or physical presence, friendship, membership, endorsement or legal agreement, one key per person, or ownership before or after any period not established by the indexed UTXO history.

2. Layers

  1. Bitcoin consensus determines whether the transaction and its inputs are valid in the best chain.
  2. Relay and miner policy determine whether an unconfirmed transaction propagates or is mined.
  3. This specification identifies and validates WITC events from Bitcoin data.
  4. Optional context manifests describe a Circle but never affect its Bitcoin validity after their hash is committed.
  5. Profiles, aliases, renderers, invitations, notifications, moderation and analytics are application services, not protocol truth.

3. Network identifiers

ByteNetworkCreation enabled
0x00Bitcoin mainnetNo
0x01Bitcoin testnet3No
0x02Bitcoin SignetYes
0x03Bitcoin regtestYes

Other values are invalid for the protocol. The marker network MUST match the chain being indexed. All four identifiers are parseable so that independent tools can classify data without enabling creation or broadcast; the reference planner and marker encoder reject mainnet and testnet3 with INVALID_NETWORK.

4. Marker

Output index 0 MUST have value zero and this exact script:

OP_RETURN PUSH40 <40-byte payload>

The byte serialization is 6a 28 <payload>, so the complete scriptPubKey is exactly 42 bytes.

OffsetSizeFieldValue
04MagicASCII WITC (57495443)
41Protocol version0x01
51Network identifier0x00 to 0x03
61Operation0x01 CIRCLE
71Participant count N2 to 16 inclusive
832Context hashSHA-256 of the serialized context manifest, never all zero

PUSHDATA1, larger pushes, extra opcodes, trailing bytes, alternate magic casing and zero-valued context hashes are invalid. Only operation 0x01 CIRCLE is valid in the protocol. Reserved values, including potential refuel or rekey operations, MUST be rejected rather than guessed.

Worked example. The marker of the published Signet vector is 6a285749544301020103ad2608134839e732280cb93bdd5b8682626dce5748a65c437a39cdcb680c2a82: 6a OP_RETURN, 28 push 40 bytes, 57495443 WITC, 01 version, 02 Signet, 01 CIRCLE, 03 three participants, then the 32 byte context hash. You can take it apart yourself in the marker decoder.

5. Context manifest

The context manifest is a JSON object serialized with RFC 8785 (JCS) and committed as:

context_hash = SHA256(UTF8(JCS(manifest)))

Required fields are protocol, version, kind, nonce, title, created and expires. Optional fields are orbit, host, media, description, renderer and aliases. The context manifest schema defines their structure.

  • expires applies to the invitation only. It does not expire a confirmed Circle.
  • Unknown manifest fields are rejected by the reference validator.
  • A manifest MAY remain private or disappear. Its absence MUST NOT invalidate a matching on-chain Circle.
  • Aliases are untrusted labels. Applications MUST escape them and MUST NOT interpret them as identities.

Schema string limits count Unicode code points, matching JSON Schema 2020-12. Every string MUST contain well-formed Unicode without unpaired surrogates, and MUST be unchanged by the ECMAScript TrimString operation used by String.prototype.trim, so leading or trailing ECMAScript whitespace is invalid. RFC 8785 preserves string code points without Unicode normalization. created and expires MUST be real RFC 3339 UTC timestamps ending in Z, and expires MUST be later than created. Alias keys MUST be 32 bytes of lowercase hex and MUST be unique within the manifest. These semantic rules are enforced by the reference validator in addition to the published structural schema.

6. Transaction grammar

A valid Circle MUST satisfy every rule below. The reference validator in src/validator.ts raises the named error code on the first rule that fails.

  1. nVersion is 2.
  2. nLockTime is 0.
  3. Every input nSequence is 0xfffffffd.
  4. There are exactly N inputs and N + 1 outputs, where N is the participant count in the marker.
  5. Every input prevout is confirmed in a lower block height than the Circle transaction.
  6. Every input prevout is a native P2TR output with script OP_1 PUSH32 <output-key>.
  7. Every input outpoint is unique.
  8. Every input scriptPubKey is unique within the Circle.
  9. Inputs are strictly ordered by their 32-byte lowercase display txid bytes, then by unsigned numeric vout.
  10. Output 0 is the exact marker described in section 4.
  11. Output i + 1 has the exact scriptPubKey of input i.
  12. Output i + 1 is at least 1,000 sats.
  13. No other output exists.
  14. Every input uses native Taproot key-path witness data with exactly one stack item.
  15. The witness item is either a 64-byte BIP340 signature using SIGHASH_DEFAULT, or a 65-byte signature whose final byte is exactly SIGHASH_ALL (0x01).
  16. Script-path witnesses, annexes, ANYONECANPAY, NONE, SINGLE, empty witnesses and other sighash bytes are invalid for a confirmed Circle.
  17. Every signature MUST verify against the P2TR output key and the BIP341 key-path message for its input.

The same script successor preserves key continuity. It does not create a covenant: the controller can spend the successor in any consensus-valid transaction.

Anatomy of a Circle transaction with three participants On the left, three confirmed Taproot inputs sorted by display txid. In the middle, the transaction. On the right, output zero is a zero value OP_RETURN carrying the forty byte WITC marker, and outputs one to three return each participant's coin to the same output key minus an equal share of the miner fee. Inputs (sorted, N = 3) Outputs (N + 1 = 4) 1111…1111:0 P2TR, 30,000 sats 2222…2222:1 P2TR, 40,000 sats 3333…3333:2 P2TR, 50,000 sats nVersion 2 nLockTime 0 nSequence 0xfffffffd every input signs every input and output 363 vB at 10 sat/vB fee 3,630 sats vout 0 value 0 OP_RETURN PUSH40 marker vout 1 28,790 sats same key as input 0 vout 2 38,790 sats same key as input 1 vout 3 48,790 sats same key as input 2 Output i + 1 always carries the exact scriptPubKey of input i. Key continuity is preserved without a covenant: the controller can spend the successor in any consensus-valid transaction. Values are the published golden Signet vector in test-vectors/v1/golden-circle.json.
Anatomy of the golden three participant Circle. Every value shown is taken from the committed test vector, not from an illustration.

7. Fees and size

The miner fee is split as evenly as integer arithmetic allows, with the remainder assigned to the lowest slots. Let F be the total fee and N the participant count:

F = sum(input_values) - sum(outputs_1_through_N)
q = floor(F / N)
r = F mod N

fee_share(i) = q + 1 when i < r, otherwise q
successor_value(i) = input_value(i) - fee_share(i)

The output values MUST match this calculation exactly; a mismatch is OUTPUT_MAPPING. The protocol defines no maximum fee. Wallets MUST enforce signer-selected absolute and fee-rate caps before signing.

For 64-byte default signatures:

weight = 246 + 402N
vbytes = ceil((246 + 402N) / 4)

Explicit SIGHASH_ALL adds one witness byte per such input. Sizes for every legal participant count are tabulated in the reference.

8. Lineages and shards

For a valid Circle input that is not the current shard of an existing lineage:

lineage_id = SHA256(
  UTF8("WITC/lineage/v1") || wire_serialized_genesis_outpoint
)

The outpoint uses Bitcoin wire form: reversed display txid bytes followed by the four-byte little-endian vout.

Each Circle creates one successor shard for each lineage. A valid later Circle can spend a current shard and create its next same-script successor. Multiple lineages participate together but never merge ownership or value.

A consensus-valid transaction that spends an active shard without satisfying every Circle rule closes that lineage. The Bitcoin is not burned by the protocol. Historical Circles remain part of the best-chain record.

The protocol has no transfer, split, merge, rekey, refuel, mint, market, burn, reward, governance or administrative operation.

9. Confirmation and mempool

Mempool observations are provisional and node-local. An indexer MAY expose pending valid candidates, conflicts, replacements and eviction, but MUST keep these projections separate from confirmed authoritative state.

A Circle becomes authoritative at one confirmation in the best chain. Applications MAY label six confirmations as settled display state, but this is not an additional protocol transition.

The transaction signals opt-in RBF. Any replacement needs new signatures from every participant, because signatures commit to all inputs and outputs. A compliant product MUST NOT promise CPFP, cancellation after broadcast, or successful relay.

10. Reorganizations

An indexer MUST store block hashes and sufficient undo information. When the indexed tip no longer matches Bitcoin Core, it MUST reverse confirmed transitions in reverse transaction order until the common ancestor, then ingest the new branch in the order transactions appear in each block.

Invalid candidate fields MUST NOT apply a Circle transition. A confirmed transaction that spends an active shard but is not a valid Circle still closes that lineage as an ordinary spend. This includes a transaction that ceases to be a valid Circle after parser correction under the parser version selected for replay.

11. Determinism and state

CompactSize integers MUST be minimally encoded. Numeric calculations MUST use checked integer arithmetic. Transaction values MUST NOT exceed Bitcoin MAX_MONEY.

Independent implementations MUST reproduce the committed test vectors. Error strings may differ, but the published error codes and the valid or invalid result must agree.

The authoritative confirmed-state snapshot is the exact object defined by the state snapshot schema. revision starts at zero and increments once for each confirmed transaction that either applies a valid Circle or closes at least one active lineage through an ordinary spend. It does not increment for unrelated transactions, or for invalid candidates that close no active lineage. Rollback restores the prior revision.

Every JSON numeric field in the snapshot MUST be a nonnegative ECMAScript safe integer, except circleCount, which MUST also be at least one. Every display outpoint MUST use lowercase txid hex and an exact decimal vout from 0 through 4294967295. Every satoshi string MUST be an exact unsigned decimal from zero through Bitcoin MAX_MONEY, with no leading zero.

Before hashing, implementations MUST order lowercase ASCII fields as follows:

  • lineages by lineageId.
  • shards by the complete display outpoint string, using ordinal byte order.
  • circles by blockHeight, then transactionIndex, then txid.
  • Each Circle's members by numeric slot.
  • edges by toCircle, then lineageId.

No implementation-specific database fields may enter this snapshot. The authoritative state hash is SHA256(UTF8(RFC8785(snapshot))), with no prefix and no trailing newline. The empty-state hash is 90e749b7720fac379610d979e29998c7d650150548622f0a47d9d3e181f1be52. The golden transaction vector commits the first-transition state hash and block envelope. The state-lifecycle vector then commits a continuation, an ordinary-spend closure and each reverse rollback root, so independent indexers can reproduce the complete lifecycle exactly.

12. Upgrade policy

New protocol behaviour requires a new version byte, a specification, a threat model, schemas, cross-language vectors, an activation policy and independent implementation review. Implementations MUST NOT reinterpret finalized protocol history under a later version.

Unknown versions and operations MAY be retained as uninterpreted candidates, but MUST NOT apply their version-specific transitions to authoritative state. If such a transaction spends an active shard, the lineage still closes under the ordinary-spend rule in section 8.

13. Wallet requirements

Before signing, a wallet MUST independently verify every rule in section 6 plus:

  • The owned outpoint appears exactly once.
  • The displayed context serializes under RFC 8785 to the marker hash.
  • The owned successor and its exact fee share are visible.
  • Total fee and fee rate are within user-approved caps.
  • No global xpub, peer derivation path, or unnecessary proprietary PSBT field is disclosed.
  • The frozen unsigned transaction matches the invitation fingerprint.

The signer-specific PSBT SHOULD contain witness_utxo for every input. Only the owner's input SHOULD include its Taproot key origin data. Contributions SHOULD return a non-finalized PSBT_IN_TAP_KEY_SIG, and the coordinator MUST verify each contribution before merge.

14. Error codes

These are the stable codes exported by src/errors.ts. Implementations may use different messages, but a conforming implementation must reach the same valid or invalid verdict and should report the same code.

CodeRaised when
AMBIGUOUS_ENCODINGA non-minimal encoding was used: PUSHDATA1 for the marker, a non-minimal CompactSize, or a superfluous SegWit marker and flag.
CONTEXT_HASH_ZEROThe 32-byte context hash in the marker payload is all zero.
DUPLICATE_INPUTThe same outpoint appears twice as an input, or twice in the validation context.
DUPLICATE_LINEAGEOne lineage would appear twice in the same Circle.
DUPLICATE_SCRIPTTwo participants presented the same P2TR output key.
FEE_CAP_EXCEEDEDA signer-selected fee share, total fee or fee rate cap would be exceeded.
FEE_NEGATIVEOutputs exceed inputs, or a negative fee was supplied to the allocator.
INPUT_COUNTThe participant count is outside 2 to 16, or does not equal the input count.
INPUT_ORDERInputs are not strictly sorted by display txid then vout.
INPUT_PREVOUT_MISSINGThe validation context does not contain exactly one prevout per input.
INPUT_UNCONFIRMEDAn input prevout is not confirmed in an earlier block.
INTEGER_RANGEA value is outside its declared range, including Bitcoin MAX_MONEY and CompactSize limits.
INVALID_CONTEXT_MANIFESTThe context manifest failed structural or semantic validation.
INVALID_HEXHex input is malformed or has the wrong length.
INVALID_MARKERThe marker script is not exactly 42 bytes, or its magic is not WITC.
INVALID_NETWORKThe network identifier is unknown, does not match the indexed chain, or creation was attempted outside Signet and regtest.
INVALID_OPCODEThe operation byte is not 0x01 CIRCLE.
INVALID_OUTPOINTAn outpoint is malformed or its vout is outside uint32.
INVALID_P2TRAn input or successor script is not native P2TR, or a scriptSig is not empty.
INVALID_SIGNATUREA BIP340 key-path signature failed verification.
INVALID_STATEA state snapshot, transition or rollback violated a structural state invariant.
INVALID_TRANSACTIONThe transaction is truncated, exceeds decoder limits, or is otherwise unparseable.
INVALID_VERSIONThe protocol version byte is not 0x01, or a vector schema version is unsupported.
LOCK_TIMEnLockTime is not zero.
MARKER_VALUEThe marker output value is not zero.
NON_CANONICAL_JSONJSON text is not in RFC 8785 form.
OUTPUT_COUNTThe output count is not N + 1, or the marker output is missing.
OUTPUT_MAPPINGA successor script or value does not match the deterministic mapping for its slot.
PREVOUT_HEIGHTA prevout block height or the current block height is invalid.
SEQUENCEAn input sequence is not 0xfffffffd.
SUCCESSOR_DUSTA successor output is below 1,000 sats.
SIGHASH_UNSAFEA sighash byte other than SIGHASH_DEFAULT or explicit SIGHASH_ALL was used.
TRANSACTION_VERSIONnVersion is not 2.
TRAILING_DATAThe raw transaction contains bytes after the locktime.
UNSUPPORTED_OPERATIONA reserved or future operation was encountered where only CIRCLE is valid.
WITNESS_SHAPEThe witness does not carry exactly one item of 64 or 65 bytes, or an unsigned candidate carried witness data.

15. Reference status

This repository is a reference implementation, not Bitcoin consensus software. Bitcoin Core remains authoritative for Bitcoin validity and local policy acceptance. Applications SHOULD call testmempoolaccept immediately before broadcast.