Skip to content

Commit a82bb31

Browse files
hyperpolymathclaude
andcommitted
feat(verification): SNIFs 2 — sharpen SEC-1, gate the buffer ABI, add a behaviour gate
SEC-1 (SnifIsolation.agda): wire confidentiality into the operational theorem (deniability re-derived over the run via run-deniable/fault-via-observe + a two-distinct-secret SecretWitness), model the real 6-origin error taxonomy (TrapOrigin guestFault/hostBudget/preExec + a call front-end + PreExecWitness), and add a non-trivial-Alive recovery witness (PartialAlive). All mutation-confirmed load-bearing by a 4-skeptic adversarial re-audit (--safe --without-K, every targeted mutation rejected). ABI-7: BufferAbi.idr models all 7 buffer_abi exports (multi-value/void-faithful WasmSig), raising gated ABI coverage to 15/20 Zig sites; abi_conformance.py is now guest-aware. CI-1: conformance runs as a CI job in proofs.yml. GAP-1b: snif_metamorphic_test.exs — dep-free metamorphic relations over the scalar kernels (found + corrected the checked_add wrapping-vs-name misnomer). Reconcile: ffi rsr-template marked scaffold; PROOF-NEEDS.md rendered; the two Rust guest trees documented as deliberate. Docs (PROOF-STATUS/README/CHANGELOG) reconciled to the verified state. Gate green this commit: just proof-check-all (exit 0), just abi-conformance (15 specs), mix test (30/30, OTP 25). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 913d141 commit a82bb31

59 files changed

