A tool for formally verifying your Noir projects.
Formal verification mathematically ensures that your code is correct for all possible inputs. Unlike traditional testing, which checks a limited set of scenarios, formal verification can eliminate entire categories of bugs by proving that your code behaves as expected under all conditions.
Noir's design, which avoids features like pointers, global mutable state, and complex memory management, makes it particularly well-suited for formal verification. This is especially important for the high-stakes world of crypto-economic protocols and smart contracts, where a single bug can have devastating consequences.
To bring formal verification to Noir, we built Verno on top of the Verus verification framework. Verus integrates the powerful Z3 SMT solver, allowing for precise logical reasoning. By compiling Noir to Verus, we've created a proof-of-concept formal verification system that you can use today.
Before you begin, you need to have the Rust programming language and its package manager, Cargo, installed on your system.
We recommend using rustup to install and manage your Rust versions. This project includes a rust-toolchain.toml file, and rustup will automatically download and use the correct Rust toolchain for you.
First, clone the Verno repository from GitHub:
git clone https://github.com/blocksense-network/verno.git
cd vernoYou have two options for setting up the development environment: using Nix or by running the provided shell scripts.
If you have the Nix package manager installed, you can easily set up a development environment by running:
nix developThis command will create a shell with all the necessary dependencies for Verno.
If you don't have Nix, you can set up the environment by running the following shell scripts from the root of the repository:
./get_verus_std.sh
./venir_build.shThese scripts will download and build the required dependencies. Please follow any instructions printed by the scripts.
Once your environment is set up, you can build Verno using Cargo:
cargo buildTo ensure everything is working correctly, run the test suite:
cargo testIf all tests pass, you have successfully installed Verno!
-
Create a new project using
nargoorverno:You can create a new Noir project using
nargo:nargo new my_program
Alternatively, if you have
nargoin your path or have set up theNARGO_PATHenvironment variable, you can usevernoto proxy the command:verno new my_program
-
Navigate to the folder:
cd my_program -
Update
src/main.nrwith your favorite text editor to:#['requires(x < 100 & 0 < y & y < 100)] #['ensures(result >= 5 + x)] fn main(x: u32, y: u32) -> pub u32 { x + y * 5 }
-
Finally, verify the program:
verno formal-verify
Consider the following code:
fn main(x: i32, y:i32, arr: [u32; 5]) -> pub u32 {
let z = arithmetic_magic(x, y);
arr[z]
}
fn arithmetic_magic(x: i32, y: i32) -> i32 {
(x / 2) + (y / 2)
}Attempting to formally verify this code will produce an error because the value of z could fall outside the valid index range for arr.
We can fix this by adding a check to ensure z is within the array bounds:
fn main(x: i32, y:i32, arr: [u32; 5]) -> pub u32 {
let z = arithmetic_magic(x, y);
if (z >= 0) & (z < 5) {
arr[z]
} else {
0
}
}
fn arithmetic_magic(x: i32, y: i32) -> i32 {
(x / 2) + (y / 2)
}This version successfully verifies.
Verno empowers developers to write safer, more reliable Noir programs.
Built with love by the blocksense.network team.