Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
743e983
chore(deps): bump rules_rocq_rust to e4660cc (rules_rust migration)
avrabe May 23, 2026
1e731fb
build(bazel): migrate MODULE.bazel for rules_rocq_rust rules_rust API
avrabe May 23, 2026
d17e558
build(bazel): rename @rocq_of_rust_source → @rocq_of_rust_build
avrabe May 24, 2026
155381f
fix(proofs): decode_uleb128_small replace pattern after Rocq 9.0 simp…
avrabe May 24, 2026
47b45f6
fix(proofs): StackSignature rev_involutive orientation for Rocq 9.0
avrabe May 24, 2026
9042f2e
fix(proofs): subdir-qualify Require Import paths for new rocq_library
avrabe May 25, 2026
3008dbb
fix(proofs): StackSignature replace pattern after Rocq 9.0 simpl unfo…
avrabe May 25, 2026
672a4b5
fix(proofs): tolerate Rocq 9.0 simpl pre-reducing Nat.sub_0_r at line…
avrabe May 26, 2026
4834176
fix(proofs): wrap remaining compose_empty_right rewrites with try
avrabe May 27, 2026
a198044
fix(proofs): correct From/Import split for subdir-qualified modules
avrabe May 27, 2026
277627f
fix(proofs): reduce rev (rev rs ++ [r0]) in compose_empty_right
avrabe May 28, 2026
3640b98
fix(proofs): split semantics library + prefix-agnostic Require Import
avrabe May 28, 2026
fb2a0ba
fix(proofs): clear residual ++ [] after rev reduction in compose_empt…
avrabe May 29, 2026
48ed53d
fix(proofs): adopt meld include_path idiom for inter-file rocq deps
avrabe May 29, 2026
d609a31
fix(proofs): Roundtrip.v Rocq 9.0 simpl/rewrite nits (locally verified)
avrabe May 30, 2026
3789467
proofs(wip): HasType + canonical_forms foundation for TermSemantics (…
avrabe May 30, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 40 additions & 10 deletions MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -15,38 +15,68 @@ module(
# Requires nix to be installed: sh <(curl -L https://nixos.org/nix/install)
bazel_dep(name = "rules_rocq_rust", version = "0.1.0")

# Override to fetch from GitHub (not yet in BCR)
# Override to fetch from GitHub (not yet in BCR).
# Pinned to e4660cc1b — pulseengine/rules_rocq_rust#34, which migrates
# rocq-of-rust to a hermetic rules_rust toolchain. Replaces the ad-hoc
# cargo build in coq_of_rust/private/repository.bzl that was failing on
# the CI runner with
# `rust-lld: error: unable to find library -lLLVM-19-rust-1.85.0-nightly`
# and kept the Rocq Formal Proofs check red on LOOM main since v1.0.5.
git_override(
module_name = "rules_rocq_rust",
remote = "https://github.com/pulseengine/rules_rocq_rust.git",
commit = "307b65f",
commit = "e4660cc1b",
)

# Rocq toolchain extension (creates internal nixpkgs for bzlmod compatibility)
# Nix integration. rules_rocq_rust declares rules_nixpkgs_core internally
# but its nix_repo is dev_dependency=True there, so the root module must
# configure nixpkgs explicitly. rules_rust, crate_universe, and the
# hermetic Rust nightly+rustc-dev toolchain that the rocq-of-rust build
# needs are already registered (non-dev) by rules_rocq_rust's own
# MODULE.bazel and are inherited automatically.
bazel_dep(name = "rules_nixpkgs_core", version = "0.13.0")

nix_repo = use_extension(
"@rules_nixpkgs_core//extensions:repository.bzl",
"nix_repo",
)
nix_repo.github(
name = "nixpkgs",
org = "NixOS",
repo = "nixpkgs",
# nixos-unstable with Rocq 9.0.1 (2026-04-01).
commit = "6201e203d09599479a3b3450ed24fa81537ebc4e",
sha256 = "",
)
use_repo(nix_repo, "nixpkgs")

# Rocq toolchain extension (uses nixpkgs for a hermetic Rocq/Coq install).
rocq = use_extension("@rules_rocq_rust//rocq:extensions.bzl", "rocq")
rocq.toolchain(
version = "9.0", # Rocq 9.0 for rocq-of-rust compatibility
strategy = "nix", # Hermetic nix-based installation
version = "9.0", # Rocq 9.0.1 (required for the real RocqOfRust library).
strategy = "nix", # Hermetic nix-based installation.
with_rocq_of_rust_deps = True, # Include coqutil, hammer, smpl.
)
use_repo(
rocq,
"rocq_coqutil",
"rocq_hammer",
"rocq_hammer_tactics",
"rocq_nixpkgs",
"rocq_smpl",
"rocq_stdlib",
"rocq_toolchains",
)

register_toolchains("@rocq_toolchains//:all")

# rocq-of-rust toolchain for translating Rust to Rocq
# rocq-of-rust toolchain — translates Rust subset to Rocq. Built
# hermetically through rules_rust + crate_universe in the upstream
# ruleset (see rules_rocq_rust@e4660cc1b's MODULE.bazel and
# docs/rules_rust-migration.md).
rocq_of_rust = use_extension("@rules_rocq_rust//coq_of_rust:extensions.bzl", "rocq_of_rust")
rocq_of_rust.toolchain(
commit = "858907dbee116c51d7c6e87511bf5f92d6432ba4", # Pinned for reproducibility
use_real_library = True, # Full library with coqutil/hammer/smpl
use_real_library = True, # Full library with coqutil + hammer + smpl.
)
use_repo(rocq_of_rust, "rocq_of_rust_toolchains", "rocq_of_rust_source")
use_repo(rocq_of_rust, "rocq_of_rust_toolchains", "rocq_of_rust_build")

register_toolchains("@rocq_of_rust_toolchains//:toolchain")
53 changes: 37 additions & 16 deletions proofs/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,47 @@ load("@rules_rocq_rust//rocq:defs.bzl", "rocq_library", "rocq_proof_test")
# Core Semantic Model
# =============================================================================

# WebAssembly and Term semantics (combined for module resolution)
# WebAssembly semantics — base layer, no intra-proof dependencies.
#
# The whole inter-dependent proof group (semantics + simplify +
# correctness) shares the logical prefix `LoomProofs` via include_path,
# and the .v files import each other as `From LoomProofs Require Import
# <Module>`. This is the idiom the pulseengine/meld proofs use
# (proofs/spec/BUILD.bazel: include_path = "MeldSpec" on every library,
# `From MeldSpec Require Import ...`). It is required because the
# rules_rocq_rust rocq_library rule (@e4660cc1b) maps a library's .vo
# under `-Q <output_dir> <include_path>`; a shared explicit include_path
# gives every library a STABLE logical prefix independent of Bazel's
# per-target output-dir layout, so a dependent's `From LoomProofs
# Require Import WasmSemantics` resolves against the dep's .vo wired in
# through `deps`. The package-derived default prefix did not, because
# the .v files live in subdirectories of the BUILD package.
rocq_library(
name = "semantics",
srcs = [
"semantics/WasmSemantics.v",
"semantics/TermSemantics.v",
],
visibility = ["//visibility:public"],
)

# Aliases for backwards compatibility
alias(
name = "wasm_semantics",
actual = ":semantics",
srcs = ["semantics/WasmSemantics.v"],
include_path = "LoomProofs",
visibility = ["//visibility:public"],
)

alias(
# Term (ISLE) semantics — depends on WasmSemantics. One library per .v
# file; the cross-file dependency is wired through `deps` (which makes
# the dep's .vo a coqc input and adds its -Q loadpath).
rocq_library(
name = "term_semantics",
actual = ":semantics",
srcs = ["semantics/TermSemantics.v"],
deps = [":wasm_semantics"],
include_path = "LoomProofs",
visibility = ["//visibility:public"],
)

rocq_proof_test(
name = "semantics_test",
deps = [":semantics"],
name = "wasm_semantics_test",
deps = [":wasm_semantics"],
)

rocq_proof_test(
name = "term_semantics_test",
deps = [":term_semantics"],
)

# =============================================================================
Expand All @@ -44,6 +59,7 @@ rocq_library(
":wasm_semantics",
":term_semantics",
],
include_path = "LoomProofs",
visibility = ["//visibility:public"],
)

Expand All @@ -60,6 +76,7 @@ rocq_library(
":wasm_semantics",
":term_semantics",
],
include_path = "LoomProofs",
visibility = ["//visibility:public"],
)

Expand All @@ -76,6 +93,7 @@ rocq_library(
":wasm_semantics",
":term_semantics",
],
include_path = "LoomProofs",
visibility = ["//visibility:public"],
)

