Skip to content

Add a pure Lean BLAKE3 implementation with checked proofs - #50

Merged
johnchandlerburnham merged 2 commits into
mainfrom
jcb/checked-pure-blake3
Sep 15, 2026
Merged

johnchandlerburnham merged 2 commits into
mainfrom
jcb/checked-pure-blake3

Conversation

@johnchandlerburnham

Copy link
Copy Markdown
Member

Formal developments using this library currently obtain hashes through opaque C or Rust functions. Add Blake3.Pure.hash : ByteArray → Blake3Hash, a total Lean implementation of standard unkeyed 32-byte BLAKE3 whose definitions are exposed for kernel reduction and proof. It has no Ix dependency and imports neither FFI backend.

Blake3.Pure.Proofs proves byte/word round trips, rotation and message-schedule properties, exact block framing, canonical tree correctness and uniqueness, and chunk-counter bounds under the native input-length bound. The test audit traverses checked types, bodies and inductive constructors for 50 proof roots, enforces their exact standard-Lean axiom sets, and rejects BLAKE3 FFI dependencies, opaque implementations and implementation replacements. It also checks the safe sources of the three generated recursion workers.

The pure API supports one-shot unkeyed hashing. Streaming, keyed hashing, key derivation and variable-length output remain available through the existing C and Rust backends. The proofs establish the stated algorithmic properties; collision resistance and universal refinement of C or Rust are separate obligations.

Validation:

  • lake build --wfail Blake3Test passes, including the 50-root audit.
  • lake test passes the existing C/Rust hash, keyed, derivation and sponge tests, plus two standard known answers, 258 pure/native boundary cases, 58 subtree compositions, 42 native chunk vectors and 64 internal-parent/digest-pair vectors. Both native backends report BLAKE3 1.8.7.
  • cargo clippy --locked --release --all-targets -- -D warnings and cargo fmt --all -- --check pass in rust/.
  • Component vectors are reproducible with the included rust/examples/pure_vectors.rs generator using the pinned BLAKE3 dependency.

@johnchandlerburnham
johnchandlerburnham enabled auto-merge (squash) September 14, 2026 00:51
@@ -0,0 +1,47 @@
//! Regenerate Tests/PureVectors.lean with:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why generate a Lean file? The following options are simpler, with the latter being much simpler than the former:

  1. Generate a raw text file, which can be read in IO and parsed. The regeneration entanglement and syntax conforming is not necessary
  2. Call Rust directly from Lean via FFI

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are test vectors. Doing 1 means Lean has to run IO and a parser, which is overhead. 2 means we have to bring in https://github.com/argumentcomputer/lean-ffi which is a large dependency. If we were in ix I would encode these using ixon syntax, but I don't have that dependency here.

I've added a change to clarify that we're just generating data though to minimize entanglement, separating out the Lean logic into a non-regened file and having the regen just be something morally json-ish

Move the vector schema into Tests/Vectors.lean and have
rust/examples/pure_vectors.rs emit one Blake3.PureTests.Vectors literal
with named fields, so the generated file is data only: an import, one
def line, and records with trailing commas. Tests/Pure.lean reads the
records by field name, parent records carry their salt, and the recorded
crate version is checked against the linked Rust backend.

32-byte values are lowercase hex strings rather than byte lists. A single
declaration holding both record lists as List UInt8 exceeds a code
generator recursion cliff at roughly 8k bindings and fails with "maximum
recursion depth has been reached" even though it elaborates; hex keeps
each record at a few bindings and matches the BLAKE3 team's own test
vector format. The vector values are unchanged.
println!("import Tests.Vectors");
println!();
println!("def Blake3.PureTests.vectors : Blake3.PureTests.Vectors := {{");
println!(" reference := \"1.8.7\",");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Marking this as likely to become stale.

@johnchandlerburnham
johnchandlerburnham merged commit 18b4b1c into main Sep 15, 2026
3 checks passed
@johnchandlerburnham
johnchandlerburnham deleted the jcb/checked-pure-blake3 branch September 15, 2026 13:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants