Spec: SHA-224, and SHA-256's update and finalize for any initial hash value - #452
Conversation
… value FIPS 180-4's SHA-224 is SHA-256 from another initial hash value (§5.3.2), truncated to 28 bytes (§6.3). As for the SHA-512 family, it shares the streaming state and vg_sha256_update/vg_sha256_finalize, and only needs an init of its own: * Spec/Sha256.lean: H0_224; finalHash iv (the 32-byte H⁽ᴺ⁾ from iv), with hash := finalHash H0 and sha224 := (finalHash H0_224 ·).take 28; ReprFrom iv, with Repr := ReprFrom H0 (so HMAC and PBKDF2's contracts, which use Repr and hash, are unchanged). * Spec/Sha256/Contract.lean: updateContract and finalizeContract hold for a state hashed from any initial hash value (finalize writes finalHash iv msg, which is hash msg for H0); init224Contract and init224Api for vg_sha224_init. The existing implementations are unchanged: their update and finalize are the generic Merkle-Damgard code, whose proofs already hold for any initial hash value, so the per-target contracts quantify over it too and the few callers that relied on H0 instantiate it. docs/algorithms/sha224.toml adds the row (spec landed, no architecture yet). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HDRg9k22FbCYq3TnciKvwG
|
This PR was dequeued because the merge-group run failed two jobs: Both died in The image's preinstalled stable is missing a file that rustup expects to remove, so every PR's armv7l jobs fail the same way (the unrelated #453 too). No fix exists yet. A newer image may fix it; otherwise, a possible workaround in - name: Install Rust
run: |
rustup toolchain uninstall ${{ matrix.rust }} || true
rustup toolchain install ${{ matrix.rust }} --profile minimal --component clippy,rustfmt,llvm-toolsThe same change would go in the Thumb job and in Generated by Claude Code |
…-256 streaming glue Main's x86 SHA-256 streaming proofs moved to Proof/Sha256/X86/Stream/Variant.lean (for any compression backend); its update_of/finalize_of now pass iv through instead of H0, as the other targets' do. src/asm/x86/sha256.rs regenerated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HDRg9k22FbCYq3TnciKvwG
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HDRg9k22FbCYq3TnciKvwG
Second of the SHA-224 PRs: the spec. (Vectors: #446. The implementation of
vg_sha224_initand the Rust API follow in their own PR once this one is merged.)FIPS 180-4's SHA-224 is SHA-256 started from a different initial hash value (§5.3.2) and truncated to 28 bytes (§6.3). This follows the SHA-512 family's design: SHA-224 shares SHA-256's streaming state and
vg_sha256_update/vg_sha256_finalize, and only gets its owninit.Trust changes (
Spec/), for reviewSpec/Sha256.leanH0_224: transcribed from §5.3.2. As a cross-check, these words are the low halves of SHA-384'sH0_384, as the standard derives them.finalHash iv m: the 32-byteH⁽ᴺ⁾ofmstarting fromiv. This is the old body ofhash, withH0turned into a parameter.hash m := finalHash H0 m(unchanged in meaning) andsha224 m := (finalHash H0_224 m).take 28.ReprFrom iv: the old body ofRepr, withH0turned into a parameter.Repr := ReprFrom H0, soReprmeans what it did before, and the HMAC-SHA-256 and PBKDF2 contracts that useReprandhashdon't change.Spec/Sha256/Contract.leanupdateContract: now∀ iv msg, ReprFrom iv m state msg → … → ReprFrom iv m' state (msg ++ …). This is a strictly stronger postcondition:iv := H0gives back the old one.finalizeContract: now∀ iv msg, ReprFrom iv … → … → bytesAt m' out 32 = finalHash iv msg. This is also strictly stronger, sincefinalHash H0 = hash. Unlike SHA-512's contract, it needs no extra length hypothesis: the 64-bit length field is determined bycountmodulo 2⁶⁴, as before.init224Contract/init224Api(vg_sha224_init, modulesha256, withvg_sha256_init's signatureinitSig): the state represents[]fromH0_224.src/asm/*/sha256.rsdiffer only in those doc comments.Proofs (untrusted)
No implementation changes. On every target,
updateandfinalizeare the generic Merkle–Damgård code, and its proofs (Proof/MdStream/) already hold for any IV; they were only being specialized toH0. So:Proof/Sha256/*/Contract.lean) now quantify overivas well, and the glue that moves the generic proofs to them passesivthrough instead ofH0. That glue is in theMd/Variant/Sharedfiles, including x86'sStream/Variant.lean, which Make x86 SHA-256 constructions generic over compression backends #460 added and which reached this PR when I merged main.iv := H0:Proof/Hmac/Arm/Finalize.leanandProof/Pbkdf2/Md/AArch64/Hashes/Sha256.lean(the latter mirrors what the SHA-512 instance already does);Proof/Sha256/Stream.leanunfolds the new definitions in two places.docs/algorithms/sha224.tomladds the README row (spec landed, no architecture yet), and the table is regenerated.Checks run locally (after merging main)
lake build(all 5623 jobs) andlake env lean --run Emit.lean --checkci/check_lean_imports.py,check_lean_speed.py,check_vectors.py,check_arch_gates.py,check_variants.py,check_mcdt.py,algorithms_table.py --checkcargo fmt --check,cargo clippy --all-targets -- -D warnings,cargo test(x86-64)🤖 Generated with Claude Code
https://claude.ai/code/session_01HDRg9k22FbCYq3TnciKvwG