Project Breakdown
This section breaks down our hello world program from the previous section.
Anatomy of a Nargo Project
Upon creating a new project with nargo new
and building the in/output files with nargo check
commands, you would get a minimal Nargo project of the following structure:
- src
- Prover.toml
- Nargo.toml
The source directory src holds the source code for your Noir program. By default only a main.nr file will be generated within it.
Prover.toml
Prover.toml is used for specifying the input values for executing and proving the program. You can specify toml
files with different names by using the --prover-name
or -p
flags, see the Prover section below. Optionally you may specify expected output values for prove-time checking as well.
Nargo.toml
Nargo.toml contains the environmental options of your project. It contains a "package" section and a "dependencies" section.
Example Nargo.toml:
[package]
name = "noir_starter"
type = "bin"
authors = ["Alice"]
compiler_version = "0.9.0"
description = "Getting started with Noir"
entry = "circuit/main.nr"
license = "MIT"
[dependencies]
ecrecover = {tag = "v0.9.0", git = "https://github.com/colinnielsen/ecrecover-noir.git"}
Nargo.toml for a workspace will look a bit different. For example:
[workspace]
members = ["crates/a", "crates/b"]
default-member = "crates/a"
Package section
The package section defines a number of fields including:
name
(required) - the name of the packagetype
(required) - can be "bin", "lib", or "contract" to specify whether its a binary, library or Aztec contractauthors
(optional) - authors of the projectcompiler_version
- specifies the version of the compiler to use. This is enforced by the compiler and follow's Rust's versioning, so acompiler_version = 0.18.0
will enforce Nargo version 0.18.0,compiler_version = ^0.18.0
will enforce anything above 0.18.0 but below 0.19.0, etc. For more information, see how Rust handles these operatorsdescription
(optional)entry
(optional) - a relative filepath to use as the entry point into your package (overrides the default ofsrc/lib.nr
orsrc/main.nr
)backend
(optional)license
(optional)expression_width
(optional) - Sets the default backend expression width. This field will override the default backend expression width specified by the Noir compiler (currently set to width 4).
Dependencies section
This is where you will specify any dependencies for your project. See the Dependencies page for more info.
./proofs/
and ./contract/
directories will not be immediately visible until you create a proof or
verifier contract respectively.
main.nr
The main.nr file contains a main
method, this method is the entry point into your Noir program.
In our sample program, main.nr looks like this:
fn main(x : Field, y : Field) {
assert(x != y);
}
The parameters x
and y
can be seen as the API for the program and must be supplied by the prover. Since neither x
nor y
is marked as public, the verifier does not supply any inputs, when verifying the proof.
The prover supplies the values for x
and y
in the Prover.toml file.
As for the program body, assert
ensures that the condition to be satisfied (e.g. x != y
) is constrained by the proof of the execution of said program (i.e. if the condition was not met, the verifier would reject the proof as an invalid proof).
Prover.toml
The Prover.toml file is a file which the prover uses to supply the inputs to the Noir program (both private and public).
In our hello world program the Prover.toml file looks like this:
x = "1"
y = "2"
When the command nargo execute
is executed, nargo will execute the Noir program using the inputs specified in Prover.toml
, aborting if it finds that these do not satisfy the constraints defined by main
. In this example, x
and y
must satisfy the inequality constraint assert(x != y)
.
If an output name is specified such as nargo execute foo
, the witness generated by this execution will be written to ./target/foo.gz
. This can then be used to generate a proof of the execution.
Arrays of Structs
The following code shows how to pass an array of structs to a Noir program to generate a proof.
// main.nr
struct Foo {
bar: Field,
baz: Field,
}
fn main(foos: [Foo; 3]) -> pub Field {
foos[2].bar + foos[2].baz
}
Prover.toml:
[[foos]] # foos[0]
bar = 0
baz = 0
[[foos]] # foos[1]
bar = 0
baz = 0
[[foos]] # foos[2]
bar = 1
baz = 2
Custom toml files
You can specify a toml
file with a different name to use for execution by using the --prover-name
or -p
flags.
This command looks for proof inputs in the default Prover.toml and generates the witness and saves it at ./target/foo.gz
:
nargo execute foo
This command looks for proof inputs in the custom OtherProver.toml and generates the witness and saves it at ./target/bar.gz
:
nargo execute -p OtherProver bar
Now that you understand the concepts, you'll probably want some editor feedback while you are writing more complex code.