Skip to content

perf(signatures): use Web Crypto API for hashing instead of @noble/hashes#51

Merged
Mythie merged 1 commit intomainfrom
perf/web-crypto-hashing
Mar 11, 2026
Merged

perf(signatures): use Web Crypto API for hashing instead of @noble/hashes#51
Mythie merged 1 commit intomainfrom
perf/web-crypto-hashing

Conversation

@Mythie
Copy link
Contributor

@Mythie Mythie commented Mar 11, 2026

The hashData functions used during PDF signing hash the entire document
bytes through pure-JS @noble/hashes, which is ~10x slower than native
crypto for large inputs. Switch to crypto.subtle.digest() which
delegates to the platform's native implementation (OpenSSL/BoringSSL).

Benchmarked on a 23MB PDF: 80ms -> 8ms (9.8x faster).

…shes

The hashData functions used during PDF signing hash the entire document
bytes through pure-JS @noble/hashes, which is ~10x slower than native
crypto for large inputs. Switch to crypto.subtle.digest() which
delegates to the platform's native implementation (OpenSSL/BoringSSL).

Benchmarked on a 23MB PDF: 80ms -> 8ms (9.8x faster).
@vercel
Copy link
Contributor

vercel bot commented Mar 11, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
core Ready Ready Preview, Comment Mar 11, 2026 5:21am

@github-actions
Copy link
Contributor

Benchmark Results

Comparison

Load PDF

Benchmark Mean p99 RME Samples
libpdf 2.21ms 3.50ms ±1.3% 226
pdf-lib 39.15ms 44.06ms ±3.9% 13
@cantoo/pdf-lib 38.63ms 43.22ms ±3.1% 14

Create blank PDF

Benchmark Mean p99 RME Samples
libpdf 55μs 120μs ±1.2% 9026
pdf-lib 395μs 1.35ms ±2.3% 1267
@cantoo/pdf-lib 429μs 1.61ms ±2.4% 1165

Add 10 pages

Benchmark Mean p99 RME Samples
libpdf 99μs 193μs ±1.0% 5047
pdf-lib 498μs 1.71ms ±2.5% 1005
@cantoo/pdf-lib 478μs 2.11ms ±3.1% 1046

Draw 50 rectangles

Benchmark Mean p99 RME Samples
libpdf 312μs 783μs ±1.4% 1604
pdf-lib 1.70ms 6.54ms ±6.8% 294
@cantoo/pdf-lib 1.93ms 5.23ms ±5.5% 259

Load and save PDF

Benchmark Mean p99 RME Samples
libpdf 2.44ms 4.63ms ±3.0% 205
pdf-lib 89.41ms 110.92ms ±7.7% 10
@cantoo/pdf-lib 158.00ms 166.20ms ±2.4% 10

Load, modify, and save PDF

Benchmark Mean p99 RME Samples
libpdf 42.36ms 55.52ms ±8.0% 12
pdf-lib 91.71ms 117.15ms ±8.8% 10
@cantoo/pdf-lib 160.51ms 174.74ms ±3.4% 10

Extract single page from 100-page PDF

Benchmark Mean p99 RME Samples
libpdf 3.73ms 6.31ms ±1.9% 135
pdf-lib 9.22ms 14.34ms ±3.0% 55
@cantoo/pdf-lib 9.57ms 11.79ms ±2.1% 53

Split 100-page PDF into single-page PDFs

Benchmark Mean p99 RME Samples
libpdf 33.82ms 44.78ms ±5.4% 15
pdf-lib 87.96ms 90.44ms ±2.3% 6
@cantoo/pdf-lib 96.35ms 120.69ms ±13.2% 6

Split 2000-page PDF into single-page PDFs (0.9MB)

Benchmark Mean p99 RME Samples
libpdf 605.44ms 605.44ms ±0.0% 1
pdf-lib 1.60s 1.60s ±0.0% 1
@cantoo/pdf-lib 1.67s 1.67s ±0.0% 1

Copy 10 pages between documents

Benchmark Mean p99 RME Samples
libpdf 4.62ms 6.37ms ±2.1% 109
pdf-lib 11.91ms 13.83ms ±1.6% 43
@cantoo/pdf-lib 13.40ms 14.67ms ±1.5% 38

Merge 2 x 100-page PDFs

Benchmark Mean p99 RME Samples
libpdf 14.83ms 39.03ms ±10.1% 34
pdf-lib 53.00ms 56.92ms ±2.4% 10
@cantoo/pdf-lib 61.99ms 69.39ms ±3.6% 9

Fill FINTRAC form fields

Benchmark Mean p99 RME Samples
libpdf 20.58ms 24.30ms ±2.9% 25
pdf-lib 33.10ms 39.89ms ±3.9% 16
@cantoo/pdf-lib 35.36ms 48.11ms ±8.7% 15

Fill and flatten FINTRAC form

Benchmark Mean p99 RME Samples
libpdf 18.48ms 21.49ms ±2.8% 28
pdf-lib FAILED - - 0
@cantoo/pdf-lib 37.87ms 45.20ms ±3.9% 14
Copying

Copy pages between documents

Benchmark Mean p99 RME Samples
copy 1 page 1.00ms 2.44ms ±2.9% 500
copy 10 pages from 100-page PDF 4.42ms 6.92ms ±2.0% 114
copy all 100 pages 7.20ms 7.84ms ±0.9% 70

Duplicate pages within same document

Benchmark Mean p99 RME Samples
duplicate page 0 866μs 1.51ms ±1.0% 578
duplicate all pages (double the document) 851μs 1.22ms ±0.8% 588

Merge PDFs

Benchmark Mean p99 RME Samples
merge 2 small PDFs 1.40ms 1.78ms ±0.6% 358
merge 10 small PDFs 7.24ms 7.85ms ±0.8% 70
merge 2 x 100-page PDFs 13.05ms 13.47ms ±0.7% 39
Drawing

benchmarks/drawing.bench.ts

Benchmark Mean p99 RME Samples
draw 100 rectangles 559μs 1.44ms ±2.8% 895
draw 100 circles 1.27ms 2.92ms ±2.8% 395
draw 100 lines 488μs 1.17ms ±1.5% 1026
draw 100 text lines (standard font) 1.55ms 2.42ms ±1.5% 323
create 10 pages with mixed content 1.30ms 2.13ms ±1.4% 386
Forms

benchmarks/forms.bench.ts

Benchmark Mean p99 RME Samples
get form fields 3.25ms 7.74ms ±3.9% 154
fill text fields 11.89ms 16.09ms ±4.8% 43
read field values 2.91ms 4.47ms ±1.5% 172
flatten form 8.14ms 11.40ms ±2.8% 62
Loading

benchmarks/loading.bench.ts

Benchmark Mean p99 RME Samples
load small PDF (888B) 58μs 142μs ±0.7% 8621
load medium PDF (19KB) 91μs 175μs ±0.5% 5467
load form PDF (116KB) 1.35ms 2.38ms ±1.6% 372
load heavy PDF (9.9MB) 2.23ms 2.63ms ±0.6% 225
Saving

benchmarks/saving.bench.ts

Benchmark Mean p99 RME Samples
save unmodified (19KB) 107μs 264μs ±0.9% 4673
save with modifications (19KB) 752μs 1.39ms ±1.5% 666
incremental save (19KB) 177μs 391μs ±1.2% 2822
save heavy PDF (9.9MB) 2.13ms 2.54ms ±0.6% 236
incremental save heavy PDF (9.9MB) 5.29ms 13.70ms ±8.8% 95
Splitting

Extract single page

Benchmark Mean p99 RME Samples
extractPages (1 page from small PDF) 971μs 2.14ms ±2.6% 515
extractPages (1 page from 100-page PDF) 3.44ms 3.87ms ±0.6% 146
extractPages (1 page from 2000-page PDF) 54.28ms 55.19ms ±0.6% 10

Split into single-page PDFs

Benchmark Mean p99 RME Samples
split 100-page PDF (0.1MB) 30.72ms 37.55ms ±4.1% 17
split 2000-page PDF (0.9MB) 575.60ms 575.60ms ±0.0% 1

Batch page extraction

Benchmark Mean p99 RME Samples
extract first 10 pages from 2000-page PDF 55.94ms 57.44ms ±0.9% 9
extract first 100 pages from 2000-page PDF 59.27ms 61.02ms ±1.3% 9
extract every 10th page from 2000-page PDF (200 pages) 63.40ms 66.57ms ±1.9% 8
Environment
  • Runner: Linux (X64)
  • Runtime: Bun 1.3.10

Results are machine-dependent.

@Mythie Mythie merged commit 12a766a into main Mar 11, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant