Interactive

Pair check

Supply two candidate halves and watch the rules run. This page implements the marker grammar and pairing rules from tandem.md directly, names the numbered rule behind every check, and reports the exact stable reason code a real parser would emit. It then tests itself against the repository's published vectors so you can see it is not lying to you.

Protocol finalized. Mainnet is not active.

Before you paste anything

Every check on this page runs in your browser. Nothing you type is sent anywhere, and there is no form submission, no analytics, and no third-party script. The page's content security policy restricts connections to this origin, and the only request it makes is a read of vectors/generated/golden.json from this same site, used for the self test at the bottom.

This is a protocol inspection tool. It does not build, sign, or broadcast Bitcoin transactions, and it never asks for a private key. Paste public keys and marker scripts only.

The main tool

Do these two records form a pair?

Paste a marker script into each side. Side A is the predecessor, side B is the proposed successor. Each half is first checked on its own, then the two are checked against each other. A half that is malformed can never pair, and two well-formed halves can still fail to belong together.

Record pair

Accepts a full marker script starting with 6a, or a bare payload starting with 544e444d.

The record that already exists on chain.

    The record that claims to follow it.

      AWAITING INPUT A B

      Paste a marker into each side, or load the published vectors below.

        How to read a failure

        Every failing line names the rule it enforces and the stable reason a conforming parser emits. Those reasons are not advisory labels. Rule INV-3 requires an implementation to return the lowest failing code, so if you are writing tests, the reason shown for the first structural failure is the one your implementation must produce.

        What each kind of mismatch means
        SymptomRuleReason emitted
        Non-minimal push, wrong payload length, trailing bytesREC-6BAD_MARKER_ENCODING_OR_LENGTH
        Marker format byte other than 0x01REC-7UNKNOWN_MARKER_FORMAT
        Network byte disagrees between the halvesID-3WRONG_NETWORK
        Namespace field disagrees between the halvesID-5WRONG_NAMESPACE
        Successor sequence is not predecessor plus onePAIR-5BAD_STATE_SEQUENCE
        Successor claims to follow a terminal recordST-3PREDECESSOR_NOT_ACTIVE
        MARK chapter commitment is all zeroREC-8BAD_COMMITMENT

        The other pair

        Do these two keys form a carrier?

        The record pair above is the protocol layer. This is the Bitcoin layer underneath it. Two compressed public keys determine one carrier address completely, and the sort order decides which key is side A.

        Carrier pair

        Compressed secp256k1 public keys only, 33 bytes each. Never paste a private key into any web page.

        Order does not matter here. The tool sorts and tells you.

        Both keys must be valid points, and they must differ.

        AWAITING INPUT

        Paste a compressed public key into each side.

          The curve check is real. The tool tests that the x coordinate lies in the field and that x³ + 7 is a quadratic residue, so a 33-byte string with a plausible prefix but no corresponding point is rejected rather than accepted. That is the difference between rule PAIR-1 and a length check.

          Identity

          Derive a namespace and an object key

          Rules ID-5 and ID-6 are pure functions of the binding. Change any input and every downstream value changes with it, which is exactly why an alternate INIT is a different protocol rather than a different deployment.

          Binding derivation

          Transaction identifiers are entered in display order, the way Bitcoin Core shows them. The tool reverses them once for you.

          The network byte is part of the commitment, so the same INIT on two chains gives two namespaces.

          SHA256 of tandem.md as raw bytes.

          Leave empty to derive the namespace alone.

          The values prefilled above are the ones the published corpus uses, so on first load this panel should reproduce 38025b6fb909d2f22226ee9ea7e3a0e895c589792a93393c136ad502c608d221 and 5e355bac07710f3bc3b271902b8deda97c52893518bf9bac8a080c318659cb52 exactly. If it does not, something is wrong and you should not trust the rest of this page.

          Proof that the tool is honest

          Vector self test

          A verifier you cannot audit is just an assertion. On load, this page runs its own rules against the repository's published golden corpus, rehashes every published preimage, and rebuilds both Merkle roots from their leaves. The results are below, computed in your browser at page load.

          Loading the published corpus.

            Watch the two leaf-length lines.

            tandem.md section 13.2 states the event-leaf preimage is 374 bytes with a 16-byte domain tag. The measurement above, taken from the published preimages themselves, is 371 bytes: a 13-byte domain tag plus the 358 field bytes the same sentence correctly states. The independent Rust verifier asserts 371 at the same point. This is documented as erratum 1 rather than quietly worked around.

            Honesty

            What this tool does not check

            The panels above take markers and keys. They do not take transactions, and they have no view of the chain. That rules out a large part of validation, and pretending otherwise would be worse than useless.

            Checks that require data this page does not accept
            Not checked hereWhyWhere it is checked
            Signatures, DER encoding, low-S, sighash typeNeeds the full transaction and its prevout amountsThe Rust verifier's service boundary, see the verifier page
            Input and output counts, roles, and sequencesNeeds the transaction, not the markerRules OP-1 to OP-6
            Fee positivity and the exact splitNeeds input and output valuesRule PAIR-3.3
            Whether a predecessor is actually activeNeeds indexed chain state at a heightIndexer semantics
            Confirmation provenance, that prevouts confirmed in an earlier blockNeeds block heightsRule OP-6 note, tandem.md section 5.3
            Whether a MARK reproduces the predecessor carrier scriptNeeds both transactionsRule PAIR-6
            Chapter and close manifest contentContent availability is never validityJSON Schema reference

            A passing verdict here means the two halves are consistent with each other as far as their markers can express. It is a necessary condition, never a sufficient one. Do not treat it as a statement about a real transaction on a real chain.