perf/virtual xor split - #558
Open
gabriel-barrett wants to merge 7 commits into
Open
Conversation
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
gabriel-barrett
force-pushed
the
perf/virtual-rotr-chain-output
branch
from
August 13, 2026 17:21
82ef2a8 to
d3b5b55
Compare
gabriel-barrett
force-pushed
the
perf/virtual-rotr-chain-output
branch
from
August 13, 2026 17:23
d2d69d7 to
7b72efc
Compare
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
Plus the trailing integration: the aiur test toplevels migrate off the removed builtins (u8_chain_rotr7/4 wrappers and the u32_rotr7 fixture become u8_xor_split7/4 wrappers and a two-operand u32_xor_rotr7, with freshly computed vectors), the new xor_split gadget helpers get clippy-clean byte casts, codegen regenerated, and all 71 kernel FFT pins + the shard aggregate re-measured (median -0.4%, shard -1.3%). aiur (cargo + prove + cross agreement), ixvm (pins + parity), multi-stark and recursive-verifier suites pass; fmt, clippy, deny clean.
Member
Author
|
!benchmark aiur-recursive fresh |
|
| constant | recursive-prove-time (main) | recursive-prove-time (PR) | Δ% | recursive-peak-ram (main) | recursive-peak-ram (PR) | Δ% | recursive-proof-size (main) | recursive-proof-size (PR) | Δ% | recursive-verify-time (main) | recursive-verify-time (PR) | Δ% | recursive-execute-time (main) | recursive-execute-time (PR) | Δ% | recursive-fft-cost (main) | recursive-fft-cost (PR) | Δ% | prove-time (main) | prove-time (PR) | Δ% | proof-size (main) | proof-size (PR) | Δ% | verify-time (main) | verify-time (PR) | Δ% | peak-ram (main) | peak-ram (PR) | Δ% |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
String.split |
37.940 s | 36.223 s | -4.5% 🟢 | 107.39 GiB | 102.47 GiB | -4.6% 🟢 | 5.30 MiB | 5.27 MiB | -0.5% | 33.5 ms | 32.6 ms | -2.6% | 5.947 s | 6.196 s | +4.2% |
180.38B | 177.01B | -1.9% | 16.489 s | 16.777 s | +1.7% | 11.21 MiB | 11.19 MiB | -0.2% | 69.4 ms | 74.9 ms | +7.9% (1.08× slower) |
32.75 GiB | 32.27 GiB | -1.5% |
Vector.append |
34.245 s | 34.186 s | -0.2% | 95.54 GiB | 89.95 GiB | -5.8% (1.06× smaller) 🟢 | 5.30 MiB | 5.27 MiB | -0.5% | 32.7 ms | 35.8 ms | +9.6% (1.10× slower) |
5.193 s | 5.231 s | +0.7% | 157.02B | 152.94B | -2.6% | 4.022 s | 4.042 s | +0.5% | 10.42 MiB | 10.39 MiB | -0.3% | 66.7 ms | 64.9 ms | -2.8% | 7.30 GiB | 6.67 GiB | -8.7% (1.09× smaller) 🟢 |
Nat.add_comm |
22.120 s | 21.069 s | -4.8% 🟢 | 58.69 GiB | 56.17 GiB | -4.3% 🟢 | 5.30 MiB | 5.27 MiB | -0.5% | 35.1 ms | 32.1 ms | -8.5% (1.09× faster) 🟢 | 3.809 s | 3.725 s | -2.2% | 113.85B | 107.33B | -5.7% (1.06× fewer) 🟢 | 1.031 s | 1.071 s | +3.9% |
8.93 MiB | 8.90 MiB | -0.3% | 53.5 ms | 55.8 ms | +4.3% |
3.57 GiB | 3.80 GiB | +6.3% (1.06× larger) |
Member
Author
|
!benchmark aiur fresh |
|
| constant | prove-time (main) | prove-time (PR) | Δ% | throughput (const/s) (main) | throughput (const/s) (PR) | Δ% | peak-ram (main) | peak-ram (PR) | Δ% | execute-time (main) | execute-time (PR) | Δ% | verify-time (main) | verify-time (PR) | Δ% | proof-size (main) | proof-size (PR) | Δ% | fft-cost (main) | fft-cost (PR) | Δ% |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Array.extract_append |
38.412 s | 40.725 s | +6.0% (1.06× slower) |
40.140 | 37.860 | -5.7% (1.06× slower) |
73.74 GiB | 73.20 GiB | -0.7% | 9.762 s | 9.839 s | +0.8% | 131.2 ms | 171.2 ms | +30.5% (1.31× slower) |
21.59 MiB | 21.54 MiB | -0.2% | 136.02B | 135.19B | -0.6% |
ByteArray.utf8DecodeChar?_utf8EncodeChar_append |
40.192 s | 36.951 s | -8.1% (1.09× faster) 🟢 | 66.950 | 72.830 | +8.8% (1.09× faster) 🟢 | 73.13 GiB | 72.14 GiB | -1.3% | 9.854 s | 9.761 s | -0.9% | 208.4 ms | 142.0 ms | -31.9% (1.47× faster) 🟢 | 21.69 MiB | 21.63 MiB | -0.2% | 138.80B | 136.87B | -1.4% |
Char.ofOrdinal_le_of_le |
31.295 s | 30.851 s | -1.4% | 84.550 | 85.770 | +1.4% | 58.55 GiB | 58.02 GiB | -0.9% | 6.842 s | 6.596 s | -3.6% 🟢 | 137.9 ms | 147.5 ms | +7.0% (1.07× slower) |
21.64 MiB | 21.58 MiB | -0.2% | 99.42B | 98.00B | -1.4% |
Vector.extract_append._proof_2 |
22.879 s | 21.115 s | -7.7% (1.08× faster) 🟢 | 56.910 | 61.660 | +8.3% (1.08× faster) 🟢 | 39.69 GiB | 39.42 GiB | -0.7% | 5.403 s | 5.145 s | -4.8% 🟢 | 143.7 ms | 136.6 ms | -4.9% (1.05× faster) 🟢 | 21.30 MiB | 21.24 MiB | -0.2% | 77.08B | 76.48B | -0.8% |
_private.Init.Data.Range.Polymorphic.SInt.0.Int64.instRxcHasSize_eq |
18.705 s | 17.135 s | -8.4% (1.09× faster) 🟢 | 96.870 | 105.750 | +9.2% (1.09× faster) 🟢 | 34.76 GiB | 34.28 GiB | -1.4% | 3.736 s | 3.563 s | -4.6% 🟢 | 147.8 ms | 135.4 ms | -8.4% (1.09× faster) 🟢 | 21.47 MiB | 21.42 MiB | -0.2% | 54.85B | 54.00B | -1.5% |
String.split |
17.152 s | 16.099 s | -6.1% (1.07× faster) 🟢 | 102.910 | 109.640 | +6.5% (1.07× faster) 🟢 | 32.73 GiB | 32.23 GiB | -1.5% | 3.316 s | 3.307 s | -0.3% | 135.6 ms | 134.7 ms | -0.7% | 21.68 MiB | 21.62 MiB | -0.2% | 50.25B | 49.51B | -1.5% |
List.mergeSort |
12.693 s | 11.910 s | -6.2% (1.07× faster) 🟢 | 114.080 | 121.580 | +6.6% (1.07× faster) 🟢 | 23.78 GiB | 23.50 GiB | -1.1% | 2.440 s | 2.416 s | -1.0% | 132.8 ms | 131.0 ms | -1.3% | 21.53 MiB | 21.48 MiB | -0.2% | 36.10B | 35.52B | -1.6% |
Vector.append |
4.202 s | 3.936 s | -6.3% (1.07× faster) 🟢 | 115.410 | 123.230 | +6.8% (1.07× faster) 🟢 | 6.88 GiB | 6.46 GiB | -6.2% (1.07× smaller) 🟢 | 695.0 ms | 665.7 ms | -4.2% 🟢 | 135.9 ms | 123.8 ms | -8.9% (1.10× faster) 🟢 | 20.13 MiB | 20.08 MiB | -0.3% | 8.02B | 7.90B | -1.5% |
Nat.gcd_comm |
3.404 s | 3.154 s | -7.4% (1.08× faster) 🟢 | 114.560 | 123.670 | +8.0% (1.08× faster) 🟢 | 5.77 GiB | 4.93 GiB | -14.6% (1.17× smaller) 🟢 | 540.1 ms | 512.6 ms | -5.1% (1.05× faster) 🟢 | 133.1 ms | 118.1 ms | -11.2% (1.13× faster) 🟢 | 19.90 MiB | 19.84 MiB | -0.3% | 5.25B | 5.15B | -1.9% |
String.append |
2.561 s | 2.369 s | -7.5% (1.08× faster) 🟢 | 118.690 | 128.340 | +8.1% (1.08× faster) 🟢 | 4.99 GiB | 5.49 GiB | +10.0% (1.10× larger) |
416.6 ms | 395.5 ms | -5.1% (1.05× faster) 🟢 | 128.8 ms | 114.0 ms | -11.5% (1.13× faster) 🟢 | 19.17 MiB | 19.12 MiB | -0.3% | 2.90B | 2.85B | -1.9% |
Int.gcd |
2.109 s | 1.976 s | -6.3% (1.07× faster) 🟢 | 98.630 | 105.240 | +6.7% (1.07× faster) 🟢 | 5.15 GiB | 4.54 GiB | -11.9% (1.13× smaller) 🟢 | 359.8 ms | 344.6 ms | -4.2% 🟢 | 122.5 ms | 111.9 ms | -8.7% (1.10× faster) 🟢 | 18.73 MiB | 18.67 MiB | -0.3% | 1.87B | 1.83B | -1.8% |
Nat.sub_le_of_le_add |
1.943 s | 1.820 s | -6.3% (1.07× faster) 🟢 | 87.510 | 93.400 | +6.7% (1.07× faster) 🟢 | 4.98 GiB | 4.50 GiB | -9.7% (1.11× smaller) 🟢 | 355.1 ms | 333.4 ms | -6.1% (1.07× faster) 🟢 | 119.2 ms | 120.7 ms | +1.3% | 19.08 MiB | 19.03 MiB | -0.3% | 1.60B | 1.58B | -1.7% |
Nat.add_comm |
1.132 s | 1.034 s | -8.7% (1.10× faster) 🟢 | 37.090 | 40.620 | +9.5% (1.10× faster) 🟢 | 3.76 GiB | 4.12 GiB | +9.6% (1.10× larger) |
265.4 ms | 242.9 ms | -8.5% (1.09× faster) 🟢 | 108.5 ms | 108.5 ms | -0.0% | 17.25 MiB | 17.20 MiB | -0.3% | 271.37M | 268.28M | -1.1% |
gabriel-barrett
force-pushed
the
perf/virtual-rotr-chain-output
branch
from
August 14, 2026 11:31
4e87352 to
67ada28
Compare
gabriel-barrett
force-pushed
the
perf/virtual-rotr-chain-output
branch
from
August 14, 2026 11:32
67ada28 to
ac1cc6d
Compare
Comment on lines
+84
to
+89
| pub fn u8_xor_split7_channel() -> G { | ||
| G::from_u8(15) | ||
| } | ||
|
|
||
| #[inline] | ||
| pub fn u8_chain_rotr4_channel() -> G { | ||
| G::from_u8(14) | ||
| pub fn u8_xor_split4_channel() -> G { | ||
| G::from_u8(16) |
Member
There was a problem hiding this comment.
No need to skip 13 and 14
The add-then-remove sequence had left u8XorSplit7/4 in different slots than u8ChainRotr7/4 occupied, scrambling the diff and the FFI tag order. Now the new ops sit exactly where the old ones were: same Bytecode.Op constructor tags (24/25, with the FFI decoder renumbered to match), same lookup channels (13/14), and the same positions in every enum, match, and gadget table. The u32-add ops stay appended at the end (tags 31-33). Codegen regenerated; all FFT pins unchanged.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fuse Blake3’s bytewise XOR and non-byte-aligned rotations using new
u8_xor_split7andu8_xor_split4operations.The old rotation-chain operations are no longer needed and have been removed completely.
Details
For two bytes
aandb, let:The new operations return the pieces required to rotate
x:Each operation is backed by one existing-style two-byte lookup. Four calls provide the pieces needed to construct a complete rotated
u32using only field additions and static reordering.For example, rotation by seven bits is assembled as:
The additions are safe byte values because the high and shifted-low pieces occupy disjoint bit ranges.
Rotation by twelve bits uses the same construction with four-bit splits and a static byte permutation.
Blake3 changes
The following patterns:
are replaced with:
For each rotated word, this changes the cost from:
4 XOR lookups + 2 rotation-chain lookups = 6 lookups
to:
4 XOR-split lookups
The auxiliary-column cost remains eight columns per word, but execution performs less intermediate work and two lookups are eliminated.
Removed operations
The fused paths make these operations and their word-level wrappers unused:
They have been removed from:
As a result, the Bytes2 table shrinks from:
Multiplicity columns: 12 → 10
Preprocessed columns: 20 → 14
Additional cleanup
The redundant packed equality assertions in
u32_addandu32_add3were removed.Their carries are already virtual expressions:
Constraining those expressions to their valid carry domains, together with range-checking the result bytes, uniquely pins the wrapping sums.
Testing