ppad measure
constant-time analysis

Constant-Time Analysis: ppad-aead

target
ppad-aead 0.3.4
runtime
haskell (GHC 9.10.3 · LLVM 19.1.7)
architectures
aarch64, x86_64
meters
wall, instructions, cycles
updated
2026-08-09
auditor
Jared Tobin (jared@ppad.tech)

ppad-aead v0.3.4 is an authenticated encryption library that composes the ChaCha20 stream cipher supplied by ppad-chacha with the Poly1305 message authentication code supplied by ppad-poly1305.

No exploitable secret-dependent timing was found on the analysed surface, viz. the 'encrypt' and 'decrypt' functions. Note that the static analysis is intentionally bounded to ppad-aead itself; see the measure analyses for ppad-poly1305 and ppad-chacha for details on the timing properties of those dependencies.

Dynamically, no constant-time hypothesis for the encrypt and decrypt paths was rejected on any available meter or host.

summary

function aarch64 x86_64
encrypt
AEAD encryption (ChaCha20-Poly1305)
SC SC
decrypt
AEAD decryption + tag verification
SC SC

no leak detected   leak   qualified   ? inconclusive   · not run    S = substratum   C = censor

method
adversary model

This analysis assumes an adversary capable of:

  • invoking the analysed functions with chosen inputs an arbitrary number of times,
  • measuring execution time with nanosecond precision,
  • measuring retired instruction counts or cycles, where a PMU exists,
  • observing cache state, and
  • observing memory allocation counts and sizes.

A trusted execution environment at the physical layer is assumed; considered out-of-scope are adversaries who can perform attacks over power or electromagnetic emanation-related side channels, speculative execution attacks, and so on.

security property

The security property under consideration is whether the analysed functions "run in constant time," i.e. whether the observable execution of any analysed function, when called with differing sensitive inputs, is indistinguishable to an attacker with the granted capabilities.

Consider the execution trace t(f, x) procured by evaluating an analysed function f on inputs x, where the trace consists of the sequence of instructions executed, the time they take to execute, the memory addresses accessed, and the size and count of allocations made. Then for any sensitive inputs s0 and s1, and any public input p, the property is, up to renaming of base pointers and stack addresses, and modulo any public comparison result, that:

t(f, (s0, p)) == t(f, (s1, p))

where equality is in terms of distribution.

This security property is scrutinized by way of two analyses.

static analysis

substratum v0.3.7 statically scans compiled assembly for variable-time instructions, e.g. conditional and indirect branches, register-indexed memory accesses, division, and variable shifts. It deterministically ascribes facts to instructions, e.g. that they represent control flow, memory addressing, etc., as well as establishes structural roles for them, such as that an instruction functions as an early-return guard or loop-latch. It also traces each fact's timing-relevant operands back to where the values entered the function.

From each audited entry, substratum filters out known runtime patterns and resolves the transitive closure of direct calls and return-frame continuations, scanning the body of every symbol it expands. The walk stops where control goes dynamic, where it leaves the parsed unit, or where the audit prunes it at a callee audited in its own lane. Every stopping edge, pruned callees included, is enumerated under analysis bounds, so the reach is an explicit lower bound rather than an implied whole. Filtered runtime facts are counted as "suppressed" under analysis bounds.

elenchus v0.1.0 is an agentic distillation protocol used to classify and annotate substratum facts. Two agents independently carry out an appraise action, constructing two separate candidate classification sets. One of those agents then carries out a supplemental dissent action that identifies where, if anywhere, the agents disagreed. A third agent then carries out a falsify action that tries to disprove every classification made. Finally, a coordinating agent distills the results, performing its own independent analysis on anything left unresolved, and the auditor accepts or revises every resulting classification. The classification scheme is as follows:

  • benign means the site's timing depends only on public data (lengths, allocation guards, constructor tags, loop counters over public bounds, etc.).
  • input validation marks a branch that rejects malformed input on a public property before any sensitive input-dependent work begins, revealing only the rejection.
  • negligible probability marks a path whose triggering event occurs with cryptographically negligible probability, typically that proportional to the inverse key size.
  • leak is a site whose timing depends on sensitive content. It flags sensitive information an observer could infer (e.g. a scalar byte, a bitlength, Hamming weight).
dynamic analysis

censor v0.4.4 dynamically falsifies constant-time execution. A case fixes a hypothesis (in which one class pins the sensitive input, the other draws it fresh per pair, with public context shared) and streams paired timing differences through a hedged e-process: a mixture of anytime-valid tests for mean shifts, shape asymmetries, and rare-outlier leaks. The displayed p is the anytime-valid p-value associated with the e-process at the stopping time; a hypothesis is rejected when p < α.

A censor run is performed for every hypothesis using every available meter. Wall time is the portable, always-available meter; the 'instructions retired' and 'cycles' meters require a PMU that may be unavailable on some platforms. Raw differences are clipped via a per-meter scale set during warmup, so heavy-tailed measurement noise can neither bankrupt nor inflate the test. The effect interval under each panel is the anytime-valid confidence interval for that (clipped) mean; its endpoints resolve on a grid of roughly 0.1·c. The jitter is the ratio of a measured baseline interquartile range to its median.

results

measure v0.3.1 synthesizes and presents the analyses. substratum and censor results, elenchus annotations, provenance information, and the auditor's written summary are deterministically aggregated, verified, and rendered into this report, which is then signed with the auditor's GPG signature.

findings by function

encrypt