Lines changed: 4954 additions & 287 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/proofs.yml

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# SPDX-License-Identifier: MPL-2.0
2+
# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) <j.d.a.jewell@open.ac.uk>
3+
#
4+
# Proof gate for SNIFS: machine-checks the formal verification artifacts.
5+
# If this gate is red, the repo's "proven" claim is void. It replaces the
6+
# previously decorative `just proof-check-*` targets, which silently passed when
7+
# the prover was absent (SKIP = exit 0) and used a broken idris2 invocation that
8+
# never resolved the ABI.* module graph — so the proofs were never actually checked.
9+
#
10+
# Toolchain is provided via Nix (nixpkgs#idris2, nixpkgs#lean4) — estate-standard,
11+
# reproducible, and avoids unpinned setup actions. NOTE: this consumes CI minutes;
12+
# if/when the bag-of-actions migration lands, this gate should move onto owned compute.
13+
# To make it BLOCKING, add the job names "Formal proofs — Idris2 + Lean4" AND
14+
# "ABI conformance — interface drift gate" to branch-protection required status
15+
# checks (owner-only). The ABI job (added 2026-06-16, SNIFs 2) builds the wasm
16+
# guests and fails if their real export signatures drift from the verified Idris2
17+
# ABI model (Foreign.idr + BufferAbi.idr) — closing the gap-1 interface gate in CI
18+
# instead of only on a local `just abi-conformance`.
19+
20+
name: Proof Gate
21+
on:
22+
push:
23+
branches: [main, master, develop]
24+
paths:
25+
- 'verification/**'
26+
- 'zig/**'
27+
- 'Justfile'
28+
- '.github/workflows/proofs.yml'
29+
pull_request:
30+
branches: [main, master]
31+
paths:
32+
- 'verification/**'
33+
- 'zig/**'
34+
- 'Justfile'
35+
- '.github/workflows/proofs.yml'
36+
workflow_dispatch:
37+
permissions: read-all
38+
concurrency:
39+
group: proofs-${{ github.ref }}
40+
cancel-in-progress: true
41+
jobs:
42+
proofs:
43+
name: Formal proofs — Idris2 + Lean4
44+
runs-on: ubuntu-latest
45+
timeout-minutes: 20
46+
steps:
47+
- name: Checkout
48+
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
49+
50+
- name: Install Nix (Determinate installer)
51+
run: |
52+
curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix \
53+
| sh -s -- install --no-confirm
54+
55+
- name: Check Idris2 + Lean4 proofs (fail-on-skip, real invocation)
56+
run: |
57+
. /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh
58+
nix shell nixpkgs#idris2 nixpkgs#lean4 nixpkgs#agda nixpkgs#just \
59+
--command bash -c 'just proof-check-all'
60+
61+
abi-conformance:
62+
name: ABI conformance — interface drift gate
63+
runs-on: ubuntu-latest
64+
timeout-minutes: 20
65+
steps:
66+
- name: Checkout
67+
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
68+
69+
- name: Install Nix (Determinate installer)
70+
run: |
71+
curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix \
72+
| sh -s -- install --no-confirm
73+
74+
- name: Build wasm guests + check ABI signatures vs the verified Idris2 model
75+
run: |
76+
. /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh
77+
# Zig 0.15+ is required (matches the repo toolchain + the safe_nif/buffer_abi build
78+
# flags). The recipe builds both guests, then the multi-guest conformance tool fails
79+
# on any export-signature drift from Foreign.idr / BufferAbi.idr.
80+
nix shell nixpkgs#zig nixpkgs#wasm-tools nixpkgs#python3 nixpkgs#just \
81+
--command bash -c 'just abi-conformance'
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# SPDX-License-Identifier: MPL-2.0
2+
# Copyright (c) Jonathan D.A. Jewell <j.d.a.jewell@open.ac.uk>
3+
#
4+
# Rust SNIF guest: build + verifier-on-by-default gate (ADR-0005).
5+
# Fail-closed. The source verifier (Kani) runs as a standard build step.
6+
name: Rust SNIF guest verify
7+
on:
8+
push:
9+
branches: [main, master]
10+
paths: ["rust/**", ".github/workflows/rust-guest-verify.yml"]
11+
pull_request:
12+
paths: ["rust/**", ".github/workflows/rust-guest-verify.yml"]
13+
14+
permissions:
15+
contents: read
16+
17+
jobs:
18+
verify:
19+
runs-on: ubuntu-latest
20+
defaults:
21+
run:
22+
working-directory: rust
23+
steps:
24+
- uses: actions/checkout@v4
25+
26+
- name: Toolchain + wasm32 target
27+
run: |
28+
rustup toolchain install 1.95.0 --profile minimal
29+
rustup default 1.95.0
30+
rustup component add clippy
31+
rustup target add wasm32-unknown-unknown
32+
33+
# ── Static gates (run for free) ────────────────────────────────────
34+
# #![forbid(unsafe_code)] on snif-logic and #![deny(unsafe_code)] on the
35+
# others are enforced by these compiles.
36+
- name: Build guest (ReleaseSafe invariant from [profile.release])
37+
run: cargo build --release --target wasm32-unknown-unknown
38+
39+
- name: wasm validate + assert ZERO imports (self-contained sandbox)
40+
run: |
41+
W=target/wasm32-unknown-unknown/release/demo_guest.wasm
42+
cargo install wasm-tools --locked || true
43+
wasm-tools validate "$W"
44+
if wasm-tools print "$W" | grep -q '(import'; then
45+
echo "::error::guest has imports — not self-contained"; exit 1
46+
fi
47+
48+
- name: Clippy (pedantic, warnings = errors)
49+
run: cargo clippy --all-targets -- -D warnings -W clippy::pedantic
50+
51+
- name: Supply-chain (bans rustler stack)
52+
run: |
53+
cargo install cargo-deny --locked || true
54+
cargo deny check
55+
56+
# ── The source verifier: verifier-on-by-default ────────────────────
57+
- name: Kani (proves snif-logic harnesses)
58+
run: |
59+
cargo install --locked kani-verifier || true
60+
cargo kani setup || true
61+
cargo kani -p snif-logic

