Media over QUIC

November 8, 2026 · kixelated

Vibe Slopped Cryptography

I’m one of the OG “rewrite it in Rust” guys. I love Rust.

Unfortunately, I wrote my last line of Rust 6 months ago. I still want Claude to write everything in Rust, but it’s difficult when rustc turns my desktop into lava.

I spent some tokens investigating on how to speed up builds for MoQ. One finding was that aws-lc-rs takes 60s+ to build. wtf why does a single crate take a full minute to build?

Despite the suffix, aws-lc-rs is actually a C library in disguise. Same with the next best crypto library: ring. wtf is C doing in my Rust library.

I did what any sane software engineer does in current_year, I pulled a 9-year old gaming PC out of the closet, installed Claude, and ran /goal rewrite it in rust *.

* and a lot of assembly

WOW FAST

rind is vibe slopped crypto. This statement alone should fill me with mortal dread, but AI is advancing so quickly that it’s no longer absurd.

rind

Not only was Opus able to make builds faster, it made the runtime faster too.

Sealing 1350 B QUIC packets · one core, averaged over 4 CPUs
1.37×

aws-lc-rs's
packets per core

rind157 ns
0
ring191 ns
0
aws-lc-rs215 ns
0
OpenSSL243 ns
0
graviola272 ns
0
RustCrypto342 ns
0
libcrux2.00 µs
0

AES-128-GCM, the geometric mean over CPUs. Arrow Lake: 1.63×, Zen 3: 1.72×, Coffee Lake: 1.12×, Apple M4: 1.11×. aws-lc is Amazon's BoringSSL fork. On Mac, rind holds DIT (constant-time mode) across each batch.

Data
LibraryArrow Lake, 32 BArrow Lake, 1350 BZen 3, 32 BZen 3, 1350 BCoffee Lake, 32 BCoffee Lake, 1350 BApple M4, 32 BApple M4, 1350 B
rind19.3 ns91.0 ns41.2 ns164 ns44.1 ns253 ns9.30 ns162 ns
aws-lc-rs37.2 ns149 ns72.7 ns282 ns88.1 ns283 ns48.6 ns179 ns
ring40.3 ns120 ns54.3 ns185 ns69.7 ns280 ns42.1 ns212 ns
RustCrypto73.1 ns273 ns94.7 ns433 ns99.7 ns545 ns23.7 ns213 ns
graviola41.3 ns221 ns67.5 ns294 ns70.4 ns392 ns78.4 ns214 ns
libcrux167 ns1.94 µs310 ns3.90 µs281 ns3.51 µs52.4 ns597 ns
OpenSSL55.5 ns159 ns115 ns317 ns150 ns348 ns65.2 ns198 ns

AES-128-GCM seal, criterion's estimate from rind's benchmark report at ccdda859, run 2026-11-09: Arrow Lake is Intel(R) Core(TM) Ultra 7 270K Plus, Zen 3 is AMD Ryzen 9 5900XT 16-Core Processor, Coffee Lake is Intel(R) Core(TM) i7-8700 CPU @ 3.20GHz, Apple M4 is Apple M4. On Mac, rind holds DIT across the timed loop, as a caller batching packets does.

Media over QUIC sends a lot of QUIC packets btw

^ This is a big deal because AES-128-GCM is the most popular TLS cipher suite by far. Even this relatively tiny reduction in CPU usage has huge impact when multiplied across every HTTPS request in the world*.

Rind started as fork of Graviola and quickly morphed into a monsterish combination of ring and aws-lc-rs (both fork BoringSSL, a fork of OpenSSL). Bits of libcrux were throw in there for good measure.

The engineers who developed these libraries are smarter than me. But I have a credit card in current_year and don’t need to be smart any more.

* this benchmark is HTTP/3 specific. HTTP/1 and HTTP/2 use different payload sizes.

WOW FAST

Rust gets dunked on for compile speeds but nerds forget that C/C++ can also be terrible.

rustls, cold release build · averaged over 4 CPUs
3.9×

faster to
build

24.2 srace clock, 12× speed
rustls + rind
rustc only
6.3 s ✓
rustls + ring
needs C compiler
11.1 s ✓
rustls + aws-lc-rs
needs C compiler
24.2 s ✓

The geometric mean over CPUs. Arrow Lake: 3.7×, Zen 3: 3.9×, Coffee Lake: 2.9×, Apple M4: 5.1×.

Data
CPUBuildTimeCPU timeBinaryTools
Arrow Lakerind3.4 s8.0 s0.84 MiBrustc only
Arrow Lakeaws-lc-rs11.8 s36.9 s2.85 MiBneeds C compiler
Arrow Lakering5.0 s7.3 s0.71 MiBneeds C compiler
Arrow LakeRustCrypto2.8 s15.8 s0.52 MiBrustc only
Arrow Lakegraviola1.9 s4.2 s0.87 MiBrustc only
Arrow Lakelibcrux4.8 s11.6 s0.71 MiBrustc only
Arrow LakeOpenSSL2.8 s7.4 s0.36 MiBneeds C compiler, pkg-config
Arrow Lakeopenssl-vendored17.9 s136.7 s4.90 MiBneeds C compiler, make, perl
Arrow Lakerustls + rind3.9 s20.2 s2.85 MiBrustc only
Arrow Lakerustls + rind-lean3.8 s20.2 s1.73 MiBrustc only
Arrow Lakerustls + aws-lc-rs14.4 s49.2 s3.92 MiBneeds C compiler
Arrow Lakerustls + ring7.5 s19.1 s1.85 MiBneeds C compiler
Zen 3rind4.5 s10.6 s0.84 MiBrustc only
Zen 3aws-lc-rs16.3 s54.6 s2.85 MiBneeds C compiler
Zen 3ring6.7 s9.5 s0.71 MiBneeds C compiler
Zen 3RustCrypto4.0 s20.7 s0.52 MiBrustc only
Zen 3graviola2.6 s5.3 s0.87 MiBrustc only
Zen 3libcrux6.8 s15.8 s0.71 MiBrustc only
Zen 3OpenSSL3.9 s9.6 s0.36 MiBneeds C compiler, pkg-config
Zen 3openssl-vendored22.8 s201.7 s4.90 MiBneeds C compiler, make, perl
Zen 3rustls + rind5.2 s26.2 s2.85 MiBrustc only
Zen 3rustls + rind-lean5.2 s26.1 s1.73 MiBrustc only
Zen 3rustls + aws-lc-rs20.6 s70.0 s3.92 MiBneeds C compiler
Zen 3rustls + ring10.1 s24.0 s1.85 MiBneeds C compiler
Coffee Lakerind7.3 s13.0 s0.84 MiBrustc only
Coffee Lakeaws-lc-rs26.0 s62.7 s2.85 MiBneeds C compiler
Coffee Lakering9.3 s12.1 s0.71 MiBneeds C compiler
Coffee LakeRustCrypto8.8 s25.6 s0.52 MiBrustc only
Coffee Lakegraviola4.2 s7.1 s0.87 MiBrustc only
Coffee Lakelibcrux10.2 s21.7 s0.71 MiBrustc only
Coffee LakeOpenSSL6.2 s12.5 s0.36 MiBneeds C compiler, pkg-config
Coffee Lakeopenssl-vendored83.3 s221.9 s4.90 MiBneeds C compiler, make, perl
Coffee Lakerustls + rind11.4 s32.1 s2.85 MiBrustc only
Coffee Lakerustls + rind-lean11.3 s32.1 s1.73 MiBrustc only
Coffee Lakerustls + aws-lc-rs33.6 s82.0 s3.92 MiBneeds C compiler
Coffee Lakerustls + ring16.2 s30.4 s1.85 MiBneeds C compiler
Apple M4rind4.1 s7.9 s0.66 MiBrustc only
Apple M4aws-lc-rs29.3 s93.2 s2.04 MiBneeds C compiler
Apple M4ring8.2 s10.2 s0.61 MiBneeds C compiler
Apple M4RustCrypto5.2 s16.3 s0.44 MiBrustc only
Apple M4graviola3.1 s5.5 s0.78 MiBrustc only
Apple M4libcrux8.1 s18.0 s0.56 MiBrustc only
Apple M4OpenSSL4.6 s10.2 s0.34 MiBneeds C compiler
Apple M4openssl-vendored132.5 s425.8 s3.58 MiBneeds C compiler, make, perl
Apple M4rustls + rind6.7 s22.4 s2.07 MiBrustc only
Apple M4rustls + rind-lean6.9 s22.8 s1.47 MiBrustc only
Apple M4rustls + aws-lc-rs34.5 s111.0 s2.93 MiBneeds C compiler
Apple M4rustls + ring12.3 s23.0 s1.53 MiBneeds C compiler

