diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..b2f868b --- /dev/null +++ b/.envrc @@ -0,0 +1,20 @@ +# Based on https://github.com/direnv/direnv-vscode/blob/158e8302c2594cc0eaa5f8b4f0cafedd4e1c0315/.envrc + +# You can define your system-specific logic (like Git settings or GH tokens) in .envrc.local +# If that logic is usable by other people and might improve development environment, consider +# contributing it to this file! + +source_env_if_exists .envrc.local + +if [[ -z "${SKIP_NIX:-}" ]] && has nix; then + + if nix flake metadata &>/dev/null && has use_flake; then + # use flakes if possible + use flake + + else + # Otherwise fall back to pure nix + use nix + fi + +fi diff --git a/.gitignore b/.gitignore index e55d771..d447b29 100644 --- a/.gitignore +++ b/.gitignore @@ -5,5 +5,7 @@ # These are backup files generated by rustfmt **/*.rs.bk -# Generated by nix +# Nix stuff result +.envrc.local +.direnv diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..64ae238 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,13 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. + // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp + // List of extensions which should be recommended for users of this workspace. + "recommendations": [ + "mkhl.direnv", + "jnoortheen.nix-ide", + "rust-lang.rust-analyzer", + "redhat.vscode-yaml" + ], + // List of extensions recommended by VS Code that should not be recommended for users of this workspace. + "unwantedRecommendations": [] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..78bfd88 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,16 @@ +{ + "direnv.restart.automatic": true, + "redhat.telemetry.enabled": false, + "yaml.recommendations.show": false, + "nix.serverPath": "nil", + "nix.enableLanguageServer": true, + "nix.serverSettings": { + "nil": { + "formatting": { + "command": [ + "nixpkgs-fmt" + ] + } + } + }, +} diff --git a/README.md b/README.md index 150fa0e..02290fe 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,80 @@ pub fn pedersen() { } ``` -## Nix +## Working on this project -We provide a [Nix Flake](./flake.nix) that shows you how to configure an environment if you're building your Rust code inside Nix. +Due to the large number of native dependencies, this project uses [Nix](https://nixos.org/) and [direnv](https://direnv.net/) to streamline the development experience. + +### Setting up your environment + +For the best experience, please follow these instructions to setup your environment: +1. Install Nix following [their guide](https://nixos.org/download.html) for your operating system +2. Create the file `~/.config/nix/nix.conf` with the contents: +```ini +experimental-features = nix-command +extra-experimental-features = flakes +``` +3. Install direnv into your Nix profile by running: +```sh +nix profile install nixpkgs#direnv +``` +4. Add direnv to your shell following [their guide](https://direnv.net/docs/hook.html) +5. Restart your shell + +### Shell & editor experience + +Now that your environment is set up, you can get to work on the project. + +1. Clone the repository, such as: +```sh +git clone git@github.com:noir-lang/barretenberg-sys +``` +2. Navigate to the directory: +```sh +cd barretenberg-sys +``` +3. You should see a __direnv error__ because projects aren't allowed by default. Make sure you trust our `.envrc` file, then you need to run: +```sh +direnv allow +``` +4. Now, wait awhile for all the native dependencies to be built. This will take some time and direnv will warn you that it is taking a long time, but we just need to let it run. +5. Once you are presented with your prompt again, you can start your editor within the project directory (we recommend [VSCode](https://code.visualstudio.com/)): +```sh +code . +``` +6. (Recommended) When launching VSCode for the first time, you should be prompted to install our recommended plugins. We highly recommend installing these for the best development experience. + +### Building and testing + +Building and testing the project is done through Nix commands. + +To build the project, run `nix build .` (or `nix build . -L` for verbose output). + +To run clippy and all tests in the project, run `nix flake check` (or `nix flake check -L` for verbose output). + +### Building against a different local/remote version of Barretenberg + +If you are working on this crate, it is likely that you want to incorporate changes from some other version of Barretenberg +instead of the version this project is pinned against. + +To reference a different version of Barretenberg, you can add the `--override-input` flag. For example: + +```sh +nix build . --override-input barretenberg /home/phated/barretenberg +``` + +```sh +nix flake check --override-input barretenberg /home/phated/barretenberg +``` + +```sh +nix flake check --override-input barretenberg github:phated/barretenberg/mybranch +``` + +### Without direnv + +If you have hesitations with using `direnv`, you can launch a subshell with `nix develop` and then launch your editor +from within the subshell. + +__Note:__ If you aren't using direnv nor launch your editor within the subshell, your editor won't have the correct environment +variables to find system dependencies and probably won't be able to build the project. diff --git a/build.rs b/build.rs index 157b8aa..2a02744 100644 --- a/build.rs +++ b/build.rs @@ -92,6 +92,8 @@ fn main() -> Result<()> { .allowlist_function("acir_proofs_get_total_circuit_size") .allowlist_function("acir_proofs_init_proving_key") .allowlist_function("acir_proofs_init_verification_key") + .allowlist_function("acir_serialize_verification_key_into_field_elements") + .allowlist_function("acir_serialize_proof_into_field_elements") .allowlist_function("acir_proofs_new_proof") .allowlist_function("acir_proofs_verify_proof") .allowlist_function("pedersen_plookup_compress_fields") diff --git a/cspell.json b/cspell.json index b3d993f..e9ee283 100644 --- a/cspell.json +++ b/cspell.json @@ -13,6 +13,13 @@ "consts", "acir", "schnorr", - "plookup" + "plookup", + "direnv", + "envrc", + "nixpkgs", + "clippy", + "subshell", + "phated", + "mybranch" ] } diff --git a/default.nix b/default.nix new file mode 100644 index 0000000..5b1b23d --- /dev/null +++ b/default.nix @@ -0,0 +1,13 @@ +let + lock = builtins.fromJSON (builtins.readFile ./flake.lock); + flakeCompatRev = lock.nodes.flake-compat.locked.rev; + flakeCompatHash = lock.nodes.flake-compat.locked.narHash; + flakeCompat = fetchTarball { + url = "https://github.com/edolstra/flake-compat/archive/${flakeCompatRev}.tar.gz"; + sha256 = flakeCompatHash; + }; + compat = import flakeCompat { + src = ./.; + }; +in +compat.defaultNix diff --git a/flake.lock b/flake.lock index da35fea..14d92ea 100644 --- a/flake.lock +++ b/flake.lock @@ -25,12 +25,18 @@ }, "crane": { "inputs": { - "flake-compat": "flake-compat", - "flake-utils": "flake-utils", + "flake-compat": [ + "flake-compat" + ], + "flake-utils": [ + "flake-utils" + ], "nixpkgs": [ "nixpkgs" ], - "rust-overlay": "rust-overlay" + "rust-overlay": [ + "rust-overlay" + ] }, "locked": { "lastModified": 1681177078, @@ -63,21 +69,6 @@ } }, "flake-utils": { - "locked": { - "lastModified": 1678901627, - "narHash": "sha256-U02riOqrKKzwjsxc/400XnElV+UtPUQWpANPlyazjH0=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "93a2b84fc4b70d9e089d029deacc3583435c2ed6", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, - "flake-utils_2": { "inputs": { "systems": "systems" }, @@ -115,37 +106,13 @@ "inputs": { "barretenberg": "barretenberg", "crane": "crane", - "flake-utils": "flake-utils_2", + "flake-compat": "flake-compat", + "flake-utils": "flake-utils", "nixpkgs": "nixpkgs", - "rust-overlay": "rust-overlay_2" + "rust-overlay": "rust-overlay" } }, "rust-overlay": { - "inputs": { - "flake-utils": [ - "crane", - "flake-utils" - ], - "nixpkgs": [ - "crane", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1680488274, - "narHash": "sha256-0vYMrZDdokVmPQQXtFpnqA2wEgCCUXf5a3dDuDVshn0=", - "owner": "oxalica", - "repo": "rust-overlay", - "rev": "7ec2ff598a172c6e8584457167575b3a1a5d80d8", - "type": "github" - }, - "original": { - "owner": "oxalica", - "repo": "rust-overlay", - "type": "github" - } - }, - "rust-overlay_2": { "inputs": { "flake-utils": [ "flake-utils" diff --git a/flake.nix b/flake.nix index cfba04f..616cc28 100644 --- a/flake.nix +++ b/flake.nix @@ -2,25 +2,45 @@ description = "Build barretenberg-sys"; inputs = { - nixpkgs.url = "github:NixOS/nixpkgs/nixos-22.11"; + nixpkgs = { + url = "github:NixOS/nixpkgs/nixos-22.11"; + }; - crane = { - url = "github:ipetkov/crane"; - inputs.nixpkgs.follows = "nixpkgs"; + flake-utils = { + url = "github:numtide/flake-utils"; }; - flake-utils.url = "github:numtide/flake-utils"; + flake-compat = { + url = "github:edolstra/flake-compat"; + flake = false; + }; rust-overlay = { url = "github:oxalica/rust-overlay"; + # All of these inputs (a.k.a. dependencies) need to align with inputs we + # use so they use the `inputs.*.follows` syntax to reference our inputs + inputs = { + nixpkgs.follows = "nixpkgs"; + flake-utils.follows = "flake-utils"; + }; + }; + + crane = { + url = "github:ipetkov/crane"; + # All of these inputs (a.k.a. dependencies) need to align with inputs we + # use so they use the `inputs.*.follows` syntax to reference our inputs inputs = { nixpkgs.follows = "nixpkgs"; flake-utils.follows = "flake-utils"; + flake-compat.follows = "flake-compat"; + rust-overlay.follows = "rust-overlay"; }; }; barretenberg = { url = "github:AztecProtocol/barretenberg"; + # All of these inputs (a.k.a. dependencies) need to align with inputs we + # use so they use the `inputs.*.follows` syntax to reference our inputs inputs = { nixpkgs.follows = "nixpkgs"; flake-utils.follows = "flake-utils"; @@ -40,21 +60,28 @@ ]; }; - rustToolchain = pkgs.rust-bin.stable."1.66.0".default; + rustToolchain = pkgs.rust-bin.stable."1.66.0".default.override { + # We include rust-src to ensure rust-analyzer works. + # See https://discourse.nixos.org/t/rust-src-not-found-and-other-misadventures-of-developing-rust-on-nixos/11570/4 + extensions = [ "rust-src" ]; + }; craneLib = (crane.mkLib pkgs).overrideToolchain rustToolchain; environment = { # rust-bindgen needs to know the location of libclang LIBCLANG_PATH = "${pkgs.llvmPackages.libclang.lib}/lib"; - }; - commonArgs = { - pname = "barretenberg-sys"; - # x-release-please-start-version - version = "0.1.1"; - # x-release-please-end + # Barretenberg fails if tests are run on multiple threads, so we set the test thread + # count to 1 throughout the entire project + # + # Note: Setting this allows for consistent behavior across build and shells, but is mostly + # hidden from the developer - i.e. when they see the command being run via `nix flake check` + RUST_TEST_THREADS = "1"; + }; + # Combine the environment and other configuration needed for crane to build our Rust packages + commonArgs = environment // { # As per https://discourse.nixos.org/t/gcc11stdenv-and-clang/17734/7 since it seems that aarch64-linux uses # gcc9 instead of gcc11 for the C++ stdlib, while all other targets we support provide the correct libstdc++ stdenv = with pkgs; @@ -65,6 +92,8 @@ src = craneLib.cleanCargoSource ./.; + # Running checks don't do much more than compiling itself and increase + # the build time by a lot, so we disable them throughout all our flakes doCheck = false; nativeBuildInputs = [ @@ -81,12 +110,17 @@ # Need libiconv on Darwin. See https://github.com/ipetkov/crane/issues/156 pkgs.libiconv ]; - } // environment; + }; # Build *just* the cargo dependencies, so we can reuse all of that work between runs cargoArtifacts = craneLib.buildDepsOnly commonArgs; barretenberg-sys = craneLib.buildPackage (commonArgs // { + pname = "barretenberg-sys"; + # x-release-please-start-version + version = "0.1.1"; + # x-release-please-end + inherit cargoArtifacts; }); in @@ -95,6 +129,7 @@ cargo-clippy = craneLib.cargoClippy (commonArgs // { inherit cargoArtifacts; + # TODO(blaine): It'd be nice to include these flags when running `cargo clippy` in a devShell. cargoClippyExtraArgs = "--all-targets -- -D warnings"; doCheck = true; @@ -103,7 +138,8 @@ cargo-test = craneLib.cargoTest (commonArgs // { inherit cargoArtifacts; - cargoTestExtraArgs = "--workspace -- --test-threads=1"; + # TODO(blaine): It'd be nice to include this flag when running `cargo test` in a devShell. + cargoTestExtraArgs = "--workspace"; doCheck = true; }); @@ -111,24 +147,22 @@ packages.default = barretenberg-sys; - # llvmPackages should be aligned to selection from libbarretenberg - # better if we get rid of llvm targets and override them from input - devShells.default = pkgs.mkShell.override { stdenv = pkgs.llvmPackages.stdenv; } ({ - inputsFrom = builtins.attrValues self.checks; + # Combine the environment settings with the inputs from our checks + # derivations and extra tooling via `nativeBuildInputs` + devShells.default = pkgs.mkShell (environment // { + inputsFrom = builtins.attrValues checks; - buildInputs = packages.default.buildInputs; - nativeBuildInputs = with pkgs; packages.default.nativeBuildInputs ++ [ + nativeBuildInputs = with pkgs; [ which starship git - cargo - rustc + nil + nixpkgs-fmt ]; shellHook = '' eval "$(starship init bash)" ''; - - } // environment); + }); }); } diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..b72d4a4 --- /dev/null +++ b/shell.nix @@ -0,0 +1,13 @@ +let + lock = builtins.fromJSON (builtins.readFile ./flake.lock); + flakeCompatRev = lock.nodes.flake-compat.locked.rev; + flakeCompatHash = lock.nodes.flake-compat.locked.narHash; + flakeCompat = fetchTarball { + url = "https://github.com/edolstra/flake-compat/archive/${flakeCompatRev}.tar.gz"; + sha256 = flakeCompatHash; + }; + compat = import flakeCompat { + src = ./.; + }; +in +compat.shellNix diff --git a/src/composer.rs b/src/composer.rs index 3906744..f2678f6 100644 --- a/src/composer.rs +++ b/src/composer.rs @@ -48,6 +48,32 @@ pub unsafe fn init_verification_key( ) } +pub unsafe fn serialize_verification_key_into_field_elements( + g2_ptr: &[u8], + vk_buf: &[u8], + serialized_vk_buf: *mut *mut u8, + serialized_vk_hash_buf: *mut *mut u8, +) -> usize { + acir_serialize_verification_key_into_field_elements( + g2_ptr.as_ptr() as *const u8, + vk_buf.as_ptr() as *const u8, + serialized_vk_buf as *const *mut u8 as *mut *mut u8, + serialized_vk_hash_buf as *const *mut u8 as *mut *mut u8, + ) +} + +pub unsafe fn serialize_proof_into_field_elements( + proof: &[u8], + serialized_proof_data_buf: *mut *mut u8, + proof_data_length: usize, +) -> usize { + acir_serialize_proof_into_field_elements( + proof.as_ptr() as *const u8, + serialized_proof_data_buf, + proof_data_length, + ) +} + /// # Safety /// pippenger must point to a valid Pippenger object pub unsafe fn create_proof_with_pk( @@ -57,6 +83,7 @@ pub unsafe fn create_proof_with_pk( cs_ptr: &[u8], witness_ptr: &[u8], proof_data_ptr: *mut *mut u8, + is_recursive: bool, ) -> usize { let cs_ptr = cs_ptr.as_ptr() as *const u8; let pk_ptr = pk_ptr.as_ptr() as *const u8; @@ -67,12 +94,19 @@ pub unsafe fn create_proof_with_pk( cs_ptr, witness_ptr.as_ptr(), proof_data_ptr as *const *mut u8 as *mut *mut u8, + is_recursive, ) } /// # Safety /// cs_prt must point to a valid constraints system structure of type standard_format -pub unsafe fn verify_with_vk(g2_ptr: &[u8], vk_ptr: &[u8], cs_ptr: &[u8], proof: &[u8]) -> bool { +pub unsafe fn verify_with_vk( + g2_ptr: &[u8], + vk_ptr: &[u8], + cs_ptr: &[u8], + proof: &[u8], + is_recursive: bool, +) -> bool { let proof_ptr = proof.as_ptr() as *const u8; acir_proofs_verify_proof( @@ -81,5 +115,6 @@ pub unsafe fn verify_with_vk(g2_ptr: &[u8], vk_ptr: &[u8], cs_ptr: &[u8], proof: cs_ptr.as_ptr() as *const u8, proof_ptr as *mut u8, proof.len() as u32, + is_recursive, ) }