Security notice. ITB is an experimental symmetric cipher construction without prior peer review, independent cryptanalysis, or formal certification. The construction's security properties have not been verified by independent cryptographers or mathematicians.
PRF-grade hash functions are required. No warranty is provided.
No bespoke cryptography. ITB introduces no cryptographic primitive of its own — no custom S-box, permutation, or round function. It is a construction over existing primitives, much as PGP composes standard ciphers rather than defining one. Such constructions are not the object of algorithm-level cryptographic certification: national regimes (NIST CAVP/FIPS in the US, GOST/FSB in Russia, OSCCA's SM-series in China, IC3S in India, SOG-IS/EUCC and national lists in the EU, ASD's ISM in Australia, CRYPTREC in Japan, KCMVP in South Korea) certify primitives and the modules built on them, not compositional schemes. Eligibility for regulated use is therefore inherited from the primitives ITB is configured with, not conferred by ITB itself.
ITB claims no resistance to any hardware-level attack; the analysis below describes architectural properties of the construction's data path, not proven security guarantees.
This document analyzes ITB's data path against known hardware-level attack classes. The analysis applies to both the Go-based pixel backend (CGO_ENABLED=0, with the Go-assembly hash kernels still engaged) and the CGO backend (GCC -O3, AVX2 on x86-64, NEON on ARM64). Analysis based on GCC 13/14 output; other compilers or versions may produce different instruction sequences.
Key architectural property: ITB's secret-dependent operations (noisePos, dataRotation, channelXOR) use only register operations (bitwise shift, XOR, AND, OR). There are no secret-dependent array accesses (no S-box, no T-tables, no key-dependent table lookups). The root cause exploited by many microarchitectural attacks against ciphers with secret-dependent table lookups — table[secret_index] — is absent from ITB's data path. This has not been independently verified.
All speculative execution attacks require a disclosure gadget: a secret-dependent memory access that leaves a cache or microarchitectural trace. ITB's data path does not contain such a gadget. This has not been independently verified.
| Attack | CVE | Mechanism | ITB Data Path | Status |
|---|---|---|---|---|
| Spectre v1 (bounds check bypass) | CVE-2017-5753 | Mistrained branch → speculative array[secret] → cache trace |
No secret-dependent array indexing; noisePos/dataRotation used as shift amounts only |
No known gadget |
| Spectre v2 (branch target injection) | CVE-2017-5715 | Poisoned BTB → speculative jump to gadget | Secret-dependent ops are register-only; no memory access under misprediction | No known gadget |
| Spectre v4 (speculative store bypass) | CVE-2018-3639 | Speculative load reads stale value before store completes | rotateBits7 is register-to-register; no store→load on same address |
No known gadget |
| Retbleed | CVE-2022-29900/01 | Exploits return instructions as speculative gadgets | Same requirement: needs secret-dependent memory access gadget | No known gadget |
| Inception / AMD Phantom | CVE-2023-20569 | Trains branch predictor to attacker-chosen address | Same requirement | No known gadget |
| Downfall / GDS | CVE-2022-40982 | Gather Data Sampling leaks from SIMD registers via gather instruction |
CGO backend does not use gather instructions (verified with GCC 13/14); AVX-512 VBMI paths use VPERMB (intra-register byte-permute, distinct from GATHER which reads from memory by index vector). See Category 5 for the per-instruction inventory |
Not applicable |
| GhostRace | CVE-2024-2193 | Spectre + race conditions on shared data | No secret-dependent branching on shared data | No known gadget |
| Indirector | 2024 (no CVE) | High-precision BPU manipulation (Intel) | Same fundamental requirement: disclosure gadget | No known gadget |
| BHI (Branch History Injection) | CVE-2022-0001 / CVE-2024-2201 | Intra-mode BTI with branch history manipulation | Same requirement | No known gadget |
| SLAM | 2023 | Spectre via Linear Address Masking | Same pattern: needs memory[secret] |
No known gadget |
| Training Solo | CVE-2024-28956 | History-based Spectre-v2 extension (Intel/ARM) | Same requirement | No known gadget |
| Branch Privilege Injection | CVE-2024-45332 | Privilege escalation via branch prediction (Intel) | Same class | No known gadget |
| TSA (Transient Scheduler Attacks) | 2025 | Leaks stale data from scheduler (AMD Zen 3/4) | Leaks data from other processes, not from ITB's secret-dependent computation | Not ITB-specific |
These attacks read stale data from internal CPU buffers (line fill buffers, store buffers, register files). If the ITB process handles seeds, stale seed bytes may remain in CPU buffers. This is identical for all software symmetric ciphers (AES round keys, ChaCha20 state) — not specific to ITB. This has not been independently verified.
| Attack | CVE | Mechanism | ITB Impact | Status |
|---|---|---|---|---|
| MDS (RIDL, Fallout, ZombieLoad) | CVE-2018-12126/27/30, CVE-2019-11091 | Leak data from line fill / store buffers | Seeds/plaintext may remain in buffers; identical to AES/ChaCha20 | Not ITB-specific |
| MMIO Stale Data | CVE-2022-21123/25/66 | Leak data from memory-mapped I/O operations | ITB does not use MMIO | Not applicable |
| RFDS (Register File Data Sampling) | 2024, Intel Atom | Leaks stale register values | dataSeed hash values could remain in registers; identical for AES round keys | Not ITB-specific |
| Zenbleed | CVE-2023-20593 | AVX register file leak (AMD Zen 2 only) | CGO backend AVX2 registers could retain hash values; fixed by microcode update, Zen 2 only | Not ITB-specific; mitigated by vendor |
| Attack | Year | Mechanism | ITB Data Path | Status |
|---|---|---|---|---|
| Hertzbleed | 2022 | CPU frequency throttling converts power analysis to remote timing; data-dependent power → frequency → timing | ITB's secret-dependent scalar operations are register-only XOR/shift with data-independent latency. Vector paths use AVX2 / AVX-512 / GFNI / VBMI / VAES / BMI2 instructions; see Category 5 for the per-instruction profile and the µarch floor (Rocket Lake+ / Zen 3+; pre-Zen-3 AMD hosts with microcode-emulated PEXT / PDEP fall through to the portable Go fallback). DVFS transitions under these instructions have not been independently measured |
No known attack surface |
| SQUIP | 2022 | Scheduler queue contention leaks execution patterns across SMT threads (AMD) | ITB's per-pixel processing executes the same instruction sequence per pixel regardless of secret values; no secret-dependent branching (not independently verified) | No known attack surface |
| Interconnect side-channels | Various | Shared bus contention leaks access patterns | Container access pattern (startPixel) is already documented as cache side-channel limitation | Documented limitation |
| Attack | Mechanism | ITB Impact | Status |
|---|---|---|---|
| Rowhammer | Repeated DRAM row activation flips bits in adjacent rows | Could corrupt seeds, container, or plaintext in memory; general memory integrity attack affecting all software | Not ITB-specific |
| RAMBleed | Reads data through Rowhammer-induced bit flips | Could read seed bytes from adjacent DRAM rows; identical for AES keys | Not ITB-specific |
Mitigation: ECC memory detects and corrects single-bit flips. For high-security deployments, ECC memory is recommended alongside hardware memory encryption (AMD SEV, Intel SGX/TDX, ARM CCA).
Heap memory exposure. Sensitive data resides in heap memory during the lifetime of the process: seed components (Seed.Components []uint64), intermediate hash buffers, and plaintext during encode/decode. The library mitigates by calling secureWipe on intermediate buffers after use, but cannot wipe Go runtime internals or kernel buffers used during crypto/rand generation. Additionally, cached hash wrappers (e.g., makeAESHash(), makeBlake3Hash()) store a fixed random key in a closure for the lifetime of the session — this key persists in heap memory and is not wiped until the process exits. If an attacker can read heap memory (Meltdown, memory dump, debugger), they can read seeds and cached keys directly — regardless of the cipher used. This is identical for all software symmetric ciphers and is not specific to ITB.
This category documents the side-channel profile of individual CPU instructions used in ITB's hardware-accelerated paths. Coverage spans:
process_pixels.c(CGO per-pixel encode/decode kernel — Tier A: AVX-512F + AVX-512BW + AVX-512VL + GFNI + AVX-512VBMI; Tier A′: AVX-512F + AVX-512BW + AVX-512VL, no GFNI, no VBMI (Cascade Lake class); Tier B: AVX2 + GFNI; Tier B′: AVX2 only, no GFNI (Zen 3 / Haswell class); Tier C: portable scalar C).internal/areionasm/areion_amd64.s+areion_soem{256,512}_amd64.s(VAES + AVX-512 implementation of the Areion-SoEM permutation — the four-lane batched arm of the primitive).internal/areionasm/areion_fusedchain{256,512}_{13,20,36,68}x4_{avx512,vaesavx2,aesni}_amd64.s,areion_fusedchain{256,512}_{13,20,36,68}x1_aesni_amd64.s,areion_fusedchain{256,512}_{20,36,68}x8_avx512_amd64.s,areion_fusedchain{256,512}_13x8_avx512_amd64.s(fused ChainHash cascade kernels for Areion-SoEM-256 / -512 — the whole component cascade per call at the four per-pixel shapes on the VAES ZMM, VAES YMM and AES-NI XMM tiers, the single-lane AES-NI arm of every tier, the eight-lane ZMM kernels at the three nonce-buf shapes, and the eight-lane ZMM Interlocked Barrier fill kernels — the batch-16 hook at width 256, the batch-32 hook at width 512 — with their fill blocks synthesised in-register; every other fill arm runs four-lane kernel calls over Go-synthesised blocks).internal/areionasm/areion_fusedchain{256,512}_{13,20,36,68}x{1,4}_neon_arm64.s,areion_fusedchain{256,512}_13x8_neon_arm64.s(the NEON + ARM Crypto Extension form of the same fused cascade kernels, two lanes per pass at width 256 and one at width 512, and the eight-lane fill kernels at four / two lanes per pass with their fill blocks synthesised into the frame).internal/areionasm/areion_arm64.s(ARM Crypto ExtensionAESE/AESMC4-lane parallel implementation of the same permutation).internal/interlock/interlockasm48_amd64.s(BMI2PEXTQ/PDEPQper-chunk kernels plus the AVX-512F batched combinadic unrankrankToMaskTripleUnrank48AVX512that derives the 48-bit Interlocked Barrier mask triple; see SCIENCE.md § 1.5 Interlocked Barrier and § 2.15 Mask Space (Theorem 11)).internal/interlock/interlockasm48_batch_amd64.s(BMI2PEXTQ/PDEPQbatched chunk-apply kernelschunk48LockBatch/unchunk48LockBatch— n consecutive 48-bit chunks apply their own mask triple under one ABI0 call with the mask as a memory operand; bit-exact with n per-chunk calls, engaged on every BMI2-capable host through theHasChunk48Batchflag).internal/interlock/interlockasm48_avx2_amd64.s(AVX2 4-lane YMM batched combinadic unrankrankToMaskTripleUnrank48AVX2— the AVX2-only-CPU counterpart, engaged when AVX2 + BMI2 are present but AVX-512F is absent).internal/interlock/interlockasm48_neon_arm64.s(NEON 8-lane batched combinadic unrankrankToMaskTripleUnrank48NEON— the AArch64 counterpart of the two amd64 unrank kernels, two qword lanes per register, engaged on every arm64 host through theHasNEONInterlockflag).internal/interlock/interlockasm48_sve2_arm64.s(SVE2BEXT/BDEPbatched chunk-apply kernelschunk48LockBatchSVE2/unchunk48LockBatchSVE2— the AArch64 counterpart of the BMI2 batched apply, engaged where FEAT_SVE_BitPerm is present through theHasSVE2Interlockflag; hosts without it run the software set-bit-walk batch ofinterlockasm48_batch_arm64.go).hashes/internal/{blake2sasm,blake3asm,chacha20asm}/*_amd64.s(AVX-512-widened ChainHash inner-block kernels for the ARX / BLAKE primitives whose native code has a Go-assembly implementation).hashes/internal/aescmacasm/aescmac_fusedchain128_{13,20,36,68}x{1,4}_{aesni,vex,vaesavx2,avx512}_amd64.s,aescmac_fusedchain128_{20,36,68}x8_avx512_amd64.s,aescmac_fusedchain128_13x16_{aesni,vex,vaesavx2,avx512}_amd64.s(fused ChainHash cascade kernels for AES-CMAC — the whole component cascade per call at the four per-pixel shapes, the eight-lane ZMM variant at the nonce-buf shapes and the batch-16 Interlocked Barrier fill kernel — on the legacy-SSE AES-NI, VEX AES-NI, VAES YMM and VAES ZMM tiers; the same families carry NEON counterparts*_neon_arm64.s).hashes/internal/siphashasm/siphash_fusedchain128_{13,20,36,68}x4_{avx512,avx2}_amd64.s,siphash_fusedchain128_{13,20,36,68}x1_gpr_amd64.s,siphash_fusedchain128_{20,36,68}x8_avx512_amd64.s,siphash_fusedchain128_13x16_avx512_amd64.s,siphash_fusedchain128_13x8_avx2_amd64.s(fused ChainHash cascade kernels for SipHash-2-4 — the whole component cascade per call at the four per-pixel shapes on the AVX-512 EVEX and AVX2 VEX tiers plus a general-purpose-register single-lane kernel, the eight-lane ZMM variant at the nonce-buf shapes, and the Interlocked Barrier fill kernels: sixteen lanes per call on ZMM, eight lanes per call on AVX2 YMM; the four-lane and single-lane families carry NEON / GPR counterparts*_neon_arm64.s/*_gpr_arm64.s, andsiphash_fusedchain128_13x8_neon_arm64.sis the eight-lane NEON fill kernel).hashes/internal/blake2basm/blake2b_fusedchain{256,512}_{13,20,36,68}x4_{avx512,avx2}_amd64.s,blake2b_fusedchain{256,512}_{20,36,68}x8_avx512_amd64.s,blake2b_fusedchain{256,512}_13x8_avx512_amd64.s,blake2b_fusedchain{256,512}_{13,20,36,68}x1_gpr_amd64.s(fused ChainHash cascade kernels for BLAKE2b-256 / -512 — the whole component cascade per call at the four per-pixel shapes on the AVX-512 EVEX YMM and AVX2 VEX YMM tiers, one qword lane per pixel, the eight-lane ZMM kernels at the three nonce-buf shapes, the eight-lane ZMM Interlocked Barrier fill kernels — the batch-16 hook at width 256, the batch-32 hook at width 512 — and the general-purpose-register single-lane arm of every tier; the four-lane family carries NEON counterparts*_neon_arm64.s, two lanes per pass, and the single-lane arm*x1_gpr_arm64.s).hashes/internal/blake2sasm/blake2s_fusedchain256_{13,20,36,68}x4_{avx512,avx2}_amd64.s,blake2s_fusedchain256_{20,36,68}x8_avx512_amd64.s,blake2s_fusedchain256_13x8_avx512_amd64.s,blake2s_fusedchain256_{13,20,36,68}x1_gpr_amd64.s(fused ChainHash cascade kernels for BLAKE2s — the whole component cascade per call at the four per-pixel shapes on the AVX-512 EVEX XMM and AVX2 VEX XMM tiers, one dword lane per pixel, the eight-lane EVEX YMM kernels at the three nonce-buf shapes, the eight-lane EVEX YMM Interlocked Barrier fill kernel of the batch-16 hook, and the general-purpose-register single-lane arm of every tier; the four-lane family carries NEON counterparts*_neon_arm64.s, four dword lanes per register, and the single-lane arm*x1_gpr_arm64.s).hashes/internal/blake3asm/blake3_fusedchain256_{13,20,36,68}x4_{avx512,avx2}_amd64.s,blake3_fusedchain256_{20,36,68}x8_avx512_amd64.s,blake3_fusedchain256_13x8_avx512_amd64.s,blake3_fusedchain256_{13,20,36,68}x1_gpr_amd64.s(fused ChainHash cascade kernels for BLAKE3 — the same plan as the BLAKE2s family: the whole component cascade per call at the four per-pixel shapes on the AVX-512 EVEX XMM and AVX2 VEX XMM tiers, one dword lane per pixel, the eight-lane EVEX YMM kernels at the three nonce-buf shapes, the eight-lane EVEX YMM Interlocked Barrier fill kernel of the batch-16 hook, and the general-purpose-register single-lane arm of every tier; NEON counterparts*_neon_arm64.sand the single-lane arm*x1_gpr_arm64.s).hashes/internal/chacha20asm/chacha20_fusedchain256_{13,20,36,68}x4_{avx512,avx2}_amd64.s,chacha20_fusedchain256_{20,36,68}x8_avx512_amd64.s,chacha20_fusedchain256_13x8_avx512_amd64.s,chacha20_fusedchain256_{13,20,36,68}x1_gpr_amd64.s(fused ChainHash cascade kernels for ChaCha20 — the whole component cascade per call at the four per-pixel shapes on the AVX-512 EVEX XMM and AVX2 VEX XMM tiers, one dword lane per pixel, the key words rebuilt each cascade round from the fixed key, the component group and the previous output and one ChaCha20 block per counter value, the eight-lane EVEX YMM kernels at the three nonce-buf shapes, the eight-lane EVEX YMM Interlocked Barrier fill kernel of the batch-16 hook, and the general-purpose-register single-lane arm of every tier; NEON counterparts*_neon_arm64.sand the single-lane arm*x1_gpr_arm64.s).
Baseline microarchitecture floor and dispatch fan-out for the shipped assembly paths. Top tier (AVX-512F + AVX-512DQ + VAES) covers Intel 11th-generation Core (Rocket Lake, i7-11700K) and newer plus AMD Zen 4 and newer: fused ZMM Areion-SoEM + AES-CMAC ChainHash kernels, AVX-512F BLAKE / ChaCha20 / SipHash ChainHash kernels, AVX-512F batched combinadic unrank for the Interlocked Barrier, and Tier A (with GFNI + VBMI) or Tier A′ (without one or both — Cascade Lake) for the pixel encoder. Mid tier — AVX2 without AVX-512F (AMD Zen 1–3, Intel Haswell through Comet Lake, AVX2-only cloud VMs) engages the VAES-on-YMM per-half Areion permute, and on the VAES-carrying subset (Alder Lake+ E-cores, P-cores with BIOS-disabled AVX-512, Zen 3, some enterprise SKUs) the YMM VAES two-lane-per-pass Areion-SoEM fused ChainHash cascade kernels (areion_fusedchain{256,512}_{13,20,36,68}x4_vaesavx2_amd64.s) for the four ITB buf shapes; the XMM AES-NI Areion-SoEM and AES-CMAC fused ChainHash cascade kernels, the AVX2 four-lane BLAKE / ChaCha20 / SipHash fused ChainHash cascade kernels, the AVX2 4-lane rank-mask kernel for the Interlocked Barrier, and Tier B (with GFNI — Zen 4-shaped hosts that lack AVX-512) or Tier B′ (without GFNI — Zen 3, Haswell) for the pixel encoder. BMI2 PEXT / PDEP are constant-time from Zen 3 and Haswell onward, so both the per-chunk and the batched Interlocked Barrier apply kernels lower to hardware PEXTQ / PDEPQ throughout the mid tier. AES-NI-only silicon without VAES (Cascade Lake Xeon Gold, Zen 3, AVX2-no-VAES cloud VMs) still activates the XMM AES-NI fused ChainHash cascade kernels for Areion-SoEM and AES-CMAC — lane- and permutation-disjoint AES-NI chains hiding the AESENC latency on a single AES issue port — rather than falling to scalar. Older hosts fall back to portable Go paths automatically. Zen 2 and older are out of scope for the BMI2 kernels because their PEXT / PDEP are microcode-emulated with data-dependent latency; those hosts run the software fallback described in the "Pure-Go fallback paths" note below. On AArch64 AES-ITB-128 and AES-CMAC carry Go-assembly ChainHash kernels — the NEON fused-cascade and batch-16 Interlocked Barrier fill kernels via the ARM Crypto Extension (aesitbasm.FusedHasARMAES / aesitbasm.HasARMAESX16, aescmacasm.FusedHasARMAES / aescmacasm.HasARMAESX16) — BLAKE2b-256 / -512 carry NEON four-lane fused-cascade kernels (two qword lanes per register, two passes) on the ARMv8-A baseline (blake2basm.FusedHasNEON / blake2basm.HasNEONX16), BLAKE2s, BLAKE3 and ChaCha20 carry NEON four-lane and general-purpose-register single-lane fused-cascade kernels (four dword lanes per register) on the ARMv8-A baseline (blake2sasm.FusedHasNEON / blake2sasm.HasNEONX16, blake3asm.FusedHasNEON / blake3asm.HasNEONX16, chacha20asm.FusedHasNEON / chacha20asm.HasNEONX16), SipHash-2-4 carries NEON four-lane and general-purpose-register single-lane fused-cascade kernels on the ARMv8-A baseline (siphashasm.FusedHasNEON / siphashasm.HasNEONX16), and Areion-SoEM-256 / -512 carry NEON fused-cascade kernels via the ARM Crypto Extension (areionasm.FusedHasARMAES / areionasm.HasARMAESX16) alongside the Areion permutation's AArch64 assembly path. Every other ChainHash instantiation on AArch64 runs its portable Go path. The Interlocked Barrier rank-mask derivation on AArch64 runs the NEON eight-lane batched unrank kernel (interlock.HasNEONInterlock); the batched chunk apply runs the SVE2 BEXT / BDEP kernels where FEAT_SVE_BitPerm is present (interlock.HasSVE2Interlock) and the software set-bit-walk batch elsewhere; the per-chunk apply entry points stay on softPEXT48 / softPDEP48 there. The -tags noitbasm build tag disables every project-private assembly path uniformly, routing all callers through the portable Go fallbacks. Runtime tier selection is exposed to the cross-build parity harness through ITB_FORCE_HASH_TIER (avx512 / vaesavx2 / avx2 / vex / aesni / neon / gpr / scalar), ITB_FORCE_INTERLOCK_TIER (avx512 / avx512x8 / avx2 / sve2 / sve / neon / scalar), ITB_FORCE_INTERLOCK_PRF_FILL_TIER (avx512 / vaesavx2 / avx2 / vex / aesni / neon / gpr / scalar, the AES-ITB-128, AES-CMAC, SipHash-2-4, Areion-SoEM-256 / -512, BLAKE2b-256 / -512, BLAKE2s, BLAKE3 and ChaCha20 batch-16 fill kernels), ITB_FORCE_CHAINHASH_X4 (1, pins the four-lane fused ChainHash kernels and the four-pixel stride where the eight-lane AES-ITB-128, AES-CMAC, SipHash-2-4, Areion-SoEM-256 / -512, BLAKE2b-256 / -512, BLAKE2s, BLAKE3 or ChaCha20 arm would be selected), and ITB_FORCE_PIXEL_TIER (A / A_NOGFNI / B / B_NOGFNI / C) — feature-suppression masks that simulate a fleet CPU class on a single reference host so every shipped arm is reachable end-to-end.
The inventory below classifies each instruction by its known data-dependent latency profile across supporting microarchitectures. ITB's correctness does not depend on any of these instructions being constant-time; the architectural barrier is software-level. The table records the instruction-level reality so that deployments targeting hardware-aware threat models can audit against it. This analysis has not been independently verified.
| Instruction | Used In | CPU Support | Side-Channel Profile | ITB Exposure |
|---|---|---|---|---|
VAESENC / VAESENCLAST |
areion_amd64.s, areion_soem*_amd64.s, areion_fusedchain{256,512}_*_{avx512,vaesavx2}_amd64.s, aescmacasm/*_amd64.s |
VAES on YMM: Ice Lake+ / Tiger Lake / Zen 3+; VAES on ZMM: Ice Lake-SP+ / Zen 4+ | Constant-time hardware AES on all known supporting microarchitectures. No T-table fallback in this path; immune to classical AES cache-timing attacks (Bernstein 2005, Osvik / Shamir / Tromer 2006) targeting software S-box / T-table implementations | Areion-SoEM permutation and its ChainHash chains, plus the AES-CMAC ChainHash chain, run entirely through VAES on supporting hosts. Non-VAES hosts route to the XMM AES-NI kernels described in the next row; hosts without either land on the portable Go path via aes.Round4HW from github.com/jedisct1/go-aes. The chain-staging data movement surrounding the AES rounds in areion_fusedchain{256,512}_*_avx512_amd64.s and aescmacasm/*_amd64.s (VINSERTI64X2 / VEXTRACTI64X2 — AVX-512DQ lane insert / extract — plus VBROADCASTI32X4, VMOVDQU64 / VMOVDQA64, VPXORD / VPXORQ, VPBROADCASTQ, all AVX-512F; in the eight-lane fill kernel areion_fusedchain256_13x8_avx512_amd64.s also the in-register message-block synthesis VPUNPCKLQDQ, VPSLLQ / VPSRLQ, VPORQ, VPADDQ over the public group-index counter) is register-to-register / fixed-offset load-store with the same constant-time profile as the ARX ChainHash row below |
AESENC / AESENCLAST (XMM, AES-NI) plus PXOR, MOVOU, MOVQ, PUNPCKLQDQ |
areion_fusedchain{256,512}_{13,20,36,68}x{1,4}_aesni_amd64.s, aescmacasm/aescmac_fusedchain128_*_{aesni,vex}_amd64.s |
AES-NI (XMM AESENC / AESENCLAST): Intel Westmere+ / Silvermont+ / AMD Bulldozer+ (Zen 1+); universal on every AVX2-capable x86 SKU |
Constant-time hardware AES on all known supporting microarchitectures. Same S-box / MixColumns semantics as VAESENC; documented fixed-latency execution on every published AES-NI-supporting µarch. The independent chains — the four per-lane chains of the AES-CMAC kernels; in the Areion-SoEM kernels the lane- and permutation-disjoint chains of each pass (two lanes × the two SoEM permutations at width 256, one lane × the two permutations at width 512) — advance in ILP-interleaved form (AESENC X13, X8; AESENC X13, X9; AESENC X13, X10; AESENC X13, X11; …), so the ~4-cycle single-issue-port AESENC latency is hidden behind chain-disjoint dependencies rather than through hardware dispatch |
Areion-SoEM ChainHash and AES-CMAC ChainHash on AES-NI-only silicon without VAES — Cascade Lake Xeon Gold, AMD Zen 3, and every AVX2-no-VAES cloud VM. The AES-CMAC round keys are pre-expanded at attach time and loaded into X6..X15 (K0 folded into the staged blocks) at function entry via MOVOU from a public read-only address; the Areion-SoEM kernels load each round constant via MOVOU from the public read-only AreionRC4x table at a fixed offset; the staged data blocks live in a stack buffer whose addresses are function-entry constants |
AESE / AESMC (ARM Crypto Extension) |
areion_arm64.s; internal/areionasm/areion_fusedchain{256,512}_{13,20,36,68}x{1,4}_neon_arm64.s; internal/areionasm/areion_fusedchain{256,512}_13x8_neon_arm64.s; internal/aesitbasm/aesitb_fusedchain128_{13,20,36,68}x{1,4}_neon_arm64.s; internal/aesitbasm/aesitb_fusedchain128_13x16_neon_arm64.s |
ARMv8-A +crypto mandatory on all server-class AArch64: Neoverse N1+/V1+/V2+ (AWS Graviton 2+), Apple M1+, Cortex-A53+ with the optional crypto extension fused |
Constant-time hardware AES on all known supporting microarchitectures. Same single-instruction round + MixColumns shape as VAESENC; no T-table fallback in this path. ARMv8 AES extension instructions are documented constant-time in the ARM Architecture Reference Manual |
Areion-SoEM permutation runs through 4-lane parallel AESE/AESMC chains on hosts with the ARM Crypto Extension. The AES-ITB-128 fused ChainHash cascade kernels and the batch-16 Interlocked Barrier fill kernel on AArch64 route their AES rounds through the same AESE / AESMC instructions under aesitbasm.FusedHasARMAES / aesitbasm.HasARMAESX16. The pure-Go Areion fallback uses aes.Round4HW from github.com/jedisct1/go-aes (which itself routes to the same ARM AES extension via armRound4 when available). Every other registry primitive's ChainHash chains run portable Go on AArch64 |
VGF2P8AFFINEQB (GFNI) |
process_pixels.c Tier A / B |
Ice Lake+ / Tremont+ / Zen 4+ | Constant-time GF(2)-affine transformation. No published side-channel attacks. Latency is not data-dependent on supporting microarchitectures | Tier A / B Phase 4 (per-pixel rotation) and Phase 5 (noise-bit insert / extract) lower to single-instruction GFNI affine. Affine matrices are fetched from compile-time-constant lookup tables indexed by noisePos / dataRotation; each table occupies a single 64-byte cache line (aligned(64)), so the secret-derived index selects within one line — a branch-free access with index-independent cache-line footprint — and the fetched matrices then enter constant-time GFNI |
VPSLLVW, VPSRLVW (AVX-512BW variable-shift, word lanes); VPSLLVD (AVX-512F); VPMULLW (AVX-512BW); VPTERNLOGQ (AVX-512F ternary); VPMULTISHIFTQB-free 8×7-bit field extraction via VPSRLVW + VPANDQ mask; the load / store / permute base ops from the AVX-512F rows above (VPERMQ intra-register qword permute for the pack step, VMOVDQU8 masked store) |
process_pixels.c Tier A′ (process8PixelsEncodeAVX512NoGFNI / process8PixelsDecodeAVX512NoGFNI and their helpers) |
AVX-512F + AVX-512BW + AVX-512VL: Skylake-X+ / Ice Lake+ / Rocket Lake+ / Zen 4+ (GFNI + VBMI not required) | Constant-time / data-oblivious latency on supporting microarchitectures. The variable-shift lanes (VPSLLVW / VPSRLVW / VPSLLVD) take a per-lane shift-count vector whose values are secret-derived (noisePos, dataRotation), but the shift-count → latency mapping is documented constant on every AVX-512BW-supporting µarch. VPTERNLOGQ replaces both the GFNI affine step (Phase 4 rotation) and the noise-mask fold (Phase 5) with a bitwise ternary logic function whose truth-table constant is compile-time. No VGF2P8AFFINEQB, no VPERMB (VBMI), no VPMULTISHIFTQB (VBMI) — the extraction and pack helpers use VPSRLVW + VPMULLW + VPACKUSWB and constant-index VPERMQ instead. No secret-dependent memory access, no secret-dependent branch |
8-pixel batched pixel encoder on AVX-512 hosts that ship without GFNI or without VBMI. Real-fleet coverage: Cascade Lake / Cooper Lake (Xeon Gold / Platinum server class), any AVX-512F+BW+VL SKU where the vendor withheld GFNI and VBMI. Dispatch selects this tier when itb_check_avx512_gfni() returns 0 but itb_check_avx512_nogfni() returns 1; the leftover 4–7-pixel batches at the end of the loop route to Tier B or Tier B′ as the host actually supports, so a Cascade Lake host completes with A′ + B′ end-to-end. Simulated by ITB_FORCE_PIXEL_TIER=A_NOGFNI for cross-build parity coverage |
VPSLLVQ, VPSLLQ, VPSLLW, VPSRLQ, VPSRLW, VPMADDUBSW, VPMADDWD, VPSHUFB, VPAND, VPANDN, VPOR, VPXOR, VPADDQ, VPBROADCASTB, VPBROADCASTQ, VMOVDQU, VMOVDQA, VEXTRACTI128, VINSERTI128, VMOVQ (AVX2 without GFNI); word-lane 8×7-bit unpack is a VPMADDUBSW-based multiply-by-{1, 2^7} fold plus a qword shift-OR, the same shape the AVX2-with-GFNI Tier B decode pack step uses |
process_pixels.c Tier B′ (process4PixelsEncodeAVX2NoGFNI / process4PixelsDecodeAVX2NoGFNI and their helpers) |
AVX2 baseline: Intel Haswell+, AMD Excavator+ (Zen 1+); GFNI not required | Constant-time / fixed-latency reciprocal throughput on supporting microarchitectures. The rotation and noise-bit-insert phases synthesise the VGF2P8AFFINEQB affine of Tier B from VPSLLVQ variable-shift and VPAND / VPOR masking; the shift-count vectors carry secret-derived per-pixel values but latency is documented constant on every AVX2-supporting µarch. Extraction / pack are the same VPMADDUBSW + VPMADDWD word-lane multiply-add tree as the Tier B / Tier A decode pack step (row above) — multiplier operands are compile-time constants, only the multiplicand lanes carry secret-derived channel values. No secret-dependent memory access, no secret-dependent branch |
4-pixel batched pixel encoder on AVX2 hosts without GFNI. Real-fleet coverage: AMD Zen 3 (desktop Ryzen 5000 series), Intel Haswell / Broadwell / Skylake-client / Coffee Lake / Comet Lake, AVX2-only cloud VMs that redact GFNI. Dispatch selects this tier when itb_check_avx2_gfni() returns 0 but itb_check_avx2_nogfni() returns 1; also handles the 4–7-pixel leftover batches under Tier A′ end-to-end. Simulated by ITB_FORCE_PIXEL_TIER=B_NOGFNI for cross-build parity coverage |
VPERMB (AVX-512 VBMI) |
process_pixels.c Tier A |
Cannon Lake+ / Ice Lake+ / Tiger Lake / Zen 4+ | Constant-time byte-permutation within a vector register. Not a memory-gather instruction — Downfall (CVE-2022-40982) targets vpgatherdd / vpgatherqq and similar GATHER family instructions that read from memory by index vector; VPERMB shuffles bytes within an existing register |
Tier A Phase 1 (8-pixel byte gather from packed plaintext), encode Phase 5 (noise-mask byte broadcast across qword lanes), and the decode Phase 4 pack step (pack56bitsX8AVX512VBMI 56-byte lane compaction before the masked store); all permutation index vectors are public compile-time constants |
VPMULTISHIFTQB (AVX-512 VBMI) |
process_pixels.c Tier A |
Ice Lake+ / Zen 4+ | Constant-time. Latency is not data-dependent on supporting microarchitectures | Tier A Phase 1: 8 × 7-bit field extraction from 64-bit packed pixel descriptors |
VPMADDUBSW / VPMADDWD (AVX2 forms in Tier B, AVX-512BW forms in Tier A) plus the Tier A masked byte store VMOVDQU8 (_mm512_mask_storeu_epi8, AVX-512BW) |
process_pixels.c decode Phase 4 pack step: pack56bitsX8AVX512VBMI (Tier A) / pack56bitsX4AVX2 (Tier B) |
AVX2: Haswell+ / Zen 1+; AVX-512BW: Skylake-X+ / Ice Lake+ / Rocket Lake+ / Zen 4+ | Constant-time fixed-latency SIMD integer multiply-add on supporting microarchitectures; latency is not data-dependent. The multiplier operands are compile-time constants ({1, 2^7} byte pairs, then {1, 2^14} word pairs); only the multiplicand lanes carry secret-derived channel values |
Decode Phase 4 batched pack: per qword lane, eight 7-bit channel values fold into one 56-bit packed word via the two-step multiply-add tree plus a qword shift-OR. Tier A then compacts lanes with VPERMB and issues one masked 56-byte store per 8-pixel batch; Tier B extracts four packed qwords and writes four overlapping 8-byte stores. Store addresses and the Tier A store k-mask derive only from public geometry (bitIndex, dataLen); the stored bytes are secret-derived plaintext — the same exposure class as every plaintext store in the pixel kernel |
PEXTQ / PDEPQ (BMI2, 64-bit forms) |
interlockasm48_amd64.s; interlockasm48_batch_amd64.s |
BMI2: Intel Haswell+, AMD Zen 3+ (constant-time hardware); AMD Zen 1 / Zen 2 microcode-emulate PEXT / PDEP with data-dependent latency (Agner Fog instruction tables; AMD Software Optimization Guide) — those hosts fall through to the software Go fallback per the µarch floor stated above |
Under the µarch floor, PEXTQ and PDEPQ execute at fixed latency independent of x and mask. The 48-bit Interlocked Barrier per-chunk kernels Chunk48Lock and Unchunk48Lock issue three PEXTQ (encode) or three PDEPQ + two OR (decode) per 6-byte chunk. The batched kernels chunk48LockBatch / unchunk48LockBatch run the same three PEXTQ / PDEPQ per chunk under an outer loop with a public trip count n (the batch size), taking each chunk's mask triple as a memory operand and folding the per-chunk byte assembly / lane store into the kernel — bit-exact with n per-chunk calls, and under the same constant-time argument (the trip count is public; PEXTQ / PDEPQ are data-oblivious; the mask memory operands are addressed by the public loop counter, not by a secret index). Mask popcount is fixed at 16 for each lane by construction (balanced 16-of-48 partition; enforced by the caller-side unrank), so secret-derived mask popcount does not modulate latency even on hosts whose PEXT latency varies with popcount. On Zen 2 and older the software fallback (softPEXT48 / softPDEP48) runs instead; see the pure-Go fallback note below |
|
VPERMT2Q, VPERMI2Q, VPCMPUQ, VPTESTMQ, VPSUBQ (mask-merged), VPORQ (mask-merged), VPANDNQ, VPXORQ, VPTERNLOGQ, VPSLLQ, VPSRLQ, VMOVDQU64, VMOVDQA64, VPMOVZXDQ (AVX-512F) |
interlockasm48_amd64.s rankToMaskTripleUnrank48AVX512 (8-lane) and interlockasm48_x16_amd64.s rankToMaskTripleUnrank48x16AVX512 (16-lane) batched combinadic unrank |
AVX-512F baseline: Skylake-X+ / Ice Lake+ / Rocket Lake+ / Zen 4+ | Constant-time / data-oblivious latency on supporting microarchitectures. VPERMT2Q (8-lane kernel) and VPERMI2Q (16-lane kernel) are semantically equivalent two-source intra-register qword permutes — the write-back register is the only difference between the two encodings — that select the per-position binomial constants C(p, k) by remaining-count. Both are register-only permutes, not memory-gathers — distinct from the Downfall GATHER family. The per-position pick is applied via mask registers (VPTESTMQ → krem != 0 k-mask fed as writemask to VPCMPUQ, whose output k-mask carries the conjunction (rank >= c) & (krem != 0) in the compare itself, then mask-merged VPSUBQ / VPORQ complete the update); no secret-indexed memory access, no secret-dependent branch. Loop constants (the per-position bit vector, the all-ones seed) are derived arithmetically via VPTERNLOGQ / VPSLLQ / VPSRLQ on an EVEX-only seed, avoiding the MOVQ GPR→XMM legacy-SSE bridge that triggers dirty-upper save/restore transitions on Golden Cove Server P-cores. Row memory reads (VMOVDQU64 (R12) and VMOVDQU64 64(R12) covering one 128-byte packed row) index by p ∈ [0, 48], which counts down through a public constant range, not by a secret index |
The batched Interlocked Barrier mask-triple derivation kernels — engaged on AVX-512F hosts by the parent dispatcher: the 16-lane rankToMaskTripleUnrank48x16AVX512 runs one pass over 16 chunks under interlock.RankToMaskTripleUnrank48x16 when UseUnrank16 and HasAVX512RankMask are true, and the 8-lane rankToMaskTripleUnrank48AVX512 runs under interlock.RankToMaskTripleUnrank48 when the caller has an 8-lane batch or the 16-lane geometry is disabled (ITB_FORCE_INTERLOCK_TIER=avx512x8). The two-step 128-bit divmod (⌊rank / B⌋ mod A, rank mod B) is computed in scalar Go before either kernel runs; both consume pre-split idx0, idx1 and produce mask triples in the same [3]uint64-per-chunk layout. The mask-space cardinality and per-chunk PRF independence properties these kernels realise are covered in SCIENCE.md § 1.5 Interlocked Barrier and § 2.15 Mask Space (Theorem 11) |
VPERMD, VPCMPEQQ, VPCMPGTQ, VPCMPEQD, VPSUBQ, VPADDD, VPOR, VPAND, VPANDN, VPXOR, VPSHUFD, VPSLLQ, VPSRLQ, VPMOVZXDQ, VMOVDQU, VMOVDQA, plus scalar PDEPQ (BMI2) in the remap tail (AVX2 + BMI2) |
interlockasm48_avx2_amd64.s rankToMaskTripleUnrank48AVX2 batched combinadic unrank |
AVX2 + BMI2: Intel Haswell+, AMD Zen 3+ (constant-time BMI2 by µarch floor above); every AVX2-capable x86 SKU without AVX-512F | Constant-time / data-oblivious latency on supporting microarchitectures. VPERMD is an intra-register dword permutation over an in-register source vector — not a memory-gather; the secret per-lane remaining-count krem is consumed as a permute index into a public-address broadcast row, so neither the memory-access pattern nor the control flow depends on the secret index. The predication that AVX-512 does with k-masks is emulated with all-ones / all-zero YMM predicates from VPCMPEQQ / VPCMPGTQ and merged via VPANDN(pred, operand) + VPOR / VPSUBQ — the same constant-time invariant VPERMT2Q establishes for the AVX-512 kernel. The pbit and mask constants at prologue entry are derived arithmetically via VPCMPEQD / VPSLLQ / VPSRLQ on an all-ones YMM seed rather than a MOVQ GPR→XMM legacy-SSE bridge, avoiding the dirty-upper save/restore transition on Golden Cove Server P-cores. The crow row address depends only on the public loop position p ∈ [0, 48]; the scalar PDEPQ remap tail is under the same fixed-latency-BMI2 µarch floor as Chunk48Lock / Unchunk48Lock above |
The AVX2 4-lane rank-mask kernel — engaged when HasAVX2RankMask is true (AVX2 + BMI2 present, AVX-512F absent). The 8-lane logical batch runs as two 4-lane YMM halves under an outer half loop; the output layout [3][8]uint64 matches the AVX-512 kernel bit-for-bit. Same mask-space cardinality, per-chunk PRF independence, and constant-time discipline as the AVX-512 row above (see SCIENCE.md § 1.5 Interlocked Barrier and § 2.15 Mask Space (Theorem 11)) |
VTBX, VCMHS, VUSHL, VUSHR, VSHL, VUSHLL / VUSHLL2, VAND, VBIC, VORR, VEOR, VADD, VSUB, VMOVI, VDUP / VMOV, VLD1, VST1 (ARMv8-A Advanced SIMD) |
interlockasm48_neon_arm64.s rankToMaskTripleUnrank48NEON batched combinadic unrank |
ARMv8-A baseline (Advanced SIMD is mandatory): Neoverse N1+/V1+/V2+ (AWS Graviton 2+), Apple M1+, Cortex-A53+ | Constant-time / data-oblivious latency on supporting microarchitectures. VTBX is an intra-register byte-table lookup over the binomial row held in eight vector registers — not a memory-gather; the secret per-lane pick count enters only as the byte index vector of that register permute, the same invariant VPERMT2Q / VPERMD establish for the amd64 kernels. An index past the table leaves the all-ones seed in place, which folds the krem != 0 predicate of the amd64 kernels into the gather. The per-position pick is applied through VCMHS all-ones / zero predicates and VAND / VBIC-masked VORR / VSUB / VADD updates; the remap tail is a fixed 48-step vector walk whose per-lane variable shifts (VUSHL by a register count) are data-oblivious. The binomial row address depends only on the public loop position p ∈ [0, 48]; trip counts are fixed (48, 32, 48). No secret-dependent branches, no secret-indexed memory |
The AArch64 8-lane rank-mask kernel — engaged under interlock.RankToMaskTripleUnrank48 when HasNEONInterlock is true (every arm64 host; ITB_FORCE_INTERLOCK_TIER=scalar clears it). Two qword lanes per register, four registers per state vector, the eight lanes sharing one binomial-row load; the output layout [3][8]uint64 matches the amd64 kernels bit-for-bit. Same mask-space cardinality, per-chunk PRF independence, and constant-time discipline as the AVX-512 row above (see SCIENCE.md § 1.5 Interlocked Barrier and § 2.15 Mask Space (Theorem 11)) |
BEXT / BDEP (SVE2 bit-permute, .D elements, emitted as raw instruction words) plus VMOV GPR↔lane moves, VLD3.P structure loads, MOVHU / MOVWU / MOVH / MOVW exact-width loads and stores |
interlockasm48_sve2_arm64.s chunk48LockBatchSVE2 / unchunk48LockBatchSVE2 batched chunk apply |
SVE2 with FEAT_SVE_BitPerm: gated on the SVE2 CPU flag and the Linux HWCAP2_SVEBITPERM auxiliary-vector bit (Neoverse V2 — AWS Graviton 4 — and later); Neoverse V1 (SVE only — AWS Graviton 3), NEON-only cores and non-Linux hosts keep the software set-bit-walk batch |
BEXT / BDEP are the vector forms of PEXT / PDEP: one instruction extracts (deposits) the bits of every 64-bit lane under the corresponding lane of a mask vector, register-only, with no secret-indexed memory access. No published report of data-dependent latency for these instructions is known; the latency has not been measured here. The trip count n is public; two chunks run per step in the low 128 bits of the Z registers, so the kernels are independent of the implemented vector length |
The AArch64 batched Interlocked Barrier chunk apply — engaged under interlock.Chunk48LockBatch / Unchunk48LockBatch when HasSVE2Interlock is true (ITB_FORCE_INTERLOCK_TIER=neon / sve clear it, scalar clears the batched entry as well). Bit-exact with n per-chunk softPEXT48 / softPDEP48 applications; the per-chunk entry points Chunk48Lock / Unchunk48Lock stay on the software path on arm64 (HasBMI2 is false there) |
VPADDQ, VPADDD, VPXORQ, VPXORD, VPRORQ, VPRORD, VPROLQ, VPROLD, VPTERNLOGQ, VPTERNLOGD, VPBROADCASTQ, VPBROADCASTD, VPEXTRQ, VPEXTRD, VPINSRQ, VPINSRD, VMOVDQU64, VMOVDQA64, VEXTRACTI64X2, VEXTRACTI32X4, VEXTRACTI64X4, VINSERTI64X2, VBROADCASTI32X4, VPERMT2Q, VPUNPCKLQDQ, VPUNPCKHQDQ, VPORQ, VPSLLQ, VPSRLQ, VPMOVQD, VMOVDQU32, VMOVDQA32, VMOVQ, VMOVD (AVX-512F + AVX-512DQ; VEXTRACTI64X2 / VINSERTI64X2 are the DQ-only requirement, emitted only by the 64-bit-lane kernels blake2basm / siphashasm — the 32-bit-lane kernels blake2sasm / blake3asm / chacha20asm stay within plain AVX-512F. VPTERNLOGQ / VPTERNLOGD also appear in the embedded-broadcast memory-operand form VPTERNLOGQ.BCST / VPTERNLOGD.BCST in blake2basm / blake2sasm / blake3asm / chacha20asm (the BLAKE2s, BLAKE3 and ChaCha20 fused cascade kernels; the ChaCha20 kernels also read their constants through VPADDD.BCST) — the only EVEX embedded-broadcast use across the shipped kernels) |
hashes/internal/{blake2basm,blake2sasm,blake3asm,chacha20asm,siphashasm}/*_amd64.s |
AVX-512F + AVX-512DQ: Skylake-X+ / Ice Lake+ / Rocket Lake+ / Zen 4+ | Constant-time / single-cycle reciprocal throughput on supporting microarchitectures. VPROR{Q,D} / VPROL{Q,D} are register-register rotates with immediate shift counts (the counts are compile-time constants derived from the round-function specifications of BLAKE2 / BLAKE3 / ChaCha20 / SipHash-2-4). VPTERNLOG{Q,D} computes a bitwise ternary logic function with a compile-time-constant truth table; the .BCST embedded-broadcast forms fold a chain-state word re-read into the same instruction via a memory operand at a fixed base-register + constant-offset address (not secret-indexed) — embedded broadcast is an EVEX encoding feature of AVX-512F and adds no CPU-feature requirement. VPERMT2Q (SipHash-2-4 batch-16 output interleave) is a two-table intra-register qword permutation — not a memory-gather instruction — whose index vector is a public compile-time constant loaded from a fixed read-only address (interleaveIdx16); the SipHash-2-4 kernels read their lane inputs through fixed-offset scalar loads and their component pairs through fixed-stride broadcasts. No secret-dependent branches, no secret-indexed memory |
The fused ChainHash cascade kernels for BLAKE2b-256 / -512, BLAKE2s, BLAKE3, ChaCha20 and SipHash-2-4, each family running at its natural active register width (XMM for the 32-bit-lane kernels, YMM for the 64-bit-lane kernels and for the BLAKE2s, BLAKE3 and ChaCha20 eight-lane per-pixel and Interlocked Barrier fill kernels, eight dword lanes per register; ZMM for the SipHash-2-4 eight-lane and batch-16 kernels and the BLAKE2b-256 / -512 eight-lane per-pixel and Interlocked Barrier fill kernels, eight lanes per register). The BLAKE2b, BLAKE2s and BLAKE3 fused kernels re-initialise the compression state each cascade round from a per-kernel read-only table (IV, parameter block, counter and final flag; for BLAKE3 the key words, IV, block length and flags) and rebuild the seed-injected message words as VPTERNLOGQ / VPTERNLOGD three-way XORs over the staged data word, the component broadcast and the previous round's output; the ChaCha20 fused kernels rebuild the eight key words the same way and start every block from the constants, the key words, the counter and the zero nonce. The two-hash noiseSeed + dataSeed calls per pixel and the 13-byte Interlocked Barrier fill-derivation batches (the whole component cascade per call; sixteen groups per batch-16 call for SipHash-2-4, eight per call for the eight-lane fill kernels of the other families) go through these kernels; the compressed state and message-block loads are lane-independent |
VPADDQ, VPADDD, VPXOR, VPAND, VPANDN, VPOR, VPSHUFB, VPSHUFD, VPSRLQ, VPSRLD, VPSLLQ, VPSLLD, VPBROADCASTQ, VPBROADCASTD, VPBROADCASTB, VMOVDQU, VMOVDQA, VEXTRACTI128, VINSERTI128, VPEXTRQ, VPEXTRD, VPINSRQ, VMOVQ (AVX2, VEX-encoded, YMM / XMM). Rotates are synthesised — ror32 = VPSHUFD $0xB1, ror24 / ror16 / ror8 = VPSHUFB against a .rodata mask, ror63 = VPSRLQ $63 ; VPADDQ ; VPOR, ror12 / ror7 = VPSRLD ; VPSLLD ; VPOR — because VPRORQ / VPRORD are AVX-512-only |
hashes/internal/{blake2basm,blake2sasm,blake3asm,chacha20asm,siphashasm}/*_avx2_amd64.s |
AVX2 baseline: Intel Haswell+, AMD Excavator+ (Zen 1+); every AVX2-capable x86 SKU shipped after 2013 | Constant-time / fixed-latency reciprocal throughput on supporting microarchitectures. The rotate synthesis uses .rodata shuffle masks whose addresses are compile-time constants (ror24MaskB2b<> / ror16MaskB2b<> and equivalents per family); the shift counts are round-function immediates. AVX2 exposes only 16 YMM registers, half the AVX-512 file, so the per-round message words spill to fixed stack slots (m[0..15] at 0(SP)..120(SP)) that the round schedule reads as memory operands at fixed base-register + constant-offset addresses — not secret-indexed. No secret-dependent branches |
The AVX2 fused ChainHash cascade kernels for BLAKE2b-256 / -512, BLAKE2s, BLAKE3, ChaCha20 and SipHash-2-4 (message words staged in the frame, read back as fixed-offset VPADDQ / VPADDD / VPXOR memory operands), engaged on AVX2-without-AVX-512F hosts (Zen 3, Cascade Lake, AVX2-only cloud VMs) through each family's FusedHasAVX2 capability flag (blake2basm.FusedHasAVX2 / blake2sasm.FusedHasAVX2 / blake3asm.FusedHasAVX2 / chacha20asm.FusedHasAVX2 / siphashasm.FusedHasAVX2). Same 4-lane parallelism as the AVX-512 tier, one YMM per state element for the 64-bit-lane families and one XMM per state element for the 32-bit-lane families |
ADDQ, XORQ, ROLQ, RORQ, SHLQ, ORQ, MOVQ, ADDL, XORL, RORL, ROLL, MOVL, MOVBLZX, DECQ / JNZ (x86-64 baseline integer ISA); ADD, EOR, ROR, ORR, ADDW, EORW, RORW, MOVD, MOVW, MOVWU, MOVBU, SUBS / BNE, SUB / CBNZ (AArch64 baseline integer ISA) |
hashes/internal/siphashasm/siphash_fusedchain128_{13,20,36,68}x1_gpr_amd64.s, siphash_fusedchain128_{13,20,36,68}x1_gpr_arm64.s; hashes/internal/blake2basm/blake2b_fusedchain{256,512}_{13,20,36,68}x1_gpr_amd64.s, blake2b_fusedchain{256,512}_{13,20,36,68}x1_gpr_arm64.s; hashes/internal/blake2sasm/blake2s_fusedchain256_{13,20,36,68}x1_gpr_amd64.s, blake2s_fusedchain256_{13,20,36,68}x1_gpr_arm64.s; hashes/internal/blake3asm/blake3_fusedchain256_{13,20,36,68}x1_gpr_amd64.s, blake3_fusedchain256_{13,20,36,68}x1_gpr_arm64.s; hashes/internal/chacha20asm/chacha20_fusedchain256_{13,20,36,68}x1_gpr_amd64.s, chacha20_fusedchain256_{13,20,36,68}x1_gpr_arm64.s |
Every x86-64 and ARMv8-A host — no SIMD extension is required; the kernels are engaged through each family's FusedHasGPR flag on every amd64 and arm64 build (cleared by ITB_FORCE_HASH_TIER=scalar) as the single-lane arm of every tier, and where no SIMD tier is selected the four-lane dispatchers and the batch-16 fill hooks (HasGPRX16) run single-lane calls over the same kernels |
Constant-time: general-purpose-register add / xor / rotate / shift with immediate counts, fixed-latency on all known x86-64 and AArch64 microarchitectures. The message words are read once per call through fixed-offset loads from the lane pointer, the component groups through a fixed-stride walk over the component array, and the only loop is the public cascade round count (DECQ / JNZ, SUBS / BNE, SUB / CBNZ on the group counter). No secret-dependent branches, no secret-indexed memory |
The single-lane fused ChainHash cascades of SipHash-2-4 (the four state words and the (lo, hi) carry in general-purpose registers across the whole cascade) and of BLAKE2b-256 / -512, BLAKE2s, BLAKE3 and ChaCha20 (the sixteen state words in general-purpose registers — fifteen on amd64, one c word in a frame slot reached through memory operands — the message or key words and, for ChaCha20, the state accumulator as frame slots; 32-bit operations for BLAKE2s, BLAKE3 and ChaCha20) — the per-pixel single-lane call and the single-lane Interlocked Barrier fill hook |
VADD, VEOR, VSHL, VSRI, VUSHR, VORR, VREV64, VREV32, VTBL, VDUP, VMOV, VZIP1, VZIP2, VLD1, VST1, FMOVQ (ARMv8-A Advanced SIMD, 64-bit lanes for SipHash-2-4 and BLAKE2b-256 / -512, 32-bit lanes for BLAKE2s, BLAKE3 and ChaCha20) |
hashes/internal/siphashasm/siphash_fusedchain128_{13,20,36,68}x4_neon_arm64.s, siphash_fusedchain128_13x8_neon_arm64.s; hashes/internal/blake2basm/blake2b_fusedchain{256,512}_{13,20,36,68}x4_neon_arm64.s; hashes/internal/blake2sasm/blake2s_fusedchain256_{13,20,36,68}x4_neon_arm64.s; hashes/internal/blake3asm/blake3_fusedchain256_{13,20,36,68}x4_neon_arm64.s; hashes/internal/chacha20asm/chacha20_fusedchain256_{13,20,36,68}x4_neon_arm64.s |
ARMv8-A baseline (Advanced SIMD is mandatory): Neoverse N1+/V1+/V2+ (AWS Graviton 2+), Apple M1+, Cortex-A53+ | Constant-time / fixed-latency SIMD integer add / xor / shift on supporting microarchitectures. Rotates are synthesised — VSHL + VSRI (shift-left, shift-right-insert) into an alternate register, VREV64 for the 64-bit-lane rotate by 32, VREV32 for the 32-bit-lane rotate by 16 and VTBL against a .rodata byte mask for the 32-bit-lane rotate by 8 — with immediate counts from the SipHash-2-4, BLAKE2b, BLAKE2s, BLAKE3 and ChaCha20 round functions; the message words are staged in fixed frame slots and read back through VLD1 / FMOVQ; the component words are broadcast with VDUP from a fixed-stride walk. No secret-dependent branches, no secret-indexed memory |
The NEON four-lane fused ChainHash cascades of SipHash-2-4 (two lanes per 128-bit register, two registers per state word), engaged through siphashasm.FusedHasNEON, of BLAKE2b-256 / -512 (two qword lanes per register, the four lanes as two passes, the state re-initialised each cascade round from a read-only table), engaged through blake2basm.FusedHasNEON, and of BLAKE2s, BLAKE3 and ChaCha20 (four dword lanes per register, one register per state word, the state re-initialised each cascade round from a read-only table and, for ChaCha20, the key words), engaged through blake2sasm.FusedHasNEON / blake3asm.FusedHasNEON / chacha20asm.FusedHasNEON; the batch-16 Interlocked Barrier fill arm on AArch64 runs four four-lane calls over Go-synthesised fill blocks for SipHash-2-4 (siphashasm.HasNEONX16), two for BLAKE2s / BLAKE3 / ChaCha20 (blake2sasm.HasNEONX16 / blake3asm.HasNEONX16 / chacha20asm.HasNEONX16) and for BLAKE2b two at width 256 and one at width 512, the width-512 batch-32 hook two (blake2basm.HasNEONX16) |
VZEROUPPER |
areion_amd64.s exit; interlockasm48_amd64.s / interlockasm48_avx2_amd64.s exit; every AVX-512 and AVX2 ChainHash kernel exit (excluding the XMM AES-NI kernels, which touch no YMM / ZMM upper halves) |
AVX | Housekeeping. Zeros bits 128..511 of YMM0..YMM15 (i.e. ZMM0..ZMM15 upper halves); does not zero Y0..Y15 lower 128 bits. VZEROALL (not used here) would clear all YMM0..YMM15 including lower 128 bits |
After VAESENC / VPERMT2Q / AVX2 rank-mask / AVX2 ChainHash paths complete, the lower 128 bits of YMM0..YMM15 may retain Areion round constants, Interlocked Barrier row constants, or ChainHash working state until the next vector instruction overwrites them. RFDS treats this as a baseline exposure for any vector-using process; it is not specific to ITB. Exit VZEROUPPER reduces the persistence window of upper halves but does not eliminate lower-half exposure. The XMM AES-NI kernels (areion_fusedchain{256,512}_*_aesni_amd64.s, aescmac_fusedchain128_*_aesni_amd64.s) touch only X0..X15, so no upper-half tail is introduced by that dispatch tier |
VPXOR / VMOVDQA / VMOVDQU (AVX / AVX2, VEX-encoded); VPAND / VPOR / VPSRLQ on ZMM (EVEX-encoded, emitted by GCC from _mm256_* / _mm512_* intrinsics) |
areion_amd64.s; process_pixels.c Tier A / B |
AVX2 / AVX-512F | Constant-time. Single-cycle reciprocal throughput on supporting microarchitectures | Building blocks for the rest of the kernels. Memory addressing for VMOVDQU / _mm*_load_si* in process_pixels.c depends on pixelOffset (derived from startPixel), so the load address pattern inherits the existing startPixel cache side-channel observation already documented in Category 3 |
GFNI matrix-table lookup. The affine matrices consumed by the Tier A / Tier B batched kernels are compile-time constants (itb_gfni_rot_matrices, itb_gfni_spread_matrices, itb_gfni_gather_matrices in process_pixels.c) — one entry per possible dataRotation / noisePos value, resident in read-only data. Each table fits a single 64-byte cache line (aligned(64); 56 / 64 / 64 bytes), so the secret-derived index never selects between cache lines: the lookup is branch-free, and its dcache footprint is index-independent on the supported microarchitecture floor (intra-line access latency is index-independent on Rocket Lake+ / Zen 3+). The fetched matrices are staged through short-lived stack buffers before the _mm256_load_si256 / _mm512_load_si512 affine application; the staged addresses are stack offsets (not secret-address-dependent), the values written are derived from secrets, and aliasing into an attacker-shared cacheline is bounded by the stack buffer lifetime.
Pixel-index arithmetic (wrap handling). The batched loops in process_pixels.c maintain the wrapped linear pixel index (% totalPixels) as a loop-carried counter with a branchless conditional subtract (mask form, no branch instruction). The batched Tier A / Tier B helpers additionally select a consecutive fast path with a single batch-entry branch on basePixel + batchWidth <= totalPixels — a predicate that is a pure function of the already-wrapped startPixel-derived counter, i.e. entirely derived from the same startPixel state that the container access pattern exposes, so the branch adds no information beyond the startPixel exposure already documented in Category 3. The wrap predicate derives from startPixel and stays within that same exposure; no data-derived branch is present in the index path, and the wrap arithmetic inside the per-pixel body remains branch-free.
Batched store / load chains (Tier A / Tier B). On wrap-crossing batches, the batched paths in process_pixels.c write per-pixel computed bytes into a stack-resident outBuf via _mm256_store_si256 / _mm512_store_si512 and then memcpy from outBuf into the container at pixelOffset[b]; consecutive batches store the vector result directly to the container with a single unaligned store. This produces a store-then-load chain on adjacent stack addresses. The chain is not secret-address-dependent: source and destination addresses are stack offsets and pixelOffset[b] (derived from startPixel, already-documented exposure). Spectre v4 (SSB) exploitation requires speculative load reading a stale value before a same-address store completes; here source and destination are different addresses, and Speculative Store Bypass would not produce a cross-channel disclosure of secret-derived bytes that the architectural store does not also produce.
Pure-Go fallback paths. When neither the AVX-512F, AVX2, nor XMM AES-NI hardware paths are available — pre-Zen-3 AMD (Zen 1 / Zen 2 whose microcode-emulated PEXT / PDEP fall outside the µarch floor) and hosts predating AVX2 entirely (Intel pre-Haswell), any AArch64 host for the Interlocked Barrier and ChainHash kernels, WASM, or a build with the project-private -tags noitbasm tag — the corresponding routines dispatch to portable Go fallbacks. The Interlocked Barrier fallback is softPEXT48 / softPDEP48 (branchless 48-iteration loops over register-only bitwise AND / OR / variable-shift operations, no secret-indexed memory access, no secret-dependent branch, no lookup table). The fused ChainHash cascade kernels fall back to the AVX2 four-lane kernels described above where AVX2 is present, and to the single-lane general-purpose-register kernels of the same family otherwise; the pure-Go reference cascades in the same subpackage run under -tags noitbasm and ITB_FORCE_HASH_TIER=scalar. The Areion permutation falls back to the XMM AES-NI fused ChainHash cascade kernels where AES-NI is present, then to aes.Round4HW from github.com/jedisct1/go-aes — which itself dispatches to hardware AES when the ARM Crypto Extension is available and to constant-time software AES otherwise. AES-CMAC follows the same descent (VAES ZMM → VAES YMM → VEX XMM AES-NI → legacy-SSE XMM AES-NI → crypto/aes scalar; NEON on AArch64). All fallback kernels are register-only and branchless with respect to secret values; the fallback exists for portability, not for production-throughput deployments (throughput drops by several × once the last dispatch tier below the AES-NI / AVX2 shelf is reached).
None of the hardware-level attacks analyzed above were found to introduce a new attack surface specific to ITB beyond what is already documented (startPixel cache side-channel, heap memory exposure). The construction's register-only data path for secret-dependent operations (noisePos, dataRotation, channelXOR) does not provide the disclosure gadget required by speculative execution attacks or the data-dependent memory access pattern required by cache-based attacks.
Note: ciphers whose implementations use secret-dependent table lookups (e.g., non-constant-time software S-box or T-table implementations) are known to provide disclosure gadgets exploitable by speculative execution, cache timing, and power analysis attacks. ITB's data path does not contain this pattern. However, modern hardware-accelerated implementations of standard ciphers (e.g., AES-NI) also avoid table lookups and are similarly not susceptible to these specific vectors. This is an architectural observation, not a security guarantee.
If a DPA/SPA attack were to recover intermediate values from ITB's data path, the most directly observable value would be the rotation amount per pixel — not the key itself. Recovering the key from rotation values would require inverting ChainHash, which is blocked under the PRF assumption (inversion is infeasible). Even in the event of a partial PRF weakness, the attacker would additionally need startPixel (derived from independent startSeed, not transmitted) to apply inversion, and would still face the 8-noisePos ambiguity from the independent noiseSeed — the pixel-layer KPA defense is 3-factor under the PRF assumption (4-factor under Partial KPA) (see Proof 4a). The always-on Interlocked Barrier (per-chunk ≈ 2^70.20 PRF-keyed mask-space; see SCIENCE.md § 1.5 Interlocked Barrier and § 2.15 Mask Space (Theorem 11)) sits between the recovered rotation values and the corresponding plaintext bits, so per-pixel rotation recovery alone does not reconstruct the barrier's mask triple. This analysis has not been independently verified and assumes the attacker targets ITB's register operations rather than the hash function itself.
- Spectre — Kocher et al., 2018
- Meltdown — Lipp et al., 2018
- Downfall/GDS — Moghimi, 2023
- Hertzbleed — Wang et al., 2022
- Zenbleed — Ormandy, 2023
- Rowhammer — Seaborn & Dullien, 2015
- Training Solo — VUSec, 2025