#system #verification

machine-check

Formal verification tool for digital systems

20 releases

new 0.4.0-alpha.9 Mar 30, 2025
0.4.0-alpha.8 Mar 29, 2025
0.3.1 Oct 9, 2024
0.3.0 Aug 26, 2024
0.1.0-alpha.3 Oct 16, 2023

#165 in Operating systems

Download history 60/week @ 2024-12-08 1/week @ 2024-12-15 3/week @ 2025-02-02 3/week @ 2025-02-09 7/week @ 2025-02-16 47/week @ 2025-03-16 642/week @ 2025-03-23

689 downloads per month
Used in machine-check-avr

MIT/Apache

41KB
654 lines

Machine-check: a formal verification tool for digital systems

Machine-check is a formal verification tool usable for e.g. machine-code or hardware verification.

Unlike classic software testing, which can find bugs but not prove their absence, formal verification can prove that specified undesirable behaviours can never occur in the system. While formal verification requires complicated reasoning, machine-check can verify arbitrary systems described as finite-state machines automatically.

The main intended use-case of machine-check is formal verification of machine-code programs on microcontrollers. However, the approach is general and allows verification of arbitrary digital systems as long as they are described in a subset of valid Rust code that machine-check understands.

A Quick Example

The magic of machine-check is unlocked by the machine_description macro, which adds verification analogues to the code it is applied to. You can then run machine-check from your own crate by constructing the system and providing it to the function [run].

A very simple example of a system verifiable by machine-check is counter, a simple finite-state machine which contains an eight-bit state field value, which is initialized to zero and then is incremented in each step exactly if the single-bit input increment is set (1). If the value reaches 157, it is immediately zeroed. The system is very simple, so it is complicated a little by a large unused bitvector array, which would make simple kinds of automated formal verification impossible.

To try things out, create a new package:

$ cargo new my-example --bin
    Creating binary (application) `my-example` package
    (...)
$ cd my-example

Copy the source code of counter to src/main and add machine-check as a dependency to Cargo.toml:

[dependencies]
machine-check = "0.4.0"

You can then verify that the counter is lesser than 157 in every reachable system state, using a specification property based on Computation Tree Logic:

$ cargo run --release -- --property 'AG![as_unsigned(value) < 157]'
   Compiling autocfg v1.1.0
   (...)
   Compiling machine-check v0.4.0
   Compiling my-example v0.1.0 ({your_path}\my-example)
    Finished `release` profile [optimized] target(s) in 21.49s
     Running `target\release\my-example.exe --property "AG![as_unsigned(value) < 157]"`
[2025-03-29T23:51:38Z INFO  machine_check] Starting verification.
[2025-03-29T23:51:38Z INFO  machine_check::verify] Verifying the inherent property first.
[2025-03-29T23:51:38Z INFO  machine_check::verify] The inherent property holds, proceeding to the given property.
[2025-03-29T23:51:38Z INFO  machine_check::verify] Verifying the given property.
[2025-03-29T23:51:39Z INFO  machine_check] Verification ended.
+--------------------------------+
|         Result: HOLDS          |
+--------------------------------+
|  Refinements:             157  |
|  Generated states:        471  |
|  Final states:            157  |
|  Generated transitions:   628  |
|  Final transitions:       315  |
+--------------------------------+

We were able to determine that the counter is lesser than 157 in every reachable state using machine-check. We can also be informed that the value is NOT lesser than 156 in every reachable state:

$ cargo run --release -- --property 'AG![as_unsigned(value) < 156]'
    Finished `release` profile [optimized] target(s) in 0.15s
     Running `target\release\my-example.exe --property "AG![as_unsigned(value) < 156]"`
[2025-03-29T23:54:17Z INFO  machine_check] Starting verification.
[2025-03-29T23:54:17Z INFO  machine_check::verify] Verifying the inherent property first.
[2025-03-29T23:54:17Z INFO  machine_check::verify] The inherent property holds, proceeding to the given property.
[2025-03-29T23:54:17Z INFO  machine_check::verify] Verifying the given property.
[2025-03-29T23:54:18Z INFO  machine_check] Verification ended.
+--------------------------------+
|     Result: DOES NOT HOLD      |
+--------------------------------+
|  Refinements:             156  |
|  Generated states:        470  |
|  Final states:            161  |
|  Generated transitions:   626  |
|  Final transitions:       318  |
+--------------------------------+

See the website and user guide for more information.

Machine-code verification

The crate machine-check-avr includes a system description of the AVR ATmega328P microcontroller (notably used in Arduino Uno R3), allowing verification of simple machine-code programs. More systems may come later.

Current status

Machine-check is still in developmental phase, with limitations in user experience and verification power. There may (and probably will be) some bugs or design oversights. Bug reports to the repository are very welcome.

Changelog

  • 0.4.0: An initial version of a Graphical User Interface, a monotonicity fix, tweaks to the verification core including no longer short-circuiting state generation on panic when verifying the inherent property.
  • 0.3.1: Each refinement continues until the state space changes. This improves performance a bit in some scenarios.
  • 0.3.0: Soundness fixes, optimisation, refinement choice tweaks for reasonable verification of machine-code systems.
  • 0.2.0: A significant rewrite, arbitrary finite-state systems now can be described as finite-state machines in Rust code. Conditional branches are supported.
  • 0.1.0: Initial version, only verification of Btor2 hardware systems supported through translation to Rust code.

License

Licensed under either of Apache License, Version 2.0 or MIT license at your option. Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this crate by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Dependencies

~8–53MB
~696K SLoC