rind's admin/build-cost: the median of cold builds with an empty target directory and a warm download cache. Arrow Lake: Core Ultra 7 270K Plus, 12 jobs, 3 runs, 2026-11-09, at ccdda859; Zen 3: Ryzen 9 5900XT, 16 jobs, 3 runs, 2026-11-09, at ccdda859; Coffee Lake: Core i7-8700, 3 jobs, 3 runs, 2026-11-09, at ccdda859; Apple M4: Apple M4, 4 jobs, 3 runs, 2026-11-09, at ccdda859. A tool counts when the build fails without it.

i’m a purist

Most of the time these builds are cached anyway but IDK it’s still nice to see smaller number. PSA You should be using mbx for Rust instead of complaining on Twitter about cargo target sizee and build times.

Also it’s nice from a maintainer point of view because aws-lc-rs does not compile on a lot of machines. rind doesn’t support every architecture yet either only because I don’t have test hardware.

Wow fast

Having accomplished my goal of making MoQ faster, I let my 9-year-old gaming PC take a vacation. This poor machine was awoken from retirement and forced to run crypto benchmarks.

lul jk I ran: /goal: Support every algorithm, and make it the fastest.

Every benchmark · one square per CPU
236/236

timings where rind is fastest,
or within 10%

rind
aws-lc-rs
ring
graviola
OpenSSL
RustCrypto
libcrux
TLS 1.3 with rustls
full handshake, X25519MLKEM768
full handshake, X25519
full handshake, P-256
full handshake, Ed25519 certificate
full handshake, RSA-2048 certificate
resumed handshake, X25519
1 MB transfer, AES-128-GCM
1 MB transfer, AES-256-GCM
1 MB transfer, ChaCha20-Poly1305
AEADs
AES-128-GCM seal, 32 B
AES-128-GCM seal, 1350 B
AES-128-GCM seal, 16 KB
AES-128-GCM open, 32 B
AES-128-GCM open, 1350 B
AES-128-GCM open, 16 KB
AES-256-GCM seal, 32 B
AES-256-GCM seal, 1350 B
AES-256-GCM seal, 16 KB
AES-256-GCM open, 32 B
AES-256-GCM open, 1350 B
AES-256-GCM open, 16 KB
ChaCha20-Poly1305 seal, 32 B
ChaCha20-Poly1305 seal, 1350 B
ChaCha20-Poly1305 seal, 16 KB
XChaCha20-Poly1305 seal, 32 B
XChaCha20-Poly1305 seal, 1350 B
XChaCha20-Poly1305 seal, 16 KB
QUIC header protection
AES-128 header protection
AES-256 header protection
ChaCha20 header protection
Key agreement
X25519
P-256 ECDH
Signatures
Ed25519 sign
Ed25519 verify
P-256 ECDSA sign
P-256 ECDSA verify
Hashes and KDFs
SHA-256, 64 B
SHA-256, 1350 B
SHA-256, 16 KB
SHA-512, 64 B
SHA-512, 1350 B
SHA-512, 16 KB
HMAC-SHA256, 64 B
HMAC-SHA256, 1350 B
HKDF-SHA256 extract and expand
HKDF-SHA256 expand
RSA
RSA-2048 PKCS#1 sign
RSA-2048 PKCS#1 verify
RSA-2048 PSS sign
RSA-2048 PSS verify
ML-KEM
ML-KEM-768 key generation
ML-KEM-768 encapsulate
ML-KEM-768 decapsulate
P-384 and P-521
P-384 ECDH
P-384 ECDSA sign
P-384 ECDSA verify
P-521 ECDH
P-521 ECDSA sign
P-521 ECDSA verify
fastest, or within 10%to 1.25×to 1.5×to 2×to 4×to 8×over 8×

Squares: Arrow Lake, Zen 3, Coffee Lake, Apple M4. Blank: not offered. On Mac, rind holds DIT (constant-time mode) across each batch.

