BSV decentralisation series · Signing scope & responsibility
What a BSV
signature commits.
A BSV signer can use the right key, produce a valid ECDSA signature and still leave part of a payment open to change. The security question begins with the transaction data the signature commits. It continues with the customer’s authority, the wallet’s policy and the service’s handling of unfinished work.
1. Keep the common rules and the customer’s instruction separate
Fixed base rules give competing BSV implementations a common validity contract. They can differ in architecture, interfaces, custody and processing strategy while preserving the meaning of the transactions they check. The BSV protocol documentation distinguishes consensus validity from operator-selected relay, admission and fee policies. A supplier’s willingness to process a transaction is a separate question from its validity.
My published research on governance and commitment examines why stable foundational semantics matter to people making protocol-specific investments. Applied here to BSV, that institutional argument supports a clear boundary: an application standard can help services cooperate without becoming the compulsory architecture of every service. This application of the argument does not make the paper a cryptographic audit.
A customer’s instruction adds another boundary. A business might authorise a payment to one recipient within a stated fee limit. Transaction validation does not, by itself, establish that the wallet received that instruction or enforced those commercial conditions. The service must carry them through its own approval and signing process.
2. Identify the digest before discussing the signature
The BSV signature-hashing reference explains how flags select the transaction material used to construct the signature digest. The examples here concern the BSV fork-ID digest path, with SIGHASH_FORKID set and the Chronicle modifier unset, under a validation context in which fork-ID is enabled. Other digest paths and historical validation contexts require their own tests; this is not a complete protocol specification.
In that selected path, SIGHASH_ALL commits all outputs, SIGHASH_NONE commits no outputs, and SIGHASH_SINGLE commits the output at the signed input’s index when that output exists. SIGHASH_ANYONECANPAY separately removes the commitment to other inputs’ outpoints. It does not cancel the selected output commitment. The signed input’s own outpoint, amount, script and sequence, together with transaction version, locktime and the signature-hash type, remain in the preimage.
Other inputs’ sequences need particular care. The aggregate sequence commitment is omitted when ANYONECANPAY is set or the base type is NONE or SINGLE. A label such as “sign the transaction” hides these distinctions. The exact flags and digest path belong in the service’s specification.
3. Follow the part left open
Consider a hypothetical one-input payment with 10,000 satoshis available, 9,000 assigned to a merchant, 900 returned as change and 100 left as a fee. If its signature uses NONE | FORKID, changing only the merchant output’s locking script does not change that signature’s digest in the selected path. The signature alone therefore cannot certify the original recipient. Other signatures, scripts and complete-transaction checks may impose further constraints; this is not a claim that every altered transaction will be accepted.
With ALL | FORKID, that output alteration changes the signed material. With SINGLE | FORKID, the output index is decisive. A signer at input zero binds output zero if it exists, rather than whichever output a user interface happens to label “merchant”. A wallet must handle a missing corresponding output explicitly instead of assuming a payment has been covered.
These modes can support different arrangements for assembling transactions. A participant may deliberately permit other inputs to be added while retaining a commitment to specified outputs. Whether that flexibility is appropriate depends on the agreement and the rest of the transaction. A service can refuse a mode it does not safely support without declaring that mode forbidden to every BSV application.
4. Treat a default as a documented choice
The BSV TypeScript SDK’s P2PKH signing template, inspected at the linked revision, defaults to signing all outputs with anyoneCanPay false. Its scope helper combines that choice with the fork-ID flag. The resulting default scope is 0x41; choosing all outputs with ANYONECANPAY gives 0xc1.
An independent implementation can reproduce the specified commitments without using this library. A voluntary interoperability profile can require particular scopes for its own workflows and publish examples that others can check. Its requirements apply to that profile, rather than acquiring authority over every valid use of BSV. Competing profiles should make the differences visible enough for a purchaser to choose and a replacement supplier to reproduce.
5. A key hierarchy does not choose the payment policy
Hierarchical derivation can help organise counterparties and purposes. It does not automatically restrict what a holder of a derived private key can sign. The wallet still has to select an appropriate digest scope and enforce its own recipient, amount and fee policies before signing.
The inspected SDK’s BRC-42-style derivation documentation also states that the construction does not supply forward secrecy, replay protection or explicit peer-identity binding. Those are distinct responsibilities for an application claiming them. A new invoice label is not, on its own, a spending limit, a customer approval or a proof that a business request has not already been fulfilled.
The earlier articles on hierarchy compromise and signing-secret security examine different parts of this problem. Here the focus is the authority exercised by a signing operation even when the key remains secret and the signature calculation is correct.
6. Scale an unchanged signing context
Repeated hashing can become significant when a service signs transactions with many inputs. The current SDK exposes cached hash components in TransactionSignature. Its cache contract requires an immutable transaction context and a fresh cache after signed fields change. Reuse is an implementation technique with an explicit condition, not permission to reuse evidence from an earlier transaction.
A supplier may choose caching, parallel signing, a separate signing device or a different internal representation. It remains responsible for showing that the customer’s approved version, the signed digest and the final assembled transaction stay connected. A useful operational record would identify the request, approved transaction data, input index, scope and final outcome without recording private keys or per-signature secrets.
7. Make substitution and interruption part of the test
A proposed comparison would give independent BSV implementations identical transaction contexts and check their preimages and digests. It would then change one field at a time: recipient script, output amount, unrelated input, sequence and locktime. The expected change depends on the declared scope. It should include the SINGLE boundary, a fresh cache after mutation, and interrupted assembly followed by a retry.
That comparison would test the wallet’s approval policy separately from digest correctness. A technically valid signature that violates the service’s promised policy is a service failure. These are proposed tests, not reported results or an allegation against a particular implementation.
BSV decentralisation leaves room for suppliers to make different engineering choices under common base rules. The useful competition is over clearly specified services: what the signature commits, what the customer authorised, what remains changeable and who bears responsibility when those accounts diverge.