Repository navigation
primitives: the NEON Keccak absorbs and stores digests through ZIP1/ZIP2 - #653
Merged
Merged
Conversation
…IP2 instead of a scalar staging buffer.
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
The aarch64 batched Keccak (
hash_many, used by the PCS Merkle leaves and nodes and by lean_da) now absorbs input blocks and stores digests with NEON loads,ZIP1/ZIP2and NEON stores. Before, both went through the defaultLanes64forms, which read every word with a scalar load into a staging buffer, reload it as a vector, and do the reverse for the digests. The permutation is unchanged, and so is every digest and proof.Mechanism
absorb_words: for the two inputs of a NEON group, one 16-byte load per input yields two words of each.ZIP1of the two loads is lane2p(word2pof input 0, word2pof input 1),ZIP2is lane2p + 1. An odd last word is combined from two scalar words. The partial word and padding stay inhash_groupas before.store_digests:ZIP1/ZIP2of digest lanes 0,1 and 2,3 give 16 consecutive bytes of each input's digest, written with four 16-byte stores.armmodule, with the same shape as the AVX-512 transposes on gattaca-com/leanVMkeccak-opt(c7d959e), so a later port of that file merges without conflicts here.Numbers
Apple M1 (Mac mini, 4P + 4E, 16 GB). Base (origin/main 1acdff1) and patched binaries were run interleaved, A/B in odd rounds and B/A in even rounds, 10 rounds each, with no cooldown between passes. Prove times are 5 passes per round (n = 50 per side), and trace spans come from the last pass of each round (n = 10). The paired statistic is the per-round difference of medians, with two-sided exact sign and Wilcoxon signed-rank tests.
Per extension encode: 2^20 149 to 144.5 ms, 2^19 64.3 to 60.6 ms, 2^18 26.4 to 24.9 ms, 2^17 11.7 to 10.8 ms (paired medians -3.4% to -7.7%).
Measured on Apple M1 only; M4 not measured. Linux arm64 (the CI
neoverse-n2runner) and x86 are not measured. x86 code is unchanged.Correctness and byte-identity
every_backend_matches_scalarandbatched_matches_one_shot_across_lengthstests check the NEON backend against the scalar hash and permutation. Their lengths have odd and even word counts, partial words, multi-block inputs and the zero-prefix state. No test is added.cargo clippyall,cargo fmt --all --check, andcargo test --release -p primitives -p pcspass.EthereumProof::to_bytes()from base and patched binaries, using a throwaway CLI hook that is not part of this PR.