Data
Operationrindaws-lc-rsringgraviolaOpenSSLRustCryptolibcrux
full handshake, X25519MLKEM768175 µs / 233 µs / 299 µs / 172 µs237 µs / 304 µs / 438 µs / 212 µs- / - / - / -188 µs / 248 µs / 374 µs / 179 µs433 µs / 638 µs / 824 µs / 457 µs- / - / - / -- / - / - / -
full handshake, X25519151 µs / 202 µs / 255 µs / 151 µs201 µs / 259 µs / 365 µs / 185 µs221 µs / 284 µs / 334 µs / 185 µs161 µs / 212 µs / 314 µs / 159 µs371 µs / 545 µs / 679 µs / 374 µs- / - / - / -- / - / - / -
full handshake, P-256174 µs / 234 µs / 291 µs / 171 µs231 µs / 297 µs / 416 µs / 206 µs219 µs / 282 µs / 325 µs / 200 µs192 µs / 252 µs / 360 µs / 190 µs400 µs / 602 µs / 750 µs / 399 µs- / - / - / -- / - / - / -
full handshake, Ed25519 certificate121 µs / 164 µs / 210 µs / 126 µs167 µs / 216 µs / 304 µs / 151 µs202 µs / 276 µs / 322 µs / 154 µs123 µs / 165 µs / 246 µs / 125 µs368 µs / 617 µs / 741 µs / 382 µs- / - / - / -- / - / - / -
full handshake, RSA-2048 certificate423 µs / 510 µs / 613 µs / 371 µs479 µs / 619 µs / 721 µs / 407 µs496 µs / 634 µs / 672 µs / 447 µs443 µs / 549 µs / 679 µs / 674 µs675 µs / 885 µs / 1.00 ms / 642 µs- / - / - / -- / - / - / -
resumed handshake, X2551952.5 µs / 74.9 µs / 113 µs / 65.1 µs101 µs / 130 µs / 213 µs / 90.3 µs111 µs / 154 µs / 183 µs / 87.0 µs54.1 µs / 75.5 µs / 149 µs / 62.1 µs230 µs / 362 µs / 458 µs / 252 µs- / - / - / -- / - / - / -
1 MB transfer, AES-128-GCM170 µs / 271 µs / 436 µs / 298 µs237 µs / 428 µs / 440 µs / 295 µs170 µs / 271 µs / 443 µs / 360 µs285 µs / 421 µs / 577 µs / 315 µs253 µs / 461 µs / 489 µs / 324 µs- / - / - / -- / - / - / -
1 MB transfer, AES-256-GCM183 µs / 284 µs / 547 µs / 334 µs267 µs / 453 µs / 551 µs / 327 µs185 µs / 287 µs / 545 µs / 370 µs334 µs / 479 µs / 687 µs / 387 µs285 µs / 492 µs / 599 µs / 360 µs- / - / - / -- / - / - / -
1 MB transfer, ChaCha20-Poly1305587 µs / 682 µs / 919 µs / 1.11 ms585 µs / 684 µs / 922 µs / 1.10 ms582 µs / 683 µs / 924 µs / 1.10 ms1.15 ms / 1.37 ms / 1.94 ms / 1.75 ms650 µs / 783 µs / 990 µs / 1.10 ms- / - / - / -- / - / - / -
AES-128-GCM seal, 32 B19.3 ns / 41.2 ns / 44.1 ns / 9.30 ns37.2 ns / 72.7 ns / 88.1 ns / 48.6 ns40.3 ns / 54.3 ns / 69.7 ns / 42.1 ns41.3 ns / 67.5 ns / 70.4 ns / 78.4 ns55.5 ns / 115 ns / 150 ns / 65.2 ns73.1 ns / 94.7 ns / 99.7 ns / 23.7 ns167 ns / 310 ns / 281 ns / 52.4 ns
AES-128-GCM seal, 1350 B91.0 ns / 164 ns / 253 ns / 162 ns149 ns / 282 ns / 283 ns / 179 ns120 ns / 185 ns / 280 ns / 212 ns221 ns / 294 ns / 392 ns / 214 ns159 ns / 317 ns / 348 ns / 198 ns273 ns / 433 ns / 545 ns / 213 ns1.94 µs / 3.90 µs / 3.51 µs / 597 ns
AES-128-GCM seal, 16 KB810 ns / 1.52 µs / 2.33 µs / 1.42 µs1.31 µs / 2.58 µs / 2.41 µs / 1.45 µs814 ns / 1.41 µs / 2.38 µs / 1.94 µs2.03 µs / 2.56 µs / 3.73 µs / 1.59 µs1.33 µs / 2.63 µs / 2.46 µs / 1.51 µs2.46 µs / 4.18 µs / 5.54 µs / 2.28 µs21.9 µs / 44.4 µs / 39.4 µs / 6.76 µs
AES-128-GCM open, 32 B14.9 ns / 32.9 ns / 39.5 ns / 11.3 ns37.4 ns / 72.2 ns / 88.1 ns / 46.5 ns40.4 ns / 58.4 ns / 77.2 ns / 39.2 ns36.3 ns / 64.5 ns / 67.9 ns / 84.4 ns59.9 ns / 123 ns / 156 ns / 65.7 ns78.1 ns / 102 ns / 105 ns / 27.4 ns158 ns / 321 ns / 300 ns / 61.3 ns
AES-128-GCM open, 1350 B87.9 ns / 160 ns / 238 ns / 175 ns147 ns / 295 ns / 282 ns / 190 ns112 ns / 186 ns / 274 ns / 242 ns174 ns / 306 ns / 356 ns / 225 ns158 ns / 336 ns / 354 ns / 197 ns282 ns / 451 ns / 561 ns / 233 ns1.95 µs / 3.92 µs / 3.46 µs / 625 ns
AES-128-GCM open, 16 KB798 ns / 1.45 µs / 2.51 µs / 1.55 µs1.26 µs / 2.72 µs / 2.57 µs / 1.57 µs811 ns / 1.49 µs / 2.56 µs / 2.15 µs1.40 µs / 2.67 µs / 3.35 µs / 1.70 µs1.29 µs / 2.78 µs / 2.66 µs / 1.66 µs2.51 µs / 4.33 µs / 5.71 µs / 2.43 µs21.8 µs / 44.3 µs / 38.7 µs / 6.76 µs
AES-256-GCM seal, 32 B21.1 ns / 44.9 ns / 48.0 ns / 10.1 ns39.5 ns / 80.0 ns / 93.2 ns / 51.9 ns43.4 ns / 57.4 ns / 73.8 ns / 44.7 ns44.8 ns / 74.7 ns / 77.4 ns / 78.3 ns59.6 ns / 121 ns / 157 ns / 66.0 ns77.3 ns / 101 ns / 108 ns / 24.7 ns217 ns / 426 ns / 340 ns / 51.9 ns
AES-256-GCM seal, 1350 B107 ns / 188 ns / 327 ns / 188 ns175 ns / 310 ns / 360 ns / 200 ns134 ns / 205 ns / 354 ns / 216 ns257 ns / 337 ns / 476 ns / 258 ns182 ns / 342 ns / 421 ns / 220 ns313 ns / 490 ns / 622 ns / 246 ns2.82 µs / 6.59 µs / 4.42 µs / 624 ns
AES-256-GCM seal, 16 KB923 ns / 1.54 µs / 3.20 µs / 1.70 µs1.58 µs / 2.77 µs / 3.30 µs / 1.70 µs941 ns / 1.55 µs / 3.22 µs / 2.04 µs2.42 µs / 2.98 µs / 4.63 µs / 2.14 µs1.58 µs / 2.81 µs / 3.38 µs / 1.77 µs2.87 µs / 4.78 µs / 6.42 µs / 2.68 µs32.2 µs / 76.1 µs / 50.4 µs / 6.94 µs
AES-256-GCM open, 32 B16.9 ns / 37.7 ns / 43.3 ns / 12.2 ns37.0 ns / 81.9 ns / 92.0 ns / 48.7 ns41.3 ns / 62.9 ns / 80.6 ns / 39.6 ns37.4 ns / 67.9 ns / 72.9 ns / 83.4 ns62.0 ns / 127 ns / 162 ns / 68.0 ns82.0 ns / 109 ns / 111 ns / 40.8 ns216 ns / 438 ns / 362 ns / 65.8 ns
AES-256-GCM open, 1350 B96.9 ns / 176 ns / 310 ns / 195 ns169 ns / 319 ns / 360 ns / 215 ns121 ns / 202 ns / 346 ns / 246 ns204 ns / 341 ns / 436 ns / 263 ns186 ns / 360 ns / 424 ns / 224 ns318 ns / 505 ns / 641 ns / 264 ns2.82 µs / 6.62 µs / 4.42 µs / 655 ns
AES-256-GCM open, 16 KB904 ns / 1.62 µs / 3.40 µs / 1.80 µs1.56 µs / 2.92 µs / 3.46 µs / 1.82 µs923 ns / 1.65 µs / 3.45 µs / 2.23 µs1.72 µs / 3.04 µs / 4.26 µs / 2.16 µs1.60 µs / 2.98 µs / 3.53 µs / 1.92 µs2.92 µs / 4.93 µs / 6.61 µs / 2.82 µs32.2 µs / 77.9 µs / 49.8 µs / 7.15 µs
ChaCha20-Poly1305 seal, 32 B98.5 ns / 114 ns / 122 ns / 145 ns103 ns / 120 ns / 135 ns / 157 ns99.1 ns / 116 ns / 122 ns / 145 ns180 ns / 215 ns / 218 ns / 195 ns175 ns / 256 ns / 316 ns / 216 ns1.05 µs / 1.18 µs / 1.13 µs / 342 ns156 ns / 218 ns / 271 ns / 170 ns
ChaCha20-Poly1305 seal, 1350 B438 ns / 530 ns / 670 ns / 744 ns446 ns / 532 ns / 684 ns / 759 ns440 ns / 531 ns / 672 ns / 738 ns892 ns / 1.08 µs / 1.20 µs / 1.22 µs580 ns / 736 ns / 910 ns / 823 ns1.68 µs / 1.93 µs / 2.04 µs / 1.74 µs1.75 µs / 2.32 µs / 2.97 µs / 1.93 µs
ChaCha20-Poly1305 seal, 16 KB4.12 µs / 4.58 µs / 6.24 µs / 7.48 µs4.13 µs / 4.54 µs / 6.29 µs / 7.47 µs4.18 µs / 4.52 µs / 6.30 µs / 7.49 µs8.21 µs / 9.83 µs / 11.7 µs / 12.4 µs4.41 µs / 5.07 µs / 6.25 µs / 7.34 µs8.01 µs / 9.78 µs / 11.8 µs / 14.9 µs19.4 µs / 25.9 µs / 33.4 µs / 21.7 µs
XChaCha20-Poly1305 seal, 32 B186 ns / 227 ns / 259 ns / 875 ns199 ns / 251 ns / 275 ns / 861 ns- / - / - / -254 ns / 337 ns / 333 ns / 908 ns- / - / - / -1.14 µs / 1.30 µs / 1.27 µs / 1.05 µs241 ns / 328 ns / 396 ns / 895 ns
XChaCha20-Poly1305 seal, 1350 B529 ns / 644 ns / 805 ns / 1.48 µs541 ns / 665 ns / 829 ns / 1.46 µs- / - / - / -971 ns / 1.20 µs / 1.32 µs / 1.93 µs- / - / - / -1.76 µs / 2.05 µs / 2.18 µs / 2.44 µs1.84 µs / 2.44 µs / 3.10 µs / 2.71 µs
XChaCha20-Poly1305 seal, 16 KB4.20 µs / 4.78 µs / 6.39 µs / 8.30 µs4.21 µs / 4.79 µs / 6.46 µs / 8.25 µs- / - / - / -8.29 µs / 10.0 µs / 11.7 µs / 13.2 µs- / - / - / -8.27 µs / 9.91 µs / 12.0 µs / 15.5 µs19.5 µs / 25.9 µs / 33.4 µs / 22.6 µs
AES-128 header protection1.71 ns / 3.78 ns / 4.76 ns / 2.75 ns3.58 ns / 6.00 ns / 7.65 ns / 2.83 ns3.41 ns / 6.98 ns / 7.66 ns / 3.19 ns- / - / - / -- / - / - / -- / - / - / -- / - / - / -
AES-256 header protection2.13 ns / 4.85 ns / 5.91 ns / 2.74 ns3.89 ns / 8.05 ns / 9.39 ns / 2.99 ns5.13 ns / 9.63 ns / 9.36 ns / 3.90 ns- / - / - / -- / - / - / -- / - / - / -- / - / - / -
ChaCha20 header protection53.0 ns / 60.8 ns / 78.8 ns / 57.8 ns68.4 ns / 81.4 ns / 97.8 ns / 72.9 ns60.3 ns / 74.5 ns / 87.4 ns / 67.8 ns- / - / - / -- / - / - / -- / - / - / -- / - / - / -
X2551917.9 µs / 23.6 µs / 24.7 µs / 16.5 µs19.4 µs / 24.2 µs / 30.8 µs / 17.7 µs34.9 µs / 45.3 µs / 53.8 µs / 24.5 µs18.5 µs / 23.6 µs / 25.0 µs / 16.6 µs33.3 µs / 48.0 µs / 54.5 µs / 35.8 µs36.2 µs / 51.9 µs / 56.1 µs / 29.6 µs42.2 µs / 62.4 µs / 72.2 µs / 37.3 µs
P-256 ECDH29.4 µs / 38.7 µs / 42.4 µs / 26.3 µs31.8 µs / 40.8 µs / 50.9 µs / 28.7 µs33.6 µs / 41.8 µs / 46.9 µs / 32.5 µs33.2 µs / 41.8 µs / 45.9 µs / 31.0 µs52.2 µs / 68.6 µs / 80.1 µs / 50.1 µs123 µs / 254 µs / 232 µs / 180 µs168 µs / 247 µs / 275 µs / 182 µs
Ed25519 sign4.12 µs / 5.74 µs / 6.62 µs / 3.93 µs4.48 µs / 6.11 µs / 7.20 µs / 4.07 µs13.1 µs / 17.1 µs / 20.8 µs / 7.05 µs4.39 µs / 5.83 µs / 6.79 µs / 4.17 µs13.5 µs / 23.3 µs / 26.7 µs / 16.5 µs9.57 µs / 13.4 µs / 15.1 µs / 8.63 µs28.5 µs / 40.7 µs / 46.9 µs / 22.1 µs
Ed25519 verify19.1 µs / 24.9 µs / 27.3 µs / 16.6 µs21.4 µs / 27.0 µs / 29.6 µs / 18.4 µs25.9 µs / 34.9 µs / 38.1 µs / 20.0 µs19.3 µs / 25.0 µs / 27.4 µs / 16.6 µs45.1 µs / 77.6 µs / 86.5 µs / 40.6 µs22.0 µs / 24.5 µs / 26.1 µs / 18.5 µs42.6 µs / 53.4 µs / 60.3 µs / 29.4 µs
P-256 ECDSA sign6.61 µs / 8.56 µs / 12.9 µs / 7.18 µs12.2 µs / 11.9 µs / 19.5 µs / 11.2 µs12.2 µs / 12.8 µs / 14.7 µs / 11.0 µs8.98 µs / 10.4 µs / 20.2 µs / 8.58 µs14.1 µs / 16.4 µs / 20.2 µs / 12.4 µs31.1 µs / 65.2 µs / 68.1 µs / 44.4 µs60.6 µs / 86.6 µs / 101 µs / 66.8 µs
P-256 ECDSA verify30.6 µs / 38.3 µs / 41.3 µs / 26.0 µs30.4 µs / 38.1 µs / 43.0 µs / 27.2 µs33.8 µs / 39.3 µs / 43.6 µs / 29.1 µs32.3 µs / 39.9 µs / 44.1 µs / 28.2 µs45.6 µs / 56.4 µs / 67.7 µs / 41.7 µs103 µs / 216 µs / 197 µs / 151 µs145 µs / 207 µs / 234 µs / 156 µs
SHA-256, 64 B29.9 ns / 52.7 ns / 236 ns / 37.0 ns56.6 ns / 94.4 ns / 314 ns / 67.2 ns57.4 ns / 77.4 ns / 273 ns / 44.3 ns39.5 ns / 61.9 ns / 568 ns / 34.8 ns156 ns / 231 ns / 505 ns / 159 ns39.0 ns / 55.0 ns / 469 ns / 36.5 ns218 ns / 334 ns / 485 ns / 226 ns
SHA-256, 1350 B268 ns / 576 ns / 2.42 µs / 410 ns306 ns / 619 ns / 2.78 µs / 440 ns299 ns / 608 ns / 2.74 µs / 412 ns292 ns / 588 ns / 6.11 µs / 474 ns412 ns / 754 ns / 2.66 µs / 524 ns295 ns / 589 ns / 5.00 µs / 473 ns2.28 µs / 3.56 µs / 5.19 µs / 2.49 µs
SHA-256, 16 KB3.24 µs / 6.74 µs / 27.7 µs / 4.96 µs3.23 µs / 6.78 µs / 31.5 µs / 4.87 µs3.26 µs / 6.78 µs / 31.2 µs / 4.84 µs3.21 µs / 6.76 µs / 70.3 µs / 6.06 µs3.33 µs / 6.92 µs / 28.0 µs / 4.99 µs3.21 µs / 6.75 µs / 57.7 µs / 5.70 µs27.3 µs / 41.7 µs / 60.7 µs / 29.2 µs
SHA-512, 64 B59.8 ns / 131 ns / 194 ns / 76.1 ns134 ns / 212 ns / 227 ns / 106 ns140 ns / 188 ns / 202 ns / 86.6 ns147 ns / 184 ns / 237 ns / 175 ns228 ns / 317 ns / 430 ns / 209 ns118 ns / 193 ns / 266 ns / 77.2 ns166 ns / 229 ns / 286 ns / 141 ns
SHA-512, 1350 B248 ns / 1.23 µs / 1.62 µs / 731 ns1.24 µs / 1.78 µs / 1.95 µs / 767 ns1.24 µs / 1.75 µs / 1.93 µs / 737 ns1.47 µs / 1.75 µs / 2.34 µs / 1.87 µs1.19 µs / 1.44 µs / 1.90 µs / 865 ns1.18 µs / 1.80 µs / 2.64 µs / 716 ns1.69 µs / 2.37 µs / 3.04 µs / 1.57 µs
SHA-512, 16 KB2.63 µs / 14.0 µs / 18.5 µs / 8.68 µs14.1 µs / 20.2 µs / 21.7 µs / 8.72 µs14.3 µs / 20.3 µs / 21.6 µs / 8.70 µs17.8 µs / 20.1 µs / 27.0 µs / 21.8 µs12.3 µs / 14.5 µs / 19.0 µs / 8.85 µs13.4 µs / 20.6 µs / 30.6 µs / 8.47 µs20.1 µs / 27.3 µs / 35.0 µs / 18.3 µs
HMAC-SHA256, 64 B72.7 ns / 130 ns / 621 ns / 99.7 ns176 ns / 263 ns / 799 ns / 244 ns142 ns / 215 ns / 700 ns / 135 ns107 ns / 168 ns / 1.43 µs / 112 ns1.55 µs / 2.52 µs / 3.70 µs / 2.05 µs103 ns / 156 ns / 1.19 µs / 99.5 ns530 ns / 833 ns / 1.19 µs / 563 ns
HMAC-SHA256, 1350 B321 ns / 655 ns / 2.77 µs / 478 ns427 ns / 794 ns / 3.27 µs / 600 ns400 ns / 749 ns / 3.24 µs / 503 ns356 ns / 694 ns / 7.06 µs / 558 ns1.78 µs / 3.01 µs / 5.91 µs / 2.44 µs353 ns / 681 ns / 5.72 µs / 541 ns2.67 µs / 4.11 µs / 5.96 µs / 2.80 µs
HKDF-SHA256 extract and expand148 ns / 252 ns / 1.06 µs / 205 ns288 ns / 376 ns / 1.28 µs / 331 ns307 ns / 399 ns / 1.18 µs / 268 ns- / - / - / -1.72 µs / 2.71 µs / 4.37 µs / 2.18 µs220 ns / 310 ns / 1.95 µs / 211 ns968 ns / 1.37 µs / 2.00 µs / 926 ns
HKDF-SHA256 expand47.4 ns / 87.8 ns / 292 ns / 70.1 ns126 ns / 179 ns / 624 ns / 154 ns120 ns / 142 ns / 326 ns / 93.1 ns- / - / - / -1.26 µs / 2.00 µs / 2.93 µs / 1.58 µs83.7 ns / 103 ns / 501 ns / 68.1 ns450 ns / 706 ns / 1.00e+3 ns / 480 ns
RSA-2048 PKCS#1 sign345 µs / 392 µs / 449 µs / 274 µs344 µs / 432 µs / 445 µs / 283 µs342 µs / 423 µs / 431 µs / 323 µs344 µs / 407 µs / 444 µs / 553 µs389 µs / 437 µs / 450 µs / 341 µs580 µs / 988 µs / 1.14 ms / 587 µs- / - / - / -
RSA-2048 PKCS#1 verify8.89 µs / 11.2 µs / 12.8 µs / 8.42 µs10.8 µs / 13.6 µs / 15.5 µs / 9.51 µs12.8 µs / 15.4 µs / 16.3 µs / 11.0 µs14.0 µs / 17.5 µs / 19.5 µs / 18.5 µs15.5 µs / 20.7 µs / 24.8 µs / 16.5 µs29.1 µs / 50.2 µs / 57.3 µs / 30.9 µs- / - / - / -
RSA-2048 PSS sign341 µs / 394 µs / 453 µs / 276 µs352 µs / 434 µs / 452 µs / 286 µs336 µs / 425 µs / 435 µs / 326 µs338 µs / 410 µs / 444 µs / 553 µs404 µs / 441 µs / 454 µs / 341 µs581 µs / 991 µs / 1.12 ms / 587 µs3.71 ms / 4.93 ms / 7.16 ms / 4.46 ms
RSA-2048 PSS verify9.11 µs / 11.5 µs / 14.3 µs / 8.76 µs11.1 µs / 14.1 µs / 17.0 µs / 9.83 µs13.4 µs / 16.0 µs / 18.1 µs / 11.4 µs14.3 µs / 17.9 µs / 22.3 µs / 18.8 µs16.2 µs / 21.8 µs / 27.0 µs / 17.3 µs35.3 µs / 58.9 µs / 69.3 µs / 39.1 µs250 µs / 284 µs / 384 µs / 298 µs
ML-KEM-768 key generation6.28 µs / 7.90 µs / 10.0 µs / 6.00 µs8.43 µs / 9.43 µs / 18.4 µs / 7.38 µs- / - / - / -7.36 µs / 8.53 µs / 10.0 µs / 6.11 µs19.8 µs / 26.4 µs / 40.3 µs / 24.9 µs39.8 µs / 57.6 µs / 59.8 µs / 26.3 µs15.0 µs / 17.2 µs / 19.8 µs / 11.8 µs
ML-KEM-768 encapsulate6.52 µs / 8.25 µs / 10.5 µs / 6.84 µs8.41 µs / 9.47 µs / 18.4 µs / 7.83 µs- / - / - / -9.17 µs / 10.3 µs / 11.2 µs / 6.39 µs18.8 µs / 27.5 µs / 41.1 µs / 23.8 µs41.8 µs / 66.9 µs / 65.9 µs / 27.8 µs12.7 µs / 14.8 µs / 17.9 µs / 9.29 µs
ML-KEM-768 decapsulate4.61 µs / 5.75 µs / 7.03 µs / 4.13 µs8.79 µs / 11.2 µs / 15.9 µs / 7.60 µs- / - / - / -6.52 µs / 7.23 µs / 7.40 µs / 4.03 µs15.8 µs / 22.4 µs / 31.6 µs / 24.5 µs54.6 µs / 86.8 µs / 82.8 µs / 34.0 µs13.4 µs / 15.5 µs / 18.9 µs / 9.44 µs
P-384 ECDH98.2 µs / 130 µs / 150 µs / 91.1 µs111 µs / 145 µs / 175 µs / 104 µs370 µs / 581 µs / 636 µs / 411 µs170 µs / 207 µs / 239 µs / 152 µs261 µs / 458 µs / 484 µs / 280 µs393 µs / 746 µs / 761 µs / 492 µs- / - / - / -
P-384 ECDSA sign23.8 µs / 31.9 µs / 39.0 µs / 22.5 µs45.8 µs / 64.7 µs / 82.2 µs / 49.5 µs197 µs / 313 µs / 341 µs / 223 µs90.4 µs / 110 µs / 129 µs / 80.6 µs88.9 µs / 152 µs / 163 µs / 103 µs85.8 µs / 164 µs / 168 µs / 112 µs- / - / - / -
P-384 ECDSA verify98.6 µs / 120 µs / 141 µs / 84.7 µs114 µs / 152 µs / 175 µs / 111 µs360 µs / 567 µs / 617 µs / 403 µs166 µs / 204 µs / 238 µs / 150 µs215 µs / 370 µs / 397 µs / 238 µs351 µs / 658 µs / 685 µs / 424 µs- / - / - / -
P-521 ECDH161 µs / 222 µs / 217 µs / 130 µs168 µs / 236 µs / 245 µs / 142 µs- / - / - / -- / - / - / -272 µs / 391 µs / 466 µs / 246 µs437 µs / 600 µs / 779 µs / 397 µs- / - / - / -
P-521 ECDSA sign39.8 µs / 55.5 µs / 64.1 µs / 36.5 µs87.9 µs / 127 µs / 156 µs / 84.0 µs- / - / - / -- / - / - / -130 µs / 187 µs / 220 µs / 133 µs94.3 µs / 144 µs / 184 µs / 79.8 µs- / - / - / -
P-521 ECDSA verify145 µs / 193 µs / 204 µs / 120 µs187 µs / 259 µs / 283 µs / 166 µs- / - / - / -- / - / - / -261 µs / 379 µs / 449 µs / 253 µs354 µs / 481 µs / 627 µs / 251 µs- / - / - / -