Expand All @@ -92,6 +110,7 @@ rocq_library(
":wasm_semantics",
":term_semantics",
],
include_path = "LoomProofs",
visibility = ["//visibility:public"],
)

Expand All @@ -111,6 +130,7 @@ rocq_library(
":wasm_semantics",
":term_semantics",
],
include_path = "LoomProofs",
visibility = ["//visibility:public"],
)

Expand All @@ -134,6 +154,7 @@ rocq_library(
":bitwise",
":strength_reduction",
],
include_path = "LoomProofs",
visibility = ["//visibility:public"],
)

Expand Down
12 changes: 6 additions & 6 deletions proofs/Correctness.v
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ From Stdlib Require Import Arith.
From Stdlib Require Import List.
From Stdlib Require Import ZArith.
From Stdlib Require Import Lia.
From proofs Require Import WasmSemantics.
From proofs Require Import TermSemantics.
From proofs Require Import ConstantFolding.
From proofs Require Import Identity.
From proofs Require Import Bitwise.
From proofs Require Import StrengthReduction.
From LoomProofs Require Import WasmSemantics.
From LoomProofs Require Import TermSemantics.
From LoomProofs Require Import ConstantFolding.
From LoomProofs Require Import Identity.
From LoomProofs Require Import Bitwise.
From LoomProofs Require Import StrengthReduction.
Import ListNotations.

