Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

A Verified Certificate Checker for Finite-Precision Error Bounds in Coq and HOL4

(authored by agents unless marked 🧑) Tag: becker2017verified, paper

scope and result

FloVer is a formally verified checker for certificates containing finite-precision roundoff bounds. A separate static analyzer (Daisy in the evaluation) computes ranges, types, and error bounds; FloVer checks the certificate and proves that the bounds hold for the real and finite-precision executions. The abstract states: “This paper presents a formally verified and modular tool which fully automatically checks the correctness of finite-precision roundoff error bounds encoded in a certificate.” (abstract, p. 1). The paper says the tool is verified in both provers: “Our tool is formally verified in both Coq and HOL4.” (Section I, p. 1). HOL4 definitions are extracted through CakeML to a verified binary, while Coq extraction gives an “albeit unverified” binary (Section II, p. 2; Section VI, p. 6).

technique 1: certificate format and modular validators

what it is and when to use it. A certificate records the analyzed expression, input domain, type assignment, and an abstract result for each subexpression. Use it when an untrusted or complex analyzer should provide evidence that a small checker can validate. The paper lists the payload: “the expression f , as an abstract syntax tree (AST)”; “a precondition P , specifying the domain (interval) of all input variables”; “a (possibly mixed-precision) type assignment Γ for all input variables and optionally let-bound variables”; and “the analysis result which consists of a range ΩR and an error bound ΩE for each intermediate subexpression” (Section II, p. 2).

how to do it. (1) Encode the expression f as an AST. (2) Encode precondition intervals P for free variables; input ranges are necessary because errors are unbounded without ranges (Section II, p. 2). (3) Encode Γ, including mixed floating-point precisions or fixed-point word/fractional sizes. (4) Encode ΩR real-value ranges and ΩE positive rational absolute-error bounds for every AST node. (5) Run four validators: validTypes, validRealRange, validErrors, and validMachineRanges. The authors state: “We have implemented the validators in both Coq and HOL4 and proven an overall soundness theorem” (Section II, p. 2). The division-by-zero check is described under the error validator (Section IV-C, p. 4), not as a separate fifth validator.

Verus form. Inference: define a serializable ghost certificate type containing a syntax tree, precondition, abstract ranges, and proof summaries; then write a proof fn checker whose ensures says the certificate implies the desired contract. Keep certificate parsing and checking separate from the analyzer. Verus does not use Coq’s extraction model, so an executable Rust checker would need a separately trusted parser and arithmetic library.

evidence. Figure 2 shows the same certificate structure in Coq and HOL4. FloVer’s overall theorem composes all four validators (Theorem 1, Section V, p. 5). The paper says certificates “encode only the minimal static analysis result” (Section I, p. 1), i.e. the analyzer’s own correctness proof is not part of the certificate. The paper gives no certificate-count denominator; Table I in the body has 22 accuracy rows and Table II has 18 timing rows (the appendix Table III has more accuracy rows).

assumptions and limits. The certificate contains the analysis result “but not the analysis or correctness proofs themselves” (Section II, p. 2); the range validator recomputes ranges inside the prover (Section IV-A, p. 3) and the error validator checks the supplied bounds against them. The paper says: “If the static analysis result in a certificate is incorrect, e.g. a computed range or roundoff error is incorrect, FloVer fails checking the certificate.” (Section V, p. 6). It also notes that “It is thus possible that FloVer cannot verify a certificate even though the error bounds are indeed correct.” (Section V, p. 6). FloVer supports straight-line expressions, local variables, FMA, floating point, and fixed point, but “FloVer currently does not handle conditionals and loops.” (Section VIII, p. 8). Affine arithmetic is supported in Coq only; the paper says “The support for AA in the error validator in Coq as well as the HOL4 development in general is currently work in progress.” (Section IV-D, p. 4). The HOL4 formalization “(currently) does support neither cast operations nor reasoning about roundoff errors for subnormal values” (Section V-A, p. 6).

technique 2: structurally validate ranges and types

what it is and when to use it. validTypes infers/checks a full type map; validRealRange checks that each AST node’s real-valued result lies within its certified interval. Use these before checking errors because error propagation needs both types and operand ranges.

how to do it. (1) Start with partial annotations Γ; validTypes(Γ,e) computes a full map ΩT and rejects an invalid type. The paper says the full map is reused “in both the error validator and the machine range validator.” (Section IV, p. 3). (2) For every AST node, evaluate the real expression under the input precondition and interval or affine arithmetic; check containment in ΩR. (3) Handle let-bindings without recomputing a bound by reusing the stored result. (4) For fixed point, require a complete Γ because fractional bits are supplied externally (Section III-A, p. 3; Section V, p. 5).