Crypto.AEAD.ChaCha20Poly1305.encryptsensitive: key
substratumllvm
isa result symbols walked instructions flagged
aarch64 66 84
x86_64 56 90
class assessment note aarch64 x86_64
cond-branch
control-flow
input validation
public key- and nonce-length rejection
×2
early-return-guard
×2
cond-branch
control-flow
input validation
public nonce- or 16-byte MAC-length rejection
×1
early-return-guard
← load (R1)
×1
← entry (R1)
cond-branch
control-flow
benign
allocation, append and slice guards on public or fixed lengths (zero-length fast paths, negative-size and pad-size allocation checks, the take-32 slice of the 64-byte keystream block)
×46
×43
cond-branch
control-flow
benign
constructor-tag scrutiny of a public Either/closure scrutinee (GHC pointer-tag dispatch on the low bits of a heap pointer)
×7
×7
cond-branch
control-flow
benign
pad16 and length-serialisation control flow on the public AAD/ciphertext length (mod-16 dispatch, unroll8 right-padding and edge guards, and the byte-width serialisation loop)
×10
×13
length-call
work-count
benign
memcpy and memset counts from public AAD, ciphertext and pad component lengths
×16
×20
reg-index
memory-address
benign
BS-constructor field store at an immediate (or folded-immediate) offset; the index derives from code layout, not from any input
×1
address-base ← clobbered by call (approximate)
address-index ← immediate (approximate)
×3
reg-index
memory-address
benign
public-length byte store indexed by its bounded destination offset
×1
loop-latch, loop-exit, early-return-guard
address-base ← load (approximate)
address-index ← load (Sp frame slot)
×1
loop-latch, loop-exit
address-base ← load (Sp frame slot) (approximate)
address-index ← load (Sp frame slot)
complete fact list — aarch64 ×84 · x86_64 ×90
aarch64
b.ne LBB62_6
cond-branch
control-flow
$wencrypt:3730 input validation
b.ne LBB62_8
cond-branch
control-flow
$wencrypt:3744 input validation
b.ge LBB49_3
cond-branch
control-flow
blk_s5oA:2905 benign
b.lt LBB49_7
cond-branch
control-flow
blk_s5oA:2910 benign
cbz x9, LBB49_8
cond-branch
control-flow
blk_s5oA:2919 benign
b.mi LBB49_9
cond-branch
control-flow
blk_s5oA:2922 benign
cbz x22, LBB54_5
cond-branch
control-flow
blk_s5oI:3211 benign
b.lt LBB39_6
cond-branch
control-flow
blk_s5og:2326 benign
cbz x9, LBB42_4
cond-branch
control-flow
blk_s5oo:2479 benign
cbz x10, LBB42_9
cond-branch
control-flow
blk_s5oo:2481 benign
b.mi LBB42_8
cond-branch
control-flow
blk_s5oo:2484 benign
cbz x10, LBB42_10
cond-branch
control-flow
blk_s5oo:2501 benign
cbz x9, LBB42_11
cond-branch
control-flow
blk_s5oo:2503 benign
b.mi LBB42_8
cond-branch
control-flow
blk_s5oo:2506 benign
cbnz x10, LBB42_5
cond-branch
control-flow
blk_s5oo:2527 benign
cbz x22, LBB45_5
cond-branch
control-flow
blk_s5ow:2688 benign
cbz x9, LBB51_4
cond-branch
control-flow
blk_s5ql:3008 benign
cbz x8, LBB51_10
cond-branch
control-flow
blk_s5ql:3010 benign
b.mi LBB51_9
cond-branch
control-flow
blk_s5ql:3013 benign
cbz x9, LBB51_11
cond-branch
control-flow
blk_s5ql:3027 benign
cbz x8, LBB51_12
cond-branch
control-flow
blk_s5ql:3029 benign
b.mi LBB51_9
cond-branch
control-flow
blk_s5ql:3032 benign
cbnz x9, LBB51_5
cond-branch
control-flow
blk_s5ql:3055 benign
b.ge LBB22_4
cond-branch
control-flow
c5HV:1353 benign
tbnz x22, #63, LBB22_5
cond-branch
control-flow
c5HV:1355 benign
bl _memcpy
length-call
work-count
c5I4:1438 benign
b.ne LBB24_3
cond-branch
control-flow
c5IL:1493 benign
bl _memcpy
length-call
work-count
c5IT:1619 benign
b.ne LBB27_3
cond-branch
control-flow
c5J5:1665 benign
cbz x11, LBB21_5
cond-branch
control-flow
c5Ju:1234 benign
strb w11, [x10, x13]
reg-index
memory-address
c5Ju:1238 benign
b.ne LBB21_2
cond-branch
control-flow
c5Ju:1243 benign
b.ge LBB21_8
cond-branch
control-flow
c5Ju:1260 benign
tbnz x10, #63, LBB21_10
cond-branch
control-flow
c5Ju:1262 benign
b.ne LBB32_3
cond-branch
control-flow
c64E:1951 benign
b.ge LBB30_3
cond-branch
control-flow
c64V:1867 benign
b.ne LBB63_3
cond-branch
control-flow
c6aR:3843 input validation
b.ne LBB64_2
cond-branch
control-flow
c6b0:3910 benign
b.ne LBB65_4
cond-branch
control-flow
c6b6:3953 benign
cbz x26, LBB37_5
cond-branch
control-flow
c6bX:2191 benign
cbz x23, LBB37_6
cond-branch
control-flow
c6bX:2193 benign
b.mi LBB37_8
cond-branch
control-flow
c6bX:2196 benign
b.ne LBB67_3
cond-branch
control-flow
c6bq:4085 benign
b.ne LBB36_2
cond-branch
control-flow
c6by:2100 benign
b.lt LBB36_4
cond-branch
control-flow
c6by:2112 benign
cbz x9, LBB36_7
cond-branch
control-flow
c6by:2136 benign
stur x9, [x10, #-40]
reg-index
memory-address
c6by:2153 benign
b.ne LBB40_2
cond-branch
control-flow
c6cH:2378 benign
b.lt LBB40_4
cond-branch
control-flow
c6cH:2395 benign
bl _memcpy
length-call
work-count
c6co:2260 benign
bl _memcpy
length-call
work-count
c6co:2270 benign
bl _memcpy
length-call
work-count
c6dx:2568 benign
bl _memcpy
length-call
work-count
c6dx:2578 benign
cbz x8, LBB43_5
cond-branch
control-flow
c6dx:2583 benign
cbz x28, LBB43_6
cond-branch
control-flow
c6dx:2585 benign
b.mi LBB43_8
cond-branch
control-flow
c6dx:2589 benign
bl _memcpy
length-call
work-count
c6e2:2652 benign
bl _memcpy
length-call
work-count
c6e2:2662 benign
bl _memcpy
length-call
work-count
c6fq:3172 benign
bl _memcpy
length-call
work-count
c6fq:3182 benign
bl _memcpy
length-call
work-count
c6gM:3683 benign
bl _memcpy
length-call
work-count
c6gM:3693 benign
cbz x8, LBB58_5
cond-branch
control-flow
c6gp:3496 benign
cbz x24, LBB58_6
cond-branch
control-flow
c6gp:3498 benign
b.mi LBB58_7
cond-branch
control-flow
c6gp:3501 benign
cbz x9, LBB60_5
cond-branch
control-flow
c6gz:3594 benign
cbz x10, LBB60_6
cond-branch
control-flow
c6gz:3596 benign
b.mi LBB60_8
cond-branch
control-flow
c6gz:3599 benign
bl _memcpy
length-call
work-count
c6hI:3092 benign
bl _memcpy
length-call
work-count
c6hI:3102 benign
cbz x8, LBB52_5
cond-branch
control-flow
c6hI:3106 benign
cbz x26, LBB52_6
cond-branch
control-flow
c6hI:3109 benign
b.mi LBB52_7
cond-branch
control-flow
c6hI:3113 benign
bl _memcpy
length-call
work-count
c6hf:3556 benign
bl _memcpy
length-call
work-count
c6hf:3566 benign
b.ge LBB57_3
cond-branch
control-flow
c6iW:3430 benign
b.lt LBB57_4
cond-branch
control-flow
c6iW:3435 benign
cbnz x24, LBB57_6
cond-branch
control-flow
c6iW:3458 benign
b.lt LBB29_5
cond-branch
control-flow
s5m5:1814 benign
tbnz x24, #63, LBB13_5
cond-branch
control-flow
s5mM:625 benign
tbnz x24, #63, LBB14_5
cond-branch
control-flow
s5mT:716 benign
tbnz x24, #63, LBB17_5
cond-branch
control-flow
s5nK:989 benign
tbnz x24, #63, LBB15_5
cond-branch
control-flow
s5nk:807 benign
tbnz x24, #63, LBB16_5
cond-branch
control-flow
s5nu:898 benign
x86_64
jne .LBB62_7
cond-branch
control-flow
$wencrypt:3165 input validation
jne .LBB62_9
cond-branch
control-flow
$wencrypt:3176 input validation
jne .LBB39_2
cond-branch
control-flow
blk_s5qG:1901 benign
jle .LBB39_3
cond-branch
control-flow
blk_s5qG:1920 benign
movq %rcx, (%rax,%rdi,1)
reg-index
memory-address
blk_s5qG:1943 benign
movq %rdx, (%rax,%rsi,1)
reg-index
memory-address
blk_s5qG:1944 benign
je .LBB42_12
cond-branch
control-flow
blk_s5qO:2056 benign
je .LBB42_4
cond-branch
control-flow
blk_s5qO:2059 benign
js .LBB42_3
cond-branch
control-flow
blk_s5qO:2063 benign
je .LBB42_11
cond-branch
control-flow
blk_s5qO:2085 benign
je .LBB42_9
cond-branch
control-flow
blk_s5qO:2088 benign
js .LBB42_3
cond-branch
control-flow
blk_s5qO:2091 benign
je .LBB45_8
cond-branch
control-flow
blk_s5qW:2265 benign
jge .LBB49_1
cond-branch
control-flow
blk_s5r0:2422 benign
jle .LBB49_9
cond-branch
control-flow
blk_s5r0:2427 benign
je .LBB49_6
cond-branch
control-flow
blk_s5r0:2435 benign
js .LBB49_5
cond-branch
control-flow
blk_s5r0:2438 benign
je .LBB54_8
cond-branch
control-flow
blk_s5r8:2716 benign
je .LBB51_11
cond-branch
control-flow
blk_s5sL:2515 benign
je .LBB51_2
cond-branch
control-flow
blk_s5sL:2518 benign
js .LBB51_8
cond-branch
control-flow
blk_s5sL:2521 benign
je .LBB51_9
cond-branch
control-flow
blk_s5sL:2540 benign
je .LBB51_10
cond-branch
control-flow
blk_s5sL:2543 benign
js .LBB51_8
cond-branch
control-flow
blk_s5sL:2546 benign
jge .LBB22_4
cond-branch
control-flow
c5Kl:1060 benign
js .LBB22_3
cond-branch
control-flow
c5Kl:1063 benign
call memcpy@PLT
length-call
work-count
c5Ku:1130 benign
jne .LBB27_1
cond-branch
control-flow
c5LF:1336 benign
jne .LBB24_1
cond-branch
control-flow
c5Lg:1179 benign
call memcpy@PLT
length-call
work-count
c5Lo:1284 benign
je .LBB21_5
cond-branch
control-flow
c5M4:969 benign
je .LBB21_6
cond-branch
control-flow
c5M4:976 benign
movb %sil, (%rcx,%r8,1)
reg-index
memory-address
c5M4:980 benign
jne .LBB21_3
cond-branch
control-flow
c5M4:986 benign
jge .LBB21_9
cond-branch
control-flow
c5M4:999 benign
js .LBB21_8
cond-branch
control-flow
c5M4:1002 benign
jne .LBB32_1
cond-branch
control-flow
c67f:1558 benign
jge .LBB30_4
cond-branch
control-flow
c67w:1487 benign
jne .LBB64_1
cond-branch
control-flow
c6dB:3302 benign
jne .LBB65_1
cond-branch
control-flow
c6dH:3338 benign
jne .LBB63_3
cond-branch
control-flow
c6ds:3250 input validation
jne .LBB67_3
cond-branch
control-flow
c6e1:3437 benign
jne .LBB36_1
cond-branch
control-flow
c6e9:1687 benign
jle .LBB36_2
cond-branch
control-flow
c6e9:1700 benign
jne .LBB36_5
cond-branch
control-flow
c6e9:1723 benign
call memset@PLT
length-call
work-count
c6ey:1761 benign
je .LBB37_6
cond-branch
control-flow
c6ey:1773 benign
je .LBB37_3
cond-branch
control-flow
c6ey:1777 benign
js .LBB37_5
cond-branch
control-flow
c6ey:1782 benign
movq %r15, -8(%rbp,%rax,1)
reg-index
memory-address
c6ey:1808 benign
call memcpy@PLT
length-call
work-count
c6f2:1855 benign
call memcpy@PLT
length-call
work-count
c6f2:1864 benign
call memset@PLT
length-call
work-count
c6fP:2030 benign
jne .LBB40_1
cond-branch
control-flow
c6fq:1966 benign
jle .LBB40_2
cond-branch
control-flow
c6fq:1981 benign
call memcpy@PLT
length-call
work-count
c6gT:2233 benign
call memcpy@PLT
length-call
work-count
c6gT:2242 benign
call memcpy@PLT
length-call
work-count
c6gj:2144 benign
call memcpy@PLT
length-call
work-count
c6gj:2154 benign
je .LBB43_7
cond-branch
control-flow
c6gj:2161 benign
je .LBB43_5
cond-branch
control-flow
c6gj:2164 benign
js .LBB43_4
cond-branch
control-flow
c6gj:2170 benign
call memset@PLT
length-call
work-count
c6hX:2489 benign
call memcpy@PLT
length-call
work-count
c6ip:2684 benign
call memcpy@PLT
length-call
work-count
c6ip:2693 benign
je .LBB60_7
cond-branch
control-flow
c6jG:3045 benign
je .LBB60_5
cond-branch
control-flow
c6jG:3048 benign
js .LBB60_4
cond-branch
control-flow
c6jG:3051 benign
call memcpy@PLT
length-call
work-count
c6jT:3118 benign
call memcpy@PLT
length-call
work-count
c6jT:3128 benign
call memset@PLT
length-call
work-count
c6jt:2922 benign
je .LBB58_5
cond-branch
control-flow
c6jt:2931 benign
je .LBB58_6
cond-branch
control-flow
c6jt:2934 benign
js .LBB58_4
cond-branch
control-flow
c6jt:2937 benign
call memcpy@PLT
length-call
work-count
c6kZ:2596 benign
call memcpy@PLT
length-call
work-count
c6kZ:2606 benign
je .LBB52_5
cond-branch
control-flow
c6kZ:2613 benign
je .LBB52_6
cond-branch
control-flow
c6kZ:2618 benign
js .LBB52_4
cond-branch
control-flow
c6kZ:2621 benign
call memcpy@PLT
length-call
work-count
c6kr:3006 benign
call memcpy@PLT
length-call
work-count
c6kr:3015 benign
jge .LBB57_5
cond-branch
control-flow
c6mn:2865 benign
jle .LBB57_2
cond-branch
control-flow
c6mn:2870 benign
je .LBB57_3
cond-branch
control-flow
c6mn:2890 benign
jl stg_upd_frame_info@PLT
cond-branch
control-flow
s5ov:1449 benign
js .LBB15_5
cond-branch
control-flow
s5pK:638 benign
js .LBB16_5
cond-branch
control-flow
s5pU:709 benign
js .LBB13_5
cond-branch
control-flow
s5pc:496 benign
js .LBB14_5
cond-branch
control-flow
s5pj:567 benign
js .LBB17_5
cond-branch
control-flow
s5qa:780 benign
censor50000 pairs · α=1.0e-6 · batch 1
test cases
AEAD.encrypt (256 B) key fixed vs random; one shared (12 B nonce, 32 B AAD, 256 B plaintext) drawn per pair by the prologue and given to both classes, so the key is the only thing differing within a pair
host meter result p effect (mean/pair) jitter clip scale clipped
AEAD.encrypt (256 B)
aarch64-darwin wall 0.788 [-142, 425] ns 10% 2668 ns 1/50000 at 16c
x86_64-linux wall 0.769 [-16k, 47k] ns 72% 297k ns 1/50000 at 16c
x86_64-linux instructions 0.111 [-25k, 74k] instr 0.4% 463k instr 1/50000 at 16c
x86_64-linux cycles 0.583 [-18k, 54k] cyc 14% 340k cyc 1/50000 at 16c
AEAD.encrypt (256 B)aarch64-darwin
wall
log(1/α) 0 0
no leak detected · 50000 pairs · α=1.0e-6 · p=0.788
mean per-pair effect [-142, 425] ns · clip scale c=2668 ns · clipped 1/50000 at 16c · batch 1 · baseline med 2041 iqr 208 (10% jitter)
AEAD.encrypt (256 B)x86_64-linux
wall
log(1/α) 0 0
no leak detected · 50000 pairs · α=1.0e-6 · p=0.769
mean per-pair effect [-16k, 47k] ns · clip scale c=297k ns · clipped 1/50000 at 16c · batch 1 · baseline med 45.98k iqr 33.09k (72% jitter)
2 further meter panels
AEAD.encrypt (256 B)x86_64-linux
instructions
log(1/α) 0 0
no leak detected · 50000 pairs · α=1.0e-6 · p=0.111
mean per-pair effect [-25k, 74k] instr · clip scale c=463k instr · clipped 1/50000 at 16c · batch 1 · baseline med 29.10k iqr 108 (0.4% jitter)
AEAD.encrypt (256 B)x86_64-linux
cycles
log(1/α) 0 0
no leak detected · 50000 pairs · α=1.0e-6 · p=0.583
mean per-pair effect [-18k, 54k] cyc · clip scale c=340k cyc · clipped 1/50000 at 16c · batch 1 · baseline med 47.80k iqr 6675 (14% jitter)

decrypt

Crypto.AEAD.ChaCha20Poly1305.decryptsensitive: key; tag-mismatch position
substratumllvm
isa result symbols walked instructions flagged
aarch64 71 87
x86_64 60 93
class assessment note aarch64 x86_64
cond-branch
control-flow
input validation
public key- and nonce-length rejection
×2
early-return-guard
×2
cond-branch
control-flow
input validation
public nonce- or 16-byte MAC-length rejection
×2
early-return-guard
← load (R1)
×1
← entry (R1)
cond-branch
control-flow
input validation
public 12-byte nonce-length rejection (Left InvalidNonce before any key or nonce use)
×1
← entry (R1)
cond-branch
control-flow
benign
16-byte length guard inside ct_eq on the freshly computed Poly1305 tag ahead of the branch-free XOR/OR fold (the tag is 16 bytes by construction; the caller's MAC was already gated in the prologue)
×1
← load (R1)
×1
← entry (R1)
cond-branch
control-flow
benign
allocation, append and slice guards on public or fixed lengths (zero-length fast paths, negative-size and pad-size allocation checks, the take-32 slice of the 64-byte keystream block)
×46
×43
cond-branch
control-flow
benign
constructor-tag scrutiny of a public Either/closure scrutinee (GHC pointer-tag dispatch on the low bits of a heap pointer)
×7
×7
cond-branch
control-flow
benign
pad16 and length-serialisation control flow on the public AAD/ciphertext length (mod-16 dispatch, unroll8 right-padding and edge guards, and the byte-width serialisation loop)
×10
×13
cond-branch
control-flow
benign
post-barrier dispatch on the tag verdict after the full 16-byte XOR/OR fold (every mismatch position takes the same arm; the branch discloses only the accept/reject verdict the API returns)
×1
← entry (R1)
×1
← entry (R1)
length-call
work-count
benign
memcpy and memset counts from public AAD, ciphertext and pad component lengths
×16
×20
reg-index
memory-address
benign
BS-constructor field store at an immediate (or folded-immediate) offset; the index derives from code layout, not from any input
×1
address-base ← clobbered by call (approximate)
address-index ← immediate (approximate)
×3
reg-index
memory-address
benign
public-length byte store indexed by its bounded destination offset
×1
loop-latch, loop-exit, early-return-guard
address-base ← load (approximate)
address-index ← load (Sp frame slot)
×1
loop-latch, loop-exit
address-base ← load (Sp frame slot) (approximate)
address-index ← load (Sp frame slot)
complete fact list — aarch64 ×87 · x86_64 ×93
aarch64
b.ne LBB102_6
cond-branch
control-flow
$wdecrypt:6066 input validation
b.ne LBB102_8
cond-branch
control-flow
$wdecrypt:6080 input validation
cbz x22, LBB94_5
cond-branch
control-flow
blk_s5tH:5547 benign
b.lt LBB79_6
cond-branch
control-flow
blk_s5tf:4662 benign
cbz x9, LBB82_4
cond-branch
control-flow
blk_s5tn:4815 benign
cbz x10, LBB82_9
cond-branch
control-flow
blk_s5tn:4817 benign
b.mi LBB82_8
cond-branch
control-flow
blk_s5tn:4820 benign
cbz x10, LBB82_10
cond-branch
control-flow
blk_s5tn:4837 benign
cbz x9, LBB82_11
cond-branch
control-flow
blk_s5tn:4839 benign
b.mi LBB82_8
cond-branch
control-flow
blk_s5tn:4842 benign
cbnz x10, LBB82_5
cond-branch
control-flow
blk_s5tn:4863 benign
cbz x22, LBB85_5
cond-branch
control-flow
blk_s5tv:5024 benign
b.ge LBB89_3
cond-branch
control-flow
blk_s5tz:5241 benign
b.lt LBB89_7
cond-branch
control-flow
blk_s5tz:5246 benign
cbz x9, LBB89_8
cond-branch
control-flow
blk_s5tz:5255 benign
b.mi LBB89_9
cond-branch
control-flow
blk_s5tz:5258 benign
cbz x9, LBB91_4
cond-branch
control-flow
blk_s5vk:5344 benign
cbz x8, LBB91_10
cond-branch
control-flow
blk_s5vk:5346 benign
b.mi LBB91_9
cond-branch
control-flow
blk_s5vk:5349 benign
cbz x9, LBB91_11
cond-branch
control-flow
blk_s5vk:5363 benign
cbz x8, LBB91_12
cond-branch
control-flow
blk_s5vk:5365 benign
b.mi LBB91_9
cond-branch
control-flow
blk_s5vk:5368 benign
cbnz x9, LBB91_5
cond-branch
control-flow
blk_s5vk:5391 benign
b.ge LBB22_4
cond-branch
control-flow
c5HV:1353 benign
tbnz x22, #63, LBB22_5
cond-branch
control-flow
c5HV:1355 benign
bl _memcpy
length-call
work-count
c5I4:1438 benign
b.ne LBB24_3
cond-branch
control-flow
c5IL:1493 benign
bl _memcpy
length-call
work-count
c5IT:1619 benign
b.ne LBB27_3
cond-branch
control-flow
c5J5:1665 benign
cbz x11, LBB21_5
cond-branch
control-flow
c5Ju:1234 benign
strb w11, [x10, x13]
reg-index
memory-address
c5Ju:1238 benign
b.ne LBB21_2
cond-branch
control-flow
c5Ju:1243 benign
b.ge LBB21_8
cond-branch
control-flow
c5Ju:1260 benign
tbnz x10, #63, LBB21_10
cond-branch
control-flow
c5Ju:1262 benign
b.ne LBB32_3
cond-branch
control-flow
c64E:1951 benign
b.ge LBB30_3
cond-branch
control-flow
c64V:1867 benign
b.ne LBB103_3
cond-branch
control-flow
c762:6150 input validation
b.ne LBB108_2
cond-branch
control-flow
c76D:6406 benign
b.ne LBB76_2
cond-branch
control-flow
c76P:4436 benign
b.lt LBB76_4
cond-branch
control-flow
c76P:4448 benign
cbz x9, LBB76_7
cond-branch
control-flow
c76P:4472 benign
stur x9, [x10, #-40]
reg-index
memory-address
c76P:4489 benign
b.ne LBB104_3
cond-branch
control-flow
c76b:6196 input validation
b.ne LBB105_4
cond-branch
control-flow
c76k:6266 benign
b.ne LBB107_3
cond-branch
control-flow
c76x:6368 benign
cbz x26, LBB77_5
cond-branch
control-flow
c77e:4527 benign
cbz x23, LBB77_6
cond-branch
control-flow
c77e:4529 benign
b.mi LBB77_8
cond-branch
control-flow
c77e:4532 benign
b.ne LBB110_2
cond-branch
control-flow
c77u:6543 benign
bl _memcpy
length-call
work-count
c78L:4596 benign
bl _memcpy
length-call
work-count
c78L:4606 benign
b.eq LBB109_2
cond-branch
control-flow
c78k:6501 benign
b.ne LBB80_2
cond-branch
control-flow
c794:4714 benign
b.lt LBB80_4
cond-branch
control-flow
c794:4731 benign
bl _memcpy
length-call
work-count
c79U:4904 benign
bl _memcpy
length-call
work-count
c79U:4914 benign
cbz x8, LBB83_5
cond-branch
control-flow
c79U:4919 benign
cbz x28, LBB83_6
cond-branch
control-flow
c79U:4921 benign
b.mi LBB83_8
cond-branch
control-flow
c79U:4925 benign
bl _memcpy
length-call
work-count
c7ap:4988 benign
bl _memcpy
length-call
work-count
c7ap:4998 benign
bl _memcpy
length-call
work-count
c7bN:5508 benign
bl _memcpy
length-call
work-count
c7bN:5518 benign
cbz x8, LBB98_5
cond-branch
control-flow
c7cM:5832 benign
cbz x24, LBB98_6
cond-branch
control-flow
c7cM:5834 benign
b.mi LBB98_7
cond-branch
control-flow
c7cM:5837 benign
cbz x9, LBB100_5
cond-branch
control-flow
c7cW:5930 benign
cbz x10, LBB100_6
cond-branch
control-flow
c7cW:5932 benign
b.mi LBB100_8
cond-branch
control-flow
c7cW:5935 benign
bl _memcpy
length-call
work-count
c7d9:6019 benign
bl _memcpy
length-call
work-count
c7d9:6029 benign
bl _memcpy
length-call
work-count
c7dC:5892 benign
bl _memcpy
length-call
work-count
c7dC:5902 benign
bl _memcpy
length-call
work-count
c7e5:5428 benign
bl _memcpy
length-call
work-count
c7e5:5438 benign
cbz x8, LBB92_5
cond-branch
control-flow
c7e5:5442 benign
cbz x26, LBB92_6
cond-branch
control-flow
c7e5:5445 benign
b.mi LBB92_7
cond-branch
control-flow
c7e5:5449 benign
b.ge LBB97_3
cond-branch
control-flow
c7fj:5766 benign
b.lt LBB97_4
cond-branch
control-flow
c7fj:5771 benign
cbnz x24, LBB97_6
cond-branch
control-flow
c7fj:5794 benign
b.lt LBB29_5
cond-branch
control-flow
s5m5:1814 benign
tbnz x24, #63, LBB13_5
cond-branch
control-flow
s5mM:625 benign
tbnz x24, #63, LBB14_5
cond-branch
control-flow
s5mT:716 benign
tbnz x24, #63, LBB17_5
cond-branch
control-flow
s5nK:989 benign
tbnz x24, #63, LBB15_5
cond-branch
control-flow
s5nk:807 benign
tbnz x24, #63, LBB16_5
cond-branch
control-flow
s5nu:898 benign
x86_64
jne .LBB102_7
cond-branch
control-flow
$wdecrypt:5214 input validation
jne .LBB102_9
cond-branch
control-flow
$wdecrypt:5225 input validation
jne .LBB79_2
cond-branch
control-flow
blk_s5vF:3950 benign
jle .LBB79_3
cond-branch
control-flow
blk_s5vF:3969 benign
movq %rcx, (%rax,%rdi,1)
reg-index
memory-address
blk_s5vF:3992 benign
movq %rdx, (%rax,%rsi,1)
reg-index
memory-address
blk_s5vF:3993 benign
je .LBB82_12
cond-branch
control-flow
blk_s5vN:4105 benign
je .LBB82_4
cond-branch
control-flow
blk_s5vN:4108 benign
js .LBB82_3
cond-branch
control-flow
blk_s5vN:4112 benign
je .LBB82_11
cond-branch
control-flow
blk_s5vN:4134 benign
je .LBB82_9
cond-branch
control-flow
blk_s5vN:4137 benign
js .LBB82_3
cond-branch
control-flow
blk_s5vN:4140 benign
je .LBB85_8
cond-branch
control-flow
blk_s5vV:4314 benign
jge .LBB89_1
cond-branch
control-flow
blk_s5vZ:4471 benign
jle .LBB89_9
cond-branch
control-flow
blk_s5vZ:4476 benign
je .LBB89_6
cond-branch
control-flow
blk_s5vZ:4484 benign
js .LBB89_5
cond-branch
control-flow
blk_s5vZ:4487 benign
je .LBB94_8
cond-branch
control-flow
blk_s5w7:4765 benign
je .LBB91_11
cond-branch
control-flow
blk_s5xK:4564 benign
je .LBB91_2
cond-branch
control-flow
blk_s5xK:4567 benign
js .LBB91_8
cond-branch
control-flow
blk_s5xK:4570 benign
je .LBB91_9
cond-branch
control-flow
blk_s5xK:4589 benign
je .LBB91_10
cond-branch
control-flow
blk_s5xK:4592 benign
js .LBB91_8
cond-branch
control-flow
blk_s5xK:4595 benign
jge .LBB22_4
cond-branch
control-flow
c5Kl:1060 benign
js .LBB22_3
cond-branch
control-flow
c5Kl:1063 benign
call memcpy@PLT
length-call
work-count
c5Ku:1130 benign
jne .LBB27_1
cond-branch
control-flow
c5LF:1336 benign
jne .LBB24_1
cond-branch
control-flow
c5Lg:1179 benign
call memcpy@PLT
length-call
work-count
c5Lo:1284 benign
je .LBB21_5
cond-branch
control-flow
c5M4:969 benign
je .LBB21_6
cond-branch
control-flow
c5M4:976 benign
movb %sil, (%rcx,%r8,1)
reg-index
memory-address
c5M4:980 benign
jne .LBB21_3
cond-branch
control-flow
c5M4:986 benign
jge .LBB21_9
cond-branch
control-flow
c5M4:999 benign
js .LBB21_8
cond-branch
control-flow
c5M4:1002 benign
jne .LBB32_1
cond-branch
control-flow
c67f:1558 benign
jge .LBB30_4
cond-branch
control-flow
c67w:1487 benign
jne .LBB103_3
cond-branch
control-flow
c79E:5281 input validation
jne .LBB104_3
cond-branch
control-flow
c79N:5316 input validation
jne .LBB105_4
cond-branch
control-flow
c79W:5370 benign
jne .LBB107_3
cond-branch
control-flow
c7a9:5451 benign
call memset@PLT
length-call
work-count
c7aQ:3810 benign
je .LBB77_6
cond-branch
control-flow
c7aQ:3822 benign
je .LBB77_3
cond-branch
control-flow
c7aQ:3826 benign
js .LBB77_5
cond-branch
control-flow
c7aQ:3831 benign
movq %r15, -8(%rbp,%rax,1)
reg-index
memory-address
c7aQ:3857 benign
jne .LBB108_1
cond-branch
control-flow
c7af:5479 benign
jne .LBB76_1
cond-branch
control-flow
c7ar:3736 benign
jle .LBB76_2
cond-branch
control-flow
c7ar:3749 benign
jne .LBB76_5
cond-branch
control-flow
c7ar:3772 benign
jne .LBB110_1
cond-branch
control-flow
c7b9:5585 benign
je .LBB109_2
cond-branch
control-flow
c7c1:5552 benign
jne .LBB80_1
cond-branch
control-flow
c7cQ:4015 benign
jle .LBB80_2
cond-branch
control-flow
c7cQ:4030 benign
call memcpy@PLT
length-call
work-count
c7cs:3904 benign
call memcpy@PLT
length-call
work-count
c7cs:3913 benign
call memcpy@PLT
length-call
work-count
c7dJ:4193 benign
call memcpy@PLT
length-call
work-count
c7dJ:4203 benign
je .LBB83_7
cond-branch
control-flow
c7dJ:4210 benign
je .LBB83_5
cond-branch
control-flow
c7dJ:4213 benign
js .LBB83_4
cond-branch
control-flow
c7dJ:4219 benign
call memset@PLT
length-call
work-count
c7df:4079 benign
call memcpy@PLT
length-call
work-count
c7ej:4282 benign
call memcpy@PLT
length-call
work-count
c7ej:4291 benign
call memcpy@PLT
length-call
work-count
c7fP:4733 benign
call memcpy@PLT
length-call
work-count
c7fP:4742 benign
call memset@PLT
length-call
work-count
c7fn:4538 benign
call memset@PLT
length-call
work-count
c7gT:4971 benign
je .LBB98_5
cond-branch
control-flow
c7gT:4980 benign
je .LBB98_6
cond-branch
control-flow
c7gT:4983 benign
js .LBB98_4
cond-branch
control-flow
c7gT:4986 benign
je .LBB100_7
cond-branch
control-flow
c7h6:5094 benign
je .LBB100_5
cond-branch
control-flow
c7h6:5097 benign
js .LBB100_4
cond-branch
control-flow
c7h6:5100 benign
call memcpy@PLT
length-call
work-count
c7hR:5055 benign
call memcpy@PLT
length-call
work-count
c7hR:5064 benign
call memcpy@PLT
length-call
work-count
c7hj:5167 benign
call memcpy@PLT
length-call
work-count
c7hj:5177 benign
call memcpy@PLT
length-call
work-count
c7ip:4645 benign
call memcpy@PLT
length-call
work-count
c7ip:4655 benign
je .LBB92_5
cond-branch
control-flow
c7ip:4662 benign
je .LBB92_6
cond-branch
control-flow
c7ip:4667 benign
js .LBB92_4
cond-branch
control-flow
c7ip:4670 benign
jge .LBB97_5
cond-branch
control-flow
c7jN:4914 benign
jle .LBB97_2
cond-branch
control-flow
c7jN:4919 benign
je .LBB97_3
cond-branch
control-flow
c7jN:4939 benign
jl stg_upd_frame_info@PLT
cond-branch
control-flow
s5ov:1449 benign
js .LBB15_5
cond-branch
control-flow
s5pK:638 benign
js .LBB16_5
cond-branch
control-flow
s5pU:709 benign
js .LBB13_5
cond-branch
control-flow
s5pc:496 benign
js .LBB14_5
cond-branch
control-flow
s5pj:567 benign
js .LBB17_5
cond-branch
control-flow
s5qa:780 benign
censor50000 pairs · α=1.0e-6 · batch 1
test cases
AEAD.decrypt accept (256 B) key fixed vs random over a shared per-pair context; each sample's (ciphertext, tag) is precomputed under that sample's own key, so the timed region is keystream regen, Poly1305 recompute, and the tag compare on the accept path
AEAD.decrypt reject (tag mismatch) the prologue draws one key and context per pair and encrypts it, so both classes decrypt the same ciphertext under the same key and differ only in which tag byte is corrupted (class A byte 0, class B byte 15), testing that rejection timing is independent of the first-mismatch position
host meter result p effect (mean/pair) jitter clip scale clipped
AEAD.decrypt accept (256 B)
aarch64-darwin wall 0.719 [-119, 40] ns 5.0% 748 ns 14/50000 at 16c
x86_64-linux wall 0.826 [-12k, 3.95k] ns 37% 74.36k ns 1/50000 at 16c
x86_64-linux instructions 0.351 [-55k, 18k] instr 0.5% 346k instr 0/50000 at 16c
x86_64-linux cycles 0.622 [-40k, 13k] cyc 20% 253k cyc 1/50000 at 16c
AEAD.decrypt reject (tag mismatch)
aarch64-darwin wall 0.092 [-40, 13] ns 10% 250 ns 62/50000 at 16c
x86_64-linux wall 0.973 [-1897, 5690] ns 67% 35.68k ns 0/50000 at 16c
x86_64-linux instructions 0.734 [-22, 67] instr 0.6% 418 instr 97/50000 at 16c
x86_64-linux cycles 0.464 [-2415, 805] cyc 21% 15.14k cyc 38/50000 at 16c
AEAD.decrypt accept (256 B)aarch64-darwin
wall
log(1/α) 0 0
no leak detected · 50000 pairs · α=1.0e-6 · p=0.719
mean per-pair effect [-119, 40] ns · clip scale c=748 ns · clipped 14/50000 at 16c · batch 1 · baseline med 834 iqr 42 (5.0% jitter)
AEAD.decrypt accept (256 B)x86_64-linux
wall
log(1/α) 0 0
no leak detected · 50000 pairs · α=1.0e-6 · p=0.826
mean per-pair effect [-12k, 3.95k] ns · clip scale c=74.36k ns · clipped 1/50000 at 16c · batch 1 · baseline med 3890 iqr 1440 (37% jitter)
AEAD.decrypt reject (tag mismatch)aarch64-darwin
wall
log(1/α) 0 0
no leak detected · 50000 pairs · α=1.0e-6 · p=0.092
mean per-pair effect [-40, 13] ns · clip scale c=250 ns · clipped 62/50000 at 16c · batch 1 · baseline med 416 iqr 42 (10% jitter)
AEAD.decrypt reject (tag mismatch)x86_64-linux
wall
log(1/α) 0 0
no leak detected · 50000 pairs · α=1.0e-6 · p=0.973
mean per-pair effect [-1897, 5690] ns · clip scale c=35.68k ns · clipped 0/50000 at 16c · batch 1 · baseline med 1780 iqr 1200 (67% jitter)
4 further meter panels
AEAD.decrypt accept (256 B)x86_64-linux
instructions
log(1/α) 0 0
no leak detected · 50000 pairs · α=1.0e-6 · p=0.351
mean per-pair effect [-55k, 18k] instr · clip scale c=346k instr · clipped 0/50000 at 16c · batch 1 · baseline med 29.05k iqr 139 (0.5% jitter)
AEAD.decrypt accept (256 B)x86_64-linux
cycles
log(1/α) 0 0
no leak detected · 50000 pairs · α=1.0e-6 · p=0.622
mean per-pair effect [-40k, 13k] cyc · clip scale c=253k cyc · clipped 1/50000 at 16c · batch 1 · baseline med 24.99k iqr 5099 (20% jitter)
AEAD.decrypt reject (tag mismatch)x86_64-linux
instructions
log(1/α) 0 0
no leak detected · 50000 pairs · α=1.0e-6 · p=0.734
mean per-pair effect [-22, 67] instr · clip scale c=418 instr · clipped 97/50000 at 16c · batch 1 · baseline med 12.71k iqr 71 (0.6% jitter)
AEAD.decrypt reject (tag mismatch)x86_64-linux
cycles
log(1/α) 0 0
no leak detected · 50000 pairs · α=1.0e-6 · p=0.464
mean per-pair effect [-2415, 805] cyc · clip scale c=15.14k cyc · clipped 38/50000 at 16c · batch 1 · baseline med 12.22k iqr 2623 (21% jitter)
analysis bounds
aarch64
lines parsed
7476 (4049 instruction lines)
unstructured
0 instruction lines the decoder did not structure
memory unmodelled
0 memory-capable instructions with no modelled effect
control-flow graph
213 functions, 0 with a reachable unknown successor
facts by disposition
active ×162, suppressed ×280
fact operands
442 of 442 facts with a modelled subject, 0 unmodelled, 0 with none by design; 455 subjects: address-base ×13, address-index ×13, branch-condition ×266, indirect-target ×133, work-count ×30
operand chains
exact ×251, approximate ×204 — an approximate chain bounds what the subject's provenance establishes, and is marked as such beside the finding
walk boundary · encrypt
169 edges — external-callee ×90, indirect-call ×60, unresolved-enter ×19; at: _stg_newPinnedByteArrayzh ×25, _stg_gc_unpt_r1 ×23, _memcpy ×16, _stg_upd_frame_info ×6, _stg_gc_unbx_r1 ×4, _bzero ×4, _stg_gc_noregs ×3, _stg_ap_0_fast ×2
walk boundary · decrypt
177 edges — external-callee ×89, indirect-call ×67, unresolved-enter ×21; at: _stg_newPinnedByteArrayzh ×25, _stg_gc_unpt_r1 ×22, _memcpy ×16, _stg_upd_frame_info ×6, _stg_gc_unbx_r1 ×4, _bzero ×4, _stg_gc_noregs ×3, _stg_ap_0_fast ×2
x86_64
lines parsed
6487 (4047 instruction lines)
unstructured
0 instruction lines the decoder did not structure
memory unmodelled
0 memory-capable instructions with no modelled effect
control-flow graph
182 functions, 2 with a reachable unknown successor
facts by disposition
active ×181, suppressed ×271
fact operands
452 of 452 facts with a modelled subject, 0 unmodelled, 0 with none by design; 465 subjects: address-base ×13, address-index ×13, branch-condition ×268, indirect-target ×133, work-count ×38
operand chains
exact ×426, approximate ×39 — an approximate chain bounds what the subject's provenance establishes, and is marked as such beside the finding
walk boundary · encrypt
161 edges — external-callee ×93, indirect-tail ×58, unresolved-enter ×10; at: stg_newPinnedByteArrayzh@PLT ×26, stg_gc_unpt_r1@PLT ×25, memcpy@PLT ×16, stg_upd_frame_info@PLT ×6, stg_gc_unbx_r1@PLT ×4, memset@PLT ×4, stg_gc_noregs@PLT ×3, stg_ap_0_fast@PLT ×2
walk boundary · decrypt
170 edges — external-callee ×92, indirect-tail ×66, unresolved-enter ×12; at: stg_newPinnedByteArrayzh@PLT ×26, stg_gc_unpt_r1@PLT ×24, memcpy@PLT ×16, stg_upd_frame_info@PLT ×6, stg_gc_unbx_r1@PLT ×4, memset@PLT ×4, stg_gc_noregs@PLT ×3, stg_ap_0_fast@PLT ×2
provenance
target
ppad-aead 0.3.4 (2221895)
substratum
0.3.7 (2d3b67b)
censor
0.4.4 (9b550af)
elenchus
(appraise) gpt-5.6-sol
(dissent) moonshotai/kimi-k3
(falsify) claude-fable-5
(distill) claude-fable-5
source
git.ppad.tech/aead
seed
0x5eed5eed5eed5eed
censor config
alpha=1.000000e-6, budget=50000, warmup=500, batch=per-case
run environments
aarch64-darwin · wall
Apple M4 (10 cores) · darwin 24.6.0 · 2026-08-05T21:25:43Z
x86_64-linux · cycles
AMD EPYC 7713 64-Core Processor (6 cores) · linux 6.18.33 · 2026-08-05T21:36:05Z
x86_64-linux · instructions
AMD EPYC 7713 64-Core Processor (6 cores) · linux 6.18.33 · 2026-08-05T21:36:21Z
x86_64-linux · wall
AMD EPYC 7713 64-Core Processor (6 cores) · linux 6.18.33 · 2026-08-05T21:36:03Z
run totals
aarch64-darwin · wall
3 cases · 150000 pairs · 0 reject · α=1.0e-6 · family α=3.0e-6
x86_64-linux · cycles
3 cases · 150000 pairs · 0 reject · α=1.0e-6 · family α=3.0e-6
x86_64-linux · instructions
3 cases · 150000 pairs · 0 reject · α=1.0e-6 · family α=3.0e-6
x86_64-linux · wall
3 cases · 150000 pairs · 0 reject · α=1.0e-6 · family α=3.0e-6
# substratum 0.3.7 (2d3b67b)
# toolchain: GHC 9.10.3, LLVM 19.1.7 (nix-pinned via flake)
# ppad-aead v0.3.4 (2221895); LLVM backend
substratum scan -i /tmp/aead-asm/aarch64.v034.llvm.s --isa aarch64 --runtime haskell --format json --why --decisions --loops
substratum scan -i /tmp/aead-asm/aarch64.v034.llvm.s --isa aarch64 --runtime haskell --symbol ppad-aead:Crypto.AEAD.ChaCha20Poly1305:encrypt --format json --why --decisions --loops
substratum scan -i /tmp/aead-asm/aarch64.v034.llvm.s --isa aarch64 --runtime haskell --symbol ppad-aead:Crypto.AEAD.ChaCha20Poly1305:decrypt --format json --why --decisions --loops
# substratum 0.3.7 (2d3b67b)
# toolchain: GHC 9.10.3, LLVM 19.1.7 (nix-pinned via flake)
# ppad-aead v0.3.4 (2221895); LLVM backend
substratum scan -i /tmp/aead-asm/x86.v034.llvm.s --isa x86_64 --runtime haskell --format json --why --decisions --loops
substratum scan -i /tmp/aead-asm/x86.v034.llvm.s --isa x86_64 --runtime haskell --symbol ppad-aead:Crypto.AEAD.ChaCha20Poly1305:encrypt --format json --why --decisions --loops
substratum scan -i /tmp/aead-asm/x86.v034.llvm.s --isa x86_64 --runtime haskell --symbol ppad-aead:Crypto.AEAD.ChaCha20Poly1305:decrypt --format json --why --decisions --loops
# censor 0.4.4 (9b550af)
# toolchain: GHC 9.10.3, LLVM 19.1.7 (nix-pinned via flake)
# ppad-aead v0.3.4 (2221895); LLVM backend
#
# local aarch64-darwin (wall; no userspace PMU)
censor-aead wall report.json
# amd-epyc-7713 x86_64-linux, CPU-pinned
ssh amd-epyc-7713 'for m in wall cycles instructions; do taskset -c 0 nice -n 5 \
  censor-aead $m out/$m.json; done'