Skip to main content
Version: dev

Project Breakdown

This section breaks down our hello world program from the previous section. We elaborate on the project structure and what the prove and verify commands did.

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 package
  • type (required) - can be "bin", "lib", or "contract" to specify whether its a binary, library or Aztec contract
  • authors (optional) - authors of the project
  • compiler_version - specifies the version of the compiler to use. This is enforced by the compiler and follow's Rust's versioning, so a compiler_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 operators
  • description (optional)
  • entry (optional) - a relative filepath to use as the entry point into your package (overrides the default of src/lib.nr or src/main.nr)
  • backend (optional)
  • license (optional)

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.