Criterion's estimates from rind's benchmark report at ccdda859, run 2026-11-09, as Arrow Lake / Zen 3 / Coffee Lake / Apple M4. Every library runs its native path on each CPU. On Mac, rind holds DIT across the timed loop, as a caller batching calls does.

AI is really fucking good at benchmarks. Moments like this fill me with dread as a professional software engineer.

A decade ago, I wasted weeks speeding up Go’s crypto. I was that guy, hand-writing assembly to use the PCLMULQDQ instruction for massive performance gains (AES-GCM). It didn’t even get merged because I insisted on trying to change the Go API like an idiot.

I should have just waited a decade for Opus 5.5 instead. idiot.

Lean into Lean

But does it actually work? How can we build confidence?

I saw an Anthropic blog post about formal verification. Like most programmers, I don’t even test my code, let alone formally verify it. But I figured I’d play along and waste a few more tokens chasing the dragon.

Because like, if you can prove the vibe slop is correct, it’s no longer vibe slop right?

Formal proofs · one square per CPU

Almost nobody proves
their crypto

rind
aws-lc-rs
ring
RustCrypto
graviola
libcrux
OpenSSL
AES-GCM
ChaCha20-Poly1305
XChaCha20-Poly1305
AES header protection
ChaCha20 header protection
SHA-256
SHA-512
HMAC-SHA256
HKDF-SHA256
X25519
Ed25519
P-256
P-384
P-521
RSA-2048 PSS
RSA-2048 PKCS#1
ML-KEM-768
proven end to endproven core, unproven glueunproven

