sha2-fv 0.1.0

Formally verified Pure Rust implementation of the SHA-2 hash function family (SHA-224, SHA-256, SHA-384, SHA-512, SHA-512/224, SHA-512/256), with Lean 4 proofs of correctness against FIPS 180-4.
Documentation
  • Coverage
  • 100%
    9 out of 9 items documented9 out of 9 items with examples
  • Size
  • Source code size: 355.99 kB This is the summed size of all the files inside the crates.io package for this release.
  • Documentation size: 219.58 kB This is the summed size of all files generated by rustdoc for all configured targets
  • Ø build duration
  • this release: 5s Average build duration of successful builds.
  • all releases: 5s Average build duration of successful builds in releases after 2024-10-23.
  • Links
  • remix7531/hashes-fv
    0 0 1
  • crates.io
  • Dependencies
  • Versions
  • Owners
  • remix7531

RustCrypto: SHA-2 (formally verified)

Apache2/MIT licensed Rust Version

Pure Rust implementation of the SHA-2 cryptographic hash algorithms, refactored for formal verification via Aeneas with the Lean 4 backend against a mechanised FIPS 180-4 specification.

The standard specifies six algorithms (sha256, sha224, sha512, sha384, sha512_256, sha512_224) over two cores (SHA-256, SHA-512); the rest are IV swaps with a state truncation.

Design

This fork replaces upstream's digest trait-based API with standalone byte-in / byte-out functions: no trait objects, no generics, friendly to Charon (Rust → LLBC) and Aeneas (LLBC → Lean 4).

RustCrypto Rust source  ->  Charon  ->  LLBC
                        ->  Aeneas  ->  Lean monadic translation  (proofs/lean/Extraction/)
                        ->  hand-written refinement              (proofs/lean/)
                        <-> FIPS 180-4 spec                       (remix7531/fips-180-4-lean)

make extract regenerates the Lean files; make prove typechecks the proofs. Mathlib comes in transitively via the Aeneas Lean library.

Verification

make prove checks one public theorem per algorithm:

theorem sha256_spec (data : Slice U8) (h : data.length < 2 ^ 61) :
    Extraction.sha256 data
    ⦃ out =>
        let hb := bytesToBits_length_lt_2_64 data.val h
        SHS.Word.fromBits (bytesToBits out.val) =
          SHS.SHA256.sha256 (bytesToBits data.val) hb ⦄

The Aeneas-extracted entry point returns the FIPS 180-4 digest for any input under 2^61 bytes. bytesToBits is the single MSB-first byte-to-bit primitive used on both sides; hb lifts the byte bound to the < 2^64 bit bound the spec wants. The five siblings live in Sha512.lean and Sha256.lean and share the shape.

Pinned axiom set: {propext, Classical.choice, Quot.sound, Aeneas.Std.core.fmt.Formatter}. The fourth is Aeneas's opacity for core::fmt::Formatter. AxiomCheck.lean audits every pinned theorem on each make prove.

Examples

# #[cfg(feature = "sha256")] {
use hex_literal::hex;

let hash256 = sha2::sha256(b"hello world");
assert_eq!(hash256, hex!("b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9"));
# }
# #[cfg(feature = "sha512")] {
use hex_literal::hex;

let hash512 = sha2::sha512(b"hello world");
assert_eq!(hash512, hex!(
    "309ecc489c12d6eb4cc40f50c902f2b4d0ed77ee511a7c7a9bcd3ca86d4cd86f"
    "989dd35bc5ff499670da34255b45b0cfd830e81f605dcf7dc5542e93ae9cd76f"
));
# }

Backends

Only the portable soft-compact backend is retained; all hardware-specific variants (aarch64-sha2, aarch64-sha3, x86-shani, x86-avx2, loongarch64-asm, riscv-zknh, riscv-zknh-compact, wasm32-simd, unrolled soft) are dropped to keep the verified surface narrow.

License

The Rust crate is dual-licensed Apache-2.0 or MIT, matching upstream RustCrypto.

The Lean proofs under proofs/lean/ are GPL-3.0-or-later, inherited from fips-180-4-lean (see proofs/lean/LICENSE). The crate does not link the proof code at runtime, so crate consumers are unaffected by GPL terms.