Media over QUIC

November 8, 2026 · kixelated

Cryptography Slop

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 MoQ build. 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.

THIS WILL NOT STAND.

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.

rind

It started as fork of Graviola and quickly morphed into a monsterish combination of ring and aws-lc-rs and libcrux.

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

aws-lc-rs's
packets per core

rind157 ns
0
ring191 ns
0
aws-lc-rs221 ns
0
OpenSSL245 ns
0
graviola275 ns
0
RustCrypto344 ns
0
libcrux2.10 µs
0

AES-128-GCM, the geometric mean over CPUs. Arrow Lake: 1.71×, Zen 3: 1.77×, Coffee Lake: 1.16×, Apple M4: 1.12×. 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.7 ns92.7 ns38.7 ns165 ns43.2 ns246 ns10.8 ns161 ns
aws-lc-rs37.5 ns159 ns78.2 ns291 ns88.8 ns285 ns49.7 ns181 ns
ring41.1 ns119 ns56.3 ns191 ns70.7 ns277 ns41.8 ns210 ns
RustCrypto73.1 ns278 ns97.0 ns434 ns100 ns547 ns23.9 ns212 ns
graviola42.1 ns226 ns69.6 ns295 ns71.4 ns400 ns79.0 ns216 ns
libcrux171 ns1.98 µs321 ns4.72 µs282 ns3.49 µs51.9 ns600 ns
OpenSSL56.8 ns160 ns115 ns326 ns156 ns352 ns66.8 ns196 ns

AES-128-GCM seal, criterion's estimate from rind's benchmark report at 00610aff, run 2026-11-06 and 2026-11-07: 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 a tiny reduction in CPU usage has huge impact when multiplied across every HTTPS request in the world*.

* this benchmark is HTTP/3 specific. HTTP/1 and HTTP/2 use different payload sizes. There be a lot of variance depending on the architecture.

WOW FAST

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

Have you ever tried to cold compile Chromium? It takes literal hours.

rustls, cold release build · averaged over 3 CPUs
4.0×

faster to
build

27.4 srace clock, 12× speed
rustls + rind
rustc only
6.8 s ✓
rustls + ring
needs C compiler
11.6 s ✓
rustls + aws-lc-rs
needs C compiler
27.4 s ✓

The geometric mean over CPUs. Arrow Lake: 3.9×, Coffee Lake: 3.2×, Apple M4: 5.2×.

Data
CPUBuildTimeCPU timeBinaryTools
Arrow Lakerind3.4 s8.0 s0.84 MiBrustc only
Arrow Lakeaws-lc-rs11.8 s37.1 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 Lakegraviola2.1 s4.5 s0.87 MiBrustc only
Arrow Lakelibcrux5.8 s13.4 s0.71 MiBrustc only
Arrow LakeOpenSSL3.4 s8.7 s0.36 MiBneeds C compiler, pkg-config
Arrow Lakeopenssl-vendored24.7 s161.4 s4.90 MiBneeds C compiler, make, perl
Arrow Lakerustls + rind4.2 s21.1 s2.86 MiBrustc only
Arrow Lakerustls + rind-lean4.5 s23.2 s1.74 MiBrustc only
Arrow Lakerustls + aws-lc-rs16.6 s55.2 s3.92 MiBneeds C compiler
Arrow Lakerustls + ring7.8 s19.3 s1.85 MiBneeds C compiler
Coffee Lakerind7.3 s12.4 s0.84 MiBrustc only
Coffee Lakeaws-lc-rs26.2 s62.9 s2.85 MiBneeds C compiler
Coffee Lakering9.3 s12.1 s0.71 MiBneeds C compiler
Coffee LakeRustCrypto8.3 s24.0 s0.52 MiBrustc only
Coffee Lakegraviola3.8 s6.5 s0.87 MiBrustc only
Coffee Lakelibcrux9.7 s20.2 s0.71 MiBrustc only
Coffee LakeOpenSSL5.8 s11.6 s0.36 MiBneeds C compiler, pkg-config
Coffee Lakeopenssl-vendored82.3 s220.2 s4.90 MiBneeds C compiler, make, perl
Coffee Lakerustls + rind11.3 s31.5 s2.82 MiBrustc only
Coffee Lakerustls + rind-lean11.8 s32.8 s1.74 MiBrustc only
Coffee Lakerustls + aws-lc-rs36.6 s88.7 s3.92 MiBneeds C compiler
Coffee Lakerustls + ring16.4 s30.5 s1.85 MiBneeds C compiler
Apple M4rind4.0 s7.5 s0.64 MiBrustc only
Apple M4aws-lc-rs29.0 s92.1 s2.04 MiBneeds C compiler
Apple M4ring8.2 s10.2 s0.61 MiBneeds C compiler
Apple M4RustCrypto5.1 s16.0 s0.44 MiBrustc only
Apple M4graviola3.1 s5.5 s0.78 MiBrustc only
Apple M4libcrux8.0 s17.7 s0.56 MiBrustc only
Apple M4OpenSSL4.6 s10.2 s0.34 MiBneeds C compiler
Apple M4openssl-vendored131.7 s420.9 s3.58 MiBneeds C compiler, make, perl
Apple M4rustls + rind6.5 s21.6 s2.07 MiBrustc only
Apple M4rustls + rind-lean6.7 s22.1 s1.47 MiBrustc only
Apple M4rustls + aws-lc-rs34.0 s109.0 s2.93 MiBneeds C compiler
Apple M4rustls + ring12.2 s22.9 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-07, at 9e7f6a5a; Coffee Lake: Core i7-8700, 3 jobs, 3 runs, 2026-11-06, at f95b91da; Apple M4: Apple M4, 4 jobs, 3 runs, 2026-11-07, at 9e7f6a5a. 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.