Squares: Arrow Lake, Zen 3, Coffee Lake, Apple M4. Blank: not offered.

Data
Primitiverindaws-lc-rsringRustCryptograviolalibcruxOpenSSL
AES-GCMArrow Lake: proven core, Zen 3: proven core, Coffee Lake: proven end to end, Apple M4: unproven · x86_64: Vale's F* AES-GCM, for every message without VAES but only short ones with itArrow Lake: proven core, Zen 3: proven core, Coffee Lake: proven core, Apple M4: unproven · x86_64: aws-lc-verification's SAW AES-GCM, for AES-256 onlyArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unprovenArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unprovenArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unprovenArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unprovenArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unproven
ChaCha20-Poly1305Arrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unprovenArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unprovenArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unprovenArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unprovenArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unprovenArrow Lake: proven end to end, Zen 3: proven end to end, Coffee Lake: proven end to end, Apple M4: proven end to endArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unproven
XChaCha20-Poly1305Arrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unprovenArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unprovenArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unprovenArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unprovenArrow Lake: proven core, Zen 3: proven core, Coffee Lake: proven core, Apple M4: proven core · x86_64: HACL*'s F* ChaCha20-Poly1305, under an unverified HChaCha20 · aarch64: HACL*'s F* ChaCha20-Poly1305, under an unverified HChaCha20
AES header protectionArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unprovenArrow Lake: proven core, Zen 3: proven core, Coffee Lake: proven core, Apple M4: unproven · x86_64: aws-lc-verification's SAW AES block, for AES-256 onlyArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unproven
ChaCha20 header protectionArrow Lake: proven end to end, Zen 3: proven end to end, Coffee Lake: proven end to end, Apple M4: proven end to endArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unprovenArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unproven
SHA-256Arrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unprovenArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unprovenArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unprovenArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unprovenArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unprovenArrow Lake: proven end to end, Zen 3: proven end to end, Coffee Lake: proven end to end, Apple M4: proven end to endArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unproven
SHA-512Arrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unprovenArrow Lake: proven end to end, Zen 3: unproven, Coffee Lake: proven end to end, Apple M4: unprovenArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unprovenArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unprovenArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unprovenArrow Lake: proven end to end, Zen 3: proven end to end, Coffee Lake: proven end to end, Apple M4: proven end to endArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unproven
HMAC-SHA256Arrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unprovenArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unprovenArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unprovenArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unprovenArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unprovenArrow Lake: proven end to end, Zen 3: proven end to end, Coffee Lake: proven end to end, Apple M4: proven end to endArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unproven
HKDF-SHA256Arrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unprovenArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unprovenArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unprovenArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unprovenArrow Lake: proven end to end, Zen 3: proven end to end, Coffee Lake: proven end to end, Apple M4: proven end to endArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unproven
X25519Arrow Lake: proven end to end, Zen 3: proven end to end, Coffee Lake: proven end to end, Apple M4: proven end to endArrow Lake: proven core, Zen 3: proven core, Coffee Lake: proven core, Apple M4: proven core · x86_64: s2n-bignum's HOL Light X25519 ladder · aarch64: s2n-bignum's HOL Light X25519 ladderArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unprovenArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unprovenArrow Lake: proven core, Zen 3: proven core, Coffee Lake: proven core, Apple M4: proven core · x86_64: s2n-bignum's HOL Light X25519 ladder · aarch64: s2n-bignum's HOL Light X25519 ladderArrow Lake: proven end to end, Zen 3: proven end to end, Coffee Lake: proven end to end, Apple M4: proven end to endArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unproven
Ed25519Arrow Lake: proven core, Zen 3: proven core, Coffee Lake: proven core, Apple M4: proven core · x86_64: s2n-bignum's HOL Light scalar multiplications · aarch64: s2n-bignum's HOL Light scalar multiplicationsArrow Lake: proven core, Zen 3: proven core, Coffee Lake: proven core, Apple M4: proven core · x86_64: s2n-bignum's HOL Light scalar multiplications · aarch64: s2n-bignum's HOL Light scalar multiplicationsArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unprovenArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unprovenArrow Lake: proven core, Zen 3: proven core, Coffee Lake: proven core, Apple M4: proven core · x86_64: s2n-bignum's HOL Light scalar multiplications · aarch64: s2n-bignum's HOL Light scalar multiplicationsArrow Lake: proven end to end, Zen 3: proven end to end, Coffee Lake: proven end to end, Apple M4: proven end to endArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unproven
P-256Arrow Lake: proven core, Zen 3: proven core, Coffee Lake: proven core, Apple M4: proven end to end · x86_64: s2n-bignum's HOL Light scalar multiplication, for ECDHArrow Lake: proven core, Zen 3: proven core, Coffee Lake: proven core, Apple M4: proven core · x86_64: s2n-bignum's HOL Light scalar multiplication, for ECDH · aarch64: s2n-bignum's HOL Light scalar multiplication, for ECDHArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unprovenArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unprovenArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unprovenArrow Lake: proven end to end, Zen 3: proven end to end, Coffee Lake: proven end to end, Apple M4: proven end to endArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unproven
P-384Arrow Lake: proven core, Zen 3: proven core, Coffee Lake: proven core, Apple M4: proven core · x86_64: s2n-bignum's HOL Light scalar multiplication, for ECDH · aarch64: s2n-bignum's HOL Light scalar multiplication, for ECDHArrow Lake: proven core, Zen 3: proven core, Coffee Lake: proven core, Apple M4: proven core · x86_64: s2n-bignum's HOL Light scalar multiplication, for ECDH · aarch64: s2n-bignum's HOL Light scalar multiplication, for ECDHArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unprovenArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unprovenArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unprovenArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unproven
P-521Arrow Lake: proven core, Zen 3: proven core, Coffee Lake: proven core, Apple M4: proven core · x86_64: s2n-bignum's HOL Light scalar multiplication, for ECDH · aarch64: s2n-bignum's HOL Light scalar multiplication, for ECDHArrow Lake: proven core, Zen 3: proven core, Coffee Lake: proven core, Apple M4: proven core · x86_64: s2n-bignum's HOL Light scalar multiplication, for ECDH · aarch64: s2n-bignum's HOL Light scalar multiplication, for ECDHArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unprovenArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unproven
RSA-2048 PSSArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unprovenArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unprovenArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unprovenArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unprovenArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unprovenArrow Lake: proven end to end, Zen 3: proven end to end, Coffee Lake: proven end to end, Apple M4: proven end to endArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unproven
RSA-2048 PKCS#1Arrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unprovenArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unprovenArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unprovenArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unprovenArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unprovenArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unproven
ML-KEM-768Arrow Lake: proven core, Zen 3: proven core, Coffee Lake: proven core, Apple M4: proven core · x86_64: s2n-bignum's and mlkem-native's HOL Light NTT and sampling · aarch64: s2n-bignum's HOL Light NTT and samplingArrow Lake: proven core, Zen 3: proven core, Coffee Lake: proven core, Apple M4: proven core · x86_64: mlkem-native's HOL Light AVX2 NTT and sampling · aarch64: mlkem-native's HOL Light aarch64 NTT and samplingArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unprovenArrow Lake: proven core, Zen 3: proven core, Coffee Lake: proven core, Apple M4: proven core · x86_64: s2n-bignum's HOL Light NTT and base multiplication · aarch64: s2n-bignum's HOL Light NTT and base multiplicationArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unprovenArrow Lake: unproven, Zen 3: unproven, Coffee Lake: unproven, Apple M4: unproven

