HMAC finalize and PBKDF2 iterate on x86 call the compression function - #579
Merged
Merged
Conversation
On 32-bit x86, HMAC's `finalize` and PBKDF2's `iterate` for MD5, SHA-1, SHA-384, SHA-512, SHA-512/224 and SHA-512/256 are now written once over a description of a Merkle-Damgard hash function (`Impl/Pbkdf2/Md/X86.lean`: its streaming functions, hash value and length-field sizes, byte order, compression function and digest code), proven once against `Proof.MdStream.Md` and instantiated per hash. * `iterate` lays the block out once (U, 0x80, zeros, the length of a B + D-byte message), and each step is two compressions: the key's inner hash value with that block, then the outer one with the digest written word by word into it. The padding a truncated digest overwrites is written back, and T ^= U is computed word by word. * HMAC `finalize` calls the streaming `finalize` for the inner hash, then computes the outer hash with one compression of a fixed-layout block: the outer hash value and the digest copied word by word, the padding and length written as word stores, the MAC written to `out` (or, truncated, to scratch and copied). The whole PBKDF2 derivation calls the new functions. The streaming-level x86 `iterate` (`Impl/Pbkdf2/Generic/X86.lean`) and HMAC `finalize`, and their proofs, are removed; HMAC's `init` is unchanged. No change to TCB/ or Spec/, to the contracts, or to other targets. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RjfTK5YMk2jDsiKRYs2dbn
Conflicts were in the docs main trimmed (#571, #572): the registration files' boilerplate and the proofs' "Untrusted" sentence, dropped here too, including from the new modules. The streaming-level x86 files main edited stay deleted. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RjfTK5YMk2jDsiKRYs2dbn
github-merge-queue
Bot
removed this pull request from the merge queue due to a conflict with the base branch
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 32-bit x86, HMAC
finalizeand PBKDF2iteratenow call the compression function directly for MD5, SHA-1, SHA-384, SHA-512, SHA-512/224 and SHA-512/256. This is the design already used on x86-64 and AArch64, and on ARMv7 in #578. It is written once over a description of a Merkle–Damgård hash and proven once againstProof.MdStream.Md.Before this change, these functions were generic over the hash's streaming functions:
updateandfinalize, twice;updateandfinalizetoo.This PR is implementation only, with no changes to
Spec/orTCB/. The functions are proven against the existingSpec.Hmac.Instance.finalizeContractanditerateContract, at the samestackas before (48).Some things stay as they are:
initstays the generic one, which runs once per key.Design
Impl/Pbkdf2/Md/X86.leanis new. ItsHashholds:initand the innerfinalizecall;N;Land its byte order;It covers both the 64-byte-block hashes (
Impl/MdStream/X86.lean) and the SHA-512 family. The block always sits right after the hash value.iterate. The prologue copiesUinto the block and writes the padding of aB + D-byte message, once. Each step then:keyand compresses;T ⊕= Uword-wise int.So each step is exactly two compressions, with no
update/finalizeand no byte loops.HMAC
finalize. It makes one call of the streamingfinalizefor the inner hash. It then reuses the inner state as the outer block, with word copies and constant word stores for the padding and length, and does one compression. The digest goes toout, through scratch and a word copy for the truncated hashes. The helpers (copyW,storeW,pad,digest,cmp) are shared withiterate.Proofs
Proof/Pbkdf2/MdHmac.lean:Link.hmac_outer,blockAt_tailPadandLink.hash_outer.Proof/Pbkdf2/Md/X86/:Block(shared pieces, andMdOk, which bundles what is needed of a hash);IterateandIterateCT;HmacFinandHmacFinCT;Hashes,LitandInstances.taint_decidecovers the code between calls;cmp_relandfin_relrelate the calls through their contracts.Proof/Pbkdf2/Whole/X86/{Lit,Instances}.lean) now calls the newiterateandfinalize.Impl/Pbkdf2/Generic/X86.lean, andProof/Pbkdf2/Generic/X86/{Iterate,IterateCT,Instances}.lean;finalizepart ofImpl/Hmac/Generic/X86.lean, with the proofs trimmed to whatinitneeds (FinalizeCT.leanbecomesInitCT.lean).Instructions executed (i686, callgrind)
finalizeMD5finalizeSHA-1finalizeSHA-384finalizeSHA-512There is no 32-bit OpenSSL here, so the bench crate doesn't build for i686. CI's "Compare with base (x86)" check will measure the change.
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_variantsandcheck_mcdtpass, andalgorithms_tableneeds no README change.cargo fmt --checkpasses, and so doescargo clippy --all-targets -- -D warningson the host and for i686.cargo testwith Wycheproof passes on the host.VG_CPU_FEATURES=none. These ran oni686-unknown-linux-musl, because the-gnutarget can't link in this environment; CI runs-gnu.Merging with #578
The two PRs conflict only in comments. #578 edited doc references in x86 files that this PR deletes or trims. Whichever merges second keeps this PR's side of those files.
🤖 Generated with Claude Code
https://claude.ai/code/session_01RjfTK5YMk2jDsiKRYs2dbn
Generated by Claude Code