Repository navigation
aarch64 SHA-256 on the SHA-2 instructions is proven - #552
Conversation
Quest-Claim: b08e8d3e702deab2
…n in HOL Light WIP checkpoint: the HOL Light proof and admin/prove's extraction are done; the Lean axiom and bridge await a build. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…Axioms Three hand models' Rust quotes had drifted from the source, so admin/prove failed before translating: Digest::id, #[must_use] on hmac::Context::sign, and the doc comment on PublicKey::verify. None changes a model. aarch64's SHA-256 theorems now rest on sha256_block_data_order_hw_spec, so its HashAxioms.lean is written by hand rather than copied from x86_64's. Its expected axiom lists are not yet checked by a build. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Maintainer decision (2026-11-10, /quest-complete): offer the HOL Light proof to awslabs/s2n-bignum: ✅ keep it vendored in rind (rejected: offer it after awslabs/s2n-bignum#415 merges; offer it now). Remove that Waiting item. The remaining work is the agent's Lean build ( (Written by Claude Opus 5.5 with low) |
…256-aarch64-hw # Conflicts: # admin/prove
S2nSha256's schedule and blocks lemmas used rewrites that no longer matched, and its choose/maj bridges used bv_decide, whose native axioms would have entered the trust base; they are now case splits. The dispatch proof in Sha256Hw.lean is rewritten against the translation, and the axiom guards hold what Lean reports. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Delete the quest and every link to it, and point the prose that cited it at the PR, recording how unmerged upstream comes in. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Your OpenCode Go account is out of credit. Top it up, then re-trigger Pullfrog. OpenCode Go's response
|
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 15 minutes. View limit details
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. |
…THMS.md's inventory Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Closes quest/m2/verified/sha256-aarch64-hw.md.
On aarch64 with the crypto extension, SHA-256 now earns the ✓, along with HMAC-SHA256 and HKDF-SHA256 (and PBKDF2 over it, which has no benchmark row). The routine is aws-lc's
sha256_block_data_order_hw, exactly as rind's release build emits it. rind's own HOL Light proof shows it computes s2n-bignum's FIPS 180-4 spec from awslabs/s2n-bignum#415. Lean restates that theorem as an axiom over the Rust wrapper and proves the spec equal toRind/HashSpec.lean's. This is the calibration quest, so most of this body is the measurement.What changed
proofs/hol-light/aarch64/sha256_block_data_order_hw.mlprovesSHA256_HW_SUBROUTINE_CORRECT. Calling the naked function withn ≥ 1blocks leaves the state atsha256_hash_blocks m h n, then returns to the caller under the ABI's frame. Its only axioms are HOL Light's three.K256table the build links against FIPS 180-4's constants.iblocks, the data pointer, and the counter.sha256h/sha256h2pair is rewritten to four spec rounds, and eachsha256su0/sha256su1pair to four schedule words.proofs/hol-light/s2n-bignum/x86/proofs/utils/sha256_spec.mlis perf(ed25519): verify without ADX through curve25519-dalek's AVX2 backend #415's file, unchanged, at79120e64ed55e37c9652565ff272b7ef17f76738. It sits ahead of the submodule on HOL Light's load path. The submodule stays at merged upstream.proofs/README.mdrecords the PR and commit.admin/prove. A naked function now comes out as an object file named<file>.o. It holds the function's whole section, its relocations, and the one.rodatasection they reach.define_assert_relocs_from_elfchecks the instructions and relocations, so no transliteration is trusted, and the table's bytes come from the build too.asm_functionfinds the function and its relocations withrind_symbolandrelocations, which moq-dev/rind#551 added on main.low::aarch64::sha256dispatches throughcompress_hw(HaveCryptoExt, ..)andcompress_nohw(..), assha512.rsdoes, so Aeneas translates the dispatch. The emitted naked function is byte-identical; the extracted object matches the one the proof was developed on.Rind/S2nSha256.leantransliterates s2n-bignum's spec and provesblock_wordsandhashBlocks_eq, which together say it isHashSpec'ssha256.compressfolded over the blocks.Rind/Aarch64/Sha256Hw.leanrestates the HOL theorem assha256_block_data_order_hw_specand proves that the dispatch meetsCompresseswheneverHaveCryptoExt::checkreturnsSome.ShaBlockssplit. It becomesSha1BlocksandSha256Blockson both targets, so a SHA-256 theorem no longer assumes SHA-1's unproven contract.Sha256Blocksis only the CPU check plus the entry checks.RunsDigesttakesShaBlocksOf a, andRunsHmacpicks per algorithm.HashAxioms.leanis now hand-written, since its SHA-256 theorems rest on the new axiom.benchmarks/verified.tomlgains the entry, which notes the pin, andBENCHMARKS.mdis re-rendered.Public API impact
None. The change is in
low::aarch64::sha256's private functions and in the proofs.Measurement
HOL Light proof
The routine is 124 instructions with one loop and no branch beyond the loop's
cbnz. Every instruction is already in s2n-bignum's aarch64 model.sha256h/h2, schedule persu0/su1, constants table, loadsadmin/prove hol-lightcompiles the aarch64 proofs (bignum_eqand this one) to native code with HOL Light'sbase.ml, and the binary checks them in 49 s. That is well within theproveworkflow's hol-light job, which has 30 minutes (the Lean job has 60). Interactively, the 115-step body takes about 5 s.read c sfact about a state other than the current one, including facts about the ghost memorymem0. Wrapping the data and table facts in one defined predicate,sha256_hw_inputs, keeps them.DATA64_CONVonly splits a table at an address writtenword (k + 0). Rewritingktok + 0first fixed it.substcaptured bound variables.mk_absandlist_mk_forallwith explicit types fixed it.ld1 {v4-v7}read memory at addresses normalized differently from the data facts. Q5 to Q7 then held unknown values and were discarded, which looked like Q0/Q1 vanishing about 20 steps later. Abbreviatingd = data + 64·ibefore stepping fixed it; bisecting by single steps found it.ARM_ADD_RETURN_STACK_TACleft thebytes_loadedprecondition unproven at the core's entry. Rewriting it to abytesread, as upstream'sBYTES_LOADED_DATAdoes, fixed it.Lean side
Sha256Hw.lean)S2nSha256.lean, trusted as a transcription)HashSpec(S2nSha256.lean)HashAxioms.lean, now hand-writtenShaBlockssplit and its consumers, both targetscargo-mutantsruns. A second session (this one) got it throughadmin/prove leanin about 2 hours, most of it waiting inquest gateon a loaded host.S2nSha256.leanthat no longer matched.getElem!_append_left/_rightdid not unify, and the strong induction inblocks_eqleft the goal inninstead ofbytes.length. Deprecatedif_pos/if_negbecameite_eq_left/ite_eq_right.choose_eqandmaj_equsedbv_decide. Its native axioms (*._native.bv_decide.ax_1_5, throughLean.ofReduceBool) showed up in every SHA-256 theorem's axiom list. They are now per-bit case splits, so the Lean side trusts no compiled code.blocksundersimp_all, and it now rewritesblocks 64 []directly.digest_ctx_new_specturned out not to rest on the new axiom, since they compress nothing or take the block function as a hypothesis. The HMAC, KDF, and P-256 signature entries in aarch64'sAxioms.leangainsha256_block_data_order_hw_spec.admin/prove leanfrom a cold.tmp/provetook 22 min on this loaded host (24 cores, load average above 100), extraction included, inside theproveworkflow's 60 minutes. The new and changed modules add about 40 s of it.admin/prove hol-lightran in 192 s, 67 s of it checking.Second route: Lean
bv_decideI wrote the Arm pseudocode for
sha256h,sha256h2,sha256su0,sha256su1and the vector add as LeanBitVecfunctions, following s2n-bignum'sarm/proofs/sha256.ml, and checked them withbv_decide(core Lean 4.35, CaDiCaL, LRAT-checked):sha256h/sha256h2equal four spec roundssha256su0+sha256su1equal four schedule wordsEvery intermediate value was named as a hypothesis so the terms stay linear. The time goes to SAT, and it grows about 5 to 15 times per doubling of rounds.
bv_decideproof could replace the lemma layer.Lean.ofReduceBool, the compiled LRAT checker.Proposed sizes for the quests that require this one
These are calibrated on this quest: 124 instructions, a loop, no model additions, about 600 lines and one session. Scalar routines unroll 64 to 80 rounds into about 1,000 instructions each. The per-round rewriting approach should carry over, but each needs its own round lemma for the ALU sequence.
sha256rnds2,sha256msg1/2: #450 adds about 200 linessha1rnds4/sha1nexte/sha1msg1/2vpalignris absentvpmadd52luq/huqare absentDecisions
Vendoring layout (chosen without asking, for review). The spec lives under
proofs/hol-light/s2n-bignum/, at its upstream path, so the proof'sneedsline is the same with or without it. When the submodule moves past perf(ed25519): verify without ADX through curve25519-dalek's AVX2 backend #415's merge, deleting the directory is the whole migration.Offer the HOL Light proof to awslabs/s2n-bignum (maintainer, 2026-11-10, comment): ✅ keep it vendored in rind (rejected: offer it after x86_64 sha256 block compression implementation without SIMD and without sha-specific instructions + functional proof + safety proof + Windows awslabs/s2n-bignum#415 merges, offer it now).
Apply the proposed quest sizes (maintainer, 2026-11-10, /quest-complete): ✅ apply them in this PR (rejected: defer to the next
/quest-audit, ignore them). x86_64 SHA-NI SHA-256 is now M, SHA-1 XL, x86_64 RSA Montgomery L; the rest are unchanged.ALGORITHMS.md's inventory refreshed (chosen without asking). The
hol-lightjob's bytes check found it stale: rind's aarch64 release build no longer definesbignum_negmodinvorbignum_sqr_p521as symbols (LLVM inlines them into their callers), soadmin/prove-bytes inventorylists them as not imported on aarch64. The table is the tool's output, unedited.Splitting
ShaBlocks(chosen without asking). Otherwise the ✓ would have rested on a hypothesis about SHA-1's routine.The ✓ covers
sha256/*,hmac-sha256/*andhkdf-sha256/*(chosen without asking). It applies on aarch64 withaes,pmull,sha2, the featuresHaveCryptoExtchecks. ECDSA already had its ✓, which leaves the message hash out.No
bv_decidein the trusted Lean (chosen without asking). Its native axioms would have joined every SHA-256 theorem's trust base for two one-line bitwise identities.The wrapper's hypotheses follow s2n-bignum's subroutine theorems:
adrp_within_boundsholds for the table.Sha256Hw.leansays why each holds for every call the Rust allows.Follow-ups
proofs/hol-light/s2n-bignum/x86/. Recommend: no quest, since the quest that bumps the submodule does it.Models
Size: L
Implementer: Claude Code, claude-opus-5-5, high effort
Implementer: Claude Code, claude-opus-5-5, high effort (iterate, L)
Implementer: Claude Code, claude-opus-5-5, low effort (iterate, S)
(Written by Opus 5.5 with high; iterated by Opus 5.5 with low)
🤖 Generated with Claude Code
Review
Rewritten by
quest reviewafter each round.01a1c6ef-8480-78c0-b14d-e49f935dc849, round 2No actionable defects were found in the documentation and quest-estimate updates since the previous review; builds and tests were not run, as instructed.