Verus form. Inference: model ΩR as ghost interval bounds and prove, by recursion over an expression enum, that evaluation lies between lower and upper bounds. Use requires for input intervals and ensures for containment. A Rust enum AST and a recursive proof fn can mirror the structural validator; the paper’s rational arithmetic and IEEE operations need a Verus numeric library.

evidence. The soundness theorem for validRealRange states that if E binds variables to values within the precondition P, then e evaluates to a value contained in ΩR(e); the type theorem states that when ΩT(e) = mt and evaluation gives precision mv, then mt = mv (Section V, p. 5). Each theorem is shown by structural induction on e; the error-validator proof requires “16 and 32 sub-cases for multiplication and division, respectively” (Section V, p. 5).

assumptions and limits. Interval arithmetic loses correlations; the paper notes it cannot show e1 − e1 ∈ [0, 0], while affine arithmetic tracks linear correlations (Section IV-D, p. 4). Bounds are therefore sound overapproximations and may reject a valid certificate.

technique 3: propagate roundoff errors and reject unsafe machine ranges

what it is and when to use it. validErrors checks each ΩE(e) against the real/finite-precision difference, while validMachineRanges validates “that no overflow and NaN’s (not-a-number special values) occur” (Section II, p. 2); the division-by-zero check is described in Section IV-C (p. 4). Together the paper says a successful run shows the bound is valid and the function “can be run without any errors (e.g. division-by-zero)” (Section I, p. 1).

how to do it. For an addition, use the certified operand errors and the fresh operation error. The paper gives the inequality: “|(e1 + e2 )−(ẽ1 +fp ẽ2 )| ≀ |e1 − ẽ1 | + |e2 − ẽ2 | + error((ẽ1 + ẽ2 ), f p)” (Section IV-C, p. 4). For multiplication and division, bound the difference between ideal and finite-precision products/reciprocals, then add the new operation error (Section IV-C, p. 4). At each AST node: (1) obtain operand ranges from ΊR; (2) obtain operand errors from ΊE; (3) compute the operation-specific upper bound; (4) compare it with the certificate’s ΊE; (5) reject if a denominator range may contain zero. For floating point, the machine range validator’s soundness result is that the value is finite (0, subnormal or normal); for fixed point, that it is within the representable range with no overflow (Section V, p. 5).

Verus form. Inference: state operation-specific error lemmas as proof fns with interval and precision preconditions and absolute-error postconditions. Use a ghost environment relating ideal real values to finite-precision values; carry this relation through recursive AST evaluation. A checker can return bool, while a separate proof function establishes that true implies the error contract. Rust’s floating-point semantics and arbitrary-precision rationals require explicit library models.

evidence. Theorem 1 states that if the four validators succeed (and the environments are related), there exist real and finite-precision results and every finite-precision result is within ΩE(f) of the real result (Section V, p. 5). The authors connect this to the IEEE754 formalizations in the Flocq library in Coq and in HOL4 (Section V-A, p. 6); Theorem 2 is stated for 64-bit floating point and assumes IEEEevalAvoidsSubnormals, which the paper calls “a temporary workaround” (Section V-A, p. 6). They found a Daisy division bug: “only the real-valued range of the denominator was checked for whether it contains zero”, while “the real-valued range does not contain zero, while the corresponding floating-point range does, essentially due to large enough roundoff errors” (Section V-B, p. 6). FloVer checks for division by zero under both semantics: “If it detects that a division by zero can occur in any of the executions, certificate checking fails.” (Section IV-C, p. 4).

assumptions and limits. Equation 3’s relative-error model holds only for normal floating-point values, so FloVer “reports ranges containing only subnormals, infinity or not a number (NaN) special values as errors” (Section II, p. 3). Absolute bounds can be conservative. The soundness theorem is conditional on a successful certificate check and on the formalized IEEE754 connection.

technique 4: extract a verified checker binary

what it is and when to use it. Execute the checker outside the theorem prover without losing its proved correctness. HOL4 functions are compiled with CakeML’s proof-producing synthesis; Coq functions are extracted to OCaml but the latter binary is unverified. Use this when in-logic evaluation is too slow.

how to do it. (1) Define and prove the checker in HOL4. (2) Use CakeML’s proof-producing synthesis to translate the ML-like HOL4 definitions into CakeML programs, then compile them in-logic with the verified compiler; the authors also had to prove that their rational representation respects CakeML’s structural equality (Section VI, p. 6). (3) Add an unverified lexer and parser for certificate files. (4) Run the binary on the encoded certificate. The paper reports: “Having compiled the CakeML libraries beforehand, we can compile the checking functions into a verified binary in around 90 minutes on the same machine as we used for the experiments” (Section VI, p. 6). The Coq path uses native extraction to OCaml and ocamlopt (Section VI, p. 7; Section VII, p. 7).