.machine_readable/META.a2ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
(meta
55
(project "snif")
6-
(full-name "SNIFs: Safe Native Implemented Functions for the BEAM via WebAssembly Sandboxing")
6+
(full-name "SNIFs: Safer Native Implemented Functions for the BEAM via WebAssembly Sandboxing")
77
(license "MPL-2.0")
88
(author "Jonathan D.A. Jewell <j.d.a.jewell@open.ac.uk>")
99
(architecture-decisions

CHANGELOG.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,45 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1313
<!-- Run: just changelog -->
1414

1515
## [Unreleased]
16+
17+
### Fixed
18+
- **Formal proofs now actually machine-check.** The 7 Idris2/Lean4 proofs were marked
19+
"100% proven" since 2026-04-16, but `Foreign`/`Platform`/`Compliance` never compiled
20+
(Idris2 unbound-implicit auto-binding; unary-`Nat` blow-up on 65536-scale arithmetic)
21+
and no CI job ever ran a prover. All 6 Idris2 modules + the Lean4 module now pass.
22+
- **Justfile was unparseable by `just`** (line 2 used `//` instead of `#`), which broke
23+
every recipe including `build-wasm` used by the e2e gate. Fixed.
24+
- **Proof gate was decorative.** `just proof-check-*` used a broken `idris2 --check`
25+
invocation (no `--source-dir`, never resolved the `ABI.*` graph) and silently passed
26+
when the prover was absent (SKIP = exit 0). Now uses the correct invocation and
27+
fails-on-skip.
28+
- **`checked_add` doc-comment corrected.** The comment claimed "overflow -> trap" but the body is
29+
`a +% b` (wrapping); the GAP-1b metamorphic gate surfaced the contradiction. The comment now
30+
states the wrapping behaviour accurately (the trapping-overflow demo is `crash_overflow`); the
31+
export name is unchanged.
32+
33+
### Changed
34+
- Project gloss **"Safe NIFs" → "Safer NIFs"** (acronym SNIF unchanged): WASM sandboxing
35+
makes NIFs *safer*, not provably *safe*. Living docs + paper/citation titles updated.
36+
NOTE: the paper carries Zenodo DOI 10.5281/zenodo.19520245 under the old title — the
37+
rename should be reflected on the next Zenodo version/deposit.
38+
- Re-modeled `Platform.idr` WASM memory-size facts over `Integer` (was unary `Nat`).
39+
40+
### Added
41+
- `.github/workflows/proofs.yml` — real CI proof gate (Idris2 + Lean4 via Nix).
42+
- **SNIFs 2 — sharpened verification.** SEC-1 (`SnifIsolation.agda`) now wires confidentiality into
43+
the operational theorem (deniability re-derived over the actual run via `run-deniable` /
44+
`fault-via-observe` + a two-distinct-secret `SecretWitness`), models the real 6-origin error
45+
taxonomy (`TrapOrigin` guestFault / hostBudget / preExec + a `call` front-end + `PreExecWitness`),
46+
and adds a non-trivial-`Alive` recovery witness (`PartialAlive`) — all mutation-confirmed
47+
load-bearing by a 4-skeptic adversarial re-audit (`--safe --without-K`, every targeted mutation
48+
rejected).
49+
- **ABI-7 buffer-guest coverage.** `verification/proofs/idris2/ABI/BufferAbi.idr` models all 7
50+
`buffer_abi` exports (multi-value/void-faithful `WasmSig`), raising gated ABI coverage to 15 of 20
51+
Zig export sites; `verification/tools/abi_conformance.py` is now guest-aware (per-guest model
52+
manifest, multi-value/void parsing). The conformance gate now runs in CI (`proofs.yml`, CI-1).
53+
- **GAP-1b behaviour gate.** `demo/test/snif_metamorphic_test.exs` — dependency-free metamorphic
54+
relations over the scalar kernels (fibonacci recurrence + base cases; `checked_add` `wrap32`
55+
oracle + boundary-wrap).
56+
- `AFFIRMATION.adoc` — point-in-time, ground-truthed honesty snapshot (the README/EXPLAINME/AFFIRMATION
57+
trio); SPDX header parked for the owner to add + sign.

CITATION.cff

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
cff-version: 1.2.0
2-
title: "SNIFs: Safe Native Implemented Functions for the BEAM via WebAssembly Sandboxing"
2+
title: "SNIFs: Safer Native Implemented Functions for the BEAM via WebAssembly Sandboxing"
33
authors:
44
- family-names: Jewell
55
given-names: Jonathan D. A.

EXPLAINME.adoc

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
:toc: preamble
55
:icons: font
66

7-
This file provides code-level evidence and implementation details for the SNIF (Safe Native Implemented Functions) architecture.
7+
This file provides code-level evidence and implementation details for the SNIF (Safer Native Implemented Functions) architecture.
88

99
== Claim-to-implementation map
1010

@@ -28,20 +28,53 @@ ____
2828
How this is implemented::
2929
The `Justfile` build recipes enforce `-OReleaseSafe` for all `priv/*.wasm` artifacts, ensuring that bounds checks are preserved in the binary.
3030

31-
== Relationship to Groove/Cleave
31+
== Scope ceiling: a safer NIF, and nothing past it
3232

33-
SNIFs provide the **Physical Cleave Surface**. While the **Groove Protocol** defines "how services talk" (communication), the SNIF architecture defines **"how they touch"** (integration). By sandboxing native code in WASM, we ensure that the "join" between high-performance logic and the safe host environment is mathematically isolated and safe to "split."
33+
SNIF deliberately stops at *NIF-parity + crash-isolation*. The goal is to **adapt and
34+
perfect something that already exists** — the BEAM NIF — for the people who already use
35+
NIFs: a safer, like-for-like drop-in for native compute/buffer functions (see the README
36+
`Scope` section), *not* a new interface paradigm. Capabilities that go **beyond** what a
37+
NIF offers — graduated/tunable integration, capability negotiation, transaction-gating,
38+
permissions that depend on an integration "mode" — are **out of SNIF scope by design**. If
39+
an idea is good but takes us past the NIF goal, it belongs to the *cleave* and *groove*
40+
layers below, and is considered there, not bolted onto SNIF.
3441

35-
== Repository Future: The Universal Pattern Hub
42+
== Relationship to Groove and the Cleave
3643

37-
Per the v0.5 reposystem roadmap, this repository is transitioning from an Elixir-only research project into the **Universal Pattern Hub** for all Safe Native Interfaces across the estate (Rust/SPARK, Zig, and Ada).
44+
Three distinct layers; SNIF is the most conservative of them:
45+
46+
* **SNIF — _perfecting an existing interface._** A SNIF **realizes a residue-clean cleave
47+
_instance_ at one boundary** (BEAM host ↔ native guest): a guest trap becomes
48+
`{:error, reason}`, the BEAM survives, and the error residue carries no recoverable guest
49+
value (the `SnifVerdict` deniability proofs). It is *an* instance of a cleave, **not "the
50+
cleave"** — the earlier phrasing "SNIFs provide the Physical Cleave Surface" overstated
51+
this and is corrected here.
52+
* **Cleave — _the new implementation of graduated integration._** A transmutable surface
53+
you can dial from near-raw FFI-ABI, through the SNIF sandbox (the safe *middle detent*),
54+
to a tight Groove-defined internal-api; closeable to a standalone secure surface. SNIF
55+
sits at the middle; the rest of the dial (transaction-gating, mode-indexed permissions,
56+
the well-founded "staircase" teardown) is **cleave scope, not SNIF scope**.
57+
* **Groove — _something new, to move beyond current interface design._** The protocol for
58+
*how services talk*: capability discovery + typed capability negotiation, soft (pub/sub)
59+
↔ hard (in-process) integration modes. SNIF merely *consumes* Groove as a communication
60+
counterpart, and only at the v0.2 roadmap level — snifs ships no Groove code today.
61+
62+
== Multi-language guests (still within the safer-NIF goal)
63+
64+
The safer-NIF pattern is realizable across guest languages — Zig today, Rust→wasm32 wired,
65+
Ada/SPARK and estate wasm-native languages (typed-wasm/ephapax/affinescript) prospective.
66+
This is *breadth of guest language within the NIF goal*, **not** an expansion of SNIF's
67+
purpose. SNIF is not a "universal interface hub"; that "beyond current interface design"
68+
ambition lives in groove/cleave, not here.
3869

3970
== Evidence Index
4071

4172
[cols="2,3", options="header"]
4273
|===
4374
| Path | Proves
44-
| `zig/src/safe_nif.zig` | Implementation of trapped failure modes.
45-
| `demo/test/snif_test.exs` | Integration tests verifying BEAM survival.
46-
| `manifest.scm` | Guix environment for reproducible WASM builds.
75+
| `zig/src/safe_nif.zig` | Implementation of trapped failure modes (8 exports, ABI-modelled).
76+
| `demo/test/snif_demo_test.exs` | Integration tests verifying BEAM survival across every crash mode.
77+
| `verification/proofs/agda/SnifIsolation.agda` | SEC-1 operational crash-isolation, proven-modulo-explicit-TCB.
78+
| `verification/proofs/agda/SnifVerdict.agda` | Residue-clean (deniability) + non-forgery at the boundary.
79+
| `verification/tools/abi_conformance.py` | Model↔binary ABI drift gate (interface-level).
4780
|===

0 commit comments

Comments
 (0)