End to end: rind's benchmarks/verified.toml at ccdda859, whose ✓ needs a machine-checked proof of all the code, glue included. Proven core: a proven routine does the whole cipher, block function, scalar multiplication, or NTT for at least some of the row's operations; field arithmetic alone doesn't count. Checked against each library's source for each CPU's architecture, at the versions rind's report locks, run 2026-11-09.

donate some tokens and make every box green

Many of these implementations are faster AND formally verified. Including the afformentioned AES-GCM (the goat). At least according to Claude so grain of salt folks.

My goal is to get every algorithm formally proven. Claude says that will take years.

If only there was somebody in the audience works for a frontier lab and wants some easy marketting piece. Steal the glory from the cryptographers instead of the mathematicians.

Please Donate Tokens

If it sounds like I’m desparate and begging for more tokens, ur right.

So I came up with a plan. I decided the best way to get tokens is to rage bait.

Bun is SUPER SLOW.
Holy shit it’s like REALLY SLOW.
Imagine doing super common stuff like TLS certificate generation in Bun.
Super SLOW.

WebCrypto and node:crypto · geomean of 54 calls
3.3×

faster than
stock Bun

Bun + rind
fastest
Node
3.2× slower
Bun
3.3× slower
Deno
7.0× slower

Shorter is faster. Same Bun commit, with rind swapped in.

