Skip to content

Latest commit

 

History

History
75 lines (64 loc) · 3.2 KB

File metadata and controls

75 lines (64 loc) · 3.2 KB

Cross-input-aggregation savings

Savings in an average taproot transaction

# Transaction with segwit v1 spends and outputs.
# Outputs size in bytes and weight units.
def tx_size(n_inputs, n_outputs):
    assert(n_inputs <= 252 and n_outputs <= 252)
    return list(map(lambda mult: (
        mult*(
            4     # version
            + 1   # number of inputs
            + n_inputs * (
                32 + 4 # prevout
                + 1    # script len
                + 4)   # sequence
            + 1   # number of outputs
            + n_outputs * (
                8       # amount
                + 1     # script len
                + 34)   # script
             + 4)  # locktime
         + 2 # witness flag & marker
         + n_inputs * (
             1       # witness stack items
             + 1     # witness item len
             + 64)), # BIP-340 sig
      [1, 4]))


# 365 day moving average according to
# - https://transactionfee.info/charts/inputs-per-transaction/?avg=365&start=2025-02-26&end=2025-02-27 and
# - https://transactionfee.info/charts/outputs-per-transaction/?avg=365&start=2025-02-26&end=2025-02-27
# retrieved 2025-02-28.
n_inputs = 2.26
n_outputs = 2.69


size = tx_size(n_inputs, n_outputs)
half_agged_tx = map(lambda s: s - (n_inputs - 1)*32, size)
half_agged_block = map(lambda s: s - n_inputs*32, size)
full_agged_tx = map(lambda s: s - (n_inputs-1)*64, size)
full_agged_tx_half_agged_block = map(lambda s: s - (n_inputs-1)*64 - 32, size)
max_agged = map(lambda s: s - n_inputs*64, size)

def savings(name, agged_sizes):
    return [name] + ["%.1f%%" % ((1 - a/b)*100) for (a,b) in zip(agged_sizes, size)]

[
    [ "", "bytes", "weight units" ],
    None,
    savings("half aggregation across tx", half_agged_tx),
    savings("half aggregation across block", half_agged_block),
    savings("full aggregation across tx", full_agged_tx),
    savings("full aggregation across tx & half aggregation across block", full_agged_tx_half_agged_block),
    savings("max (like infinite large fully aggregated coinjoin)", max_agged)
]
bytesweight units
half aggregation across tx10.9%3.9%
half aggregation across block19.6%7.1%
full aggregation across tx21.8%7.9%
full aggregation across tx & half aggregation across block30.5%11.0%
max (like infinite large fully aggregated coinjoin)39.1%14.1%

Graftroot

Spending a taproot-like output via graftroot requires a 64-byte signature of the script that the signers delegate control to. In comparison, opening a taproot commitment only requires revealing the 32-byte “internal” pubkey (if the committed script is at depth zero). With half- or full-aggregation of signatures outside script, the graftroot signature can be aggregated just like key-spend signatures. As a result, graftroot spends would be equal to or more efficient that taproot script spends.