Repository navigation
feat(stdlib): SHA-256 as a standard-library member (SL-02, stage 1 of #126) - #172
Draft
humuhumu33 wants to merge 7 commits into
Draft
humuhumu33 wants to merge 7 commits into
humuhumu33 wants to merge 7 commits into
Conversation
`stdlib/src/Sha256.lex.tex` states FIPS 180-4 SHA-256 over the closed language-1.2 primitives with the rust-std production roots `sha256` and `sha256Hex`. `SL-02` (suite `stdlib`, SPEC.md §17.22) checks their eligibility, runs them under the evaluator and rustc on the FIPS 180-4 examples, every NIST CAVP SHA-256 short- and long-message vector, and a seeded corpus against the `sha2` crate, plants one bit in the round function, and compares the exported packages with the committed ones. Goldens and packages are regenerated in a following commit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Register 386 on main plus SL-01 (#153) and SL-02 = 388, in the four places the count lives; RT-01..RT-04 and the SL rows are kept in that order in model/ids.toml, the SPEC §31 table, and the test list. Goldens and packages of the stdlib project are regenerated on the merged tree in a following commit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…g bound (#126) A rendered package's program is canonical JSON read under a 128-level nesting bound, and the linear 64-element round-constant list and 16-way hex chain were past it. The round constant is now a balanced search on the round number (depth 6) and each hex nibble a balanced test of its bits (depth 4). The stdlib lock follows the compiler semantics of the merged main. SL-02 without its Lean half passes in 114 s: evaluator and rustc on the FIPS 180-4 examples, all 129 NIST CAVP vectors, the sha2 corpus, the million-a message, and the planted round bit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Exact axiom sets as Lean observes them (`roundConstant` uses none), and `wordAt` combines four bytes with no Nat arithmetic: with the position additions inside it, certificate A of `sha256` was rejected at the call from `scheduleWord`'s inner else branch (expected the callee infallible). The stdlib project now verifies, both modules, in WSL under Lean 4.32.1. A minimal two-function repro of that rejection did not reproduce, so the defect is not filed yet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Main through #155 and #166. The register is 405: main's 404 and SL-02, set by hand in README, SPEC §31, repository.rs, and spec_links.rs. stdlib/ and bootstrap/ are relocked (bootstrap pins stdlib's tree, which gains Sha256); the stdlib records are regenerated next. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
stdlib/expected/{build,verify} and tests/production-export/stdlib/packages
for the project with Sha256 (the sha256 and sha256_hex packages are new);
bootstrap/expected/build follows the stdlib tree its lock pins.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
One bit of the round function (a := (add t1 t2) exclusive-or 1) fails conformance_sl_02 on 372 of 372 runs from abc; the source was restored and the case passes in 305 s with the production export under Lean. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
Stage 1 of #126 (plan item L5.1 of #106, under #27's rule that no handwritten code carries normative semantics), in #92's lane of more standard-library members: SHA-256 as a certified member of the standard library, with its evidence. Stage 2, switching every identity of SPEC §8 and §21 from the
sha2crate to this module, is a later PR; the measurement it needs is below.Refs #126. Refs #92.
The branch contains main at
8765feea(through #155 and #166), merged with a merge commit. The register is 405 (main's 404 andSL-02), set by hand in README, SPEC §31,repository.rs, andxtask/src/spec_links.rs.What this adds
stdlib/src/Sha256.lex.tex: FIPS 180-4 SHA-256 in the authoring notation, over the closed language-1.2 primitives and nothing else. Two production roots forrust-std, each admitting exactly the effects its closure realizes (allocation,overflow,recursion):sha256 (message : Bytes) : DigestUInt32wordssha256Hex (message : Bytes) : BytesThe FIPS 180-4 example digests (
abc, the two-block message, the empty message) are stated in the module as theorems byreflexivityon theDigestrecord, which the kernel replays underverify.How it is said, since [v0.4] #27 stage 8: the production compiler authored in .lex.tex and compiled by LexLean to production software #92's spike predicted "expressible today over UInt32 bit ops and iterate" and three things were missing on the way:
addischecked_addof the operands widened toUInt64bychecked_convert, narrowed bybit_andandchecked_convert(thenonearms are unreachable and would fail every vector);Option) andbit_or;checked_convertrefuses aNatinput and nothing turns a fixed-width value intoBytes, so the message is never padded as bytes. Every word of every block is read by position (indexbelow the length,0x80at it, zero beyond), the two length words come fromquotientandremainderof the bit length through a 32-stepiterateover its bits (wordOfNat), and each hexadecimal digit is chosen from its nibble bybit_andandequaltests. feat(semantic-ir): byte and fixed-width widening conversions in language 1.2 (SM-32, #114) #151 (to_nat, [0.5.0] Byte-to-fixed-width conversion in the language-1.2 surface #114) would shortenwordOfNatandbyteAt; this PR does not depend on it.The schedule is a sixteen-word window advanced each round and the sixty-four rounds are
iterateover a record of the working variables, the window, and the round number; the round constant is a balanced search on that number (depth 6) and each hex nibble a balanced test of its four bits.SL-02(one scenario, oneconformance_sl_02, incrates/conformance/src/cases/stdlib_sha256.rs):rust-stdwith exactly their declared effects;rust-stdpackage under the pinned rustc compute the FIPS 180-4 examples, every vector of the NIST CAVPSHA256ShortMsg.rsp(65) andSHA256LongMsg.rsp(64) files, committed verbatim undertests/stdlib/sha256/with their provenance, and agree with thesha2crate on a seeded corpus: every length 0..200 (so 55, 56, 63, 64, 119, 120 and their neighbours), then random lengths to 4 KiB, and the million-aexample under rustc. The two oracles are checked against each other before either judges the module, and a disagreement fails closed: it is a defect, never resolved by adopting an oracle's digest;a := (add t1 t2)exclusive-or 1) and the first FIPS vector disagrees;lexlean production build, §24.7) certifies both roots (certificates A, B, E) intorust-stdpackages byte-identical to the committed ones undertests/production-export/stdlib/packages/, each realizing the program the differential ran.SPEC §17.22 gains the module and its oracles; §7 lists
tests/stdlib/; CHANGELOG, README, CONFORMANCE.md regenerated; the VERIFICATION.md record of the planted bit.Regenerated for the new module only:
stdlib/lexlean.lock,stdlib/expected/{build,verify},tests/production-export/stdlib/packages/.bootstrap/lexlean.lockandbootstrap/expected/buildfollow, sincebootstrap/pins the standard library's tree as a source package (feat(packages): source packages, a project imports the modules of a locked package (PK-01..PK-04) #162); its verify records and packages are unchanged.Three findings on the way
ifchain) and the rendered package was refused (package manifest is not canonical JSON: recursion limit exceeded): the reader parses the program's canonical JSON under serde_json's 128-level limit, and a 64-deepconsis past it. The module stays inside it with balanced lookups; the bound is worth a line in §17.16 or a register row of its own, and this PR does not changecalculus/rust/.else. Certificate A refusedsha256whilewordAt(whose argument positions areNatadditions) was called from the innermostelseofscheduleWord; moving the additions to the caller (wordAttakes the four bytes) is accepted. A two-function reduction did not reproduce it, so it is not filed yet; it belongs to the [v0.4] #27 stage 5: certificates A, B, E and the audit modules as typed data, with no Lean text template in the production compiler #89 lane.roundConstanthas no axioms. A balanced<?search overNatliterals closes with no axioms at all, so its exact policy is[], not theQuot.sound, propextits siblings carry (LLV7005until it was aligned).Measurement for stage 2
Measured on this branch's committed
sha256_hexpackage (the production export forrust-std, built--releasewith the pinned rustc 1.97.1) againstsha20.10, one thread on an AMD Ryzen AI Max 390 under WSL, nothing else running; seeded messages, both sides producing the lowercase hex digest. Every one of the 2,572 digests of each run equalssha2's. Third of three runs (every time of the other two within 20% of it, most within 5%):The module runs at 70 to 90 MB/s, 24 to 35 times slower than
sha2from 16 KiB up;sha2uses the CPU's SHA extensions here (about 2.4 GB/s at 16 MiB). The small-input ratios flatter the module, since thesha2side formats its hex withformat!per byte. For stage 2 that is about 0.7 s for a 48 MB module's identity in place of about 20 ms. The 16 MiB message runs on a thread with a 4 GiB stack reservation, becauseiteraterecurses once per block; how much of it is needed was not measured. The harness (seeded corpus,sha2as reference) is not committed; it can go undertests/stdlib/sha256/if wanted.What it does not do
sha2anywhere in the compiler (stage 2).rflis kernel work out of proportion to its evidence; those are held by the differential.iterateis realized as a recursive function until production: the collection and iteration primitives are realized by self-recursive functions but registeredrecursion = false; a root overflows the stack at about 40k iterations #105 step 2, so a root over a 48 MB module is 750 000 blocks of stack depth; the harness runs on the 64 MiB thread the generated harness already uses. Stage 2 depends on production: the collection and iteration primitives are realized by self-recursive functions but registeredrecursion = false; a root overflows the stack at about 40k iterations #105 for the host stack as much as on the ratio.Evidence
Local, WSL x86-64, Lean 4.32.1:
cargo fmt --check,validate-model,validate-spec-links(405 rows),check-test-inventory,RP-07,RP-11,RP-13,RP-14, clippy with-D warningson the suite,conformance_sl_01(206 s) andconformance_sl_02(305 s) with the production export under the pinned Lean,check-golden, andcheck-production-export(every exported project). Fulljust vvon CI.Closes nothing; #126 stays open for stage 2.
🤖 Generated with Claude Code