Files
zeekay b0ba9d20bd p3q: add p3q-c-abi crate — callable C ABI for the strict-PQ verifier
Adds a thin extern "C" shim crate that lets non-Rust callers (luxcpp,
multichain-cpp, cevm precompiles) invoke the strict-PQ verifier
without re-implementing the wire format. Single entry point:

    int32_t p3q_verify(const uint8_t* public_input,
                       uintptr_t      public_input_len,
                       const uint8_t* proof,
                       uintptr_t      proof_len);

The shim:

  * validates (ptr, len) pairs (NULL with non-zero len -> P3Q_ERR_NULL_PTR;
    NULL with len=0 is legal and yields an empty slice),
  * forwards to p3q_verifier::verify,
  * maps every P3qError variant onto a stable integer (P3Q_OK,
    P3Q_REJECTED, P3Q_ERR_PARSE, P3Q_ERR_UNSUPPORTED_PROFILE,
    P3Q_ERR_MERKLE, P3Q_ERR_FRI, P3Q_ERR_STARK, P3Q_ERR_TRANSCRIPT,
    P3Q_ERR_FIELD, P3Q_ERR_CIRCUIT, P3Q_ERR_PANIC),
  * catches every Rust panic at the FFI boundary via
    std::panic::catch_unwind so a panic NEVER crosses into C.

build.rs runs cbindgen on every build to regenerate
crates/p3q-c-abi/include/lux/p3q.h so the header stays in lockstep
with src/lib.rs — never edit it by hand.

The verifier body in p3q v0.0.1 is the documented "not yet
audit-gated" stub: any structurally valid proof currently returns
P3Q_ERR_STARK ("verifier body not yet audit-gated"). When the
audited verifier lands in v0.1.0, callers automatically pick up
real verification — no C ABI churn.

Install path:
    /opt/homebrew/lib/libp3q.dylib        (cdylib, install_name set)
    /opt/homebrew/include/lux/p3q.h       (cbindgen-generated)

unsafe_code is allow'd in this one crate because every extern "C" fn
must reconstitute &[u8] from raw pointers. Each unsafe block is
paired with the catch_unwind boundary; the rest of the p3q workspace
keeps the forbid(unsafe_code) lint.

9/9 unit tests pass (cargo test -p p3q-c-abi --release).
2026-05-30 17:18:08 -07:00

32 lines
1.0 KiB
TOML

[package]
name = "p3q-c-abi"
description = "C ABI shim for the P3Q strict-PQ verifier. Exposes `p3q_verify` to non-Rust callers (luxcpp, multichain-cpp, cevm precompiles)."
version.workspace = true
authors.workspace = true
edition.workspace = true
license.workspace = true
repository.workspace = true
homepage.workspace = true
rust-version.workspace = true
keywords = ["zk", "stark", "ffi", "c-abi", "post-quantum"]
categories = ["cryptography", "external-ffi-bindings"]
[lib]
name = "p3q_c_abi"
crate-type = ["cdylib", "staticlib", "rlib"]
[dependencies]
p3q-core = { workspace = true }
p3q-verifier = { workspace = true }
[build-dependencies]
cbindgen = "0.27"
# The C ABI shim is the ONE place in the workspace where `unsafe` is
# unavoidable: every `extern "C" fn` receives raw `*const u8` pointers
# that must be reconstituted into `&[u8]`. Each unsafe block is paired
# with an explicit panic-catching boundary so a Rust panic NEVER
# crosses the FFI boundary.
[lints.rust]
unsafe_code = "allow"