Skip to content

feat(ffi): wire real BLAKE3 combiner — build+link libochrance.so, drop dead stubs#58

Merged
hyperpolymath merged 1 commit into
mainfrom
claude/dazzling-noether-hkgAV
Jun 18, 2026
Merged

feat(ffi): wire real BLAKE3 combiner — build+link libochrance.so, drop dead stubs#58
hyperpolymath merged 1 commit into
mainfrom
claude/dazzling-noether-hkgAV

Conversation

@hyperpolymath

Copy link
Copy Markdown
Owner

Summary

Closes the cryptographic-integrity gap (CLAUDE.md rule 4): the production verification path now computes real BLAKE3 through libochrance.so, verified end-to-end at runtime — not stubbed, not aspirational.

The root cause was a real, silent bug: build.zig named the shared library ochrance-sharedlibochrance-shared.so, but the Idris bindings declare %foreign "C:blake3_hash,libochrance", so the runtime loader looks for libochrance.so. That file was never produced — the FFI could never have loaded at runtime.

Changes

Build/link

  • ffi/zig/build.zig: name the shared library ochrance so it emits libochrance.so (the soname the %foreign loader resolves). Static libochrance.a and shared libochrance.so coexist (distinct extensions).

Runtime tests — the contract Idris2's FFI loader actually depends on

  • ffi/zig/test/link_test.c + run_link_test.sh: dlopen libochrance.so and call each exported symbol against published KAT vectors (BLAKE3 / SHA-256 / SHA3-256), plus discriminators proving the Merkle combiner is order-sensitive with no XOR self-cancellation — i.e. real BLAKE3, not the XOR stub. Wired into zig-ffi.yml CI (uses cc, already present on the runner).
  • tests/ffi/CryptoFFITest.idr: an Idris executable that drives blake3 / sha256 / sha3_256 / rootHashBytesIO across %foreign and checks the production Merkle root equals BLAKE3(leafA ++ leafB) and differs from the XOR spec root. (Local/maintainer recipe just test-ffi-idris; not CI-gated, since CI has no Idris2.)

Idris cleanup

  • FFI/Crypto.idr: remove the dead zero/false stubs blake3Stub, sha256Stub, sha3_256Stub, ed25519VerifyStub (superseded by the real FFI functions; were referenced only in docs).
  • Rename hashPairStubxorCombiner across Crypto/Merkle/PropertyTests. It is the totality-friendly pure spec instance of the combiner-generic theorems, not a crypto fallback — a pure BLAKE3 combiner is impossible (BLAKE3 only crosses the FFI boundary in IO). Security rests on the explicit, isolated CollisionResistant assumption (pigeonhole-false; MerkleAssumption).

Docs/state: CLAUDE.md, EXPLAINME.adoc, VALENCE_SHELL_BRIDGE.adoc, STATE.a2ml, debt.a2ml updated to reflect the closed gap honestly (Merkle roots are cryptographic commitments given a collision-resistant BLAKE3 — the standard, clearly-stated trust root).

Verification (run locally — idris2 0.8.0 built from source + zig 0.11.0)

Check Result
Core proof corpus idris2 --build ochrance.ipkg (--total) 29/29, axiom-free
Property tests 47/47
A2ML + integration suites green (integration 55/55)
zig build test (Zig KAT + Ed25519 round-trip) pass
C dlopen link test 10/10
Idris→FFI runtime test (real BLAKE3 via libochrance.so) 6/6
e2e_test.sh (grep guards incl. soname regression) 27/27

What this does not claim

Collision resistance remains the single, irreducible, explicit assumption (CollisionResistant, pigeonhole-false, isolated in MerkleAssumption) — supplied at the verification boundary, never proved. Full Ed25519 attestation still needs a key-management / trust-root layer (the signature primitive is real and linked; the pure validateManifest path skips signatures by construction).

🤖 Generated with Claude Code


Generated by Claude Code

…p dead stubs

Closes the cryptographic-integrity gap (CLAUDE.md rule 4): the production
verification path now computes real BLAKE3 through libochrance.so, verified end
to end at runtime.

Build/link
- build.zig: name the shared library "ochrance" so it emits libochrance.so. It
  was "ochrance-shared" -> libochrance-shared.so, which the Idris %foreign loader
  ("C:blake3_hash,libochrance") could never resolve. This was the actual reason
  the FFI was never loadable at runtime.

Runtime tests (the contract Idris2's FFI loader depends on)
- ffi/zig/test/link_test.c + run_link_test.sh: dlopen libochrance.so and call
  each exported symbol against published KAT vectors; assert the Merkle combiner
  is order-sensitive with no XOR self-cancellation (real BLAKE3, not the stub).
  Gated in zig-ffi.yml CI.
- tests/ffi/CryptoFFITest.idr: Idris executable driving blake3 / sha256 /
  sha3_256 / rootHashBytesIO across %foreign; checks the production Merkle root
  equals BLAKE3(leafA ++ leafB) and differs from the XOR spec root.

Idris cleanup
- FFI/Crypto.idr: remove dead zero/false stubs blake3Stub, sha256Stub,
  sha3_256Stub, ed25519VerifyStub (superseded by the real FFI functions).
- Rename hashPairStub -> xorCombiner across Crypto/Merkle/PropertyTests: it is
  the totality-friendly pure spec instance of the combiner-generic theorems, not
  a crypto fallback (a pure BLAKE3 combiner is impossible — BLAKE3 only crosses
  the FFI boundary in IO). Security rests on the explicit, isolated
  CollisionResistant assumption (pigeonhole-false; MerkleAssumption).

Docs/state: CLAUDE.md, EXPLAINME.adoc, VALENCE_SHELL_BRIDGE.adoc, STATE.a2ml,
debt.a2ml updated to reflect the closed gap.

Verified locally (idris2 0.8.0 + zig 0.11.0): core 29/29 (--total, axiom-free),
property 47/47, A2ML + integration green, zig build test, C link test 10/10,
Idris->FFI runtime test 6/6.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011z2t8zAxfcCNLJzU7YdpBQ
@hyperpolymath
hyperpolymath marked this pull request as ready for review June 18, 2026 13:35
@hyperpolymath
hyperpolymath merged commit 703fa00 into main Jun 18, 2026
21 checks passed
@hyperpolymath
hyperpolymath deleted the claude/dazzling-noether-hkgAV branch June 18, 2026 13:36
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