HMAC finalize and PBKDF2 iterate on ARMv7 call the compression function - #578
Merged
Merged
Conversation
…on (MD5, SHA-1, SHA-224, SHA-384, SHA-512, SHA-512/224, SHA-512/256) Port the compression-level design of x86-64 and AArch64 to 32-bit ARM for every Merkle-Damgard hash function but SHA-256 (which keeps its own code). New `Impl/Pbkdf2/Md/Arm.lean` (`Hash`: the streaming `Hash` plus the hash value size N, the length field L, byte order, compression scratch offset, digest-writing code and compression function): * PBKDF2 `iterate` lays out the message block once in scratch (U || 0x80 || zeros || the length of B + D bytes, as word stores). Each step copies the key's inner hash value into scratch word-wise, compresses the block once, writes the digest back over U (restoring the padding it overwrites when N > D), does the same with the outer hash value, and XORs U into T word-wise. Two compressions per step, no calls of update or finalize, no byte loops. * HMAC `finalize` calls the streaming finalize for the inner hash, then copies the outer hash value word-wise, pads the digest into a fixed block with word stores, compresses it once and writes the digest to out (via scratch and a word copy when D < N). Proofs (`Proof/Pbkdf2/Md/Arm/`), once for every hash function, against the `iterG`/`finG` contracts at 16 bytes of stack, moved to the shared `Spec.Hmac.*I.iterateContract`/`finalizeContract`: correctness against `Proof.MdStream.Md` (`Iterate.lean`, `HmacFin.lean`, with the target-independent `Md.iterate_hmac` and `Md.hmac_outer` in `Proof/Pbkdf2/MdStep.lean`); constant time with RelCT, the code between calls by `taint_decide` and the calls by `compressBlock_rel` and `fin_rel` (`IterateCT.lean`, `HmacFinCT.lean`); and the instances (`Instances.lean`, `Sha224.lean`). The whole `vg_pbkdf2_hmac_<hash>` (#564) now calls the new functions (`Proof/Pbkdf2/Whole/Arm/Instances.lean` and `Sha224.lean`, `fnsOf`). Deleted the streaming-level generic `iterate` and `finalize` on ARMv7 (`Impl/Pbkdf2/Generic/Arm.lean`, `Proof/Pbkdf2/Generic/Arm/`, `Proof/Hmac/Generic/Arm/Finalize.lean`, `finalize` in `Impl/Hmac/Generic/Arm.lean`); HMAC `init` is unchanged. No changes to TCB/ or Spec/. Instructions per PBKDF2 iteration on ARMv7 (counted by emulating the generated code; compressions included): MD5 3472 -> 1378 SHA-1 5494 -> 3296 SHA-224 7256 -> 4812 SHA-384 22554 -> 18006 SHA-512 22762 -> 18010 SHA-512/224 22294 -> 17996 SHA-512/256 22346 -> 17998 HMAC finalize (20-byte message): SHA-1 4679 -> 3542, SHA-512 21023 -> 18486. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RjfTK5YMk2jDsiKRYs2dbn
…al-labmxq-md-arm # Conflicts: # lean/VerifiedGarbage/Artifacts/HmacMd5/Arm.lean # lean/VerifiedGarbage/Artifacts/HmacSha1/Arm.lean # lean/VerifiedGarbage/Artifacts/HmacSha224/Arm.lean # lean/VerifiedGarbage/Artifacts/HmacSha384/Arm.lean # lean/VerifiedGarbage/Artifacts/HmacSha512/Arm.lean # lean/VerifiedGarbage/Artifacts/HmacSha512_224/Arm.lean # lean/VerifiedGarbage/Artifacts/HmacSha512_256/Arm.lean # lean/VerifiedGarbage/Artifacts/Pbkdf2Md5/Arm.lean # lean/VerifiedGarbage/Artifacts/Pbkdf2Sha1/Arm.lean # lean/VerifiedGarbage/Artifacts/Pbkdf2Sha224/Arm.lean # lean/VerifiedGarbage/Artifacts/Pbkdf2Sha384/Arm.lean # lean/VerifiedGarbage/Artifacts/Pbkdf2Sha512/Arm.lean # lean/VerifiedGarbage/Artifacts/Pbkdf2Sha512_224/Arm.lean # lean/VerifiedGarbage/Artifacts/Pbkdf2Sha512_256/Arm.lean # lean/VerifiedGarbage/Proof/Hmac/Generic/Arm/Finalize.lean # lean/VerifiedGarbage/Proof/Hmac/Generic/Arm/Instances.lean # lean/VerifiedGarbage/Proof/Hmac/Generic/X86/Finalize.lean # lean/VerifiedGarbage/Proof/Hmac/Generic/X86/Instances.lean # lean/VerifiedGarbage/Proof/Pbkdf2/Generic/Arm/Instances.lean # lean/VerifiedGarbage/Proof/Pbkdf2/Generic/Arm/Sha224.lean # lean/VerifiedGarbage/Proof/Pbkdf2/Generic/X86/Instances.lean # lean/VerifiedGarbage/Proof/Pbkdf2/Generic/X86/Iterate.lean # lean/VerifiedGarbage/Proof/Pbkdf2/Generic/X86/IterateCT.lean
This was referenced Oct 2, 2026
alex
pushed a commit
that referenced
this pull request
Oct 2, 2026
The conflicts were #578's doc-only edits to x86 files this branch deletes or trims; this branch's side is kept. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RjfTK5YMk2jDsiKRYs2dbn
alex
pushed a commit
that referenced
this pull request
Oct 2, 2026
#578, #579 and #582 are now on main; this branch already carries #578 and #579 and builds on them, so its side is kept in the files both changed. src/hmac/mod.rs takes main's, which adds #582's uninitialized scratch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RjfTK5YMk2jDsiKRYs2dbn
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
On ARMv7, HMAC
finalizeand PBKDF2iteratenow call the compression function directly, for MD5, SHA-1, SHA-224, SHA-384, SHA-512, SHA-512/224 and SHA-512/256. This is the design x86-64 and AArch64 already use (Impl/Pbkdf2/{X86_64,AArch64}.lean,Impl/Pbkdf2/Md/). It is written once over a description of a Merkle–Damgård hash and proven once againstProof.MdStream.Md.Until now these functions were generic over the hash's streaming functions:
updateandfinalize, and did both twice, with byte loops;updateandfinalizetoo.This PR is implementation only. There are no changes to
Spec/orTCB/: the functions are proven against the existingSpec.Hmac.Instance.finalizeContract/iterateContractatstack := 16, as before.What is unchanged:
initstays the generic one; it runs once per key.Design
Impl/Pbkdf2/Md/Arm.leanis new. ItsHashholds the hash's streaming functions plus what the compression-level code needs:N;Land the byte order;It covers both the 64-byte-block hashes (
Impl/MdStream/Arm.lean) and the SHA-512 family, which has its own streaming code.iterate.U ‖ 0x80 ‖ zeros ‖ length of a (B + D)-byte messageonce, with word stores.U, restoring the padding whenD < N;T ⊕= Uword-wise.update/finalizecalls, no byte loops, no stack.HMAC
finalize.finalizefor the inner hash, which has a variable-length message.iterate: the outer hash value is copied word-wise, and the padding and length words are written at fixed offsets.outdirectly whenD = N, otherwise through scratch and a word copy.copyW,padFrom,constW,lenWordsandxorW.Proofs
Proof/Pbkdf2/Md/Arm/holdsWords,Compress,Hash,Iterate,IterateCT,HmacFin,HmacFinCT,Sha512,InstancesandSha224.Md.iterate_hmacandMd.hmac_outer, inProof/Pbkdf2/MdStep.lean.taint_decidecovers the blocks between calls;compressBlock_relandfin_relcover the calls.Proof/Pbkdf2/Whole/Arm/{Instances,Sha224}.lean) now calls the newiterateandfinalize, through their new theorems.Impl/Pbkdf2/Generic/Arm.leanand its proofs;Proof/Hmac/Generic/Arm/Finalize.lean;finalizepart ofImpl/Hmac/Generic/Arm.lean;finalizeparts ofProof/Hmac/Generic/Arm/{Instances,Sha224}.lean.Instructions executed (generated code, compression calls included)
The counts come from a small ARMv7 interpreter run over the generated
src/asm/arm/*.rs, which also checked every result against Python'shmac.finalize(20-byte message)Excluding the compressions, the overhead per iteration dropped from 2276 to 78 instructions for SHA-1, and from 4984 to 232 for SHA-512. CI's "Compare with base (arm)" check will measure the real-world speedup.
Validation
lake build, thenlake env lean --run Emit.lean --check. The axiom and compiler-override audits pass, and the generated code matches.check_lean_imports,check_lean_speed,check_vectors,check_arch_gates,check_variants,check_mcdtandalgorithms_tableall pass.cargo fmt --check;cargo clippy --all-targets -- -D warnings, on the host and with--target armv7-unknown-linux-gnueabihf;cargo check --target armv7-unknown-linux-gnueabihf --all-targets;cargo testwith Wycheproof on the host.🤖 Generated with Claude Code
https://claude.ai/code/session_01RjfTK5YMk2jDsiKRYs2dbn
Generated by Claude Code