Concrete example:
Horizontal storage today:
row[i] = hash32 | pubkey33 | sig64 | correlation_key6
For ECDSA that is 129 bytes of verification data plus the 6-byte key. The bridge then has to de-interleave this into:
hashes[n][32]
pubkeys[n][33]
sigs[n][64]
before calling the existing UF GPU verification ABI.
Vertical storage would instead keep the data as:
hashes[] = mmap column, n * 32 bytes
pubkeys[] = mmap column, n * 33 bytes for ECDSA, or n * 32 for Schnorr
sigs[] = mmap column, n * 64 bytes
keys[] = independent libbitcoin correlation column, not needed by UF verify
Then the bridge can call the column API directly:
ufsecp_lbtc_verify_ecdsa_columns(
ctrl,
hashes,
pubkeys,
sigs,
count,
results);
or, if you want the collect-style behavior:
ufsecp_lbtc_verify_ecdsa_columns_collect(
ctrl,
hashes,
pubkeys,
sigs,
count,
keys,
6);
In the pure verify case UF does not need the key column at all. The key can remain fully owned by libbitcoin and used later for correlation.
Cost example for 3.5B ECDSA tuples:
3.5B * (32 + 33 + 64) = 451.5 GB of verification payload.
A row-to-column transform must at least read that payload once and write the column buffers once:
~451.5 GB read + ~451.5 GB write = ~903 GB memory traffic.
At 100 GB/s sustained host memory bandwidth, that is roughly 9 seconds of extra memory-bandwidth work. At 50 GB/s it is roughly 18 seconds. If the 6-byte key is also copied, add about 42 GB more traffic, but with vertical storage the key does not need to be passed to UF verification.
So the transform is not algorithmically complex, but over a full-chain-sized 3.5B tuple run it is a real memory-bandwidth tax. If libbitcoin can produce vertical columns directly, UF can skip that pass and use the existing GPU-facing layout directly.
check dev branch