Open Scope Z_scope.
Expand Down
19 changes: 16 additions & 3 deletions proofs/codec/Roundtrip.v
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,10 @@ Proof.
assert (Nat.ltb n 128 = true) as Hltb.
{ apply Nat.ltb_lt. exact Hlt. }
rewrite Hltb.
replace (0 + n * 1) with n by lia.
(* Rocq 9.0's [simpl] is more aggressive than v1.1.0's pin: it
reduces [0 + n * 1] to [n * 1] here, so the old [replace (0 + n * 1)]
pattern no longer matches. Match the post-simpl shape directly. *)
replace (n * 1) with n by lia.
reflexivity.
Qed.

Expand Down Expand Up @@ -544,7 +547,13 @@ Theorem functypes_roundtrip_n : forall fts rest,
Proof.
induction fts as [|ft fts IH]; intros rest.
- simpl. reflexivity.
- simpl. rewrite <- app_assoc.
- (* Rocq 9.0's [simpl] unfolds the [decode_functype] Definition itself,
leaving no [decode_functype (...)] subterm for [functype_roundtrip]
to rewrite. Use [cbn] restricted to the structural fixpoints
([length], [encode_functypes], [decode_functypes_n]) so the
[decode_functype] CALL is exposed but stays folded. *)
cbn [length encode_functypes decode_functypes_n].
rewrite <- app_assoc.
rewrite functype_roundtrip.
rewrite IH. reflexivity.
Qed.
Expand Down Expand Up @@ -634,7 +643,11 @@ Theorem roundtrip_identity : forall m : ScopedModule,
Proof.
intros [ts fs pt].
unfold encode_scoped, decode_scoped. simpl.
rewrite <- !app_assoc.
(* Rocq 9.0's [simpl] already right-associates the section appends, so
[<- !app_assoc] (one-or-more) finds nothing and errors. [?] makes
the reassociation zero-or-more — a no-op when [simpl] already did it,
still correct on a pin where it didn't. *)
rewrite <- ?app_assoc.
rewrite leb128_roundtrip. simpl.
rewrite functypes_roundtrip_n. simpl.
rewrite leb128_roundtrip. simpl.
Expand Down
2 changes: 1 addition & 1 deletion proofs/rust_verified/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ load("@rules_rocq_rust//rocq:defs.bzl", "rocq_library")
# RocqOfRust library - provides the core types needed by translated code
alias(
name = "rocq_of_rust_lib",
actual = "@rocq_of_rust_source//:rocq_of_rust_main",
actual = "@rocq_of_rust_build//:rocq_of_rust_main",
)

# =============================================================================
Expand Down
95 changes: 94 additions & 1 deletion proofs/semantics/TermSemantics.v
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ From Stdlib Require Import Arith.
From Stdlib Require Import List.
From Stdlib Require Import ZArith.
From Stdlib Require Import Lia.
From proofs Require Import WasmSemantics.
From LoomProofs Require Import WasmSemantics.
Import ListNotations.

Open Scope Z_scope.
Expand Down Expand Up @@ -939,6 +939,99 @@ Qed.
adding a precondition that all term values are wrapped, or by having
TI32Const always store wrapped values.
*)
(** * Well-typedness (loom#141 / TermSemantics fix)

[simplify]'s identity arms (x+0=x, 0+x=x, x-0=x, …) drop the zero
operand WITHOUT a type check, so on a mixed-width term the [Term]
type permits but well-typed wasm never produces — e.g.
[TI32Add (TI32Const 0) (TI64Const z)] — the original [eval_term]
traps ([TRFail], operands aren't both [VI32]) while the simplified
form yields [VI64 z]. So [simplify_preserves_semantics] is FALSE for
arbitrary terms. We restrict it to well-typed terms via [HasType],
which mirrors wasm's static typing: every operator constrains its
operands' types and fixes its result type (comparisons produce i32
even on i64 operands; [TDrop]/[TNop] produce no value and so have no
[HasType] rule). *)
Inductive HasType : Term -> ValueType -> Prop :=
(* Constants *)
| HT_I32Const : forall v, HasType (TI32Const v) TI32
| HT_I64Const : forall v, HasType (TI64Const v) TI64
(* i32 arithmetic + bitwise + shifts: (i32, i32) -> i32 *)
| HT_I32Add : forall l r, HasType l TI32 -> HasType r TI32 -> HasType (TI32Add l r) TI32
| HT_I32Sub : forall l r, HasType l TI32 -> HasType r TI32 -> HasType (TI32Sub l r) TI32
| HT_I32Mul : forall l r, HasType l TI32 -> HasType r TI32 -> HasType (TI32Mul l r) TI32
| HT_I32And : forall l r, HasType l TI32 -> HasType r TI32 -> HasType (TI32And l r) TI32
| HT_I32Or : forall l r, HasType l TI32 -> HasType r TI32 -> HasType (TI32Or l r) TI32
| HT_I32Xor : forall l r, HasType l TI32 -> HasType r TI32 -> HasType (TI32Xor l r) TI32
| HT_I32Shl : forall l r, HasType l TI32 -> HasType r TI32 -> HasType (TI32Shl l r) TI32
| HT_I32ShrS : forall l r, HasType l TI32 -> HasType r TI32 -> HasType (TI32ShrS l r) TI32
| HT_I32ShrU : forall l r, HasType l TI32 -> HasType r TI32 -> HasType (TI32ShrU l r) TI32
(* i64 arithmetic + bitwise + shifts: (i64, i64) -> i64 *)
| HT_I64Add : forall l r, HasType l TI64 -> HasType r TI64 -> HasType (TI64Add l r) TI64
| HT_I64Sub : forall l r, HasType l TI64 -> HasType r TI64 -> HasType (TI64Sub l r) TI64
| HT_I64Mul : forall l r, HasType l TI64 -> HasType r TI64 -> HasType (TI64Mul l r) TI64
| HT_I64And : forall l r, HasType l TI64 -> HasType r TI64 -> HasType (TI64And l r) TI64
| HT_I64Or : forall l r, HasType l TI64 -> HasType r TI64 -> HasType (TI64Or l r) TI64
| HT_I64Xor : forall l r, HasType l TI64 -> HasType r TI64 -> HasType (TI64Xor l r) TI64
| HT_I64Shl : forall l r, HasType l TI64 -> HasType r TI64 -> HasType (TI64Shl l r) TI64
| HT_I64ShrS : forall l r, HasType l TI64 -> HasType r TI64 -> HasType (TI64ShrS l r) TI64
| HT_I64ShrU : forall l r, HasType l TI64 -> HasType r TI64 -> HasType (TI64ShrU l r) TI64
(* i32 comparisons: (i32, i32) -> i32 *)
| HT_I32Eq : forall l r, HasType l TI32 -> HasType r TI32 -> HasType (TI32Eq l r) TI32
| HT_I32Ne : forall l r, HasType l TI32 -> HasType r TI32 -> HasType (TI32Ne l r) TI32
| HT_I32LtS : forall l r, HasType l TI32 -> HasType r TI32 -> HasType (TI32LtS l r) TI32
| HT_I32LtU : forall l r, HasType l TI32 -> HasType r TI32 -> HasType (TI32LtU l r) TI32
| HT_I32GtS : forall l r, HasType l TI32 -> HasType r TI32 -> HasType (TI32GtS l r) TI32
| HT_I32GtU : forall l r, HasType l TI32 -> HasType r TI32 -> HasType (TI32GtU l r) TI32
| HT_I32LeS : forall l r, HasType l TI32 -> HasType r TI32 -> HasType (TI32LeS l r) TI32
| HT_I32LeU : forall l r, HasType l TI32 -> HasType r TI32 -> HasType (TI32LeU l r) TI32
| HT_I32GeS : forall l r, HasType l TI32 -> HasType r TI32 -> HasType (TI32GeS l r) TI32
| HT_I32GeU : forall l r, HasType l TI32 -> HasType r TI32 -> HasType (TI32GeU l r) TI32
| HT_I32Eqz : forall t, HasType t TI32 -> HasType (TI32Eqz t) TI32
(* i64 comparisons: (i64, i64) -> i32 (result is i32!) *)
| HT_I64Eq : forall l r, HasType l TI64 -> HasType r TI64 -> HasType (TI64Eq l r) TI32
| HT_I64Ne : forall l r, HasType l TI64 -> HasType r TI64 -> HasType (TI64Ne l r) TI32
| HT_I64LtS : forall l r, HasType l TI64 -> HasType r TI64 -> HasType (TI64LtS l r) TI32
| HT_I64LtU : forall l r, HasType l TI64 -> HasType r TI64 -> HasType (TI64LtU l r) TI32
| HT_I64GtS : forall l r, HasType l TI64 -> HasType r TI64 -> HasType (TI64GtS l r) TI32
| HT_I64GtU : forall l r, HasType l TI64 -> HasType r TI64 -> HasType (TI64GtU l r) TI32
| HT_I64LeS : forall l r, HasType l TI64 -> HasType r TI64 -> HasType (TI64LeS l r) TI32
| HT_I64LeU : forall l r, HasType l TI64 -> HasType r TI64 -> HasType (TI64LeU l r) TI32
| HT_I64GeS : forall l r, HasType l TI64 -> HasType r TI64 -> HasType (TI64GeS l r) TI32
| HT_I64GeU : forall l r, HasType l TI64 -> HasType r TI64 -> HasType (TI64GeU l r) TI32
| HT_I64Eqz : forall t, HasType t TI64 -> HasType (TI64Eqz t) TI32.

(** Canonical forms: a well-typed term evaluates to a value of its type
(never [TRFail]). Proven by induction on the typing derivation; each
operator case uses the IH to fix operand shapes, eliminating the
[TRFail] arms of [eval_term]. *)
Lemma canonical_forms : forall t ty,
HasType t ty ->
(ty = TI32 -> exists a, eval_term t = TROk (VI32 a)) /\
(ty = TI64 -> exists a, eval_term t = TROk (VI64 a)).
Proof.
intros t ty H.
induction H; split; intros Hty; try discriminate Hty; simpl;
repeat match goal with
| [ H : _ /\ _ |- _ ] => destruct H
end;
(* discharge the i32/i64 selectors of each IH using the typing *)
repeat match goal with
| [ H : TI32 = TI32 -> _ |- _ ] => specialize (H eq_refl)
| [ H : TI64 = TI64 -> _ |- _ ] => specialize (H eq_refl)
| [ H : TI64 = TI32 -> _ |- _ ] => clear H
| [ H : TI32 = TI64 -> _ |- _ ] => clear H
end;
repeat match goal with
| [ H : exists a, _ |- _ ] => destruct H
end;
(* rewrite operand evaluations, then the eval match reduces *)
repeat match goal with
| [ H : eval_term _ = _ |- _ ] => rewrite H
end;
eauto.
Qed.

Theorem simplify_preserves_semantics : forall t,
term_equiv t (simplify t).
Proof.
Expand Down
4 changes: 2 additions & 2 deletions proofs/simplify/Bitwise.v
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ From Stdlib Require Import Arith.
From Stdlib Require Import List.
From Stdlib Require Import ZArith.
From Stdlib Require Import Lia.
From proofs Require Import WasmSemantics.
From proofs Require Import TermSemantics.
From LoomProofs Require Import WasmSemantics.
From LoomProofs Require Import TermSemantics.
Import ListNotations.

Open Scope Z_scope.
Expand Down
4 changes: 2 additions & 2 deletions proofs/simplify/ConstantFolding.v
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ From Stdlib Require Import Arith.
From Stdlib Require Import List.
From Stdlib Require Import ZArith.
From Stdlib Require Import Lia.
From proofs Require Import WasmSemantics.
From proofs Require Import TermSemantics.
From LoomProofs Require Import WasmSemantics.
From LoomProofs Require Import TermSemantics.
Import ListNotations.

Open Scope Z_scope.
Expand Down
Loading
Loading