Data
OperationBun + rindNodeBunDeno
WebCrypto Ed25519 generateKey6.18 µs20.8 µs9.71 µs15.6 µs
WebCrypto Ed25519 importKey pkcs85.55 µs18.6 µs16.1 µs6.20 µs
WebCrypto Ed25519 sign7.73 µs19.5 µs12.1 µs13.6 µs
WebCrypto Ed25519 verify22.9 µs50.0 µs32.0 µs26.4 µs
WebCrypto Ed25519 exportKey jwk0.510 µs1.48 µs8.39 µs8.30 µs
WebCrypto X25519 generateKey4.58 µs20.1 µs9.50 µs46.6 µs
WebCrypto X25519 deriveBits18.1 µs28.5 µs22.5 µs40.9 µs
WebCrypto P-256 generateKey6.15 µs19.3 µs6.10 µs22.8 µs
WebCrypto P-256 importKey pkcs89.86 µs31.2 µs9.84 µs6.75 µs
WebCrypto P-256 importKey spki1.05 µs21.1 µs1.04 µs7.11 µs
WebCrypto P-256 sign17.7 µs31.5 µs17.8 µs356 µs
WebCrypto P-256 verify33.2 µs55.2 µs33.2 µs453 µs
WebCrypto P-256 exportKey pkcs83.45 µs12.0 µs3.41 µs3.54 µs
WebCrypto P-256 ECDH deriveBits31.5 µs38.6 µs31.6 µs444 µs
WebCrypto P-384 generateKey26.4 µs76.4 µs203 µs47.9 µs
WebCrypto P-384 importKey pkcs821.9 µs121 µs405 µs7.37 µs
WebCrypto P-384 importKey spki1.56 µs52.8 µs1.21 µs7.39 µs
WebCrypto P-384 sign27.4 µs127 µs241 µs955 µs
WebCrypto P-384 verify97.0 µs237 µs246 µs1.23 ms
WebCrypto P-384 exportKey pkcs80.480 µs21.1 µs16.8 µs3.36 µs
WebCrypto P-384 ECDH deriveBits84.7 µs164 µs221 µs1.23 ms
WebCrypto P-521 generateKey41.5 µs81.5 µs491 µs480 µs
WebCrypto P-521 importKey pkcs836.6 µs125 µs982 µs7.19 µs
WebCrypto P-521 importKey spki1.56 µs53.0 µs1.63 µs7.63 µs
WebCrypto P-521 sign44.4 µs165 µs585 µs1.38 ms
WebCrypto P-521 verify142 µs283 µs607 µs1.72 ms
WebCrypto P-521 exportKey pkcs80.480 µs20.0 µs44.2 µs3.84 µs
WebCrypto P-521 ECDH deriveBits127 µs172 µs537 µs1.63 ms
node:crypto Ed25519 generateKeyPairSync5.12 µs15.9 µs9.39 µs12.2 µs
node:crypto Ed25519 sign4.54 µs14.9 µs8.63 µs9.57 µs
node:crypto Ed25519 verify19.6 µs45.8 µs28.4 µs22.0 µs
node:crypto Ed25519 sign, PEM key each call9.21 µs36.0 µs17.1 µs22.6 µs
node:crypto X25519 generateKeyPairSync5.02 µs14.8 µs9.24 µs11.8 µs
node:crypto X25519 diffieHellman14.3 µs20.9 µs19.1 µs36.0 µs
node:crypto P-256 generateKeyPairSync5.83 µs13.2 µs5.80 µs141 µs
node:crypto P-256 sign14.0 µs15.4 µs14.0 µs305 µs
node:crypto P-256 verify29.5 µs40.0 µs29.6 µs294 µs
node:crypto P-256 createPrivateKey pem6.07 µs12.1 µs5.53 µs144 µs
node:crypto P-256 export pkcs8 pem3.82 µs11.0 µs3.82 µs143 µs
node:crypto P-256 diffieHellman27.8 µs32.6 µs27.7 µs141 µs
node:crypto P-256 ECDH computeSecret31.9 µs61.0 µs31.8 µs282 µs
node:crypto P-384 generateKeyPairSync21.4 µs67.8 µs203 µs355 µs
node:crypto P-384 sign23.7 µs91.9 µs235 µs742 µs
node:crypto P-384 verify93.3 µs201 µs238 µs711 µs
node:crypto P-384 createPrivateKey pem22.0 µs14.9 µs204 µs358 µs
node:crypto P-384 export pkcs8 pem0.780 µs20.2 µs17.2 µs357 µs
node:crypto P-384 diffieHellman81.1 µs158 µs217 µs355 µs
node:crypto P-384 ECDH computeSecret81.0 µs284 µs418 µs708 µs
node:crypto P-521 generateKeyPairSync36.6 µs74.2 µs491 µs443 µs
node:crypto P-521 sign40.2 µs131 µs577 µs972 µs
node:crypto P-521 verify138 µs249 µs591 µs933 µs
node:crypto P-521 createPrivateKey pem37.6 µs15.3 µs493 µs427 µs
node:crypto P-521 export pkcs8 pem0.900 µs19.3 µs44.9 µs425 µs
node:crypto P-521 diffieHellman125 µs164 µs534 µs422 µs
node:crypto P-521 ECDH computeSecret125 µs296 µs1.02 ms-

Core Ultra 7 270K Plus, one pinned core, the median of 5 alternating rounds, 2026-11-07. Bun + rind: bun 1.4.4 (fb621aaac); Node: node v24.21.0; Bun: bun 1.4.4 (b1007f117); Deno: deno 2.9.8. Bun and Bun + rind are release builds of the same Bun commit, without and with the rind prototype, which moves Ed25519, X25519, P-384, and P-521 onto rind; P-256 still runs BoringSSL in both.

rip dino

I threw Deprecated Deno in just because it uses RustCrypto. Oh man, I used to hate RustCrypto back when I was a programmer. Do not use it, even though they registered official sounding crates like aes and rsa.

Anyway, back to dunking on JS runtimes for being slow at things they weren’t designed to do, like cryptography:

Every call · one row each
49/55

calls where Bun + rind is fastest,
or within 10%

Bun + rind
Node
Bun
Deno
WebCrypto · Ed25519
generateKey
6.18 µs
20.8 µs
9.71 µs
15.6 µs
importKey pkcs8
5.55 µs
18.6 µs
16.1 µs
6.20 µs
sign
7.73 µs
19.5 µs
12.1 µs
13.6 µs
verify
22.9 µs
50.0 µs
32.0 µs
26.4 µs
exportKey jwk
0.510 µs
1.48 µs
8.39 µs
8.30 µs
WebCrypto · X25519
generateKey
4.58 µs
20.1 µs
9.50 µs
46.6 µs
deriveBits
18.1 µs
28.5 µs
22.5 µs
40.9 µs
WebCrypto · P-256
generateKey
6.15 µs
19.3 µs
6.10 µs
22.8 µs
importKey pkcs8
9.86 µs
31.2 µs
9.84 µs
6.75 µs
importKey spki
1.05 µs
21.1 µs
1.04 µs
7.11 µs
sign
17.7 µs
31.5 µs
17.8 µs
356 µs
verify
33.2 µs
55.2 µs
33.2 µs
453 µs
exportKey pkcs8
3.45 µs
12.0 µs
3.41 µs
3.54 µs
ECDH deriveBits
31.5 µs
38.6 µs
31.6 µs
444 µs
WebCrypto · P-384
generateKey
26.4 µs
76.4 µs
203 µs
47.9 µs
importKey pkcs8
21.9 µs
121 µs
405 µs
7.37 µs
importKey spki
1.56 µs
52.8 µs
1.21 µs
7.39 µs
sign
27.4 µs
127 µs
241 µs
955 µs
verify
97.0 µs
237 µs
246 µs
1.23 ms
exportKey pkcs8
0.480 µs
21.1 µs
16.8 µs
3.36 µs
ECDH deriveBits
84.7 µs
164 µs
221 µs
1.23 ms
WebCrypto · P-521
generateKey
41.5 µs
81.5 µs
491 µs
480 µs
importKey pkcs8
36.6 µs
125 µs
982 µs
7.19 µs
importKey spki
1.56 µs
53.0 µs
1.63 µs
7.63 µs
sign
44.4 µs
165 µs
585 µs
1.38 ms
verify
142 µs
283 µs
607 µs
1.72 ms
exportKey pkcs8
0.480 µs
20.0 µs
44.2 µs
3.84 µs
ECDH deriveBits
127 µs
172 µs
537 µs
1.63 ms
node:crypto · Ed25519
generateKeyPairSync
5.12 µs
15.9 µs
9.39 µs
12.2 µs
sign
4.54 µs
14.9 µs
8.63 µs
9.57 µs
verify
19.6 µs
45.8 µs
28.4 µs
22.0 µs
sign, PEM key each call
9.21 µs
36.0 µs
17.1 µs
22.6 µs
node:crypto · X25519
generateKeyPairSync
5.02 µs
14.8 µs
9.24 µs
11.8 µs
diffieHellman
14.3 µs
20.9 µs
19.1 µs
36.0 µs
node:crypto · P-256
generateKeyPairSync
5.83 µs
13.2 µs
5.80 µs
141 µs
sign
14.0 µs
15.4 µs
14.0 µs
305 µs
verify
29.5 µs
40.0 µs
29.6 µs
294 µs
createPrivateKey pem
6.07 µs
12.1 µs
5.53 µs
144 µs
export pkcs8 pem
3.82 µs
11.0 µs
3.82 µs
143 µs
diffieHellman
27.8 µs
32.6 µs
27.7 µs
141 µs
ECDH computeSecret
31.9 µs
61.0 µs
31.8 µs
282 µs
node:crypto · P-384
generateKeyPairSync
21.4 µs
67.8 µs
203 µs
355 µs
sign
23.7 µs
91.9 µs
235 µs
742 µs
verify
93.3 µs
201 µs
238 µs
711 µs
createPrivateKey pem
22.0 µs
14.9 µs
204 µs
358 µs
export pkcs8 pem
0.780 µs
20.2 µs
17.2 µs
357 µs
diffieHellman
81.1 µs
158 µs
217 µs
355 µs
ECDH computeSecret
81.0 µs
284 µs
418 µs
708 µs
node:crypto · P-521
generateKeyPairSync
36.6 µs
74.2 µs
491 µs
443 µs
sign
40.2 µs
131 µs
577 µs
972 µs
verify
138 µs
249 µs
591 µs
933 µs
createPrivateKey pem
37.6 µs
15.3 µs
493 µs
427 µs
export pkcs8 pem
0.900 µs
19.3 µs
44.9 µs
425 µs
diffieHellman
125 µs
164 µs
534 µs
422 µs
ECDH computeSecret
125 µs
296 µs
1.02 ms
fastest, or within 10%to 1.25×to 1.5×to 2×to 4×to 8×over 8×