Wow fast

Having accomplished my goal of making MoQ faster, I let my 9-year-old gaming PC take a vacation.

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

Every benchmark · one square per CPU
233/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, X25519MLKEM768172 µs / 261 µs / 302 µs / 174 µs234 µs / 332 µs / 458 µs / 212 µs- / - / - / -188 µs / 343 µs / 376 µs / 179 µs439 µs / 803 µs / 831 µs / 463 µs- / - / - / -- / - / - / -
full handshake, X25519151 µs / 228 µs / 260 µs / 151 µs202 µs / 292 µs / 370 µs / 183 µs221 µs / 328 µs / 338 µs / 184 µs161 µs / 239 µs / 316 µs / 159 µs366 µs / 574 µs / 687 µs / 375 µs- / - / - / -- / - / - / -
full handshake, P-256175 µs / 243 µs / 296 µs / 172 µs228 µs / 304 µs / 417 µs / 206 µs220 µs / 282 µs / 328 µs / 202 µs192 µs / 270 µs / 369 µs / 190 µs401 µs / 624 µs / 760 µs / 401 µs- / - / - / -- / - / - / -
full handshake, Ed25519 certificate122 µs / 187 µs / 213 µs / 129 µs167 µs / 233 µs / 306 µs / 150 µs202 µs / 293 µs / 325 µs / 155 µs124 µs / 186 µs / 250 µs / 124 µs368 µs / 640 µs / 747 µs / 383 µs- / - / - / -- / - / - / -
full handshake, RSA-2048 certificate433 µs / 550 µs / 614 µs / 373 µs480 µs / 646 µs / 758 µs / 409 µs488 µs / 647 µs / 678 µs / 447 µs440 µs / 568 µs / 687 µs / 674 µs671 µs / 992 µs / 1.01 ms / 644 µs- / - / - / -- / - / - / -
resumed handshake, X2551954.4 µs / 77.2 µs / 121 µs / 65.9 µs101 µs / 133 µs / 229 µs / 89.8 µs111 µs / 158 µs / 200 µs / 87.2 µs55.6 µs / 77.3 µs / 160 µs / 61.6 µs232 µs / 371 µs / 497 µs / 253 µs- / - / - / -- / - / - / -
1 MB transfer, AES-128-GCM168 µs / 289 µs / 441 µs / 309 µs233 µs / 458 µs / 443 µs / 313 µs170 µs / 282 µs / 449 µs / 373 µs290 µs / 424 µs / 579 µs / 334 µs251 µs / 470 µs / 491 µs / 340 µs- / - / - / -- / - / - / -
1 MB transfer, AES-256-GCM185 µs / 293 µs / 545 µs / 349 µs265 µs / 461 µs / 558 µs / 347 µs189 µs / 290 µs / 567 µs / 387 µs338 µs / 490 µs / 691 µs / 401 µs286 µs / 533 µs / 597 µs / 372 µs- / - / - / -- / - / - / -
1 MB transfer, ChaCha20-Poly1305597 µs / 689 µs / 924 µs / 1.11 ms595 µs / 688 µs / 928 µs / 1.10 ms590 µs / 693 µs / 925 µs / 1.10 ms1.16 ms / 1.37 ms / 1.64 ms / 1.73 ms658 µs / 783 µs / 984 µs / 1.11 ms- / - / - / -- / - / - / -
AES-128-GCM seal, 32 B19.7 ns / 38.7 ns / 43.2 ns / 10.8 ns37.5 ns / 78.2 ns / 88.8 ns / 49.7 ns41.1 ns / 56.3 ns / 70.7 ns / 41.8 ns42.1 ns / 69.6 ns / 71.4 ns / 79.0 ns56.8 ns / 115 ns / 156 ns / 66.8 ns73.1 ns / 97.0 ns / 100 ns / 23.9 ns171 ns / 321 ns / 282 ns / 51.9 ns
AES-128-GCM seal, 1350 B92.7 ns / 165 ns / 246 ns / 161 ns159 ns / 291 ns / 285 ns / 181 ns119 ns / 191 ns / 277 ns / 210 ns226 ns / 295 ns / 400 ns / 216 ns160 ns / 326 ns / 352 ns / 196 ns278 ns / 434 ns / 547 ns / 212 ns1.98 µs / 4.72 µs / 3.49 µs / 600 ns
AES-128-GCM seal, 16 KB799 ns / 1.38 µs / 2.33 µs / 1.43 µs1.32 µs / 2.63 µs / 2.42 µs / 1.44 µs818 ns / 1.39 µs / 2.38 µs / 1.94 µs2.05 µs / 2.57 µs / 3.75 µs / 1.60 µs1.35 µs / 2.61 µs / 2.45 µs / 1.51 µs2.49 µs / 4.28 µs / 5.62 µs / 2.26 µs22.0 µs / 53.9 µs / 39.9 µs / 6.78 µs
AES-128-GCM open, 32 B15.1 ns / 44.4 ns / 37.6 ns / 12.6 ns37.8 ns / 72.4 ns / 90.4 ns / 47.0 ns41.1 ns / 57.9 ns / 97.7 ns / 39.2 ns36.3 ns / 64.6 ns / 68.7 ns / 83.9 ns59.0 ns / 118 ns / 159 ns / 65.6 ns78.0 ns / 102 ns / 104 ns / 27.6 ns162 ns / 317 ns / 303 ns / 61.4 ns
AES-128-GCM open, 1350 B89.5 ns / 174 ns / 236 ns / 178 ns151 ns / 298 ns / 285 ns / 191 ns114 ns / 185 ns / 296 ns / 243 ns175 ns / 305 ns / 358 ns / 225 ns162 ns / 333 ns / 355 ns / 199 ns283 ns / 451 ns / 564 ns / 232 ns1.99 µs / 3.92 µs / 3.48 µs / 618 ns
AES-128-GCM open, 16 KB793 ns / 1.44 µs / 2.52 µs / 1.56 µs1.26 µs / 2.72 µs / 2.60 µs / 1.58 µs814 ns / 1.45 µs / 2.62 µs / 2.16 µs1.40 µs / 2.65 µs / 3.39 µs / 1.71 µs1.29 µs / 2.77 µs / 2.85 µs / 1.65 µs2.51 µs / 4.29 µs / 5.75 µs / 2.43 µs21.9 µs / 44.3 µs / 41.7 µs / 6.82 µs
AES-256-GCM seal, 32 B21.4 ns / 41.1 ns / 48.6 ns / 11.9 ns39.2 ns / 81.7 ns / 95.4 ns / 53.4 ns43.2 ns / 56.9 ns / 74.8 ns / 44.8 ns44.5 ns / 74.4 ns / 77.6 ns / 79.0 ns61.2 ns / 118 ns / 161 ns / 67.1 ns78.2 ns / 101 ns / 107 ns / 24.9 ns217 ns / 426 ns / 344 ns / 51.8 ns
AES-256-GCM seal, 1350 B107 ns / 184 ns / 325 ns / 188 ns175 ns / 311 ns / 363 ns / 201 ns134 ns / 205 ns / 353 ns / 219 ns257 ns / 337 ns / 476 ns / 258 ns184 ns / 345 ns / 437 ns / 220 ns313 ns / 489 ns / 623 ns / 239 ns2.87 µs / 6.91 µs / 4.50 µs / 630 ns
AES-256-GCM seal, 16 KB954 ns / 1.51 µs / 3.22 µs / 1.69 µs1.58 µs / 2.78 µs / 3.30 µs / 1.70 µs975 ns / 1.53 µs / 3.25 µs / 2.03 µs2.46 µs / 2.98 µs / 4.71 µs / 2.13 µs1.60 µs / 2.82 µs / 3.34 µs / 1.77 µs2.90 µs / 4.78 µs / 6.45 µs / 2.63 µs32.9 µs / 80.6 µs / 50.9 µs / 7.08 µs
AES-256-GCM open, 32 B16.4 ns / 48.4 ns / 44.7 ns / 13.1 ns37.8 ns / 78.6 ns / 101 ns / 48.6 ns43.0 ns / 60.8 ns / 107 ns / 39.4 ns37.7 ns / 67.5 ns / 73.1 ns / 84.3 ns61.1 ns / 122 ns / 172 ns / 67.6 ns82.3 ns / 109 ns / 118 ns / 40.8 ns215 ns / 441 ns / 363 ns / 65.7 ns
AES-256-GCM open, 1350 B98.9 ns / 192 ns / 328 ns / 197 ns172 ns / 322 ns / 422 ns / 213 ns121 ns / 204 ns / 388 ns / 247 ns201 ns / 341 ns / 510 ns / 263 ns189 ns / 354 ns / 643 ns / 224 ns318 ns / 508 ns / 677 ns / 278 ns2.85 µs / 6.79 µs / 4.74 µs / 663 ns
AES-256-GCM open, 16 KB899 ns / 1.60 µs / 3.62 µs / 1.81 µs1.55 µs / 2.92 µs / 3.69 µs / 1.82 µs933 ns / 1.62 µs / 3.70 µs / 2.23 µs1.71 µs / 3.04 µs / 4.54 µs / 2.19 µs1.58 µs / 2.98 µs / 3.87 µs / 1.93 µs2.92 µs / 4.93 µs / 7.23 µs / 2.77 µs32.6 µs / 79.2 µs / 54.0 µs / 7.06 µs
ChaCha20-Poly1305 seal, 32 B98.5 ns / 114 ns / 129 ns / 145 ns103 ns / 119 ns / 149 ns / 157 ns98.9 ns / 113 ns / 130 ns / 145 ns177 ns / 216 ns / 232 ns / 193 ns175 ns / 257 ns / 337 ns / 216 ns1.05 µs / 1.18 µs / 1.21 µs / 340 ns157 ns / 220 ns / 301 ns / 170 ns
ChaCha20-Poly1305 seal, 1350 B440 ns / 533 ns / 718 ns / 741 ns446 ns / 532 ns / 755 ns / 759 ns448 ns / 527 ns / 714 ns / 741 ns890 ns / 1.08 µs / 1.29 µs / 1.21 µs587 ns / 745 ns / 971 ns / 826 ns1.64 µs / 1.93 µs / 2.18 µs / 1.75 µs1.77 µs / 2.34 µs / 3.16 µs / 1.94 µs
ChaCha20-Poly1305 seal, 16 KB4.19 µs / 4.68 µs / 6.81 µs / 7.50 µs4.13 µs / 4.78 µs / 6.63 µs / 7.50 µs4.12 µs / 4.68 µs / 6.60 µs / 7.57 µs8.29 µs / 10.1 µs / 12.5 µs / 12.6 µs4.35 µs / 5.14 µs / 6.64 µs / 7.37 µs8.03 µs / 10.1 µs / 12.6 µs / 15.0 µs19.3 µs / 26.7 µs / 35.5 µs / 22.1 µs
XChaCha20-Poly1305 seal, 32 B186 ns / 243 ns / 256 ns / 897 ns199 ns / 267 ns / 278 ns / 871 ns- / - / - / -255 ns / 357 ns / 335 ns / 905 ns- / - / - / -1.15 µs / 1.36 µs / 1.27 µs / 1.06 µs244 ns / 351 ns / 400 ns / 900 ns
XChaCha20-Poly1305 seal, 1350 B529 ns / 775 ns / 804 ns / 1.47 µs539 ns / 723 ns / 831 ns / 1.45 µs- / - / - / -974 ns / 1.31 µs / 1.32 µs / 1.94 µs- / - / - / -1.73 µs / 2.18 µs / 2.20 µs / 2.44 µs1.83 µs / 2.70 µs / 3.16 µs / 2.71 µs
XChaCha20-Poly1305 seal, 16 KB4.17 µs / 5.23 µs / 6.38 µs / 8.23 µs4.23 µs / 5.37 µs / 6.44 µs / 8.31 µs- / - / - / -8.40 µs / 10.8 µs / 11.9 µs / 13.2 µs- / - / - / -8.15 µs / 11.4 µs / 12.0 µs / 15.6 µs19.6 µs / 28.7 µs / 33.4 µs / 22.4 µs
AES-128 header protection1.71 ns / 3.99 ns / 4.73 ns / 2.81 ns3.25 ns / 5.79 ns / 9.22 ns / 2.82 ns3.46 ns / 6.94 ns / 8.19 ns / 3.17 ns- / - / - / -- / - / - / -- / - / - / -- / - / - / -
AES-256 header protection2.08 ns / 5.85 ns / 8.09 ns / 2.91 ns5.32 ns / 7.71 ns / 10.2 ns / 3.00 ns5.13 ns / 9.58 ns / 10.0 ns / 3.89 ns- / - / - / -- / - / - / -- / - / - / -- / - / - / -
ChaCha20 header protection53.1 ns / 60.9 ns / 84.1 ns / 57.8 ns68.5 ns / 81.6 ns / 104 ns / 72.5 ns60.4 ns / 74.1 ns / 98.1 ns / 67.4 ns- / - / - / -- / - / - / -- / - / - / -- / - / - / -
X2551918.2 µs / 24.0 µs / 25.0 µs / 16.5 µs19.2 µs / 24.6 µs / 30.9 µs / 18.1 µs35.6 µs / 46.7 µs / 53.6 µs / 24.9 µs18.1 µs / 23.9 µs / 25.0 µs / 16.6 µs34.0 µs / 49.7 µs / 55.2 µs / 36.2 µs36.1 µs / 52.1 µs / 56.6 µs / 29.7 µs42.7 µs / 64.6 µs / 72.3 µs / 37.3 µs
P-256 ECDH29.5 µs / 42.8 µs / 42.8 µs / 26.4 µs31.8 µs / 42.6 µs / 51.7 µs / 28.8 µs33.6 µs / 46.0 µs / 47.1 µs / 32.2 µs33.7 µs / 47.9 µs / 46.4 µs / 31.2 µs52.9 µs / 71.3 µs / 81.7 µs / 50.4 µs121 µs / 269 µs / 234 µs / 178 µs172 µs / 269 µs / 281 µs / 183 µs
Ed25519 sign4.11 µs / 5.72 µs / 7.13 µs / 3.93 µs4.49 µs / 6.13 µs / 7.81 µs / 4.07 µs13.1 µs / 17.2 µs / 22.3 µs / 7.03 µs4.40 µs / 5.83 µs / 7.22 µs / 4.21 µs13.7 µs / 23.4 µs / 31.0 µs / 16.6 µs9.60 µs / 13.3 µs / 17.4 µs / 8.65 µs28.5 µs / 41.4 µs / 53.7 µs / 22.0 µs
Ed25519 verify21.4 µs / 27.1 µs / 31.8 µs / 18.8 µs21.4 µs / 27.0 µs / 31.6 µs / 18.5 µs25.9 µs / 34.8 µs / 42.5 µs / 20.2 µs21.5 µs / 27.1 µs / 32.2 µs / 18.9 µs44.8 µs / 79.3 µs / 93.1 µs / 41.3 µs21.9 µs / 24.8 µs / 29.9 µs / 18.6 µs41.8 µs / 54.5 µs / 69.1 µs / 29.4 µs
P-256 ECDSA sign6.74 µs / 9.62 µs / 13.1 µs / 7.13 µs12.2 µs / 12.7 µs / 19.8 µs / 11.2 µs12.2 µs / 13.7 µs / 14.9 µs / 10.9 µs8.97 µs / 11.5 µs / 19.9 µs / 8.58 µs14.5 µs / 18.0 µs / 20.4 µs / 12.4 µs31.3 µs / 70.6 µs / 69.1 µs / 44.0 µs61.8 µs / 95.5 µs / 102 µs / 66.9 µs
P-256 ECDSA verify30.6 µs / 39.2 µs / 41.6 µs / 26.3 µs29.8 µs / 40.2 µs / 43.3 µs / 27.4 µs33.2 µs / 41.2 µs / 43.9 µs / 29.2 µs32.4 µs / 41.9 µs / 44.3 µs / 28.2 µs46.5 µs / 60.3 µs / 68.3 µs / 41.9 µs103 µs / 226 µs / 197 µs / 152 µs147 µs / 216 µs / 237 µs / 156 µs
SHA-256, 64 B28.2 ns / 68.7 ns / 244 ns / 36.6 ns57.0 ns / 95.8 ns / 307 ns / 70.3 ns56.3 ns / 78.5 ns / 277 ns / 44.0 ns40.1 ns / 67.3 ns / 576 ns / 35.3 ns158 ns / 244 ns / 505 ns / 159 ns39.1 ns / 58.7 ns / 473 ns / 36.2 ns218 ns / 385 ns / 485 ns / 225 ns
SHA-256, 1350 B269 ns / 620 ns / 2.46 µs / 409 ns306 ns / 740 ns / 2.79 µs / 434 ns304 ns / 637 ns / 2.82 µs / 410 ns292 ns / 637 ns / 6.07 µs / 480 ns406 ns / 815 ns / 2.68 µs / 533 ns296 ns / 618 ns / 5.11 µs / 473 ns2.29 µs / 3.71 µs / 5.23 µs / 2.46 µs
SHA-256, 16 KB3.19 µs / 6.86 µs / 28.1 µs / 5.01 µs3.23 µs / 6.88 µs / 31.5 µs / 4.86 µs3.22 µs / 6.97 µs / 32.4 µs / 4.84 µs3.22 µs / 7.08 µs / 69.8 µs / 5.79 µs3.36 µs / 7.37 µs / 28.8 µs / 4.98 µs3.22 µs / 7.22 µs / 58.2 µs / 5.66 µs26.9 µs / 43.1 µs / 61.7 µs / 29.0 µs
SHA-512, 64 B60.1 ns / 138 ns / 198 ns / 75.1 ns134 ns / 224 ns / 228 ns / 105 ns140 ns / 198 ns / 203 ns / 84.3 ns148 ns / 206 ns / 236 ns / 175 ns226 ns / 355 ns / 430 ns / 205 ns120 ns / 192 ns / 270 ns / 76.9 ns166 ns / 246 ns / 289 ns / 142 ns
SHA-512, 1350 B249 ns / 1.77 µs / 1.65 µs / 730 ns1.24 µs / 1.90 µs / 1.97 µs / 768 ns1.26 µs / 1.87 µs / 1.93 µs / 743 ns1.49 µs / 1.98 µs / 2.35 µs / 1.87 µs1.17 µs / 1.76 µs / 1.90 µs / 893 ns1.17 µs / 1.92 µs / 2.67 µs / 723 ns1.72 µs / 2.94 µs / 3.08 µs / 1.56 µs
SHA-512, 16 KB2.63 µs / 16.3 µs / 18.5 µs / 8.72 µs14.1 µs / 25.2 µs / 21.9 µs / 8.91 µs14.1 µs / 25.4 µs / 21.8 µs / 8.70 µs17.5 µs / 21.0 µs / 27.2 µs / 21.7 µs12.3 µs / 15.1 µs / 19.0 µs / 9.33 µs13.5 µs / 24.1 µs / 30.7 µs / 8.59 µs20.1 µs / 29.8 µs / 35.4 µs / 18.4 µs
HMAC-SHA256, 64 B75.1 ns / 147 ns / 628 ns / 110 ns180 ns / 264 ns / 811 ns / 245 ns145 ns / 214 ns / 707 ns / 134 ns110 ns / 172 ns / 1.44 µs / 112 ns1.55 µs / 2.57 µs / 3.69 µs / 2.09 µs103 ns / 155 ns / 1.19 µs / 99.4 ns537 ns / 851 ns / 1.20 µs / 564 ns
HMAC-SHA256, 1350 B328 ns / 692 ns / 2.79 µs / 487 ns435 ns / 853 ns / 3.30 µs / 597 ns397 ns / 791 ns / 3.19 µs / 502 ns358 ns / 731 ns / 7.05 µs / 562 ns1.81 µs / 3.11 µs / 5.94 µs / 2.41 µs356 ns / 728 ns / 5.80 µs / 545 ns2.68 µs / 4.39 µs / 6.02 µs / 2.80 µs
HKDF-SHA256 extract and expand158 ns / 257 ns / 1.15 µs / 226 ns285 ns / 369 ns / 1.44 µs / 330 ns303 ns / 399 ns / 1.31 µs / 273 ns- / - / - / -1.72 µs / 2.72 µs / 4.33 µs / 2.16 µs223 ns / 309 ns / 1.98 µs / 212 ns965 ns / 1.37 µs / 2.04 µs / 936 ns
HKDF-SHA256 expand66.1 ns / 88.6 ns / 300 ns / 74.1 ns124 ns / 179 ns / 636 ns / 154 ns120 ns / 142 ns / 337 ns / 92.6 ns- / - / - / -1.23 µs / 2.00 µs / 2.87 µs / 1.55 µs83.8 ns / 103 ns / 512 ns / 68.8 ns480 ns / 714 ns / 1.01 µs / 481 ns
RSA-2048 PKCS#1 sign341 µs / 523 µs / 447 µs / 275 µs344 µs / 532 µs / 449 µs / 284 µs336 µs / 523 µs / 434 µs / 323 µs344 µs / 474 µs / 446 µs / 551 µs393 µs / 520 µs / 454 µs / 340 µs580 µs / 1.26 ms / 1.14 ms / 588 µs- / - / - / -
RSA-2048 PKCS#1 verify8.92 µs / 12.3 µs / 12.9 µs / 8.41 µs11.0 µs / 14.6 µs / 15.9 µs / 9.54 µs12.8 µs / 16.6 µs / 16.5 µs / 11.0 µs14.0 µs / 19.2 µs / 19.1 µs / 18.4 µs15.5 µs / 23.6 µs / 24.5 µs / 16.8 µs29.0 µs / 54.1 µs / 57.8 µs / 31.0 µs- / - / - / -
RSA-2048 PSS sign341 µs / 424 µs / 446 µs / 276 µs347 µs / 481 µs / 462 µs / 285 µs342 µs / 472 µs / 437 µs / 323 µs345 µs / 449 µs / 450 µs / 551 µs390 µs / 475 µs / 457 µs / 342 µs581 µs / 1.06 ms / 1.15 ms / 590 µs3.69 ms / 5.86 ms / 7.22 ms / 4.47 ms
RSA-2048 PSS verify9.15 µs / 12.7 µs / 14.4 µs / 8.74 µs11.2 µs / 15.9 µs / 17.0 µs / 9.89 µs13.2 µs / 18.0 µs / 18.2 µs / 11.4 µs14.3 µs / 19.6 µs / 21.8 µs / 18.8 µs16.2 µs / 23.6 µs / 27.2 µs / 17.5 µs35.3 µs / 64.7 µs / 70.0 µs / 38.9 µs252 µs / 312 µs / 378 µs / 298 µs
ML-KEM-768 key generation6.35 µs / 8.43 µs / 10.2 µs / 6.11 µs8.13 µs / 9.41 µs / 18.4 µs / 7.31 µs- / - / - / -7.37 µs / 9.28 µs / 10.4 µs / 6.11 µs19.8 µs / 26.8 µs / 40.6 µs / 24.9 µs39.6 µs / 60.2 µs / 60.0 µs / 26.3 µs15.0 µs / 18.1 µs / 20.1 µs / 11.8 µs
ML-KEM-768 encapsulate6.50 µs / 8.53 µs / 10.6 µs / 6.77 µs8.48 µs / 10.4 µs / 18.7 µs / 7.91 µs- / - / - / -9.00 µs / 11.0 µs / 11.1 µs / 6.32 µs18.8 µs / 30.0 µs / 41.2 µs / 23.9 µs41.4 µs / 72.0 µs / 67.0 µs / 27.9 µs12.8 µs / 16.0 µs / 18.1 µs / 9.25 µs
ML-KEM-768 decapsulate4.64 µs / 6.07 µs / 7.07 µs / 4.12 µs8.90 µs / 12.0 µs / 16.0 µs / 7.67 µs- / - / - / -6.54 µs / 7.72 µs / 7.42 µs / 4.02 µs15.8 µs / 24.6 µs / 31.7 µs / 24.7 µs54.9 µs / 95.2 µs / 84.4 µs / 33.9 µs13.4 µs / 16.2 µs / 19.0 µs / 9.48 µs
P-384 ECDH100 µs / 180 µs / 151 µs / 90.1 µs109 µs / 180 µs / 175 µs / 105 µs370 µs / 601 µs / 646 µs / 414 µs174 µs / 303 µs / 245 µs / 151 µs265 µs / 657 µs / 484 µs / 281 µs402 µs / 1.04 ms / 770 µs / 488 µs- / - / - / -
P-384 ECDSA sign23.5 µs / 53.1 µs / 39.6 µs / 22.3 µs46.5 µs / 97.5 µs / 82.7 µs / 49.2 µs197 µs / 475 µs / 343 µs / 222 µs90.3 µs / 185 µs / 129 µs / 80.2 µs89.0 µs / 236 µs / 165 µs / 103 µs85.5 µs / 238 µs / 171 µs / 112 µs- / - / - / -
P-384 ECDSA verify100 µs / 157 µs / 141 µs / 84.0 µs116 µs / 199 µs / 176 µs / 111 µs357 µs / 727 µs / 623 µs / 397 µs166 µs / 316 µs / 239 µs / 149 µs216 µs / 552 µs / 400 µs / 238 µs360 µs / 872 µs / 695 µs / 422 µs- / - / - / -
P-521 ECDH160 µs / 284 µs / 234 µs / 130 µs172 µs / 288 µs / 262 µs / 142 µs- / - / - / -- / - / - / -277 µs / 506 µs / 497 µs / 247 µs428 µs / 868 µs / 841 µs / 396 µs- / - / - / -
P-521 ECDSA sign40.1 µs / 58.3 µs / 64.3 µs / 36.3 µs88.3 µs / 152 µs / 159 µs / 84.1 µs- / - / - / -- / - / - / -128 µs / 220 µs / 221 µs / 132 µs94.1 µs / 177 µs / 186 µs / 80.1 µs- / - / - / -
P-521 ECDSA verify145 µs / 222 µs / 214 µs / 121 µs187 µs / 327 µs / 303 µs / 167 µs- / - / - / -- / - / - / -261 µs / 474 µs / 460 µs / 254 µs353 µs / 610 µs / 636 µs / 252 µs- / - / - / -

Criterion's estimates from rind's benchmark report at 00610aff, run 2026-11-06 and 2026-11-07, 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. It’s terrifying.

Moments like this fill me with dread as a professional software engineer. A decade ago, I wasted weeks speeding up Go’s crypto. I could have just waited a decade for Opus 5.5 instead. idiot

Lean into Lean

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 00610aff, 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-06 and 2026-11-07.

donate some tokens and make every box green

Green boxes are formally verified, dashed are mostly formally verified.

libcrux is cool because they try to formally verify everything, but if you saw the last grid, it’s super slow. rind will only use a formal proof if the performance was within 10%, which has surprisingly decent coverage.

aes-gcm being verified on some architectures is awesome, because it’s the goat of crypto.

I’m sure we could get every algorithm formally proven. If only there was somebody in the audience works for a frontier lab and wants some easy marketting piece instead of stealing all of the glory from 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 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.

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 secret model nobody else has access to, 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 Opus 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, I 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 with a credit card.

I know we still need humans to tell the AI to do dumb shit. Like to rewrite libraries in Rust.

But like, for how much longer?