Sitemap

Sizing Post-Quantum Inputs: BTQ’s Witness Scale Factor and the 657-Unit RPC Check

4 min readOct 29, 2026

--

Press enter or click to view image in full size

Post-quantum signatures make witness sizing an important part of wallet engineering. BTQ implements ML-DSA-44, whose cryptographic signatures occupy 2,420 bytes before transaction-specific framing.

That signature size is separate from the wallet’s minimum accepted explicit input weight. A merged btq-core fix, PR #213, corrects an inherited assertion in that validation path from 165 to 657 weight units.

Understanding the fix requires separating witness scaling, the serialization helper and the complete size of an input that can actually spend a coin.

Weight assigns different costs to base and witness bytes

Bitcoin’s SegWit accounting assigns 4 weight units to each non-witness byte and 1 to each witness byte. BTQ uses a factor of 16 for non-witness bytes while retaining 1 weight unit per witness byte.

For a transaction with base size B and total size T, BTQ’s weight calculation is 15 × B + T. Equivalently, it is 16 × B + witness bytes.

This is a relative witness discount. Increasing the factor makes base bytes more expensive in weight units relative to witness bytes; it does not reduce a witness byte below 1 weight unit or change the cryptographic signature’s byte length.

The corresponding weight-based virtual size divides by 16 and rounds up. Signature-operation policy can impose a larger virtual size, so weight alone is not always the final policy sizing input.

Block limits remain separate from that fee calculation. Current btq-core constants set a maximum block weight of 8,000,000 weight units and a maximum serialized block size of 8,000,000 bytes.

These constraints explain why the factor should not be described as a throughput multiplier. The capacity available to a particular transaction mix depends on its base data, witness data and the other applicable rules.

Where the 41 base bytes come from

An empty transaction input, represented by CTxIn(), has four non-witness fields:

  1. A 32-byte previous transaction ID.
  2. A 4-byte output index.
  3. A 1-byte length for the empty scriptSig.
  4. A 4-byte sequence number.

The total is 41 bytes. No signature, public key or spending script has been added to that empty structure.

Get Bitcoin Quantum’s stories in your inbox

Join Medium for free to get updates from this writer.

The helper GetTransactionInputWeight includes the serialized witness stack as well. An empty stack is encoded by a one-byte zero item count, giving these helper results:

  • Bitcoin: 41 × 4 + 1 = 165 weight units.
  • BTQ: 41 × 16 + 1 = 657 weight units.

The result describes the helper’s empty-input accounting. It is not a complete ML-DSA input estimate.

It is also not a universal serialized-input consensus floor. A transaction without witness data does not serialize a separate empty witness stack for every input, even though this helper includes that stack in its calculation.

The inherited assertion that blocked explicit weights

The shared funding code used by fundrawtransaction, walletcreatefundedpsbt and send validates user-supplied input_weights. For each entry, it computes the helper value and checks it before enforcing the permitted weight range.

The inherited code contained CHECK_NONFATAL(min_input_weight == 165). BTQ's helper already returned 657 because its witness scale factor was already 16.

As a result, supplying an input-weight entry could return an internal-bug error at that assertion. The problem was a mismatch between an inherited check and existing BTQ accounting, rather than a change in the size of a signature.

PR #213 replaces the assertion with CHECK_NONFATAL(min_input_weight == 657) and updates the lower-bound error message. It preserves the structure of the validation path.

What the test record establishes

The merged PR also updates the functional fixtures in wallet_send.py, rpc_psbt.py and wallet_fundrawtransaction.py for BTQ's subsidy, fees and witness scaling. It removes six legacy/descriptor entries from the known-failures list.

The PR reports a full-suite run with 252 passes, 43 known failures and 9 skips, with no new failures. This is the recorded result for that change, rather than evidence that every wallet test or transaction workflow succeeds on every later build.

What wallet builders still need to estimate

A real input’s weight depends on its satisfaction data. Depending on the output, that may include a scriptSig, signatures, public keys, a witness script, a P2MR leaf and its Merkle proof.

Passing the 657-unit lower-bound check does not establish that an explicit estimate covers those items. Coin selection and fee calculation still need the expected complete input weight, and the final signed transaction should be checked against the intended fee and size limits.

The fix keeps a validation constant consistent with BTQ’s accounting. Precise transaction construction still depends on keeping the empty-input helper, signed-input estimate and full transaction virtual size distinct.

--

--