Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
32 changes: 32 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -249,3 +249,35 @@ jobs:
working-directory: tests/charon_llbc
run: bazel test //:hello_verified --test_output=errors
timeout-minutes: 30

relay-coverage:
name: Aeneas coverage — real relay primitive (Linux)
runs-on: [self-hosted, linux, x64, rust-cpu]
steps:
- uses: actions/checkout@v4
- uses: bazelbuild/setup-bazelisk@v3
- uses: actions/cache@v4
with:
path: ~/.cache/bazel
key: bazel-relaycov-${{ runner.os }}-${{ hashFiles('tests/relay_coverage/MODULE.bazel') }}
restore-keys: bazel-relaycov-${{ runner.os }}-
# Translate a real relay `plain` primitive (CRC32) to Lean and print it —
# coverage discovery for relay's verification-oriented Rust.
- name: Translate relay CRC32 (Rust -> LLBC -> Lean)
id: translate
working-directory: tests/relay_coverage
run: bazel build //:crc32_lean_check
timeout-minutes: 20
continue-on-error: true
- name: Show Aeneas output (full on success, partial on error)
working-directory: tests/relay_coverage
run: |
echo "===== Aeneas-generated Lean (may be partial if it errored) ====="
# no-sandbox action writes into out_dir even when it errors mid-way.
f=$(find bazel-bin bazel-out -name 'Crc32Llbc.lean' 2>/dev/null | head -1)
[ -n "$f" ] && cat "$f" || echo "(no output produced)"
- name: Fail if translation failed
if: steps.translate.outcome != 'success'
run: |
echo "Aeneas translation of relay CRC32 did not succeed (see partial output above)."
exit 1
34 changes: 34 additions & 0 deletions tests/relay_coverage/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
load("@rules_lean//aeneas:defs.bzl", "aeneas_translate", "charon_llbc")

# Aeneas coverage experiment on a real relay primitive (CRC32).
# Rust -> LLBC (Charon) -> Lean (Aeneas). Translate-only: reveals what Aeneas
# can handle from relay's `plain` verification code, without the heavy compile.
charon_llbc(
name = "crc32_llbc",
srcs = ["src/lib.rs"],
crate_name = "crc32",
crate_root = "src/lib.rs",
)

aeneas_translate(
name = "crc32_lean",
srcs = [":crc32_llbc"],
)

# Assert Aeneas produced a non-empty module.
genrule(
name = "crc32_lean_check",
srcs = [":crc32_lean"],
outs = ["crc32_lean_check.stamp"],
cmd = """
set -euo pipefail
LEAN=$(SRCS)
if [ ! -s "$$LEAN" ]; then
echo "ERROR: aeneas produced an empty module at $$LEAN" >&2
exit 1
fi
echo "aeneas translated relay CRC32 -> $$LEAN ($$(wc -c < "$$LEAN") bytes)"
echo "OK" > $@
""",
testonly = True,
)
46 changes: 46 additions & 0 deletions tests/relay_coverage/MODULE.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
module(name = "test_relay_coverage", version = "0.0.0")

bazel_dep(name = "rules_lean", version = "0.1.0")
local_path_override(
module_name = "rules_lean",
path = "../..",
)

bazel_dep(name = "bazel_skylib", version = "1.7.1")
bazel_dep(name = "platforms", version = "0.0.11")
bazel_dep(name = "rules_shell", version = "0.3.0")

# Charon + Aeneas binary toolchains (translate-only; no lean toolchain needed).
aeneas = use_extension("@rules_lean//aeneas:extensions.bzl", "aeneas")
aeneas.charon_toolchain(
version = "build-2026.04.22.081730-2d35584fb79ef804c50f106d8c40bd3728284f8d",
)
aeneas.toolchain(
version = "build-2026.04.22.084123-1a8946778f0934266d63564c2aac74ec1fff4b68",
rev = "1a8946778f0934266d63564c2aac74ec1fff4b68",
lean_version = "4.28.0-rc1",
sha256 = {
"macos_aarch64": "62393cd005c67290fc38cf0e4361f9bf242b73e695aa1777bd7685023a60db09",
"macos_x86_64": "6320148064af0c98c556f27c66077309869e585da449776c53dde65d21da6ae2",
"linux_x86_64": "f0b9e245c11eae567ab57317e91fca3fc090a246d2ebdb8d618d8d70b90c8ecc",
},
)

use_repo(
aeneas,
"charon_toolchains",
"charon_macos_aarch64",
"charon_macos_x86_64",
"charon_linux_x86_64",
"charon_linux_aarch64",
"aeneas_toolchains",
"aeneas_macos_aarch64",
"aeneas_macos_x86_64",
"aeneas_linux_x86_64",
"aeneas_lean_lib",
)

register_toolchains(
"@charon_toolchains//:all",
"@aeneas_toolchains//:all",
)
46 changes: 46 additions & 0 deletions tests/relay_coverage/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//! Aeneas coverage experiment: a REAL relay primitive translated verbatim.
//!
//! Source: pulseengine/relay `crates/relay-primitives/plain/src/crc32.rs`
//! (test module stripped). Exercises features beyond the trivial example:
//! a const-eval array, `&[u8]` slices, indexing, `as` casts, `%`, bit ops,
//! `while` loops. The point is to discover what Aeneas can translate from
//! relay's verification-oriented `plain` code.

/// CRC32 lookup table for polynomial 0xEDB88320 (standard reflected).
///
/// WORKAROUND: computed by a runtime fn instead of a `const`. Aeneas
/// (build-2026.04.22) hits an internal error translating the const-eval'd
/// global array form (the identical body as a `const` fails at src/lib.rs:10).
pub fn crc32_table() -> [u32; 256] {
let mut table = [0u32; 256];
let mut i: usize = 0;
while i < 256 {
let mut crc: u32 = i as u32;
let mut j: usize = 0;
while j < 8 {
if crc & 1 != 0 {
crc = (crc >> 1) ^ 0xEDB8_8320u32;
} else {
crc = crc >> 1;
}
j = j + 1;
}
table[i] = crc;
i = i + 1;
}
table
}

/// Compute CRC32 over a byte slice. Pure, deterministic, total.
pub fn crc32_compute(data: &[u8]) -> u32 {
let table = crc32_table();
let mut crc: u32 = 0xFFFF_FFFFu32;
let mut i: usize = 0;
while i < data.len() {
let byte = data[i];
let raw_index = ((crc ^ (byte as u32)) % 256u32) as usize;
crc = (crc >> 8) ^ table[raw_index];
i = i + 1;
}
crc ^ 0xFFFF_FFFFu32
}
Loading