{"id":51371100,"url":"https://github.com/pulseengine/ordeal","last_synced_at":"2026-07-03T07:00:36.580Z","repository":{"id":368703847,"uuid":"1286438909","full_name":"pulseengine/ordeal","owner":"pulseengine","description":"Ordeal — a pure-Rust, certificate-checked QF_BV SMT solver for the PulseEngine toolchain. Untrusted solver + formally-verified LRAT checker (CompCert pattern), wasm32-wasip2-native. Part of the PulseEngine toolchain.","archived":false,"fork":false,"pushed_at":"2026-07-03T06:00:20.000Z","size":305,"stargazers_count":1,"open_issues_count":3,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-07-03T07:00:13.827Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pulseengine.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":"ROADMAP.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-07-01T19:31:33.000Z","updated_at":"2026-07-03T06:00:26.000Z","dependencies_parsed_at":"2026-07-03T07:00:25.034Z","dependency_job_id":null,"html_url":"https://github.com/pulseengine/ordeal","commit_stats":null,"previous_names":["pulseengine/ordeal"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/pulseengine/ordeal","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pulseengine%2Fordeal","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pulseengine%2Fordeal/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pulseengine%2Fordeal/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pulseengine%2Fordeal/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pulseengine","download_url":"https://codeload.github.com/pulseengine/ordeal/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pulseengine%2Fordeal/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35075805,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-03T02:00:05.635Z","response_time":110,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-07-03T07:00:18.085Z","updated_at":"2026-07-03T07:00:36.542Z","avatar_url":"https://github.com/pulseengine.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n# Ordeal\n\n\u003csup\u003eA certificate-checked QF_BV SMT solver for the PulseEngine toolchain\u003c/sup\u003e\n\n\u0026nbsp;\n\n![Rust](https://img.shields.io/badge/Rust-CE422B?style=flat-square\u0026logo=rust\u0026logoColor=white\u0026labelColor=1a1b27)\n![License: Apache-2.0](https://img.shields.io/badge/License-Apache--2.0-blue?style=flat-square\u0026labelColor=1a1b27)\n\n\u0026nbsp;\n\n\u003ch6\u003e\n  \u003ca href=\"https://github.com/pulseengine/meld\"\u003eMeld\u003c/a\u003e\n  \u0026middot;\n  \u003ca href=\"https://github.com/pulseengine/loom\"\u003eLoom\u003c/a\u003e\n  \u0026middot;\n  \u003ca href=\"https://github.com/pulseengine/synth\"\u003eSynth\u003c/a\u003e\n  \u0026middot;\n  \u003ca href=\"https://github.com/pulseengine/ordeal\"\u003eOrdeal\u003c/a\u003e\n  \u0026middot;\n  \u003ca href=\"https://github.com/pulseengine/kiln\"\u003eKiln\u003c/a\u003e\n  \u0026middot;\n  \u003ca href=\"https://github.com/pulseengine/sigil\"\u003eSigil\u003c/a\u003e\n\u003c/h6\u003e\n\n\u003c/div\u003e\n\n\u0026nbsp;\n\nOrdeal (meaning \"verdict / judgment\") is a specialized, **certificate-checked** QF_BV SMT solver. It decides bitvector equivalence and satisfiability queries for the [PulseEngine](https://github.com/pulseengine) toolchain — specifically the queries that [loom](https://github.com/pulseengine/loom) (verified WASM optimizer) and [synth](https://github.com/pulseengine/synth) (verified WASM→ARM codegen) actually emit.\n\n**Status (v0.4.1, on [crates.io](https://crates.io/crates/ordeal)).** The engine is live: the full bit-blast → AIG → Tseitin CNF → pure-Rust CDCL → LRAT pipeline decides the closed QF_BV fragment. `Sat` verdicts carry a self-checked counterexample model; `Unsat` verdicts carry an LRAT certificate that the `ordeal-lrat` checker validated before the verdict was returned; `Unknown` stays conservative (never optimize on it). The array/UF sliver (`Solver::check_sliver`), a bool→BV `ite` bridge, derived-op lowering helpers, and a resource-bounded `check_with_limit` are all available. A minimal SMT-LIB2 front-end (`ordeal check foo.smt2`) reads the QF_BV subset loom/synth emit. The one remaining soundness obligation is the checker's formal proof (Rust → Lean 4 via Aeneas, issue #12); until it discharges, trust rests on the small, dependency-free, mutation-tested Rust checker — still strictly stronger than trusting the solver.\n\nPart of PulseEngine — a WebAssembly toolchain for safety-critical embedded systems:\n\n| Project | Role |\n|---------|------|\n| [**Loom**](https://github.com/pulseengine/loom) | WASM optimizer with SMT verification |\n| [**Synth**](https://github.com/pulseengine/synth) | WASM-to-ARM AOT compiler with Rocq proofs |\n| [**Ordeal**](https://github.com/pulseengine/ordeal) | Certificate-checked QF_BV SMT solver |\n| [**Meld**](https://github.com/pulseengine/meld) | WASM Component Model static fuser |\n| [**Kiln**](https://github.com/pulseengine/kiln) | WASM runtime for safety-critical systems |\n| [**Sigil**](https://github.com/pulseengine/sigil) | Supply chain attestation and signing |\n\n## Why ordeal exists\n\nLoom and synth both verify their transformations with an SMT solver, and both pay for it in build pain: statically linking Z3 is a recurring source of toolchain friction (header discovery, `Z3_SYS_Z3_HEADER`, `LIBRARY_PATH`, cross-compilation to `wasm32`, reproducibility). This is filed as **loom issue #246**.\n\nThe deeper problem is a *trust* problem, not just a build problem: Z3 is a large, fast, general-purpose solver, and when it says \"UNSAT\" we take it on faith. For a toolchain whose whole pitch is *provably correct* transformation, \"trust the big C++ solver\" is an uncomfortable link in the chain.\n\nOrdeal fixes both:\n\n- **Build pain:** a pure-Rust default build with **zero external dependencies**. No Z3 to link. The default build is also **`wasm32-wasip2`-clean**, so loom/synth can verify in-process even when compiled to a WebAssembly component.\n- **Trust:** the solver is **untrusted**. It emits a machine-checkable certificate that a small, formally-verified checker validates. Only the checker is trusted.\n\n## Architecture in brief\n\nOrdeal follows the **certifying-algorithm** pattern (CompCert-style; blueprint = Lean 4's `bv_decide`, OOPSLA 2025):\n\n\u003e An **untrusted solver** produces an answer *plus a proof*. A **formally-verified checker** validates the proof. A bug in the (large, fast, evolving) solver can at worst make it fail to produce a valid certificate — it can never make a wrong answer be accepted.\n\nFor an UNSAT verdict the proof is an **LRAT certificate**; the verified checker replays it. Only the checker is in the trusted computing base.\n\n**How the checker gets verified.** The checker is written in Rust and translated to **Lean 4 via [Aeneas](https://github.com/AeneasVerif/aeneas)**, where its soundness theorem (*accept ⇒ UNSAT*) is discharged — the \"not lots of hand-math\" path. This is the chosen route; the alternative of writing the checker directly in Lean (the `bv_decide` style) is kept as a documented fallback. The Lean side is built with the org's `rules_lean` (reserved in `MODULE.bazel`).\n\n```\nterm graph → bit-blast → AIG → CNF (Tseitin) → SAT → LRAT → verified checker\n```\n\n- **SAT core — we own it.** The primary engine on **every** target (including `wasm32-wasip2`) is **ordeal's own pure-Rust CDCL solver** — FFI-free, permissively licensed, LRAT-emitting. This is a deliberate full-control decision: no off-the-shelf pure-Rust core is simultaneously maintained, permissive, and LRAT-emitting (varisat is stale, splr is MPL/DRAT-only, CreuSAT is the wrong shape), so owning it is the only way to satisfy wasip2 **and** certificate-checking together. Native **CaDiCaL** (C++ via FFI) is an *optional accelerator/benchmark only* — `cfg`-gated off on wasm, never load-bearing. The default build carries no external solver, so it stays zero-dep and wasip2-clean.\n- **Z3 is a differential oracle + benchmark rival, not the engine.** During development/CI, queries can be cross-checked against Z3 (behind the off-by-default `oracle` feature); any disagreement is a bug. Z3 is *not* part of the soundness argument, and a later phase drops it from soundness reasoning entirely.\n\nSee [ARCHITECTURE.md](ARCHITECTURE.md) for the full pipeline and trust boundary.\n\n### An honest note on \"beating Z3\"\n\nOrdeal does **not** aim to out-solve Z3's SAT engine — Z3 is world-class and we will not beat it at raw SAT. The win is **amortized per-op integration latency**: ordeal runs *in-process*, with no SMT-LIB text to emit and parse, no process spawn, and no general theory-combination machinery for a fragment that never needs it. For the tight, repeated, small equivalence queries loom and synth emit, that integration overhead dominates — and that is what ordeal removes.\n\n## Scope: the closed fragment\n\nOrdeal decides a deliberately **closed** QF_BV fragment (widths 8 / 32 / 64):\n\n- **Bitvector ops:** `bvadd`, `bvsub`, `bvmul`, `bvudiv`, `bvand`, `bvor`, `bvxor`, `bvshl`, `bvlshr`, `bvashr`, `bvrotr`, `extract{hi,lo}`, `concat`, `zero_ext{by}`, `sign_ext{by}`.\n- **Boolean predicates** (what you assert/check): `eq`, `ne`, `ult`, `ule`, `ugt`, `uge`, `slt`, `sle`, `sgt`, `sge`, plus `not` / `and` / `or`.\n- **Query shape:** one-shot `check-sat` expecting **UNSAT** (equivalence), returning a **counterexample model** when SAT.\n\nA later **sliver** (represented today as a TODO in `term.rs`, not implemented): non-extensional `Array(BV32 → BV8)` select/store, plus uninterpreted `pure_call` congruence.\n\n**Not in scope:** quantifiers, floating-point, `Optimize`, incremental solving.\n\n## Quickstart\n\nRequires Rust (edition 2024). The default build has no external dependencies.\n\n```bash\ngit clone https://github.com/pulseengine/ordeal.git\ncd ordeal\ncargo build\ncargo test\n\n# Development-only: enable the Z3 differential oracle feature\ncargo build --features oracle\n\n# Run the CLI banner (documents the check subcommand)\ncargo run --bin ordeal\n\n# Decide an SMT-LIB2 file (QF_BV subset), or read from stdin with `-`\ncargo run --bin ordeal -- check query.smt2\necho '(declare-const x (_ BitVec 32))(assert (= x #x0000002a))(check-sat)(get-model)' \\\n  | cargo run --bin ordeal -- check -\n# → sat\n#   ((x #x0000002a))\n```\n\nThe primary production interface remains the Rust API; the `check` subcommand is\na convenience/front-end for SMT-LIB2 text. Any construct outside the closed\nQF_BV subset is reported as `unsupported: \u003cwhat\u003e` and exits non-zero — the\ncertificate-checked solver never guesses.\n\n### wasm32-wasip2 (first-class target)\n\nloom self-optimizes as a WebAssembly component and embeds ordeal in-process, so\n`wasm32-wasip2` is a **first-class, CI-gated build target** — not an\nafterthought. Ordeal's own pure-Rust CDCL core is the engine here (as on every\ntarget); the optional native CaDiCaL accelerator is `cfg`-gated out.\n\n```bash\nrustup target add wasm32-wasip2\ncargo build --target wasm32-wasip2 --release\n```\n\n### Bazel (org build)\n\nOrdeal also builds with the PulseEngine org Bazel rules (`rules_rust` for the\ncrate, `rules_wasm_component` for the wasip2 component; `rules_lean` reserved\nfor the future verified checker):\n\n```bash\nbazel build //...                         # native library + CLI\nbazel build --config=wasm //crates/ordeal # wasm32-wasip2 component (once a WIT world exists)\n```\n\nThe Bazel job is advisory in CI; the enforced wasip2 gate is the cargo command\nabove.\n\nLibrary sketch:\n\n```rust\nuse ordeal::{Solver, BoolTerm, BvTerm, Sort, CheckResult};\n\nlet bv32 = Sort::new(32);\nlet x = BvTerm::Var { name: \"x\".into(), sort: bv32 };\n\nlet mut s = Solver::new();\ns.assert(BoolTerm::Eq(Box::new(x.clone()), Box::new(x)));\n\nmatch s.check() {\n    CheckResult::Unsat(cert) =\u003e { /* equivalence holds; validate cert */ }\n    CheckResult::Sat(model)  =\u003e { /* counterexample in model */ }\n    CheckResult::Unknown     =\u003e { /* MUST treat conservatively: do not optimize */ }\n}\n```\n\nThe crate is published as [`ordeal`](https://crates.io/crates/ordeal) on crates.io.\n\n## Roadmap\n\nFull detail in [ROADMAP.md](ROADMAP.md). Summary:\n\n| Phase | Goal |\n|-------|------|\n| **P0** | Skeleton: closed fragment types, conservative `Unknown` solver, CI. |\n| **P1** | Bit-blaster: fragment → AIG → CNF (Tseitin); SAT backend integrated. |\n| **P2** | **Certificate-checked solver:** LRAT emission + formally-verified checker. Z3 demoted to oracle/benchmark. |\n| **P3** | The array/UF sliver; loom \u0026 synth integrated as first callers. |\n| **P4** | **Drop Z3 from the soundness argument** — trust rests on the verified checker alone. |\n| **P5** | Performance: amortized per-op latency at or below the Z3 integration path. |\n\n## Related issues\n\n- loom [#246](https://github.com/pulseengine/loom/issues/246) — Z3 build pain (the grounding for ordeal).\n- loom [#231](https://github.com/pulseengine/loom/issues/231) — verification tiering.\n- synth [#76](https://github.com/pulseengine/synth/issues/76) — Z3 translation-validation integration.\n- synth [#494](https://github.com/pulseengine/synth/issues/494) — SMT backend for codegen verification.\n\n## License\n\nApache-2.0 — see [LICENSE](LICENSE).\n\n---\n\n\u003cdiv align=\"center\"\u003e\n\n\u003csub\u003ePart of \u003ca href=\"https://github.com/pulseengine\"\u003ePulseEngine\u003c/a\u003e \u0026mdash; WebAssembly toolchain for safety-critical systems\u003c/sub\u003e\n\n\u003c/div\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpulseengine%2Fordeal","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpulseengine%2Fordeal","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpulseengine%2Fordeal/lists"}