Skip to main content

synth_verify/
lib.rs

1//! Formal Verification for Synth Compiler
2//!
3//! This crate provides SMT-based translation validation and property-based testing
4//! to formally verify the correctness of WebAssembly-to-native synthesis.
5//!
6//! # Architecture
7//!
8//! The verification system proves that synthesized native code has
9//! semantically equivalent behavior to the input WASM code, discharging the
10//! QF_BV queries through a thin solver trait ([`solver::BvSolver`], #553):
11//!
12//! - **Default engine:** [`ordeal`] — pure Rust, certificate-checked
13//!   (every `Unsat` verdict carries an LRAT proof validated by the trusted
14//!   `ordeal-lrat` checker). No C++ toolchain required.
15//! - **Differential oracle** (feature `z3-solver`): Z3, the former engine.
16//!   With both backends compiled in and `SYNTH_SOLVER_DIFF=1`, every query
17//!   runs through both — a verdict disagreement is a hard error; an ordeal
18//!   `Unknown` falls through to Z3's verdict.
19//!
20//! ## Backend-Agnostic Traits
21//!
22//! `SourceSemantics` and `TargetSemantics` traits allow any backend to provide
23//! SMT semantics. The ARM semantics are one implementation, behind the `arm`
24//! feature. All semantics encode into the solver-agnostic [`term::BV`] /
25//! [`term::Bool`] terms.
26//!
27//! ## Translation Validation
28//!
29//! For each synthesis rule WASM → target, we construct SMT formulas:
30//! - φ_wasm: Semantics of WASM operations
31//! - φ_target: Semantics of generated target operations
32//! - Prove: ∀inputs. φ_wasm(inputs) ⟺ φ_target(inputs)
33
34// Solver-agnostic terms + the thin solver trait (always available)
35pub mod solver;
36pub mod term;
37
38// Trap-preservation obligations over `ordeal::trap` (VCR-VER-002, #166): maps
39// WASM partial ops (div/rem, load/store, call_indirect, unreachable,
40// float→int trunc) to trap
41// conditions and gates a lowering on preserving them. Backend-agnostic (builds
42// on `term`), so always available like `wasm_semantics`.
43pub mod trap;
44
45// Verification traits (always available)
46pub mod traits;
47
48// WASM semantics — source language for all backends (always available)
49pub mod wasm_semantics;
50
51// Proof-carrying specialization (VCR-PERF-002 / #494 Phase 2): value-range
52// facts ⇒ dead conditional-branch elision, each site behind a per-elision
53// ordeal obligation. Backend-agnostic (rewrites the WasmOp stream), so it is
54// always available like `wasm_semantics`.
55pub mod fact_spec;
56
57// ARM semantics (behind the arm feature)
58#[cfg(feature = "arm")]
59pub mod arm_semantics;
60
61// Translation validator (requires arm for the existing concrete implementation)
62#[cfg(feature = "arm")]
63pub mod translation_validator;
64
65// Validator-pattern prototype (issue #76 — CompCert-style certifying
66// validator scaffolding; see docs/validator-pattern.md).
67#[cfg(feature = "arm")]
68pub mod validator_pattern;
69
70// Expansion-level certifying validation for the i64 pseudo-ops (#667 move 2):
71// decodes the SHIPPED encoder's emitted Thumb-2 bytes and proves them
72// equivalent to the WASM op — see docs/validator-pattern.md.
73#[cfg(feature = "arm")]
74pub mod expansion_validator;
75
76// Property-based testing (requires arm: exercises the ARM synthesis rules)
77#[cfg(feature = "arm")]
78pub mod properties;
79
80#[cfg(feature = "arm")]
81pub use properties::CompilerProperties;
82
83#[cfg(feature = "arm")]
84pub use arm_semantics::{ArmSemantics, ArmState};
85#[cfg(feature = "arm")]
86pub use expansion_validator::{
87    ExpansionError, ExpansionWitness, covered_i64_pseudo_selections, validate_expansion,
88};
89pub use fact_spec::{FactSpecResult, specialize_function};
90pub use solver::{BvSolver, CheckOutcome, OrdealSolver, new_solver};
91pub use term::{BV, Bool};
92#[cfg(feature = "arm")]
93pub use translation_validator::{
94    CallIndirectSpec, TranslationValidator, ValidationResult, VerificationError,
95};
96#[cfg(feature = "arm")]
97pub use validator_pattern::{
98    CertifiedSelection, SolverResultKind, ValidationError as PatternValidationError, Validator,
99    Witness, Z3ArmValidator,
100};
101pub use wasm_semantics::WasmSemantics;
102
103/// Run verification operations in a configured context.
104///
105/// With the default (ordeal) engine this is a plain call — the pure-Rust
106/// solver needs no global context. With the `z3-solver` feature compiled in,
107/// it additionally configures the Z3 thread-local context (30-second timeout,
108/// model generation) so the differential oracle is ready.
109pub fn with_verification_context<F, R>(f: F) -> R
110where
111    F: FnOnce() -> R + Send + Sync,
112    R: Send + Sync,
113{
114    #[cfg(feature = "z3-solver")]
115    {
116        with_z3_context(f)
117    }
118    #[cfg(not(feature = "z3-solver"))]
119    {
120        f()
121    }
122}
123
124/// Run verification operations with a configured Z3 context.
125///
126/// Z3 0.19 uses thread-local context — this function configures it
127/// with a 30-second timeout and model generation enabled.
128#[cfg(feature = "z3-solver")]
129pub fn with_z3_context<F, R>(f: F) -> R
130where
131    F: FnOnce() -> R + Send + Sync,
132    R: Send + Sync,
133{
134    let mut cfg = z3::Config::new();
135    cfg.set_timeout_msec(30000); // 30 second timeout
136    cfg.set_model_generation(true);
137    z3::with_z3_config(&cfg, f)
138}
139
140/// Create a Z3 solver with default configuration (differential-oracle use)
141#[cfg(feature = "z3-solver")]
142pub fn create_solver() -> z3::Solver {
143    z3::Solver::new()
144}
145
146#[cfg(test)]
147mod tests {
148    use super::*;
149
150    #[test]
151    fn test_default_solver_decides() {
152        with_verification_context(|| {
153            let mut solver = new_solver();
154            let x = BV::new_const("x", 32);
155            solver.assert(&x.eq(&x).not());
156            assert_eq!(solver.check(), CheckOutcome::Unsat);
157        });
158    }
159
160    #[cfg(feature = "z3-solver")]
161    #[test]
162    fn test_z3_context_creation() {
163        with_z3_context(|| {
164            let solver = create_solver();
165            assert_eq!(solver.check(), z3::SatResult::Sat);
166        });
167    }
168}