Blank: the runtime refuses it. P-256 runs BoringSSL in both Buns.

Data
OperationBun + rindNodeBunDeno
WebCrypto Ed25519 generateKey6.18 µs20.8 µs9.71 µs15.6 µs
WebCrypto Ed25519 importKey pkcs85.55 µs18.6 µs16.1 µs6.20 µs
WebCrypto Ed25519 sign7.73 µs19.5 µs12.1 µs13.6 µs
WebCrypto Ed25519 verify22.9 µs50.0 µs32.0 µs26.4 µs
WebCrypto Ed25519 exportKey jwk0.510 µs1.48 µs8.39 µs8.30 µs
WebCrypto X25519 generateKey4.58 µs20.1 µs9.50 µs46.6 µs
WebCrypto X25519 deriveBits18.1 µs28.5 µs22.5 µs40.9 µs
WebCrypto P-256 generateKey6.15 µs19.3 µs6.10 µs22.8 µs
WebCrypto P-256 importKey pkcs89.86 µs31.2 µs9.84 µs6.75 µs
WebCrypto P-256 importKey spki1.05 µs21.1 µs1.04 µs7.11 µs
WebCrypto P-256 sign17.7 µs31.5 µs17.8 µs356 µs
WebCrypto P-256 verify33.2 µs55.2 µs33.2 µs453 µs
WebCrypto P-256 exportKey pkcs83.45 µs12.0 µs3.41 µs3.54 µs
WebCrypto P-256 ECDH deriveBits31.5 µs38.6 µs31.6 µs444 µs
WebCrypto P-384 generateKey26.4 µs76.4 µs203 µs47.9 µs
WebCrypto P-384 importKey pkcs821.9 µs121 µs405 µs7.37 µs
WebCrypto P-384 importKey spki1.56 µs52.8 µs1.21 µs7.39 µs
WebCrypto P-384 sign27.4 µs127 µs241 µs955 µs
WebCrypto P-384 verify97.0 µs237 µs246 µs1.23 ms
WebCrypto P-384 exportKey pkcs80.480 µs21.1 µs16.8 µs3.36 µs
WebCrypto P-384 ECDH deriveBits84.7 µs164 µs221 µs1.23 ms
WebCrypto P-521 generateKey41.5 µs81.5 µs491 µs480 µs
WebCrypto P-521 importKey pkcs836.6 µs125 µs982 µs7.19 µs
WebCrypto P-521 importKey spki1.56 µs53.0 µs1.63 µs7.63 µs
WebCrypto P-521 sign44.4 µs165 µs585 µs1.38 ms
WebCrypto P-521 verify142 µs283 µs607 µs1.72 ms
WebCrypto P-521 exportKey pkcs80.480 µs20.0 µs44.2 µs3.84 µs
WebCrypto P-521 ECDH deriveBits127 µs172 µs537 µs1.63 ms
node:crypto Ed25519 generateKeyPairSync5.12 µs15.9 µs9.39 µs12.2 µs
node:crypto Ed25519 sign4.54 µs14.9 µs8.63 µs9.57 µs
node:crypto Ed25519 verify19.6 µs45.8 µs28.4 µs22.0 µs
node:crypto Ed25519 sign, PEM key each call9.21 µs36.0 µs17.1 µs22.6 µs
node:crypto X25519 generateKeyPairSync5.02 µs14.8 µs9.24 µs11.8 µs
node:crypto X25519 diffieHellman14.3 µs20.9 µs19.1 µs36.0 µs
node:crypto P-256 generateKeyPairSync5.83 µs13.2 µs5.80 µs141 µs
node:crypto P-256 sign14.0 µs15.4 µs14.0 µs305 µs
node:crypto P-256 verify29.5 µs40.0 µs29.6 µs294 µs
node:crypto P-256 createPrivateKey pem6.07 µs12.1 µs5.53 µs144 µs
node:crypto P-256 export pkcs8 pem3.82 µs11.0 µs3.82 µs143 µs
node:crypto P-256 diffieHellman27.8 µs32.6 µs27.7 µs141 µs
node:crypto P-256 ECDH computeSecret31.9 µs61.0 µs31.8 µs282 µs
node:crypto P-384 generateKeyPairSync21.4 µs67.8 µs203 µs355 µs
node:crypto P-384 sign23.7 µs91.9 µs235 µs742 µs
node:crypto P-384 verify93.3 µs201 µs238 µs711 µs
node:crypto P-384 createPrivateKey pem22.0 µs14.9 µs204 µs358 µs
node:crypto P-384 export pkcs8 pem0.780 µs20.2 µs17.2 µs357 µs
node:crypto P-384 diffieHellman81.1 µs158 µs217 µs355 µs
node:crypto P-384 ECDH computeSecret81.0 µs284 µs418 µs708 µs
node:crypto P-521 generateKeyPairSync36.6 µs74.2 µs491 µs443 µs
node:crypto P-521 sign40.2 µs131 µs577 µs972 µs
node:crypto P-521 verify138 µs249 µs591 µs933 µs
node:crypto P-521 createPrivateKey pem37.6 µs15.3 µs493 µs427 µs
node:crypto P-521 export pkcs8 pem0.900 µs19.3 µs44.9 µs425 µs
node:crypto P-521 diffieHellman125 µs164 µs534 µs422 µs
node:crypto P-521 ECDH computeSecret125 µs296 µs1.02 ms-

Core Ultra 7 270K Plus, one pinned core, the median of 5 alternating rounds, 2026-11-07. Bun + rind: bun 1.4.4 (fb621aaac); Node: node v24.21.0; Bun: bun 1.4.4 (b1007f117); Deno: deno 2.9.8. Bun and Bun + rind are release builds of the same Bun commit, without and with the rind prototype, which moves Ed25519, X25519, P-384, and P-521 onto rind; P-256 still runs BoringSSL in both.

Imagine being marginally slower than Node

Did the rage bait work? Login to your work account, choose the unreleased model, then /quest-spawn to work on the backlog I planned.

k thx

try it?

Up to you, it depends on your tolerance for vibe slop. This is cryptography so it’s dangerous to get wrong.

But as Sun Tzu once said: yolo

# safer/faster API
rind = "0.3"

# if you use ring
ring = { package = "rind-ring", version = "0.17" }

# if you use rustls
rustls = { version = "0.23", default-features = false, features = ["std", "tls12"] }
rind-rustls = "0.23"

# if you use aws-lc-rs
aws-lc-rs = { package = "rind-aws-lc-rs", version = "1" }

There’s other adapters too if you’re lazy. Or just tell Mr AI to migrate to the rind API.

The Bill

All of this crypto jizz, it must have been expensive, right?

This took my 9-year old desktop PC… 12 days. And much of that was waiting for a usage reset.

The total was about $4.2k at API pricing. But API pricing is a meme.

RIND
OCT 27 → NOV 07 2026
12 DAYS · TERMINAL /goal

CLAUDE OPUS 5.5$4,158

TOKENS10.30B
CACHE READS98%
AGENT HRS559.4
HUMAN HRS28.3

LIST PRICE$4,158.00
SUBSIDIES−$4,118.00

12 DAYS OF $100/MO · YOU SAVED 99%

THANK YOU FOR VIBING
Data
LineAmount
Claude Opus 5.5$4,158
Tokens10.30B
Cache reads98%
Agent hrs559.4
Human hrs28.3
List price$4,158.00
Paid$40.00

From the final tally in moq-dev/rind#499, through November 7, 2026, at 14:32 PT. Sessions working in a rind checkout, or whose task names moq-dev/rind, from the graviola bootstrap on 2026-10-27. Opus usage from Claude Code logs, each API message counted once, priced at its standard API rate. Paid: 12 days of a $100 a month plan. Human hours are the maintainer's prompts, with gaps over 15 minutes counted as away. Agent hours cover Claude Code sessions.

Thanks god for the upcoming IPO

That’s right, my credit card made the internet a better place* for $40. It’s ridiculous.

* Assuming anybody actually uses this library.

FIN

Real talk: Programming is dead. We had a good run.

Many of these crypto libraries have been hand optimized by some of the smartest people I know (cryptography nerds). And they get completely blown out of the water by a vibe coder.

I know we still need humans to tell the AI to do dumb shit. Like to rewrite libraries in Rust. I know that AI is still terrible at anything involving user experience.

But like, for how much longer?