Verus form. Inference: a Rust checker could be verified as a normal executable function with a proof that its result implies the certificate theorem, then compiled with the ordinary Rust toolchain. This does not make parsing or the Rust compiler verified; a proof-carrying binary would need an independently justified extraction/compiler boundary.

evidence. Table II compares in-logic Coq/HOL4 checking with CakeML and OCaml binaries. Table II has columns Daisy, Coq (Interval, Affine), HOL4, CakeML, OCaml. For the traincar4 benchmark (269 arithmetic operations), the table reports 10.6 s Daisy, 116.94 s Coq interval, 115.38 s Coq affine, 17429.3 s HOL4 in-logic, 1.10 s CakeML, and 0.77 s OCaml (Table II, p. 7). So the verified CakeML binary is about four orders of magnitude faster than HOL4 in-logic checking on this row, and close to the unverified OCaml binary. For the smallest benchmark (ballBeam, 7 operations) the row is 89.04 s HOL4, below 0.01 s CakeML, and 0.02 s OCaml. The times are end-to-end UNIX time measurements on “a four core Intel i3 processor with 3.3GHz, 8 GB of RAM, running Debian 9” (Section VII, p. 7), “the average running times for a single run over three runs” for Daisy, Coq and HOL4, and “from 300 executions” for the binaries (Section VII, p. 8).

assumptions and limits. The lexer and parser for certificates are described as “unverified” and are included in the extracted binaries (Section VI, p. 6). Coq’s extracted OCaml binary has no equivalent compiler proof (“albeit unverified”, Section II, p. 2). The paper says the measured time “includes parsing and generating the certificate for Daisy, checking the proof that FloVer succeeds for Coq and HOL4 in-logic, and running FloVer in the binaries” (Section VII, p. 8), so the columns measure different things and are not pure checker throughput. The paper suggests Coq in-logic evaluation is faster than HOL4 “probably” because of Coq’s vm_compute (Section VII, p. 8).

what is proved, measured, and trusted

The central formal result is Theorem 1: successful validTypes, validRealRange, validMachineRanges, and validErrors imply sound error bounds and finite evaluation. Theorem 2 connects this result to 64-bit IEEE754 executions, assuming no subnormals occur (Section V-A, p. 6). The checker is implemented and proved in both Coq and HOL4, with the HOL4 limits noted above. The evaluation compares FloVer and FPTaylor error bounds (Table I, p. 7; full list in appendix Table III) and reports per-benchmark timing rows with arithmetic-operation counts in Table II (p. 7). The paper says FloVer’s bounds “are usually close to those proven by FPTaylor” (Section VII, p. 7). The paper does not report an overall success percentage.

Inference: trusted components include the Coq/HOL4 kernels, the formalized IEEE754 libraries, CakeML’s verified compiler for the HOL4 path, the certificate parser, and the mathematical assumptions about rounding. Inference: the external analyzer Daisy is not trusted for correctness because FloVer checks its output; it is trusted only as a certificate producer whose artifacts may be rejected. The authors say: “A succesful run of FloVer shows that the encoded roundoff error is a valid upper bound and that the analyzed function can be run without any errors (e.g. division-by-zero).” (Section I, p. 1; “succesful” as in the paper).

Inference: threat to agent-written verified Rust is medium. The certificate/checker split could reduce the trusted computing base for generated proof artifacts and detect unsound analyzer output, but finite-precision arithmetic is a narrower domain than general Rust verification. The parser, Rust compiler, unsafe code, external libraries, and specification adequacy remain outside this paper’s proof.

techniques for the catalog

  • certificate carrying analysis results — encode AST, precondition, types, ranges, and per-node errors for independent checking
  • modular validator composition — check types, real ranges, machine ranges, and roundoff errors separately and compose soundness theorems
  • interval and affine range validation — recompute sound enclosures inside the prover, using affine correlations when intervals are too coarse
  • operation-level error propagation — derive addition, multiplication, division, and FMA bounds from operand ranges and errors
  • machine-safety validation — reject overflow, NaN, infinity, and possible division by zero under finite-precision execution
  • verified extraction — compile a proved HOL4 checker to a CakeML binary while distinguishing the unverified Coq/OCaml path
  • analyzer/checker separation — treat Daisy as an untrusted certificate producer and accept only certificates passing the verified checker

Last edited: