Cost of the second signature verifier: 2026-10-21 and 2026-10-22, ARM build machine

Cost of checking every signature with two independent verifiers, liboqs and qanum-pqverify, on an aarch64 machine: three stages of qanum-pqverify, with raw data.

This page reproduces docs/benchmarks/2026-10-21_arm_second-verifier/README.md from qanum-core v0.9.2 (release tag). Links to files that are not published on this site are shown as plain text until the source repository is public.

Contents

Produced by examples/pq_dual_bench. It measures what the node pays for checking every post-quantum signature with two independent verifiers: liboqs and qanum-pqverify. The same benchmark was run on three successive states of qanum-pqverify, so this page compares them:

Stage Folder qanum-pqverify code
1 1-initial/ First version: SHAKE through the hashing API of the sha3 crate; ML-DSA arithmetic reduced with % after every operation.
2 2-sponge/ The SHAKE sponge (FIPS 202) written in the crate over the Keccak permutation of the keccak crate.
3 3-montgomery/ Stage 2, plus ML-DSA arithmetic with Montgomery multiplication in the NTT (FIPS 204 Appendix A), conditional reductions and one reduction per coefficient for sums of products.

The verification results are the same in all three stages; only the speed changes. The .jsonl files are the raw output (the commit fields of meta are left out); this page is a summary of those files.

Machine and method

  Gold core Silver core
Files gold-core6.jsonl silver-core2.jsonl
Core (taskset -c) 6 (CPU part 0xd0d) 2 (CPU part 0x805)
Max frequency during the runs 1.08 GHz (capped by the system) 1.80 GHz
Run time, stages 1 / 2 / 3 76 s / 67 s / 67 s 137 s / 123 s / 114 s

The second verifier alone

Median time per valid signature. The percentage is against liboqs in the same run.

Suite Core liboqs Stage 1 Stage 2 Stage 3
ML-DSA-44 Gold 121 µs 278 µs (230 %) 267 µs (221 %) 265 µs (219 %)
  Silver 188 to 192 µs 597 µs (316 %) 574 µs (305 %) 424 µs (222 %)
ML-DSA-87 Gold 342 µs 708 µs (208 %) 667 µs (196 %) 643 µs (189 %)
  Silver 541 to 565 µs 1.48 ms (275 %) 1.41 ms (261 %) 1.06 ms (187 %)
SLH-DSA-128s Gold 1.81 to 1.86 ms 3.45 ms (191 %) 1.78 ms (98 %) 1.83 ms (99 %)
  Silver 3.02 to 3.13 ms 5.54 ms (183 %) 3.02 ms (97 %) 2.89 ms (96 %)
SLH-DSA-256s Gold 3.75 to 3.83 ms 7.14 ms (191 %) 3.91 ms (102 %) 3.89 ms (104 %)
  Silver 6.35 to 6.72 ms 11.65 ms (179 %) 6.26 ms (99 %) 6.64 ms (99 %)

Both verifiers (valid signatures)

Suite Core dual enforce, stage 1 Stage 2 Stage 3
ML-DSA-44 Gold 400 µs (330 %) 388 µs (321 %) 387 µs (319 %)
  Silver 799 µs (423 %) 770 µs (410 %) 628 µs (328 %)
ML-DSA-87 Gold 1.06 ms (310 %) 1.01 ms (296 %) 989 µs (290 %)
  Silver 2.09 ms (388 %) 2.01 ms (372 %) 1.66 ms (295 %)
SLH-DSA-128s Gold 5.23 ms (289 %) 3.55 ms (196 %) 3.68 ms (198 %)
  Silver 8.61 ms (284 %) 6.14 ms (197 %) 5.92 ms (197 %)
SLH-DSA-256s Gold 10.86 ms (290 %) 7.81 ms (204 %) 7.64 ms (204 %)
  Silver 18.18 ms (280 %) 12.63 ms (200 %) 13.37 ms (200 %)

A valid signature costs the sum of both verifiers. dual shadow gives the same times within 1 % in every stage (see the .jsonl files).

Invalid signatures (one byte flipped), stage 3

Suite liboqs Gold / Silver dual enforce Gold / Silver dual shadow Gold / Silver
ML-DSA-44 121.4 µs / 192.2 µs 121.4 µs / 194.5 µs 387.2 µs / 628.6 µs
ML-DSA-87 342.3 µs / 567.6 µs 342.4 µs / 560.6 µs 992.0 µs / 1.66 ms
SLH-DSA-128s 1.85 ms / 3.08 ms 1.88 ms / 3.07 ms 3.69 ms / 6.04 ms
SLH-DSA-256s 3.76 ms / 6.65 ms 3.81 ms / 6.64 ms 7.66 ms / 13.14 ms

In enforce mode the second verifier is not called when liboqs rejects, so an invalid signature costs what it cost before, in every stage. Shadow mode runs both.

Verify Units under enforce mode

Estimate = ceil(100 × median / median of ML-DSA-44), both through dual enforce. Gold / Silver.

Suite Stage 1 Stage 2 Stage 3 Consensus VU
ML-DSA-44 100 / 100 100 / 100 100 / 100 100
ML-DSA-87 265 / 263 261 / 261 256 / 265 290
SLH-DSA-128s 1309 / 1078 917 / 797 951 / 943 1600
SLH-DSA-256s 2719 / 2276 2015 / 1640 1977 / 2128 3600

Every constant covers its estimate in every stage. ML-DSA-87 has the least room (265 of 290).

Worst-case block estimate

A block holding as many signatures of one suite as MAX_BLOCK_VERIFY_UNITS (200,000) allows, times the median of one signature, on one core. This is an estimate, not a measured block. Block validation spreads signatures over all cores, so a node with several cores takes less.

Suite (signatures) liboqs Gold / Silver dual, stage 1 dual, stage 3
ML-DSA-44 (2000) 243 ms / 384 ms 799 ms / 1,598 ms 774 ms / 1,257 ms
ML-DSA-87 (689) 236 ms / 390 ms 728 ms / 1,444 ms 682 ms / 1,145 ms
SLH-DSA-128s (125) 233 ms / 378 ms 654 ms / 1,077 ms 460 ms / 741 ms
SLH-DSA-256s (55) 207 ms / 370 ms 598 ms / 1,000 ms 421 ms / 736 ms

liboqs columns from stage 3. On the slowest core the worst block goes from about 0.4 s of signature checks with liboqs alone to about 1.3 s with both verifiers (1.6 s in stage 1).