Skip to content

About

SwiftSync aggregator benchmarks, with hardware and software implementations

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

SwiftSync aggregator benchmark

Compares SwiftSync OutPoint aggregator designs on two historical mainnet blocks: sums of 128-bit tags from keyed SHA256, AES-CMAC and SipHash128, and GF(2²⁵⁶) products. See why these designs for more details.

Hardware and software backends are benchmarked in separate builds.

Build SHA256 AES-CMAC SipHash128 GF256
Native on ARM64 ARM SHA2 if available, otherwise software Hardware ARM AES Scalar + NEON SIMD/interleaved Hardware PMULL
Native on x86-64 SHA-NI if available, otherwise software Hardware AES-NI Portable scalar code Hardware PCLMULQDQ
Software on any CPU Portable rust-bitcoin implementation RustCrypto software AES Scalar + NEON SIMD/interleaved on ARM64 Portable optimized kernel

Benchmarks

Results for block 866,342, shown as median time (µs) per block. The charts use different vertical scales, and SipHash128 implementation stays the same.

Native build: median time per block in microseconds for Apple M5 Pro, Apple M1 and Intel Core i5-1035G1.

Software build: median time per block in microseconds for Apple M5 Pro, Apple M1 and Intel Core i5-1035G1.

See the full benchmark tables for exact timings and relative time multipliers, and what is timed for the methodology.

Run

You need Rust 1.87 or newer and a C compiler for zstd. Run the commands below from the repository root.

Native hardware

Requires both AES and carry-less multiplication instructions. Native binaries must only run on CPUs with those features.

Enable AES at compile time so RustCrypto can inline its hardware code. The flag works on ARM64 and x86-64. It is optional on Apple Silicon, where AES is already enabled by default.

RUSTFLAGS='-C target-feature=+aes' cargo test
RUSTFLAGS='-C target-feature=+aes' cargo run --release

In PowerShell:

$env:RUSTFLAGS = '-C target-feature=+aes'
cargo test
cargo run --release
Remove-Item Env:RUSTFLAGS

Software

Works on CPUs without those instructions, and forces software even on CPUs that have them:

RUSTFLAGS='--cfg aes_backend="soft"' cargo test --no-default-features --features software
RUSTFLAGS='--cfg aes_backend="soft"' cargo run --release --no-default-features --features software

All three settings are required:

  • --no-default-features disables SHA256 hardware dispatch.
  • --features software selects software GF256 and CMAC.
  • RUSTFLAGS forces software AES.

AES uses RustCrypto's constant-time implementation. ARM64 SipHash retains NEON.

GF256 uses bit-hole integer multiplication, Karatsuba and shift/XOR reduction, without carry-less multiplication instructions. It avoids secret-dependent branches and lookups, assuming constant-time integer multiplication on the host CPU.

Each run prints its backends. Append -- --quick for a short check.

Tests

Tests verify:

  • GF256 against independent polynomial vectors and the bit-at-a-time reference.
  • CMAC and SHA256 against OpenSSL vectors.
  • SipHash against siphasher.
  • Software builds disable SHA256 and GF256 hardware dispatch. The runner also verifies that AES acceleration is disabled.

What is timed?

Each case visits every non-coinbase input and every UTXO-eligible output (OP_RETURN and scripts over 10,000 bytes are excluded). The bundled compressed blocks are copies of Floresta's block_367891/raw.zst and block_866342/raw.zst.

Mainnet block Inputs Eligible outputs Character
367,891 20,817 852 Input-heavy
866,342 7,972 6,356 More output work and txid reuse

Timing includes fingerprinting, aggregator updates and the final merge. Decompression, parsing, txid calculation, output filtering and session-key setup are excluded.

Results report median microseconds per block across 11 samples (each one taking ~100 ms). ns/record divides this by the total input and eligible-output count.

Case Timed strategy
Keyed SHA256 First 128 bits of SHA256(txid || vout_le || secret16), one compression per record
AES-CMAC Fixed 36-byte message, reusing the txid work across a transaction's outputs
AES-CMAC 8-way Eight independent records via RustCrypto, with the same txid reuse
SipHash128 scalar Fixed 36-byte scalar kernel with the same txid reuse
SipHash128 NEON (ARM64 only) Four hashes per batch, using two interleaved two-lane NEON vector states and the same txid reuse
GF256 direct Two interleaved product chains, computing each r·vout
GF256 common-vout Four or eight chains with a 0–255 vout table and direct fallback
GF256 fast 0/1 Four or eight chains with precomputed vouts 0 and 1 and direct fallback
GF256 bit-at-a-time (software build) Independent reference using the direct/two-chain strategy

CMAC and NEON input batches can span transactions. Outputs reuse scalar txid prefixes, then batch their vout finalizations. Batch preparation and scalar tails are timed. CMAC uses RustCrypto, except for the original ARM hardware case's specialized kernel.

GF256 chains are independent partial products interleaved in one thread and merged at the end. They are not SIMD lanes or worker threads.

Why these designs?

Two aggregator models: SHA256, AES-CMAC and SipHash128 share pairs of u128 sums S+ and S-, one sum for each 64-bit fingerprint half. GF256 compares products P+ and P-.

Design Why consider it? False-pass bound
Keyed SHA256 Familiar hardware-accelerated reference, already used in consensus 2⁻¹²⁸ in the ideal-tag model, assuming secret-suffix SHA256 behaves as a PRF
AES-CMAC Standardized MAC, fast with hardware AES Same ideal bound, plus the CMAC PRF assumption
SipHash128 Small, portable, with an ARM SIMD option Same ideal bound, plus the SipHash PRF assumption
GF256 Statistical check without a keyed-function assumption N / 2²⁵⁶, or 2⁻²²⁴ at N = 2³²

The additive designs' ideal bound assumes independent uniform 128-bit tags for distinct OutPoints. Their two widened sums cannot overflow with up to 2⁶⁴ records per side, including repetitions. Applying this model to a keyed function requires a PRF assumption: without the key, its outputs behave like those of a random function. The SHA256 case uses a secret suffix, not HMAC.

N is the larger count of added or removed OutPoints. GF256's bound follows from a nonzero polynomial evaluated at independent, uniformly random secrets z and r. It uses the same random-product multiset-check idea described for PLONK.

All bounds require fresh private secrets and records chosen independently of them. Benchmark keys are fixed only for timing.

Background: SwiftSync proposal, CMAC specification, SipHash reference, and PLONK's two-challenge product proof (Appendix A, Claim A.1).

About

SwiftSync aggregator benchmarks, with hardware and software implementations

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages